Back to skill

Security audit

Clanker

Security checks for vulnerabilities and agentic risk

Overview

This skill is meant for crypto token deployment, but it handles wallet keys and irreversible mainnet transactions with insufficient safeguards.

Review carefully before installing. Use only throwaway testnet keys until the key handling, file permissions, dependency pinning, contract addresses, and explicit pre-transaction confirmation are fixed. Do not use a funded mainnet wallet with this version unless you fully accept the risk of key exposure and irreversible ETH spending.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/clanker.sh:318
Finding
Wallet Private Key Exposed Through Process Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/clanker.sh`, lines 318-327; `scripts/deploy.py`, lines 586-607 **Vulnerability Type**: Sensitive credential exposure through process arguments **Risk Level**: High ### Vulnerable Code ```bash local private_key=$(get_private_key "$network") if [[ -z "$private_key" ]]; then print_error "Cannot deploy: private key not configured" exit 1 fi local rpc_url=$(get_rpc_url "$network") # Use Python deployment helper python3 "$SCRIPT_DIR/deploy.py" "$network" "$name" "$symbol" "$lp_eth" "$private_key" --rpc-url "$rpc_url" ``` The Python helper explicitly accepts the key as a positional argument: ```python parser.add_argument( "private_key", help="Private key (with or without 0x prefix)" ) args = parser.parse_args() deploy_token( args.network, args.name, args.symbol, args.initial_lp_eth, args.private_key, args.rpc_url, ) ``` ### Technical Analysis The shell script reads the wallet private key from the configuration and inserts it directly into the `python3` process argument vector. On operating systems that expose process arguments through facilities such as `/proc/<pid>/cmdline`, `ps`, process-monitoring agents, audit logs, crash diagnostics, or endpoint telemetry, the complete private key may become visible outside the deployment process. The deployment helper may remain active while waiting up to 120 seconds for a transaction receipt, increasing the observation window. Although `deploy.py` signs transactions locally and transmits only signed transactions to the RPC endpoint, that protection is undermined by exposing the signing key in the local process metadata. Passing the arguments as a quoted array prevents shell command injection, but quoting does not protect the key from process-list disclosure. ### Attack Path 1. A user configures a funded Base wallet and invokes `clanker.sh deploy` or `clanker.sh testnet-deploy`. 2. `clanker.sh` extracts the complet ...[truncated 1355 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the positional `private_key` argument from `deploy.py`. - Pass the key through a protected anonymous pipe or standard input, ensuring it is never printed or included in error messages. - Prefer a signer abstraction backed by a hardware wallet, operating-system keychain, encrypted keystore, or external signing service. - If an environment variable is used as an interim measure, remove it immediately after reading and recognize that some process-inspection environments may expose environment variables as well. - Avoid storing the complete configuration JSON, including keys, in global shell variables. - Clear shell variables holding secrets as soon as signing is complete. - Add automated tests that inspect the child process command line and verify that no private key is present. - Document that any wallet previously used with this implementation should be considered at risk if untrusted local monitoring or telemetry was present. A safer interface would read the key from standard input: ```bash get_private_key "$network" | python3 "$SCRIPT_DIR/deploy.py" \ "$network" "$name" "$symbol" "$lp_eth" \ --private-key-stdin \ --rpc-url "$rpc_url" ``` The Python process should then read exactly one line from standard input without logging it. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/test.sh:16
Finding
Plaintext Wallet Configuration Is Created Without Restrictive File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/test.sh`, lines 16-30 **Vulnerability Type**: Insecure storage permissions for wallet credentials **Risk Level**: Medium ### Vulnerable Code ```bash CONFIG_FILE="$HOME/.clawdbot/skills/clanker/config.json" if [[ ! -f "$CONFIG_FILE" ]]; then mkdir -p "$HOME/.clawdbot/skills/clanker" cat > "$CONFIG_FILE" << 'EOF' { "mainnet": { "rpc_url": "https://1rpc.io/base", "private_key": "PLACEHOLDER" }, "testnet": { "rpc_url": "https://base-sepolia.public.blastapi.io", "private_key": "PLACEHOLDER" } } EOF echo "Created test config at $CONFIG_FILE" fi ``` The documented production configuration uses the same plaintext format: ```json { "mainnet": { "rpc_url": "https://1rpc.io/base", "private_key": "YOUR_PRIVATE_KEY" }, "testnet": { "rpc_url": "https://sepolia.base.org", "private_key": "YOUR_TESTNET_PRIVATE_KEY" } } ``` ### Technical Analysis The test script creates the configuration with ordinary shell redirection but does not set a restrictive `umask`, apply `chmod 600`, or validate ownership and permissions before later reading the file. Under a common `umask` of `022`, the file is created with mode `0644`, making it readable by other local users. The initially generated file contains placeholders, not real secrets. However, the documented workflow instructs users to place real mainnet and testnet private keys in this same file. If a user edits the generated file, its original permissive mode normally remains unchanged. The runtime also accepts existing configuration files without checking whether they are symlinks, owned by the current user, or accessible by group and other users. ### Attack Path 1. The user runs `scripts/test.sh`, which creates `~/.clawdbot/skills/clanker/config.json` using the current default `umask`. 2. The resulting file may be readable by group members or all local users. 3. The user follows the setup instructions and r ...[truncated 950 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Set a restrictive mask before creating credential directories or files: ```bash umask 077 mkdir -p "$HOME/.clawdbot/skills/clanker" ``` - Create configuration files atomically and explicitly enforce permissions: ```bash install -m 600 /dev/null "$CONFIG_FILE" ``` - Enforce directory mode `0700` and file mode `0600`. - Before loading the file, reject it if it: - Is a symbolic link. - Is not owned by the current effective user. - Is writable or readable by group or other users. - Replace raw private keys with encrypted Web3 keystore files, hardware-wallet signing, or an operating-system credential store. - Update `SKILL.md` to include exact permission-hardening commands. - Avoid instructing users to place mainnet keys in files created by test utilities. - Add a startup warning and refuse mainnet deployment when unsafe permissions are detected. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:43
Finding
Unpinned Third-Party Python Dependencies Installed from Mutable Package Sources<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 43-49; `scripts/clanker.sh`, lines 301-305; `scripts/deploy.py`, lines 5-31 **Vulnerability Type**: Unpinned supply-chain dependency installation **Risk Level**: Low ### Vulnerable Code ```bash pip install web3 ``` The deployment helper also presents mutable installation commands: ```python Requires: web3 Python package (includes eth_abi) Install: pip install web3 ``` ```python except ImportError: print("Error: web3 package not installed.") print("Install with: pip install web3") sys.exit(1) ``` ```python except ImportError: print("Error: eth_abi package not installed.") print("Install with: pip install eth-abi") sys.exit(1) ``` ### Technical Analysis The project instructs users to install `web3` and `eth-abi` without version constraints, lock files, hashes, or an isolated virtual environment. Consequently, the code installed at setup time can differ from the code reviewed and tested by the Skill author. These are established package names rather than apparent typosquatting attempts, and the Skill does not automatically execute `pip install`. The issue is therefore a supply-chain hardening weakness rather than evidence of an intentionally malicious dependency. Nevertheless, a compromised upstream release, malicious transitive dependency, or incompatible future version would execute in the same Python context that handles wallet private keys and signs transactions. ### Attack Path 1. A user follows the documented deployment setup and runs `pip install web3`. 2. The package resolver downloads the latest available release and its current transitive dependency graph. 3. A compromised or malicious package release executes installation-time or runtime code. 4. The user invokes token deployment. 5. The dependency runs inside `deploy.py`, where it can access the private key supplied to the process, alter transaction construction, replace the destination contract, o ...[truncated 709 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Provide a reviewed dependency lock file with exact versions and hashes. - Install using hash verification, for example: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` - Pin both direct and transitive dependencies. - Use a dedicated virtual environment instead of modifying the user or system Python environment. - Run dependency vulnerability and provenance checks in CI. - Regularly review and deliberately update pinned versions rather than resolving the latest release during installation. - Document the expected package index and discourage untrusted mirrors. - Consider packaging the helper with reproducible build metadata and signed release artifacts. ]]>
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The documented behavior does not match the reported implementation: private key handling differs, deployment is reportedly done through direct contract/web3 calls rather than a higher-level SDK, and there is additional undeclared transaction behavior. For a blockchain deployment skill handling private keys and funds, this mismatch is dangerous because operators may authorize actions under false assumptions, leading to unintended transactions, fund movement, or key exposure.

