T09 · Insecure Skill Coding Practices
- Location
patterns.md:29- Finding
Incomplete Server-Side Order Validation Before Payment Capture
- Content
View full analysis
{ const token = await getToken(); // First verify the order const order = await fetch(`https://api.paypal.com/v2/checkout/orders/${orderId}`, { headers: { 'Authorization': `Bearer ${token}` } }).then(r => r.json()); if (order.status !== 'APPROVED') { throw new Error(`Invalid order status: ${order.status}`); } // Then capture const capture = await fetch(`https://api.paypal.com/v2/checkout/orders/${orderId}/capture`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }); return capture.json(); }; ``` ### Technical Analysis The capture function accepts an `orderId` that the documented frontend submits to the server. Before capture, the server retrieves the selected PayPal order but validates only that its status is `APPROVED`. The function does not verify that: - The order belongs to the authenticated application user or current checkout. - The PayPal order is linked to the expected internal order. - The amount equals the server-side expected amount. - The currency equals the expected currency. - The payee merchant ID is the intended merchant. - The order intent and purchase units match the expected transaction. This omission is especially significant because `SKILL.md` lines 74–84 explicitly state that amount, currency, and merchant must be checked before fulfillment. The operational capture pattern does not implement those checks. ### Attack Path 1. An attacker starts or identifies a lower-value PayPal order available through the same integration. 2. The attacker approves that lower-value order through PayPal. 3. During a higher-value application checkout, the attacker sends the approved lower-value ...[truncated 1085 chars]- Remediation
View remediation
