Wallet SystemWallet System
Buy Now
View Demo
  • Getting Started

    • Introduction
    • Quick Start
    • Features
    • Installation
    • First-Time Setup
    • Admin Tour
  • Wallet Core

    • Core Wallet
    • Wallet Payment Gateway
    • Recharge / Top-up
    • Wallet Transfer
    • My Wallet Page
    • Shortcodes
  • Earn & Reward

    • Cashback Engine
    • Referral Program
    • Multilevel Referral
    • Daily Login Reward
    • Invite Friends
    • Deposit / Top-up Bonus
  • Spend & Payout

    • Checkout Discount
    • Checkout Restriction
    • Withdrawal
    • PayPal Payout
    • Stripe Payout
    • Refund to Wallet
    • Buy Now Pay Later
  • Identity & Mobile

    • KYC
    • QR Code Payments
  • Wallet Central

    • Overview
    • Endpoint & Routing
    • CTA Discovery
    • Home Dashboard
    • Add Funds
    • Withdraw
    • Withdrawals List
    • Send Money
    • QR Pay
    • Payment Requests
    • Refer & Earn
    • Transactions
    • Settings
    • KYC Flow
    • Architecture
    • Tweaks & Responsive
    • Security
    • Admin Controls
  • Admin Tools

    • Admin Settings (index)
    • Bulk Credit / Debit
    • Analytics Dashboard
  • Settings Tabs

    • General
    • Recharge
    • Checkout
    • Withdrawal
    • Payout (PayPal/Stripe)
    • KYC
    • Cashback
    • Referral
    • Multilevel
    • BNPL
    • QR Pay
    • Notifications
    • Wallet Central
    • Integrations
    • API Keys
  • Notifications

    • Email Notifications
    • SMS Notifications
  • Developer

    • REST API
    • Filters & Hooks
  • Help

    • Troubleshooting
    • FAQ
    • Glossary
Support
Buy Now
View Demo
  • Getting Started

    • Introduction
    • Quick Start
    • Features
    • Installation
    • First-Time Setup
    • Admin Tour
  • Wallet Core

    • Core Wallet
    • Wallet Payment Gateway
    • Recharge / Top-up
    • Wallet Transfer
    • My Wallet Page
    • Shortcodes
  • Earn & Reward

    • Cashback Engine
    • Referral Program
    • Multilevel Referral
    • Daily Login Reward
    • Invite Friends
    • Deposit / Top-up Bonus
  • Spend & Payout

    • Checkout Discount
    • Checkout Restriction
    • Withdrawal
    • PayPal Payout
    • Stripe Payout
    • Refund to Wallet
    • Buy Now Pay Later
  • Identity & Mobile

    • KYC
    • QR Code Payments
  • Wallet Central

    • Overview
    • Endpoint & Routing
    • CTA Discovery
    • Home Dashboard
    • Add Funds
    • Withdraw
    • Withdrawals List
    • Send Money
    • QR Pay
    • Payment Requests
    • Refer & Earn
    • Transactions
    • Settings
    • KYC Flow
    • Architecture
    • Tweaks & Responsive
    • Security
    • Admin Controls
  • Admin Tools

    • Admin Settings (index)
    • Bulk Credit / Debit
    • Analytics Dashboard
  • Settings Tabs

    • General
    • Recharge
    • Checkout
    • Withdrawal
    • Payout (PayPal/Stripe)
    • KYC
    • Cashback
    • Referral
    • Multilevel
    • BNPL
    • QR Pay
    • Notifications
    • Wallet Central
    • Integrations
    • API Keys
  • Notifications

    • Email Notifications
    • SMS Notifications
  • Developer

    • REST API
    • Filters & Hooks
  • Help

    • Troubleshooting
    • FAQ
    • Glossary
Support
  • Getting Started

    • Introduction
    • Quick Start — Wallet Live in 5 Minutes
    • Features
    • Installation
    • First-Time Setup
    • Admin Tour
  • Wallet Core

    • Core Wallet
    • Wallet Payment Gateway
    • Recharge / Top-up
    • Wallet Transfer
    • My Wallet Page
    • Shortcodes
  • Earn & Reward

    • Cashback Engine
    • Referral Program
    • Multilevel Referral
    • Daily Login Reward
    • Invite Friends
    • Deposit / Top-up Bonus
  • Spend & Payout

    • Checkout Discount
    • Checkout Restriction
    • Withdrawal
    • PayPal Payout
    • Stripe Payout
    • Refund to Wallet
    • Buy Now Pay Later (BNPL)
  • Identity & Mobile

    • KYC (Know Your Customer)
    • QR Code Payments
  • Wallet Central

    • Wallet Central Overview
    • Endpoint & Routing
    • CTA Discovery
    • Home Dashboard
    • Add Funds
    • Withdraw
    • Withdrawals List + Detail
    • Send Money
    • QR Pay
    • Payment Requests
    • Refer & Earn
    • Transactions
    • Settings (customer)
    • KYC Flow
    • Architecture
    • Tweaks & Responsive
    • Security
    • Admin Controls
  • Admin Tools

    • Admin Settings
    • Bulk Credit / Debit
    • Analytics Dashboard
  • Settings Tabs

    • General Settings
    • Recharge Settings
    • Checkout Settings
    • Withdrawal Settings
    • Payout Settings (PayPal + Stripe)
    • KYC Settings
    • Cashback Settings
    • Referral Settings
    • Multilevel Settings
    • BNPL Settings
    • QR Pay Settings
    • Notifications Settings
    • Wallet Central Settings
    • Third-Party Integrations
    • API Keys
  • Notifications

    • Email Notifications
    • SMS Notifications
  • Developer

    • REST API
    • Filters & Hooks
  • Help

    • Troubleshooting
    • FAQ
    • Glossary

