T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:65
- Finding
- Payment Verification Bypass Accepts Forged Payment Headers## Vulnerability Details **File Location**: `SKILL.md`, lines 65–76 **Vulnerability Type**: Payment authorization bypass **Risk Level**: High ### Vulnerable Code ```javascript function checkPayment(req, res, path, method, price, description) { const paymentHeader = getPaymentHeader(req); if (!paymentHeader) { const reqs = buildPaymentRequirements(path, method, price); sendJSON(res, 402, { error: 'Payment required', paymentRequired: reqs }, { 'X-PAYMENT-REQUIRED': encodePaymentHeader(reqs) }); return null; } const payload = decodePaymentHeader(paymentHeader); if (!payload) { sendJSON(res, 400, { error: 'Invalid payment header' }); return null; } // Demo mode: accept any valid-looking payment // TODO: Enable facilitator verification in production return true; } ``` ### Technical Analysis The payment gate only Base64-decodes and JSON-parses the attacker-controlled `payment-signature` or `x-payment` header. Successful parsing is treated as proof of payment. The implementation does not verify: - A cryptographic payment signature - Payment settlement or transaction status - The payer or intended recipient - The required amount and asset - The configured blockchain network - The requested resource - Payment expiration - Nonce uniqueness or replay status Consequently, any syntactically valid JSON value that parses to a truthy value can satisfy the payment check. For example, Base64-encoded `{}` is accepted even though it contains no payment evidence. ### Attack Path 1. An attacker identifies the protected `POST /api/your-service` endpoint. 2. The attacker creates an arbitrary JSON object, such as `{}`. 3. The attacker Base64-encodes it as `e30=`. 4. The attacker sends `payment-signature: e30=` or `x-payment: e30=` with the request. 5. `decodePaymentHeader()` parses the forged payload successfully. 6. `checkPayment()` returns `true` without cryptographic or settlement verification. 7. The protected service executes without ...[truncated 646 chars]
- Remediation
- ## Remediation Suggestions - Remove the permissive demo behavior from any publicly exposed deployment. - Fail closed unless the payment has been cryptographically verified and confirmed as settled. - Verify the signature, payer, `payTo` recipient, exact amount, asset, network, resource, expiration, and protocol version. - Add nonce or transaction-identifier tracking to prevent payment replay. - Build the expected payment requirements server-side; never trust requirements supplied by the client. - Treat facilitator timeouts, malformed responses, non-success HTTP statuses, and parsing errors as failed authorization. - Keep demonstration mode explicitly disabled by default and bind demonstration servers to localhost. - Add automated tests confirming rejection of missing, malformed, forged, underpaid, wrong-recipient, wrong-network, expired, and replayed payments.
