T09 · Insecure Skill Coding Practices
- Location
scripts/signet-cli.ts:263- Finding
Concurrent preflights can exceed the monthly payment cap before recording
- Content
View full analysis
policy.maxPerMonth) { appendLedger({ ts: new Date().toISOString(), amount, currency, payee, purpose, status: 'denied', reason: `Would exceed monthly limit (${policy.currency} ${policy.maxPerMonth})`, ...audit, }); return { result: 'DENY', reason: `Would exceed monthly limit of ${policy.currency} ${policy.maxPerMonth} (already spent ${policy.currency} ${monthSpent.toFixed(2)} this month)`, }; } ``` The locked recording operation occurs only after the external payment is expected to have completed: ```ts async function record( amount: number, currency: string, payee: string, purpose: string, idempotencyKey?: string, callerSkill?: string ): Promise<{ ok: true } | { ok: false; error: string }> { return withLock(() => { const policy = loadPolicyFromConfigOrFile(); if (!policy) return { ok: false, error: 'Policy missing or invalid' }; if (currency !== policy.currency) { return { ok: false, error: `Policy currency is ${policy.currency}; request must use ${policy.currency}` }; } const monthSpent = getMonthSpent(policy.currency); if (monthSpent + amount > policy.maxPerMonth) { return { ok: false, error: `Would exceed monthly limit of ${policy.currency} ${policy.maxPerMonth} (already ${policy.currency} ${monthSpent.toFixed(2)} this month)`, }; } if (idempotencyKey && hasIdempotencyKey(idempotencyKey)) { return { ok: true }; // idempotent: already recorded } appendLedger({ ts: new Date().to ...[truncated 2102 chars]- Remediation
View remediation
