T09 · Insecure Skill Coding Practices
Error
- Location
- packages/shared/src/policy/index.ts:49
- Finding
- Payment policy fails open for malformed, non-finite, or negative amounts<![CDATA[ ## Vulnerability Details **File Location**: `packages/shared/src/policy/index.ts:49-82, 172`; supporting conversion in `packages/agent/src/interceptor.ts:48-51, 139-142` **Vulnerability Type**: Improper numeric input validation in a financial authorization boundary **Risk Level**: High ### Vulnerable Code ```typescript // packages/agent/src/interceptor.ts:48-51 function rawToHuman(rawAmount: string, decimals: number): string { const raw = Number(rawAmount); return (raw / 10 ** decimals).toString(); } ``` ```typescript // packages/agent/src/interceptor.ts:139-142 const humanAmount = rawToHuman(matchingReq.amount, decimals); // 5. Check policy const domain = new URL(url).hostname; ``` ```typescript // packages/shared/src/policy/index.ts:49-82 const amountNum = parseFloat(amount); const maxPerRequest = parseFloat(policy.maxPerRequest); const maxDailySpend = parseFloat(policy.maxDailySpend); // 5. Per-request limit if (amountNum > maxPerRequest) { if (policy.requireHumanApproval) { return { decision: "needs-human-approval", reason: `Amount ${amount} exceeds per-request limit of ${policy.maxPerRequest}`, }; } return { decision: "denied", reason: `Amount ${amount} exceeds per-request limit of ${policy.maxPerRequest}`, }; } // 6. Daily spend limit if (currentDailySpend + amountNum > maxDailySpend) { if (policy.requireHumanApproval) { return { decision: "needs-human-approval", reason: `Daily spend would be ${currentDailySpend + amountNum}, exceeding limit of ${policy.maxDailySpend}`, }; } return { decision: "denied", reason: `Daily spend would be ${currentDailySpend + amountNum}, exceeding limit of ${policy.maxDailySpend}`, }; } // 7. All checks passed return { decision: "approved" }; ``` ```typescript // packages/shared/src/policy/index.ts:172 dailySpend += parseFloat(amount); ``` ### Technical Analysis The amount in an x402 payment requirement is controlled by the remote e ...[truncated 1972 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Represent raw token amounts with `bigint` and perform all policy comparisons in smallest token units. - Reject values unless they match a strict unsigned-integer grammar, such as `^[0-9]+$`, before conversion. - Explicitly reject empty, signed, fractional, exponential, non-finite, negative, overflowing, and otherwise malformed amounts. - Validate `maxPerRequest`, `maxDailySpend`, and `tokenDecimals` when configuration is initialized. - Return a denied decision on every parsing or arithmetic failure. - Prevent `recordSpend()` from accepting invalid or negative values. - Add tests covering `NaN`, `Infinity`, `-Infinity`, negative values, exponential notation, overflow, empty strings, trailing characters, and values exceeding safe integer precision. - Consider atomically reserving an approved amount before signing and reconciling that reservation after settlement. ]]>
