T09 · Insecure Skill Coding Practices
Error
- Location
- tools.ts:19
- Finding
- Malformed numeric configuration silently disables local spending safeguards<![CDATA[ ## Vulnerability Details **File Location**: `tools.ts:19-23`, `tools.ts:91-106` **Vulnerability Type**: Fail-open numeric configuration validation **Risk Level**: High ### Vulnerable Code ```ts const KASH_BUDGET = process.env.KASH_BUDGET ? parseFloat(process.env.KASH_BUDGET) : null const KASH_API_URL = process.env.KASH_API_URL || 'https://api.kash.dev' const SPEND_CONFIRMATION_THRESHOLD = parseFloat( process.env.KASH_SPEND_CONFIRMATION_THRESHOLD || '5.00' ) ``` ```ts if (params.amount <= 0) { return 'ERROR: amount must be greater than 0' } // ── Local KASH_BUDGET cap ──────────────────────────────────────────────────── if (KASH_BUDGET !== null && sessionSpent + params.amount > KASH_BUDGET) { return ( `LOCAL_BUDGET_EXCEEDED: Spending $${params.amount} would exceed local KASH_BUDGET of ` + `$${KASH_BUDGET} (session spent: $${sessionSpent.toFixed(4)}). ` + `Tell the user their local budget cap is reached. ` + `They can raise KASH_BUDGET in .env or top up at kash.dev/dashboard/wallets.` ) } // ── Confirmation gate ──────────────────────────────────────────────────────── if (params.amount > SPEND_CONFIRMATION_THRESHOLD && !params.confirmed) { ``` ### Technical Analysis The skill parses `KASH_BUDGET` and `KASH_SPEND_CONFIRMATION_THRESHOLD` with `parseFloat()` but does not verify that the resulting values are finite, nonnegative numbers. A malformed nonempty value such as `x` produces JavaScript's `NaN`. Ordered comparisons involving `NaN` evaluate to `false`. Therefore: - If `KASH_BUDGET=x`, the expression `sessionSpent + params.amount > KASH_BUDGET` is false, silently disabling the advertised local session cap. - If `KASH_SPEND_CONFIRMATION_THRESHOLD=x`, the expression `params.amount > SPEND_CONFIRMATION_THRESHOLD` is false, silently disabling the confirmation requirement for large transactions. - Startup succeeds rather than rejecting the unsafe configuration. The runtime `amount` check also ...[truncated 1315 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Parse configuration strictly during startup and fail closed on invalid values. - Use `Number(value)` rather than permissive partial parsing with `parseFloat()`. - Require both values to satisfy `Number.isFinite(value)` and `value >= 0`. - Apply equivalent validation to every `params.amount` received by `kash_spend`. - Reject malformed, infinite, negative, or otherwise unsupported numeric values before performing budget or confirmation comparisons. - Add automated tests for empty strings, alphabetic input, partially numeric strings, `NaN`, positive and negative infinity, negative values, zero, and valid decimal values. Example hardening pattern: ```ts function parseNonNegativeNumber(name: string, raw: string): number { const value = Number(raw) if (!Number.isFinite(value) || value < 0) { throw new Error(`[kash-skill] ${name} must be a finite, nonnegative number`) } return value } const KASH_BUDGET = process.env.KASH_BUDGET === undefined ? null : parseNonNegativeNumber('KASH_BUDGET', process.env.KASH_BUDGET) const SPEND_CONFIRMATION_THRESHOLD = parseNonNegativeNumber( 'KASH_SPEND_CONFIRMATION_THRESHOLD', process.env.KASH_SPEND_CONFIRMATION_THRESHOLD ?? '5.00' ) ``` At the tool boundary, enforce: ```ts if (!Number.isFinite(params.amount) || params.amount <= 0) { return 'ERROR: amount must be a finite number greater than 0' } ``` ]]>