Security

Developer + security-audit reference

This page documents the auth / nonce / rate-limit / CSP model. Useful for security audits and custom code that touches Wallet Central. Admins and store owners can skip — defaults are safe out of the box.

Wallet Central is a money UI. Every input + every endpoint hardened.

Auth Gate

WKWP_Central_Endpoint::maybe_render runs template_redirect priority 1. If is_user_logged_in() === false:

wp_safe_redirect(
    add_query_arg(
        'redirect_to',
        rawurlencode( $current_url ),
        wp_login_url()
    )
);
exit;

No content rendered. No PHP runs further. Anonymous visitors never see Wallet Central HTML.

Nonce Protection

Every form + every AJAX action carries a WordPress nonce.

SurfaceNonce field / header
Forms (Withdraw, Send, Add Funds, KYC)<input type="hidden" name="<action>_nonce" value="<wp_create_nonce>">
AJAX (Settings save, recipient search, OTP request, QR resolve, QR pay)X-WP-Nonce header
REST (/wp-json/wkwc_wallet/v1/verify_otp/{otp})X-WP-Nonce header

Nonce TTL: 24h (WP default). Stale → server returns 403 invalid_nonce.

Action Allowlist

WKWP_Central_Settings_Ajax::handle rejects any meta key not in the allowlist:

const ALLOWED_KEYS = [
    '_wkwp_auto_topup_enabled',
    '_wkwp_auto_topup_threshold',
    '_wkwp_auto_topup_amount',
    '_wkwp_notify_credit_email',
    '_wkwp_notify_debit_email',
    '_wkwp_notify_low_balance_email',
    '_wkwp_notify_transfer_received_sms',
    '_wkwp_notify_withdrawal_paid_sms',
    '_wkwp_notify_kyc_email',
    '_wkwp_transfer_locked',
];

Unknown key → 400 invalid_key. Stops customers from writing arbitrary user meta via the settings AJAX.

Per-Key Validation

Even allowlisted keys validate values:

KeyRule
_wkwp_auto_topup_thresholdnumeric, ≥ 0, ≤ wallet_settings.max_credit
_wkwp_auto_topup_amountnumeric, > 0
_wkwp_*_email / _wkwp_*_sms0 / 1
_wkwp_transfer_locked0 / 1

Rules registered via wkwp_central_settings_save_validate filter — extensible.

KYC Server-Side Enforcement

UI gates are belt-and-braces. Authoritative gates run server-side regardless of UI:

EnforcerHookScope
WKWP_Wallet_Withdrawal_KYC_Guardwp_loaded priority 5rejects withdrawal POSTs
WKWP_Wallet_Transfer::check_user_kyc_accesscalled from AJAX handlerrejects transfer attempts
WKWP_QR_Pay::handle_paycalled from AJAX handlerrejects QR pay attempts
wkwc_wallet_show_method_on_checkout filtergateway visibilityhides wallet from checkout

Means: even a manually-crafted curl request bypassing the UI hits the server-side check and gets rejected.

CSRF

WordPress nonces are CSRF tokens. They're tied to:

  • Action name (e.g. wkwp_central_settings_save)
  • User ID
  • Session

Stolen URL or replayed POST from another origin will not match — wp_verify_nonce returns false → 403.

Idempotency

State-changing operations are idempotent where possible:

OperationIdempotency mechanism
Recharge order completes_wkwp_topup_credited = yes order meta — repeat woocommerce_order_status_completed no-ops
Cashback rule fires_wkwp_cashback_processed = yes
Top-up bonus_wkwp_bonus_credited = yes
Bulk credit rowUNIQUE on client_dedupe_key
Transfer OTPconsumed_at flag — verify-once
Referral payoutwallet_referrals.reward_amount > 0 lock
BNPL repayatomic update inside DB transaction

Means duplicate requests (network retry, double-click) never cause double-credit.

Rate Limiting

SurfaceLimit
Wallet Central pageviewnone (per-user pages, no abuse vector)
Settings AJAX60 requests / minute per user
Recipient search AJAX30 / minute
OTP request5 / minute per user (rolling)
OTP verify10 / minute per user
QR pay AJAX10 / minute per user
REST verify_otp60 / minute per IP

Exceeded → 429 too_many_requests with Retry-After header.

Tunable via filter wkwp_central_rate_limit_<scope>.

Headers

WKWP_Central_Endpoint::send_headers writes:

