Back to skill

Security audit

Multichain Portfolio Tracker

Security checks for vulnerabilities and agentic risk

Overview

This crypto tracker is mostly purpose-aligned, but its shell scripts can execute unintended local code from crafted inputs and the documentation overstates some financial-tracking features.

Install only if you are comfortable reviewing and fixing the scripts first. Do not run it with untrusted token names, wallet addresses, alert values, or config paths, and avoid cron use until the Python interpolation bugs are removed and privacy/storage behavior is clearly documented.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/check-wallet.sh:16
Finding

Arbitrary Python Code Execution Through Wallet Arguments

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/price.sh:27
Finding

Arbitrary Python Code Execution Through Token Arguments

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/portfolio.sh:46
Finding

Python Injection Through Portfolio Configuration Path

Content
View full analysis
/dev/null | while read -r WALLET_JSON; do ``` The same unsafe pattern is repeated for manual entries: ```bash python3 -c " import json with open('$CONFIG') as f: config = json.load(f) manual = config.get('manual', []) ``` ### Technical Analysis `CONFIG` can be supplied as a command-line argument. Although the script checks that the named file exists, it inserts the filename directly into single-quoted Python source. Unix filenames can contain quotes, semicolons, comment characters, and newlines. Consequently, an attacker who can create a specially named file and influence the config-path argument can terminate or restructure the generated `with open(...)` statement and append arbitrary Python instructions. The file-existence check does not sanitize the filename and therefore does not prevent source injection. The vulnerable code is reached twice during a normal portfolio scan. ### Attack Path 1. An attacker creates a file whose filename contains Python syntax and also arranges for any path referenced by the resulting injected expression to exist. 2. The attacker causes `portfolio.sh` to run with that specially crafted filename as its configuration argument. 3. The shell substitutes the filename into the double-quoted `python3 -c` program. 4. The embedded quote or newline changes the structure of the Python program. 5. Injected Python executes while the script attempts to load wallets or manual entries. ### Impact Assessment The injected code executes as the user running the portfolio scan. It can acces ...[truncated 364 chars]
Remediation
View remediation
/dev/null`; report parsing and validation failures safely. - Consolidate configuration parsing into one safe invocation rather than repeating vulnerable source construction. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/alerts.sh:21
Finding

Python Injection Through Alert Configuration Path

Content
View full analysis
/dev/null) ``` The path is interpolated again later: ```bash python3 -c " import json, sys with open('$CONFIG') as f: config = json.load(f) ``` ### Technical Analysis The optional configuration path is controlled by the first command-line argument and is directly embedded in Python source. A specially crafted filename can escape the intended Python string and introduce executable statements. Checking `[ -f "$CONFIG" ]` establishes only that a file with that name exists. It does not make the filename safe for insertion into source code. Since the alert script is explicitly intended for cron use, this injection point may be reached in a recurring, unattended context. ### Attack Path 1. An attacker creates a specially named configuration file containing Python metacharacters in its filename. 2. The attacker influences the path passed to `alerts.sh` or an automated alert command. 3. Bash substitutes the filename into the `python3 -c` source. 4. The resulting Python program contains attacker-supplied statements. 5. Those statements execute during alert-token extraction or subsequent alert processing. ### Impact Assessment Exploitation grants arbitrary code execution as the account running the alert checker. The attacker can read local data, execute commands, alter user files, and initiate arbitrary network connections. When the script runs from cron, the vulnerability can provide reliable repeated execution under the cron account, altho ...[truncated 87 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/alerts.sh:39
Finding

Python Source Injection Through Embedded Price API Response

Content
View full analysis
/dev/null) TRIGGERED=0 python3 -c " import json, sys with open('$CONFIG') as f: config = json.load(f) prices_raw = '''$PRICES_JSON''' try: prices = json.loads(prices_raw) ``` ### Technical Analysis `PRICES_JSON` is produced from a CoinGecko network response and is inserted directly into a triple-quoted Python literal. Triple-quoted strings are not a safe serialization boundary. Content containing a matching triple-quote sequence can terminate the literal and append Python statements. Under expected CoinGecko behavior, the response is ordinary JSON and does not intentionally contain executable content. Exploitation therefore requires control or manipulation of the upstream response, a compromised data source, or another means of influencing the captured output. Nevertheless, network data must be treated as untrusted, and directly converting it into source code creates an avoidable code-execution sink. The outbound request itself sends only requested token identifiers and is consistent with the declared price-alert functionality; the issue is how the returned data is locally processed. ### Attack Path 1. An attacker gains control over, or can manipulate, the price response consumed by `price.sh`. 2. The response contains content that closes the `'''...'''` Python literal and introduces a Python statement. 3. `alerts.sh` captures that output in `PRICES_JSON`. 4. Shell expansion places the malicious response inside the `python3 -c` program. 5. Python parses and executes the injected statement before JSON validation can provide protection. ### Impact Assessment If the response-manipulation prerequisite is met, arbitrary Python executes with the privi ...[truncated 373 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

