T09 · Insecure Skill Coding Practices
- Location
assets/payment-interceptor.ts:11- Finding
Hourly, Daily, and Human-Approval Spend Controls Are Not Enforced
- Content
View full analysis
; maxAmountPerPayment: number; fallbackMode: 'fail-open-guarded' | 'fail-closed'; }; ``` ```ts const row = policy.find((p) => p.route === route); if (!row) return { allow: false, outcome: 'deny', route, reason: 'no policy for route' }; if (!row.allowedRails.includes(req.rail)) { return { allow: false, outcome: 'deny', route, reason: 'rail not allowed for route' }; } if (req.amount > row.maxAmountPerPayment) { return { allow: false, outcome: 'deny', route, reason: 'amount exceeds maxAmountPerPayment' }; } return { allow: row.authorization === 'allow' || row.authorization === 'allow_with_limits', outcome: row.authorization, route, reason: 'policy match', }; ``` ### Technical Analysis The documented payment policy requires `maxAmountPerHour`, `maxAmountPerDay`, and `requireHumanApprovalOver`. The policy validator also requires these fields. However, the interceptor's `PolicyRow` type omits them, and `authorizeOutgoingPayment` only enforces `maxAmountPerPayment`. Consequently, a policy can pass `scripts/validate-payment-policy.mjs` while the runtime interceptor silently ignores cumulative spend limits and human-approval requirements. The implementation also lacks the documented counterparty concentration, idempotency, and replay controls. Secure cumulative-limit enforcement requires atomic accounting because concurrent requests can otherwise independently observe an available balance and collectively exceed the limit. ### Attack Path 1. An attacker or compromised caller submits a payment to a counterparty whose Valiron route maps to `allow` or `allow_with_limits`. ...[truncated 996 chars]- Remediation
View remediation
