Back to skill

Security audit

CDP Wallet

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed Coinbase wallet skill, but it lets an agent spend real funds and automatically pay arbitrary x402 URLs without built-in limits, allowlists, or confirmation gates.

Only install this for a dedicated, low-balance wallet with CDP policy limits already configured. Treat CDP_WALLET_SECRET like a private key, restrict which agents can access these environment variables, use allowlists or operator approval before any send-usdc or pay-x402 call, and do not let the agent pay arbitrary URLs or forward authorization headers to untrusted services.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
src/index.js:409
Finding

Unbounded Server-Directed x402 Wallet Payments

Content
View full analysis

Vulnerability Details

File Location: src/index.js, lines 409-422
Vulnerability Type: Missing payment authorization constraints
Risk Level: High

Vulnerable Code:

js
// Construct the x402 client with the CDP-backed signer.
let response;
try {
  const { account } = await loadAccount();
  const signer = toX402Signer(account);
  const client = new x402Client();
  registerExactEvmScheme(client, { signer });
  const fetchWithPayment = wrapFetchWithPayment(fetch, client);

  response = await fetchWithPayment(url, {
    method,
    headers,
    ...(body !== undefined ? { body } : {}),
  });

Technical Analysis

The Skill converts the funded CDP account into a signer and gives it directly to an x402 client. The remote endpoint supplies the payment requirements, but the Skill does not locally enforce:

  • A maximum payment amount
  • A cumulative or daily spending limit
  • An allowed chain or network list
  • An allowed token or token-contract list
  • A recipient or facilitator allowlist
  • Interactive approval for unexpected payment terms

The declared CDP_NETWORK setting does not constrain pay-x402; therefore, the server can select any EVM network and payment terms supported by the installed x402 client and signer. Relying exclusively on Agent reasoning or optional external CDP policies does not provide a secure default in this implementation.

Attack Path

  1. An attacker causes the Agent to invoke pay-x402 with a malicious or compromised endpoint.
  2. The endpoint returns an HTTP 402 response containing attacker-selected, x402-compatible payment requirements.
  3. wrapFetchWithPayment processes those requirements using the unrestricted CDP-backed signer.
  4. The wallet signs a payment authorization without a local amount, asset, network, or recipient policy check.
  5. The x402 flow submits the authorization and retries the resource request.
  6. Funds can be settled acco ...[truncated 652 chars]
Remediation
View remediation

Remediation Suggestions

  1. Parse the HTTP 402 payment requirements before creating or signing an authorization.
  2. Enforce an operator-configured maximum amount per payment and a cumulative spending limit.
  3. Restrict payments to explicit chain IDs, such as Base mainnet and optionally Base Sepolia.
  4. Validate the requested asset against an allowlist of known USDC contract addresses.
  5. Add recipient and facilitator allowlists where operationally possible.
  6. Reject ambiguous, malformed, unsupported, or multi-option requirements unless one option passes every policy check.
  7. Require explicit operator confirmation when payment terms exceed a configured threshold or do not match a preapproved policy.
  8. Configure equivalent hard limits in the CDP policy engine as defense in depth.
  9. Log proposed and approved payment terms without logging credentials or sensitive authorization material.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
src/index.js:372
Finding

Server-Side Request Forgery Through Unrestricted pay-x402 URLs

Content
View full analysis

Vulnerability Details

File Location: src/index.js, lines 372-422
Vulnerability Type: Server-Side Request Forgery and unrestricted outbound requests
Risk Level: Medium

Vulnerable Code:

js
let parsedUrl;
try {
  parsedUrl = new URL(url);
} catch {
  exitError(`Invalid URL: ${url}`);
}
if (parsedUrl.protocol !== "https:" && parsedUrl.protocol !== "http:") {
  exitError(`URL must be http or https: ${url}`);
}

const method = (opts.method || "GET").toUpperCase();

// Build request headers from --header flags. Each --header is "Name: Value".
const headers = {};
const rawHeaders = Array.isArray(opts.header)
  ? opts.header
  : opts.header
    ? [opts.header]
    : [];
for (const h of rawHeaders) {
  const idx = h.indexOf(":");
  if (idx === -1) {
    exitError(`Malformed header (expected "Name: Value"): ${h}`);
  }
  const name = h.slice(0, idx).trim();
  const value = h.slice(idx + 1).trim();
  if (!name) {
    exitError(`Empty header name in: ${h}`);
  }
  headers[name] = value;
}

const body = typeof opts.body === "string" ? opts.body : undefined;
if (body && method === "GET") {
  exitError("Cannot send a body with method GET. Use --method POST or similar.");
}

// Construct the x402 client with the CDP-backed signer.
let response;
try {
  const { account } = await loadAccount();
  const signer = toX402Signer(account);
  const client = new x402Client();
  registerExactEvmScheme(client, { signer });
  const fetchWithPayment = wrapFetchWithPayment(fetch, client);

  response = await fetchWithPayment(url, {
    method,
    headers,
    ...(body !== undefined ? { body } : {}),
  });

Technical Analysis

URL validation only permits the http and https schemes. It does not reject:

  • Loopback destinations such as 127.0.0.1 or localhost
  • Private network ranges
  • Link-local addresses
  • Cloud instance me ...[truncated 1948 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require HTTPS by default and permit plaintext HTTP only through explicit operator configuration.
  2. Resolve the destination hostname before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 ranges.
  3. Block known cloud metadata destinations, including link-local metadata addresses.
  4. Disable automatic redirects or validate every redirect destination using the same DNS and IP checks.
  5. Protect against DNS rebinding by ensuring the validated address is the address used for the connection.
  6. Prefer an explicit hostname allowlist for approved x402 providers.
  7. Restrict HTTP methods to those required by the declared use case.
  8. Deny sensitive or connection-specific headers by default, including Host, proxy headers, and externally supplied payment headers.
  9. Require explicit confirmation before forwarding authorization or cookie headers to a new origin.
  10. Apply short connection and response timeouts, response-size limits, and outbound network firewall rules as defense in depth.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (18)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill explicitly requires environment secrets and outbound network access, and it can move funds, but the manifest declares no explicit permission or tool scope. In an agent runtime, that weakens operator visibility and policy enforcement because a payment-capable skill can be loaded without a machine-readable declaration of its sensitive capabilities.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

md
### 1. Get CDP credentials

Sign in at [portal.cdp.coinbase.com](https://portal.cdp.coinbase.com), create a CDP API key, and generate a Wallet Secret. You'll have three values:

- `CDP_API_KEY_ID`
- `CDP_API_KEY_SECRET`

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation describes a direct fund-transfer command and even encourages autonomous invocation, but it does not prominently require confirmation before sending money. In an agent setting, that omission can lead to unintended or prompt-induced transfers because the skill normalizes payment execution as a routine action.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The x402 flow is documented as transparent and automatic, including signing an authorization and settling to a remote service, but it lacks a strong warning that calling an arbitrary URL may authorize on-chain payment. This is more dangerous than a normal HTTP request because an agent could be tricked into visiting attacker-controlled endpoints that convert requests into spend events.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

pay-x402 <url>

sh
node src/index.js pay-x402 https://api.example.com/protected
node src/index.js pay-x402 https://api.example.com/protected -H "Authorization: Bearer abc123"
node src/index.js pay-x402 https://api.example.com/protected -X POST -d '{"k":"v"}' -H "Content-Type: application/json"

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

pay-x402 <url>

sh
node src/index.js pay-x402 https://api.example.com/protected
node src/index.js pay-x402 https://api.example.com/protected -H "Authorization: Bearer abc123"
node src/index.js pay-x402 https://api.example.com/protected -X POST -d '{"k":"v"}' -H "Content-Type: application/json"

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

pay-x402 <url>

sh
node src/index.js pay-x402 https://api.example.com/protected
node src/index.js pay-x402 https://api.example.com/protected -H "Authorization: Bearer abc123"
node src/index.js pay-x402 https://api.example.com/protected -X POST -d '{"k":"v"}' -H "Content-Type: application/json"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The pay-x402 command will automatically negotiate and authorize payment to any caller-supplied URL, including arbitrary headers and body, with no allowlist, amount cap, confirmation step, or explicit policy gate. In an agent setting, this is dangerous because untrusted prompts or tool inputs can cause real on-chain spending and data transmission to attacker-controlled endpoints, making prompt-injection-driven fund loss or exfiltration materially easier.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This is a manifest file, so vague-trigger review applies. The description advertises a general-purpose wallet skill for multiple agent ecosystems but does not specify concrete invocation phrases, scope limits, or exclusion conditions, which can make activation matching overly broad in agent registries that rely on descriptions.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

Using caret ranges for a wallet/payment dependency allows newer minor or patch releases to be installed without review, which can introduce supply-chain risk or behavior changes in code that controls USDC transfers and signing. In a financial skill, even small dependency drift is more dangerous because compromised or buggy upstream updates could affect transaction construction, authorization, or destination handling.

Content

Scanner excerpt · package.json (reported line 27)May include surrounding context.

json
"node": ">=22"
  },
  "dependencies": {
    "@coinbase/cdp-sdk": "^1.40.0",
    "@x402/core": "^2.0.0",
    "@x402/evm": "^2.0.0",
    "@x402/fetch": "^2.0.0",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

An unpinned @x402/core version permits unreviewed updates into payment negotiation logic. Because this skill is explicitly built to settle x402-protected resources with a persistent wallet, dependency changes can alter signing or payment semantics in security-sensitive flows.

Content

Scanner excerpt · package.json (reported line 28)May include surrounding context.

json
},
  "dependencies": {
    "@coinbase/cdp-sdk": "^1.40.0",
    "@x402/core": "^2.0.0",
    "@x402/evm": "^2.0.0",
    "@x402/fetch": "^2.0.0",
    "bs58": "^6.0.0",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

Caret-pinning @x402/evm creates avoidable supply-chain exposure in EVM payment/signing paths. In a wallet skill, unreviewed upstream code changes may affect chain interactions, typed-data signing, or settlement verification and therefore have direct financial consequences.

Content

Scanner excerpt · package.json (reported line 29)May include surrounding context.

json
"dependencies": {
    "@coinbase/cdp-sdk": "^1.40.0",
    "@x402/core": "^2.0.0",
    "@x402/evm": "^2.0.0",
    "@x402/fetch": "^2.0.0",
    "bs58": "^6.0.0",
    "commander": "^12.1.0",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

Allowing floating updates for @x402/fetch can introduce unsafe networking or protocol-handling changes without explicit review. Since this component likely participates in the HTTP 402 negotiation/resubmission flow, changes here could redirect payments, mishandle challenges, or weaken validation around paid requests.

Content

Scanner excerpt · package.json (reported line 30)May include surrounding context.

json
"@coinbase/cdp-sdk": "^1.40.0",
    "@x402/core": "^2.0.0",
    "@x402/evm": "^2.0.0",
    "@x402/fetch": "^2.0.0",
    "bs58": "^6.0.0",
    "commander": "^12.1.0",
    "dotenv": "^16.4.5",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
78% confidence
Finding

Using a caret range for bs58 is a generic supply-chain hygiene issue rather than a direct exploitable flaw by itself. However, because it may participate in address or key-related encoding/decoding in a financial tool, unexpected dependency changes could still cause subtle correctness or security issues.

Content

Scanner excerpt · package.json (reported line 31)May include surrounding context.

json
"@x402/core": "^2.0.0",
    "@x402/evm": "^2.0.0",
    "@x402/fetch": "^2.0.0",
    "bs58": "^6.0.0",
    "commander": "^12.1.0",
    "dotenv": "^16.4.5",
    "viem": "^2.21.0"

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
74% confidence
Finding

commander is a CLI parsing library, so the direct impact of version drift is lower than payment libraries, but unreviewed updates still expand the supply-chain attack surface. In an agent-invoked wallet CLI, argument parsing changes could affect command safety, defaults, or validation behavior.

Content

Scanner excerpt · package.json (reported line 32)May include surrounding context.

json
"@x402/evm": "^2.0.0",
    "@x402/fetch": "^2.0.0",
    "bs58": "^6.0.0",
    "commander": "^12.1.0",
    "dotenv": "^16.4.5",
    "viem": "^2.21.0"
  },

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
72% confidence
Finding

dotenv is not inherently dangerous, but a floating version can introduce unreviewed changes to environment parsing in a tool that depends on secrets and wallet configuration. Misparsing or altered precedence rules could impact which credentials or wallet names are loaded.

Content

Scanner excerpt · package.json (reported line 33)May include surrounding context.

json
"@x402/fetch": "^2.0.0",
    "bs58": "^6.0.0",
    "commander": "^12.1.0",
    "dotenv": "^16.4.5",
    "viem": "^2.21.0"
  },
  "overrides": {

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
88% confidence
Finding

viem is a core blockchain interaction library, so floating updates create meaningful risk in transaction formation, chain RPC behavior, signing, and token handling. In a Base USDC payment skill, unnoticed upstream changes can directly impact funds movement or the correctness of on-chain operations.

Content

Scanner excerpt · package.json (reported line 34)May include surrounding context.

json
"bs58": "^6.0.0",
    "commander": "^12.1.0",
    "dotenv": "^16.4.5",
    "viem": "^2.21.0"
  },
  "overrides": {
    "axios": "^1.16.0"

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
80% confidence
Finding

The override for axios still uses a caret range, so transitive resolution can drift over time despite the override. While this is often done to force a safer minimum version, leaving it unpinned still permits unreviewed supply-chain changes into the dependency graph.

Content

Scanner excerpt · package.json (reported line 37)May include surrounding context.

json
"viem": "^2.21.0"
  },
  "overrides": {
    "axios": "^1.16.0"
  },
  "license": "MIT",
  "repository": {

Static analysis

No suspicious patterns detected.