Back to skill

Security audit

Valiron

Security checks for vulnerabilities and agentic risk

Overview

The skill fits its payment-authorization purpose, but its bundled interceptor template leaves important spend and approval controls unenforced.

Install only if you treat the bundled interceptor as a starter template, not production-ready payment authorization code. Before using it on real payment rails, add runtime schema validation, positive finite money handling, hourly and daily spend accounting, human approval enforcement, idempotency and replay protection, audit logging, and fail-closed behavior backed by durable storage.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
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

T09 · Insecure Skill Coding Practices

Warning
Location
assets/payment-interceptor.ts:48
Finding

Invalid Numeric Payment Amounts Can Bypass the Per-Payment Cap

Content
View full analysis
row.maxAmountPerPayment) { return { allow: false, outcome: 'deny', route, reason: 'amount exceeds maxAmountPerPayment' }; } ``` ### Technical Analysis The TypeScript `number` annotation provides no runtime validation. The authorization function does not verify that the amount is finite, positive, or valid for the specified currency. A negative amount makes the expression `req.amount > row.maxAmountPerPayment` evaluate to false for a normal non-negative cap. Non-finite values such as `NaN`, if supplied by an internal JavaScript caller or introduced during request processing, also make the comparison false. The request can therefore proceed to an allow result when the matched policy authorization is `allow` or `allow_with_limits`. Using floating-point numbers directly for money also creates precision and boundary risks. Financial values should generally be represented as integer minor units or validated fixed-precision decimals. ### Attack Path 1. A caller constructs an otherwise valid request with a valid counterparty identity and permitted rail. 2. The caller supplies a negative `amount`. An internal JavaScript caller could also supply `NaN` despite the TypeScript declaration. 3. The Valiron lookup returns a route whose policy authorization is `allow` or `allow_with_limits`. 4. The upper-bound comparison evaluates to false and does not deny the request. 5. The function returns `allow: true`. 6. If downstream code trusts this decision without independently validating the amount, the malformed payment reaches accounting or payment-ra ...[truncated 460 chars]
Remediation
View remediation
0`. - Reject missing, coerced, or nonnumeric values. 2. Represent monetary amounts as integer minor units, such as cents, or use a vetted fixed-precision decimal library. 3. Maintain a currency allowlist and enforce currency-specific decimal precision and minimum/maximum values. 4. Validate `requestId`, counterparty identifiers, currency, and rail through a strict runtime schema. 5. Ensure the downstream payment rail independently validates the amount rather than relying exclusively on this authorization result. 6. Add tests covering negative values, zero, `NaN`, positive and negative infinity, fractional precision, and exact cap boundaries. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (1)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The function sends counterpartyAgentId to sdk.checkAgent and counterpartyWallet to sdk.getWalletProfile, which are network calls involving payment-related identifiers. In this file there is no confirmation prompt, logging, print statement, or explanatory comment/docstring disclosing that external lookups occur.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
references/decision-policy.md:11