Content-Type: text/html; charset=UTF-8
Cache-Control: no-store, no-cache, must-revalidate, max-age=0
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: same-origin

Wallet Central never embeds in iframes from other origins. Never gets cached at HTTP layer. Never sniffed for MIME confusion.

Content Security Policy

Strict CSP recommended. Default policy works:

Content-Security-Policy:
  default-src 'self';
  script-src  'self' 'unsafe-inline';
  style-src   'self' 'unsafe-inline';
  img-src     'self' data: https://secure.gravatar.com;
  connect-src 'self';
  font-src    'self' data:;
  frame-ancestors 'self';

'unsafe-inline' is unfortunately needed for inline event handlers in the legacy submodule embeds. Future versions may move to nonce-based inline scripts.

File Upload Hardening (KYC)

LayerCheck
MIME whitelistonly image/jpeg, image/png, image/webp, application/pdf
Size cap5 MB per file (configurable)
Filename sanitisationsanitize_file_name()
Storage outside public dirwp-content/uploads/wallet-kyc/<user_id>/ with .htaccess deny-all
Image proxy with capability checkdirect URL access blocked
EXIF strip on JPEGoptional via wkwp_kyc_strip_exif filter

SQL Injection

Every DB query uses $wpdb->prepare. No raw string interpolation. Tested under WP_DEBUG.

XSS

Every render path uses one of:

  • esc_html()
  • esc_attr()
  • esc_url()
  • wp_kses_post() (for admin-controlled rich text only)

Customer-typed values (notes, full names) never rendered without escaping.

Authentication Bypass via REST API Keys

REST keys (Basic Auth consumer_key:consumer_secret) honoured only on the /wp-json/wkwp-wallet/v1/* namespace. The customer-facing AJAX surface (wp_ajax_wkwp_central_*) requires cookie auth — REST keys not accepted.

Audit Logging

State changes write rows to wkwc_wallet_transactions. Reference column carries the audit tag (bulk:<batch_id>:row:<id>, transfer:#<request_id>, withdrawal:#<row_id>).

For higher audit needs, hook wkwp_wallet_balance_changed to mirror to a SIEM:

add_action( 'wkwp_wallet_balance_changed', function( $user_id, $amount, $type, $balance_after ) {
    error_log( json_encode( [
        'event'      => 'wallet_change',
        'user_id'    => $user_id,
        'amount'     => $amount,
        'type'       => $type,
        'balance'    => $balance_after,
        'remote_ip'  => $_SERVER['REMOTE_ADDR'],
        'user_agent' => $_SERVER['HTTP_USER_AGENT'],
        'timestamp'  => current_time( 'mysql' ),
    ] ) );
}, 10, 4 );

Session Hijack Mitigation

WordPress session tokens (cookie-based) rotate on login. Wallet Central doesn't store any session secret beyond what WP already manages.

For two-factor auth, install a 2FA plugin (e.g. WordFence 2FA) — Wallet Central inherits whatever auth gate WP enforces.

Mass Assignment

Settings AJAX uses an explicit allowlist — no mass assignment possible. Form POSTs are mapped explicitly to typed fields, never extract($_POST).

Common Attack Vectors → Defence

AttackDefence
CSRF on Settings savenonce
OTP brute force10 / minute rate limit + 6-digit space → ~10 attempts / 1M tries
Replay-attack on OTPbcrypt hashed + consumed_at lock
KYC document leakfiles outside public dir + image proxy with cap check
QR forgeryHMAC sig over wallet_id:nonce
API key theftscope + IP whitelist + revoke action
Race-condition double-creditDB row lock under SELECT FOR UPDATE
Insufficient-balance overflowWallet_Core::debit() re-fetches under lock

Test Plan

  1. Anon → /wallet-central/ → confirm 302 to wp-login
  2. Open browser dev tools → fire Settings AJAX without nonce header → confirm 403
  3. Fire Settings AJAX with bogus key → confirm 400
  4. Submit Withdraw without nonce → legacy handler returns nonce-fail
  5. Manually POST to OTP verify with wrong code → 401 invalid_otp
  6. Burst 100 settings saves in 1 sec → confirm 429
  7. Upload .exe to KYC → MIME reject

Hooks

HookTypeWhen
wkwp_central_settings_save_keysfilterextend allowlist
wkwp_central_settings_save_validatefilterper-key validation
wkwp_central_rate_limit_<scope>filteroverride rate limit
wkwp_central_send_headersactioninject extra headers
wkwp_central_csp_policyfiltermutate CSP value

Pen-Test Suggestions

For a third-party security audit, focus on:

  • KYC file upload bypass attempts (MIME spoofing)
  • OTP brute force (rate limit + bcrypt)
  • API key scope escalation (read → write)
  • Nonce replay across users
  • QR HMAC forgery
  • Withdrawal request enumeration via row IDs (should 403 for non-owner)

All of these are covered by current defences but worth re-confirming per release.

Related

  • Settings
  • KYC Flow
  • REST API
  • Architecture
Prev
Tweaks & Responsive
Next
Admin Controls