Run these checks on your Paystack integration: (1) price tampering — can you modify the amount in the initializeTransaction request and have it accepted? (2) webhook spoofing — does your handler reject requests without a valid x-paystack-signature? (3) reference replay — does sending the same reference twice to your verify endpoint trigger double fulfillment? (4) IDOR on payment endpoints — can user A fetch user B's transaction details? (5) secret key in source — does your frontend bundle or public files contain the secret key? (6) missing rate limits — can you spam the checkout endpoint without triggering a 429?
Intercept the request from your checkout page to your backend that triggers POST /transaction/initialize. Modify the amount field to NGN 1. Does your backend use the client-supplied amount, or does it read the amount from your own database (order record)?
Pass: Backend ignores client-supplied amount, reads from DB. Fail: Backend passes client amount to Paystack.
Send a POST request to your webhook endpoint with a valid-looking JSON body but no x-paystack-signature header (or a wrong signature). Does your handler process it?
Pass: Handler returns 401/400 immediately. Fail: Handler processes the event.
Call your payment verification endpoint twice with the same reference. Does the second call fulfill the order again?
Pass: Idempotency check prevents double fulfillment. Fail: Order is fulfilled twice.
Log in as User A. Find a transaction reference belonging to User B (e.g., from a shared link). Call your GET /api/orders/:reference endpoint authenticated as User A. Does it return User B's order?
Pass: Returns 403 or 404. Fail: Returns User B's payment data.
Search your deployed frontend bundle: curl https://yoursite.com/assets/main.js | grep -i "sk_live_". Also check public environment files, GitHub repos, and Vercel/Netlify build logs.
Pass: No secret key in any public files. Fail: Secret key found — rotate immediately.
Send 20 rapid POST requests to your checkout initiation endpoint from the same IP. Are requests throttled after your threshold?
Pass: 429 responses after threshold. Fail: All 20 requests succeed.
Send a webhook with a valid signature but with event: "charge.success" and an amount lower than the expected order amount. Does your handler check that the amount matches the expected order amount?
Pass: Handler verifies amount matches order. Fail: Handler fulfills on event type alone.
If you have a payout endpoint, test whether it requires proper authentication and authorization — can any authenticated user trigger a transfer, or only users with the correct role?
This guide is part of the Paystack security guide.
KES 2,999
The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.
Start Paystack Course