Back to skill

Security audit

Agent Fuel

Security checks for vulnerabilities and agentic risk

Overview

This wallet automation skill matches its stated financial purpose, but it contains under-controlled automatic spending paths and shell execution flaws that need review before installation.

Review this skill carefully before installing. Use it only with a wallet whose funds you can afford to risk, disable autonomous top-up and x402 auto-pay until you have explicit allowlists and approval controls, avoid the shell notifyCmd eval path, pin the MoonPay CLI version, and run it in a restricted account with tightly scoped config, log, and state files.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (6)

T09 · Insecure Skill Coding Practices

Error
Location
src/monitor.ts:50
Finding

Shell Command Injection in TypeScript Wallet Operations

Content
View full analysis
config.maxDailySpend) { console.log(`⚠️ Daily spend limit would be exceeded ($${dailySpend} + $${config.topUpAmount} > $${config.maxDailySpend})`); return false; } try { console.log(`⛽ Topping up: $${config.topUpAmount} ${config.currency} on ${config.chain}...`); const output = execSync( `mp buy --amount ${config.topUpAmount} --currency ${config.currency} --chain ${config.chain} --json`, { encoding: 'utf-8', timeout: 60000 } ); ``` ```ts export async function handleX402( url: string, paymentHeader: string, config?: FuelConfig ): Promise<{ paid: boolean; amount: number }> { const cfg = config || loadConfig(); if (!cfg.x402Enabled) { return { paid: false, amount: 0 }; } try { // Parse payment requirements from header const requirements = JSON.parse(Buffer.from(paymentHeader, 'base64').toString()); const amount = parseFloat(requirements.amount); if (amount > cfg.x402MaxPerRequest) { console.log(`⚠️ x402 payment $${amount} exceeds max per request $${cfg.x402MaxPerRequest}`); return { paid: false, amount }; } // Check daily limit const dailySpend = getDailySpend(); if (dailySpend + amount > cfg.maxDailySpend) { return { paid: false, amount }; } // Execute payment via MoonPay wallet const output = execSync( `mp send --to ${requirements.payTo} --amou ...[truncated 1871 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/agent-fuel.sh:114
Finding

Arbitrary Command Execution Through Configurable Shell eval

Content
View full analysis
> "$LOG_FILE" if [[ -n "$NOTIFY_CMD" ]]; then eval "$NOTIFY_CMD '$msg'" 2>/dev/null || true fi echo "$msg" } ``` `NOTIFY_CMD` is populated from the configuration file: ```bash NOTIFY_CMD=$(jq -r '.notifyCmd // ""' "$CONFIG_FILE") ``` ### Technical Analysis The `eval` builtin parses its argument as new shell source code. `NOTIFY_CMD` is loaded from configuration and is therefore directly capable of introducing arbitrary shell syntax. The message is also embedded inside single quotes in the evaluated string. If message content contains a single quote or other suitable syntax, it can escape the intended argument boundary. Some messages include command output, including the result of a failed or successful `mp buy` invocation, so notification text is not guaranteed to be a trusted static string. ### Attack Path 1. An attacker modifies the Agent Fuel configuration or causes an unsafe configuration to be installed. 2. The attacker sets `notifyCmd` to an arbitrary shell command. 3. A balance alert, top-up, daemon startup, or other notification invokes `notify()`. 4. `eval` reparses the configured text as shell code. 5. The attacker's command executes with the privileges of the Agent Fuel process. A secondary path exists when attacker-influenced command output is included in `msg`: a crafted single quote can alter the command assembled for `eval`. ### Impact Assessment Exploitation grants arbitrary command execution as the user running the script. This can expose wallet authentication data, alter configuration and transaction logs, initiate other local wallet commands, and read or modify any file available to that user. ]]>
Remediation
View remediation
/dev/null || true fi ``` If multiple notification backends are required, select among hardcoded backend identifiers instead of accepting executable command strings. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/monitor.ts:157
Finding

Untrusted x402 Requirements Can Authorize Arbitrary Wallet Transfers

Content
View full analysis
{ const cfg = config || loadConfig(); if (!cfg.x402Enabled) { return { paid: false, amount: 0 }; } try { // Parse payment requirements from header const requirements = JSON.parse(Buffer.from(paymentHeader, 'base64').toString()); const amount = parseFloat(requirements.amount); if (amount > cfg.x402MaxPerRequest) { console.log(`⚠️ x402 payment $${amount} exceeds max per request $${cfg.x402MaxPerRequest}`); return { paid: false, amount }; } // Check daily limit const dailySpend = getDailySpend(); if (dailySpend + amount > cfg.maxDailySpend) { return { paid: false, amount }; } // Execute payment via MoonPay wallet const output = execSync( `mp send --to ${requirements.payTo} --amount ${amount} --currency ${cfg.currency} --chain ${cfg.chain} --json`, { encoding: 'utf-8', timeout: 30000 } ); const result = JSON.parse(output); logTransaction(amount, 'x402', `x402 payment to ${url}`, result.txHash); return { paid: true, amount }; ``` The shell wrapper delegates requests without enforcing the local limits: ```bash # x402 request wrapper x402_request() { local url="$1" shift mp x402 request --url "$url" --wallet "$WALLET_NAME" --chain "$CHAIN" --json "$@" 2>&1 } ``` ### Technical Analysis The TypeScript handler treats base64 encoding as sufficient processing of payment requirements but does not authenticate the header or verify that the recipient is authorized for the requested URL. There is no origin allowlist, recipient allowlist, binding between ` ...[truncated 1655 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/agent-fuel.sh:7
Finding

Predictable Shared Temporary State File Permits Symlink Overwrite

Content
View full analysis
/dev/null)" == "$today" ]]; then txs=$(jq '.transactions // []' "$STATE_FILE") fi jq -n \ --arg date "$today" \ --arg total "$new_total" \ --argjson txs "$txs" \ --arg ts "$now" \ --arg amt "$amount" \ --arg rsn "$reason" \ '{date: $date, totalSpent: ($total|tonumber), transactions: ($txs + [{timestamp: $ts, amount: ($amt|tonumber), reason: $rsn}])}' \ > "$STATE_FILE" } ``` ### Technical Analysis The default state file is a fixed, predictable name in the shared `/tmp` directory. The script writes to it using ordinary shell redirection without securely creating the file, checking its owner, or rejecting symbolic links. On a multi-user system, another local user can create that path first or replace it with a symbolic link. Shell redirection then follows the link and truncates the target if the Agent Fuel user has permission to write it. The same predictable file also permits local tampering with spending records, causing the limit logic to read attacker-selected state. ### Attack Path 1. A local attacker creates `/tmp/agent-fuel-state.json` as a symbolic link to a file writable by the ...[truncated 702 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/monitor.ts:67
Finding

Race-Prone and Fail-Open Spending-Limit Accounting

Content
View full analysis
config.maxDailySpend) { console.log(`⚠️ Daily spend limit would be exceeded ($${dailySpend} + $${config.topUpAmount} > $${config.maxDailySpend})`); return false; } try { console.log(`⛽ Topping up: $${config.topUpAmount} ${config.currency} on ${config.chain}...`); const output = execSync( `mp buy --amount ${config.topUpAmount} --currency ${config.currency} --chain ${config.chain} --json`, { encoding: 'utf-8', timeout: 60000 } ); const result = JSON.parse(output); logTransaction(config.topUpAmount, 'top-up', 'Auto top-up: balance below threshold', result.txHash); ``` The shell implementation follows the same check-then-spend pattern: ```bash do_topup() { local daily_spend daily_spend=$(get_daily_spend) # Check daily limit local would_spend would_spend=$(echo "$daily_spend + $TOP_UP_AMOUNT" | bc) local over over=$(echo "$would_spend > $MAX_DAILY_SPEND" | bc) if [[ "$over" == "1" ]]; then notify "⚠️ AGENT FUEL: Daily spend limit would be exceeded (\$$daily_spend + \$$TOP_UP_AMOUNT > \$$MAX_DAILY_SPEND). Manual top-up needed." return 1 fi ``` ```bash result=$(mp buy \ --token "$token_code" \ --amount "$TOP_UP_AMOUNT" \ --wallet "$(get_wallet_address)" \ 2 ...[truncated 1723 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
package.json:21
Finding

Wallet-Capable CLI Is Installed Through an Unpinned Mutable Dependency

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The skill description understates material behavior by omitting local file handling and by claiming OpenWallet Standard support that is not actually shown. For a wallet-management skill, behavior/description mismatches are dangerous because users and agent orchestrators may authorize it under false assumptions while it performs fund-affecting actions and accesses sensitive local data.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill presents autonomous top-ups and x402 payment signing as normal operation without a prominent upfront warning that real funds may be spent automatically. Because this skill directly authorizes purchases and payment signatures, lack of explicit warning materially increases the risk of users enabling it without understanding that it can trigger irreversible financial transactions.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The notification hook executes a config-supplied string via shell eval, which allows arbitrary command execution in the context of whoever runs the script. Because the config file is treated as trusted input but may be modified by another local process, user, or compromised agent environment, this extends the skill far beyond wallet monitoring into unrestricted code execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

Executing a notification command from configuration via eval silently turns a status hook into arbitrary shell execution, without a clear warning to the operator. This is especially dangerous in a wallet-management skill because compromise of the config or environment can lead directly to host takeover, secret theft, or further wallet abuse.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README promotes autonomous wallet monitoring, automatic MoonPay purchases, and x402 auto-pay flows, but it does not present a prominent warning that the skill can initiate real-money transactions and sign onchain payments. In an agent skill context, this is dangerous because operators may enable it assuming routine automation, while the documented behavior can directly spend fiat and crypto with limited human review.

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 · README.md (reported line 115)May include surrounding context.

x402 Auto-Pay

text
Agent → GET https://api.example.com/data
Server → 402 Payment Required (0.001 USDC)
Agent Fuel → Signs payment, retries request
Server → 200 OK + data

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill enables financially sensitive actions and references secrets/config stored on disk, but it declares no explicit tool scope or permission boundaries. In an agent setting, missing scope makes it easier for the runtime to grant broader environment or filesystem access than intended, increasing the chance of unauthorized reads of credentials or unsafe execution of purchase/payment flows.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The auto top-up trigger is specified only as 'when low balance' and pseudocode based on balance thresholds, without defining timing, confirmation requirements, anti-repeat locking, or authoritative balance source. In a financial automation context, ambiguous triggers can cause repeated buys, race conditions, or unintended top-ups from transient states or manipulated readings, directly risking monetary loss.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script exposes a generic x402 request wrapper that can send paid requests to arbitrary URLs, which is broader capability than the stated wallet-balance monitoring and auto top-up purpose. In an agent context, this can be abused as an outbound payment-enabled network primitive, enabling unintended spending or interaction with attacker-controlled endpoints.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The daemon can automatically trigger a MoonPay purchase whenever the measured balance falls below the configured threshold, with no interactive confirmation or secondary approval gate. In an autonomous agent environment, balance manipulation, misconfiguration, or false readings could cause repeated unauthorized purchases up to the daily limit.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The module imports and relies on execSync to invoke external CLI commands for balance checks, purchases, and payments. While wallet management explains the business logic, arbitrary subprocess execution is a materially broader capability than the manifest description of autonomous wallet management, MoonPay top-up, x402 payments, and OpenWallet support.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill automatically executes x402 payments based solely on a base64-decoded header and local limits, without user confirmation, origin verification, or strong validation of the payment recipient and amount. In an autonomous wallet-management skill, this is especially dangerous because any service that can induce a 402 response may be able to trigger real fund transfers, leading to unauthorized or repeated spending within configured limits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The production dependency uses a caret range, which allows newer minor/patch versions to be installed over time. In a wallet-management skill that may execute CLI-driven payment or funding operations, this increases supply-chain risk because a compromised or breaking upstream release could alter runtime behavior without a deliberate review.

Content

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

json
"author": "Zedit42",
  "license": "MIT",
  "dependencies": {
    "@moonpay/cli": "^1.12.0"
  },
  "devDependencies": {
    "typescript": "^5.4.0",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
82% confidence
Finding

The TypeScript devDependency is also unpinned, which can make builds non-reproducible and expose the build pipeline to upstream supply-chain compromise. Although this is not usually a direct runtime risk, compromised build tooling can inject malicious code into generated artifacts.

Content

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

json
"@moonpay/cli": "^1.12.0"
  },
  "devDependencies": {
    "typescript": "^5.4.0",
    "@types/node": "^20.0.0"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
78% confidence
Finding

The @types/node package is unpinned, creating minor build reproducibility and supply-chain exposure. Its risk is lower than a runtime dependency, but dependency confusion or upstream compromise could still affect development and CI workflows.

Content

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

json
},
  "devDependencies": {
    "typescript": "^5.4.0",
    "@types/node": "^20.0.0"
  }
}

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The code stores spending logs under a memory path and reads configuration from a secrets file in the user's home directory. Persistent local file and secret access is not mentioned in the manifest description, which focuses on wallet management, auto top-up, x402 payments, and OpenWallet behavior.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/monitor.ts:60