External Script Fetching

High
Category
Supply Chain
Content
local params="$2"
    local rpc_url="$3"
    
    curl -s -X POST "$rpc_url" \
        -H "Content-Type: application/json" \
        -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"$method\",\"params\":$params}" \
        | python3 -c "import sys,json; print(json.load(sys.stdin).get('result','0x'))"
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
local network="$2"
    local rpc_url=$(get_rpc_url "$network")
    
    local receipt=$(curl -s -X POST "$rpc_url" \
        -H "Content-Type: application/json" \
        -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getTransactionReceipt\",\"params\":[\"$txhash\"]}")
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Lp3

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding
The skill documents use of shell, file, and environment-dependent behavior but does not declare any explicit tool scope or permissions boundaries. In an agent setting, this can cause the skill to run with broader capabilities than users expect, increasing the chance of unintended file access, secret exposure, or command execution during token deployment workflows.

Session Persistence

Medium
Category
Rogue Agent
Content
---
name: clanker
description: Deploy ERC20 tokens on Base using Clanker SDK. Create tokens with built-in Uniswap V4 liquidity pools. Supports Base mainnet and Sepolia testnet. Requires PRIVATE_KEY in config.
metadata: {"clawdbot":{"emoji":"🪙","homepage":"https://clanker.world","requires":{"bins":["curl","jq","python3"]}}}
---
Confidence
84% confidence
Finding
The skill instructs users to store persistent private keys in a config file under the home directory, creating session-persistent secret material on disk. In an agent ecosystem with file access, persistent wallet keys materially raise the impact of compromise because later runs, other skills, or local malware could read and misuse them to sign transactions.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest advertises token deployment support, but the body of the documentation later states deployment is only a placeholder and direct deployment is not implemented. This inconsistency can mislead users or downstream agents into attempting high-risk financial operations with an incomplete or nonfunctional workflow, which is especially risky in a crypto context.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The usage section presents deploy commands as if they are operational, while later notes say deployment is placeholder-only and not implemented. This contradiction can cause users or agents to trust unsafe or nonexistent behavior, potentially resulting in mistaken execution attempts, confusion around transaction signing, or reliance on incomplete deployment logic.