If the skill only performs limited token price lookup while claiming full wallet balance tracking, aggregation, alerting, and multi-chain support, users may expose wallet data and rely on outputs under false assumptions. The crypto-finance context makes this more dangerous because accuracy and coverage directly affect monitoring, trading, and record-keeping decisions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

If the skill only performs limited token price lookup while claiming full wallet balance tracking, aggregation, alerting, and multi-chain support, users may expose wallet data and rely on outputs under false assumptions. The crypto-finance context makes this more dangerous because accuracy and coverage directly affect monitoring, trading, and record-keeping decisions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the skill only performs limited token price lookup while claiming full wallet balance tracking, aggregation, alerting, and multi-chain support, users may expose wallet data and rely on outputs under false assumptions. The crypto-finance context makes this more dangerous because accuracy and coverage directly affect monitoring, trading, and record-keeping decisions.

Content

No source excerpt is available for this finding.

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/portfolio.sh (reported line 39)May include surrounding context.

sh
echo "================================"

# Get prices for native tokens
PRICES=$(curl -s "https://api.coingecko.com/api/v3/simple/price?ids=ethereum,solana,matic-network&vs_currencies=usd" 2>/dev/null)
ETH_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; print(json.load(sys.stdin).get('ethereum',{}).get('usd',0))" 2>/dev/null)
SOL_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; print(json.load(sys.stdin).get('solana',{}).get('usd',0))" 2>/dev/null)
MATIC_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; print(json.load(sys.stdin).get('matic-network',{}).get('usd',0))" 2>/dev/null)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill advertises shell and network-driven workflows but does not declare any tool scope such as permissions or allowed-tools. In an agent environment, that omission weakens policy boundaries and can allow the skill to be invoked with broader-than-expected capabilities, increasing the chance of unintended command execution or outbound requests.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · scripts/portfolio.sh (reported line 39)May include surrounding context.

sh
echo "================================"

# Get prices for native tokens
PRICES=$(curl -s "https://api.coingecko.com/api/v3/simple/price?ids=ethereum,solana,matic-network&vs_currencies=usd" 2>/dev/null)
ETH_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; print(json.load(sys.stdin).get('ethereum',{}).get('usd',0))" 2>/dev/null)
SOL_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; print(json.load(sys.stdin).get('solana',{}).get('usd',0))" 2>/dev/null)
MATIC_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; print(json.load(sys.stdin).get('matic-network',{}).get('usd',0))" 2>/dev/null)

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · scripts/price.sh (reported line 49)May include surrounding context.

sh
echo "================================"

# Get prices for native tokens
PRICES=$(curl -s "https://api.coingecko.com/api/v3/simple/price?ids=ethereum,solana,matic-network&vs_currencies=usd" 2>/dev/null)
ETH_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; print(json.load(sys.stdin).get('ethereum',{}).get('usd',0))" 2>/dev/null)
SOL_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; print(json.load(sys.stdin).get('solana',{}).get('usd',0))" 2>/dev/null)
MATIC_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; print(json.load(sys.stdin).get('matic-network',{}).get('usd',0))" 2>/dev/null)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The script invokes a secondary wallet-checking script for each configured wallet address, which by the skill's purpose likely results in external lookups tied to the user's wallet addresses. Although the script prints portfolio results, it does not disclose before execution that user wallet information will be sent to external services during scanning.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The documentation instructs users to query wallet balances and prices through public RPCs and third-party APIs without disclosing that wallet addresses and query metadata are sent to external providers. In a crypto portfolio context, this can reveal sensitive financial associations and tracking information, especially when public RPCs are used repeatedly or via automation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The cron example instructs users to append portfolio snapshots to a local history file without warning that this creates persistent financial records. Even if written locally, those records can disclose wallet holdings, balances, and activity patterns to other users, backups, or later processes on the same system.

Content

No source excerpt is available for this finding.