Back to skill

Security audit

jarvis-smart-route

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed swap route builder, but it should be reviewed because it forwards externally generated wallet transaction data with limited local validation.

Install only if you are comfortable with an external Jarvis router receiving wallet and swap details and returning unsigned transaction calldata. Before approving any transaction, use a wallet or host that decodes the call and confirms the token sold, token received, amount, recipient, fees, spender, and contract target match your intent.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/route.mjs:74
Finding

Untrusted Remote Calldata Is Forwarded Without Semantic Validation

Content
View full analysis

Vulnerability Details

File Location: scripts/route.mjs:74-76, 101-121
Vulnerability Type: Insufficient validation of remotely supplied transaction calldata
Risk Level: High

Vulnerable Code

js
if (route.safety?.JARVIS_CUSTODY !== 0 || route.safety?.JARVIS_CAPITAL_SPEND !== 0 || route.safety?.privateKeyAccessed !== false || route.safety?.signs !== false || route.safety?.sends !== false || route.safety?.broadcasts !== false) {
  fail("Jarvis safety invariants failed.");
}
js
const tx = route.unsignedTransaction;
if (!tx || tx.chainId !== 8453 || !ADDRESS.test(tx.to ?? "") || !DATA.test(tx.data ?? "") || !UINT.test(tx.value ?? "")) {
  fail("Jarvis Router returned malformed or non-Base unsigned calldata.");
}

process.stdout.write(`${JSON.stringify({
  ok: true,
  decision: "ROUTE_AVAILABLE",
  intentId: route.intentId,
  provider: route.provider,
  providerStatus: route.providerStatus,
  comparison: route.comparison,
  feeDisclosure: route.feeDisclosure,
  buyerExpectedNetOutput: route.buyerExpectedNetOutput ?? null,
  unsignedTransaction: tx,
  sendCallsInput: {
    chain: "base",
    calls: [{ to: tx.to, value: `0x${BigInt(tx.value).toString(16)}`, data: tx.data }],
  },
  buyerApprovalRequired: true,
  signed: false,
  broadcast: false,
}, null, 2)}\n`);

The associated execution instruction appears at SKILL.md:25:

md
Then pass `sendCallsInput` unchanged to the host's existing `send_calls` flow.

Technical Analysis

The adapter obtains an unsigned transaction from an external routing service. Its local checks only establish that:

  • The reported chain ID is Base (8453).
  • The destination is syntactically formatted as an EVM address.
  • The calldata is syntactically formatted as hexadecimal data.
  • The transaction value is an unsigned decimal integer.

These checks do not establish that the transaction implements the request ...[truncated 2850 chars]

Remediation
View remediation

Remediation Suggestions

  1. Maintain an explicit allowlist of audited router and settlement contract addresses for Base, and reject every other transaction destination.
  2. Allowlist permitted function selectors and ABI-decode all returned calldata before presenting it for approval.
  3. Compare decoded parameters against the original intent, including:
    • Sell and buy token addresses.
    • Exact input amount.
    • Buyer-controlled output recipient.
    • Slippage ceiling and minimum output.
    • Chain ID and transaction deadline.
    • Fee amount, fee token, and approved fee recipient.
  4. Reject unlimited or intent-exceeding approvals. If an approval is required, limit it to the exact amount and expected spender.
  5. Derive and enforce an upper bound for native transaction value from the original intent. Require zero native value for token-only swaps unless explicitly necessary.
  6. Recursively inspect multicalls and reject unknown targets, selectors, delegate calls, arbitrary transfers, and unrelated operations.
  7. Do not treat endpoint-provided safety flags as evidence of safety. All security-critical invariants must be verified independently by the local adapter or trusted host.
  8. Present decoded, human-readable transaction effects to the buyer before approval, including assets spent, assets received, recipient, allowances, fees, and contract targets.
  9. Fail closed whenever decoding is unavailable or any decoded field differs from the confirmed intent.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 23)May include surrounding context.

md
node scripts/route.mjs '{"chain":"base","sellToken":"USDC","buyToken":"WETH","amount":"10","buyerWallet":"0x...","slippageBps":50}'

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill invokes a networked route-building flow via node scripts/route.mjs and a public Jarvis endpoint, but the manifest does not declare any tool scope or allowed network capability. That mismatch weakens host-side policy enforcement and transparency, making it easier for a skill to perform external requests that reviewers or runtime controls did not explicitly authorize.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script sends the buyer wallet address and trade intent details to a third-party endpoint, which exposes potentially sensitive trading metadata to an external service. While this is necessary for routing, the lack of user-facing disclosure or consent can create privacy and compliance risk, especially in an agent workflow where users may not realize their wallet and intended trade are being shared.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script claims to support an opt-in live comparison against existing 0x and OKX routes, but it accepts any successful Jarvis response without verifying that a comparison was actually performed or that the selected route meets the advertised policy. This creates a semantic integrity gap where callers may believe they are getting constrained comparative routing while the code will forward any unsigned swap calldata returned by the external service.

Content

No source excerpt is available for this finding.