Session Persistence

Medium
Category
Rogue Agent
Content
### Step 1: Set Up Testnet Config

```bash
# Create config with testnet private key
cat > ~/.clawdbot/skills/clanker/config.json << 'EOF'
{
  "testnet": {
Confidence
87% confidence
Finding
The testing guide explicitly tells users to write a private key into a persistent file in ~/.clawdbot/skills/clanker/config.json. This creates durable sensitive material in a predictable location, making credential theft and unauthorized transaction signing more likely if the host or agent environment is compromised.

External Transmission

Medium
Category
Data Exfiltration
Content
- Base Mainnet: ~0.01 - 0.05 ETH gas (varies with network usage)
- Base Sepolia: Free (testnet)

## Common Operations via curl

### Get Token Info (ERC20 ABI)
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
local params="$2"
    local rpc_url="$3"
    
    curl -s -X POST "$rpc_url" \
        -H "Content-Type: application/json" \
        -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"$method\",\"params\":$params}" \
        | python3 -c "import sys,json; print(json.load(sys.stdin).get('result','0x'))"
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
local params="$2"
    local rpc_url="$3"
    
    curl -s -X POST "$rpc_url" \
        -H "Content-Type: application/json" \
        -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"$method\",\"params\":$params}" \
        | python3 -c "import sys,json; print(json.load(sys.stdin).get('result','0x'))"
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The deploy and testnet-deploy paths invoke the deployment helper with a configured private key and no explicit confirmation, dry-run, or irreversible-action warning. In this skill’s context, that means a user or upstream agent can trigger real blockchain transactions and spend funds immediately, which is especially risky on mainnet because transactions are irreversible and may create unwanted contracts or liquidity positions.

Session Persistence

Medium
Category
Rogue Agent
Content
$0 info 0xabcd... --network testnet

Setup:
    Create ~/.clawdbot/skills/clanker/config.json with RPC and private keys.
    See SKILL.md for configuration details.

EOF
Confidence
90% confidence
Finding
The skill instructs users to persist private keys in a long-lived plaintext config file under ~/.clawdbot/skills/clanker/config.json. Storing signing keys unencrypted on disk materially increases the chance of wallet compromise through local malware, accidental disclosure, backups, or overly permissive file permissions.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
When initial_lp_eth > 0, the script silently adds a dev-buy extension and sends ETH as part of the deployment transaction, introducing an on-chain purchase side effect beyond straightforward token deployment. In a skill that asks users for a private key and signs live transactions, this hidden extra spend increases the chance of unintended fund usage and misleading operator expectations.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script signs and broadcasts a live blockchain transaction immediately after building it, with no interactive confirmation, dry-run mode, or final summary requiring user approval. Because the skill explicitly requires a private key and may send ETH value, a mistaken invocation, wrong RPC, malformed parameters, or misleading wrapper automation can directly cause irreversible on-chain loss.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The header comment says the script 'Tests read-only operations on Base mainnet', which implies no local state changes. However, when the config does not exist, the script creates directories and writes a new config.json file in ~/.clawdbot/skills/clanker, so the documentation contradicts the actual side effects.

Vague Triggers

Low
Confidence
84% confidence
Finding
The description explains what the skill does but does not define specific trigger phrases, invocation constraints, or when it should not activate. In a markdown skill file, this can lead to overly broad or unintended invocation because the activation boundary is left implicit.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
print(f"Warning: Could not verify hook/locker/mev module enablement: {exc}")

    # Get the correct function based on deploy method
    deploy_func = getattr(clanker_contract.functions, deploy_method)

    # Build transaction
    nonce = w3.eth.get_transaction_count(account.address)
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Static analysis

No suspicious patterns detected.