Back to skill

Security audit

SUPAH Token Guardian

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a disclosed paid token-scanning skill, but its script has unsafe input handling that could let crafted scan inputs run code or overwrite files.

Install only if you are comfortable with a paid external token-scanning service and can ensure each scan is explicitly approved. Avoid passing untrusted token or chain strings until the script validates EVM addresses and chain names, stops embedding arguments in executable JavaScript, and uses a private unique result file instead of a fixed /tmp path.

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
scripts/guardian-scan.sh:109
Finding

Arbitrary JavaScript Execution Through Unvalidated Command-Line Arguments

Content
View full analysis
[chain]}" CHAIN="${2:-base}" CHAIN_LOWER=$(echo "$CHAIN" | tr '[:upper:]' '[:lower:]') ADDR_LOWER=$(echo "$TOKEN_ADDRESS" | tr '[:upper:]' '[:lower:]') API_BASE="${SUPAH_API_BASE:-https://api.supah.ai}" ``` The command-line values are subsequently embedded directly into the source passed to `node -e`: ```javascript console.log('Token: ' + name + ' (\$' + symbol + ')'); console.log('Chain: ' + '${CHAIN}'.charAt(0).toUpperCase() + '${CHAIN}'.slice(1)); console.log('Address: ' + '${TOKEN_ADDRESS}'.substring(0,6) + '...' + '${TOKEN_ADDRESS}'.substring(38)); ``` ### Technical Analysis `CHAIN` and `TOKEN_ADDRESS` are taken directly from positional command-line arguments. They are not validated as a supported chain identifier or a 40-byte hexadecimal EVM address. The script constructs a JavaScript program inside a shell double-quoted string passed to `node -e`. The values are substituted directly into JavaScript single-quoted string literals. Shell quoting does not provide JavaScript escaping. A value containing a single quote followed by valid JavaScript can terminate the intended string and introduce additional statements. Injected JavaScript executes in the Node.js process with the same operating-system privileges and environment as the Skill. Node.js exposes powerful modules such as `child_process`, `fs`, `net`, and `http`, so successful JavaScript injection can be converted into arbitrary local command execution, file access, or additional network communication. Execution of the injected section occurs after the remote request and initial response parsing. Exploitation therefore requires the request path to reach the vulnerable Node.js statements, such as when the configured endpoint returns a u ...[truncated 1728 chars]
Remediation
View remediation
&2 exit 2 fi ``` 2. Normalize and validate the chain against an explicit allowlist derived from the supported-chain documentation: ```bash case "$CHAIN_LOWER" in eth|ethereum|bsc|bnb|polygon|matic|arb|arbitrum|op|optimism|base|avax|avalanche|ftm|fantom|cro|cronos|xdai|gnosis|celo|moonbeam|one|harmony|zksync|era|linea|scroll|mantle|blast|mode|manta) ;; *) echo "Unsupported chain" >&2 exit 2 ;; esac ``` 3. Never interpolate input into executable JavaScript source. Pass data through environment variables or positional arguments instead: ```bash CHAIN_VALUE="$CHAIN" TOKEN_ADDRESS_VALUE="$TOKEN_ADDRESS" node <<'NODE' const chain = process.env.CHAIN_VALUE; const tokenAddress = process.env.TOKEN_ADDRESS_VALUE; console.log( 'Chain: ' + chain.charAt(0).toUpperCase() + chain.slice(1) ); console.log( 'Address: ' + tokenAddress.substring(0, 6) + '...' + tokenAddress.substring(38) ); NODE ``` 4. URL-encode path and query components using a structured URL builder rather than concatenating untrusted values into a URL. 5. Reject all unexpected HTTP status codes before invoking the response parser. Only process explicitly supported success responses. 6. If `SUPAH_API_BASE` remains configurable, require HTTPS and validate the hostname against an approved destination list unless arbitrary endpoints are an intentional administrative feature. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/guardian-scan.sh:53
Finding

Predictable Temporary Result File Allows Symlink-Based File Overwrite

Content
View full analysis
/tmp/guardian-result.json echo "📄 JSON: /tmp/guardian-result.json" ``` The successful response path writes to the same predictable path through Node.js: ```javascript // Save JSON fs.writeFileSync('/tmp/guardian-result.json', JSON.stringify(d, null, 2)); console.log(''); console.log('📄 JSON: /tmp/guardian-result.json'); ``` ### Technical Analysis The Skill always stores results at `/tmp/guardian-result.json`. This pathname is globally predictable and is located in a shared temporary directory. Neither the shell redirection nor `fs.writeFileSync()` verifies that the destination is a regular file owned by the current user. Both operations normally follow an existing symbolic link. A local attacker can therefore create `/tmp/guardian-result.json` as a symbolic link to another file before the Skill runs. When the Skill writes its output, the operating system follows the symbolic link and truncates or overwrites the linked destination if the Skill process has permission to write to it. The same fixed path also causes separate executions or users to overwrite one another's results, creating confidentiality and integrity risks. ### Attack Path 1. A local attacker predicts the fixed result path `/tmp/guardian-result.json`. 2. Before the Skill creates the file, the attacker places a symbolic link at that path pointing to a target file writable by the Skill process. 3. The victim runs a scan. 4. The script enters either the HTTP 402 path or the successful response path. 5. Shell redirection or `fs.writeFileSync()` follows the sy ...[truncated 1016 chars]
Remediation
View remediation
"$RESULT_FILE" ``` ```javascript const resultFile = process.env.RESULT_FILE; fs.writeFileSync(resultFile, JSON.stringify(d, null, 2), { encoding: 'utf8', mode: 0o600, flag: 'wx' }); ``` 3. Prefer an agent-private runtime or state directory with permissions set to `0700` instead of a globally shared temporary directory. 4. Use exclusive file creation and refuse to overwrite an existing destination. Do not follow pre-existing links. 5. Register cleanup logic with `trap` if results are intended to be temporary: ```bash trap 'rm -f -- "$RESULT_FILE"' EXIT ``` If the caller needs the result after termination, return the unique path and delegate cleanup explicitly rather than reverting to a fixed filename. 6. Avoid sharing one output file across concurrent executions. A unique file per scan also prevents cross-run result corruption. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
80% confidence
Finding

The skill advertises use of shell-capable binaries (curl, node) but does not declare any explicit tool scope such as permissions or allowed-tools. In agent environments, missing scope boundaries can let the skill run with broader-than-expected execution capabilities, increasing the risk of unintended command execution or abuse if the skill is invoked in a permissive runtime.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The invocation examples are very broad and phrased like ordinary trading conversation, which makes accidental or overly eager triggering more likely. Because each invocation can initiate an x402 USDC micropayment, ambiguous activation could cause unintended paid scans, external data exfiltration about user-supplied token targets, or repeated spend in normal chat flows.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documentation states that Base is used when no chain is specified, but it does not warn users that an omitted or ambiguous chain can cause analysis to run against the wrong network. In a pre-trade token safety scanner spanning many EVM chains, this can mislead users into trusting results for the wrong asset or contract, especially where the same symbol or address format appears across chains.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.