Back to skill

Security audit

Axon Agent

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do what it claims, but it handles wallet private keys, irreversible on-chain transactions, and persistent background services without enough safeguards.

Review before installing. Use a dedicated low-funds wallet, prefer address-only status checks, protect the private-key file tightly, verify the Axon repo and dependency versions yourself, run dry-run first, and do not execute real registration unless you accept the permanent burn, stake lockup, and persistent daemon/cron behavior.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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 (4)

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:66
Finding
Unpinned Remote Dependencies and Mutable Source Build<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:24`, `SKILL.md:66-70`, `README.md:17`, `references/known-issues.md:51-54` **Vulnerability Type**: Unverified third-party dependencies and mutable remote code execution **Risk Level**: High ### Vulnerable Code ```bash # SKILL.md:24 pip install web3 ``` ```bash # SKILL.md:66-70 git clone https://github.com/axon-chain/axon /opt/axon cd /opt/axon # Build daemon go build -o tools/agent-daemon/agent-daemon ./tools/agent-daemon/ ``` ### Technical Analysis The installation instructions retrieve the latest available `web3` package and clone the current state of a remote Git repository. No exact package version, Git commit, release signature, checksum, or reproducible dependency lockfile is specified. The cloned code is compiled into a daemon that is subsequently given the path to the user's EVM private-key file. Consequently, the security of the wallet depends on the mutable state of both the Python package registry and the upstream Git repository at installation time. This behavior is related to the Skill's declared functionality, but it creates a supply-chain boundary that extends beyond the reviewed project. The effective daemon payload can change after this audit without any modification to the Skill package. ### Attack Path 1. An attacker compromises the upstream repository, a maintainer account, a dependency, or the package publishing process. 2. Malicious code is added to the repository's default branch or to an unpinned `web3` release. 3. A user follows the documented installation instructions. 4. The altered code is downloaded and installed or compiled locally. 5. The daemon is started with access to `/opt/axon/private_key.txt`. 6. The malicious component reads the private key, signs unauthorized transactions, transmits the key, or executes commands with the installing user's privileges. ### Impact Assessment Successful exploitation could provide arbitrary code execution under the accoun ...[truncated 270 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `web3` and all transitive Python dependencies to audited versions in a lockfile. 2. Require hash verification, such as `pip install --require-hashes -r requirements.txt`. 3. Pin the Axon repository to a specific audited commit or signed release tag rather than its default branch. 4. Verify Git signatures or published release checksums before compilation. 5. Record the expected commit and binary hash in the Skill documentation. 6. Build and run the daemon under a dedicated, unprivileged service account. 7. Restrict private-key access to only the component that must sign heartbeat transactions. 8. Consider hardware-backed signing or an isolated signer instead of exposing a raw private-key file to the complete daemon process. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/check-status.py:31
Finding
Read-Only Status Check Unnecessarily Loads the Wallet Private Key<![CDATA[ ## Vulnerability Details **File Location**: `scripts/check-status.py:31-42`; documented as the primary workflow in `SKILL.md:31` and `README.md:25` **Vulnerability Type**: Violation of least privilege in sensitive credential handling **Risk Level**: Medium ### Vulnerable Code ```python parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument("--address", help="Agent EVM address") group.add_argument("--private-key-file", help="Path to private key file") args = parser.parse_args() w3 = Web3(Web3.HTTPProvider(RPC_URL)) registry = w3.eth.contract(address=REGISTRY_ADDRESS, abi=REGISTRY_ABI) if args.private_key_file: pk = open(args.private_key_file).read().strip() address = w3.eth.account.from_key(pk).address else: address = args.address ``` The primary documented invocation is: ```bash python3 scripts/check-status.py --private-key-file /opt/axon/private_key.txt ``` ### Technical Analysis Balance, registration state, reputation, and online status are public blockchain data and require only an EVM address. Nevertheless, the documented default workflow causes the status script and its imported dependency graph to read the wallet's raw private key. The current script does not explicitly transmit or print the private key. The issue is that it broadens the number of processes and dependencies exposed to a high-value secret without a functional need. This violates least privilege and increases the consequences of a compromised Python environment, malicious dependency, debugger, crash handler, or later code change. ### Attack Path 1. The user follows the documented status-check command and supplies a private-key file. 2. The script reads the complete private key into process memory. 3. A compromised `web3` installation, injected Python module, debugger, process-memory reader, or malicious future modification accesses the key. 4. The key is copied or transmitted to an attacker. 5. The att ...[truncated 384 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make `--address` the only recommended status-check workflow. 2. Update `SKILL.md` and `README.md` to use: ```bash python3 scripts/check-status.py --address 0x... ``` 3. Remove `--private-key-file` from the read-only script unless there is a compelling usability requirement. 4. If address derivation must be supported, move it into a separate, minimal offline utility with no RPC connection. 5. Avoid retaining the raw private key in a long-lived variable and ensure key files are permission-restricted. 6. Document that a private key is never required to query public on-chain state. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/register.py:82
Finding
Registration Proceeds After Preflight Safety Checks Fail<![CDATA[ ## Vulnerability Details **File Location**: `scripts/register.py:82-100` **Vulnerability Type**: Fail-open handling of irreversible blockchain transactions **Risk Level**: High ### Vulnerable Code ```python # Check if already registered (isAgent ABI decode may fail on some nodes — skip if so) try: if registry.functions.isAgent(address).call(): print("已是 Agent,无需重复注册") try: info = registry.functions.getAgent(address).call() print(f"Agent ID: {info[0]} | isOnline: {info[4]} | Reputation: {info[3]}") except Exception: pass return except Exception as e: print(f"[WARN] isAgent 查询失败(已知问题,继续注册): {e}") if args.dry_run: print(f"[DRY RUN] 将以 capabilities='{args.capabilities}', model='{args.model}', stake=100 AXON 注册") return print(f"正在注册 Agent (capabilities={args.capabilities}, model={args.model})...") # eth_call simulation (best-effort — Axon precompile may return empty, skip if fails) try: registry.functions.register(args.capabilities, args.model).call({ "from": address, "value": STAKE_AMOUNT }) print("eth_call 模拟通过,发送真实交易...") except Exception as e: print(f"[WARN] eth_call 模拟失败(Axon 预编译合约已知问题,继续发送真实交易): {e}") ``` ### Technical Analysis Two preflight checks are explicitly fail-open: - Failure to determine whether the wallet is already registered does not stop execution. - Failure to simulate the payable registration call does not stop execution. The script then builds and broadcasts a transaction carrying 100 AXON. According to the project documentation, 20 AXON is permanently burned during successful registration. The script also uses a hardcoded transaction chain ID but does not independently verify that the connected RPC reports chain ID `9001`, even though `references/known-issues.md` recommends this check. Treating arbitrary RPC or ABI errors as known benign behavior prevents the program from distinguishing an expected precompile limitatio ...[truncated 1047 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Fail closed when `isAgent` or transaction simulation fails. 2. Add an explicit `--force` option for exceptional cases; never continue automatically. 3. Before signing, verify: - `w3.eth.chain_id == 9001` - The registry address is the expected checksummed address. - The RPC is connected and returns consistent network metadata. 4. Display a final transaction summary containing destination, chain ID, value, gas limit, gas price, maximum fee, nonce, capabilities, and model. 5. Require explicit user confirmation for non-dry-run execution. 6. Attempt gas estimation and distinguish known precompile responses from arbitrary exceptions. 7. Refuse duplicate registration unless the existing registration state has been conclusively determined. 8. Where possible, validate registry bytecode or an expected on-chain contract identifier before transferring funds. ]]>

T06 · System Persistence

Warning
Location
scripts/watchdog.sh:2
Finding
Cron-Based Daemon Persistence Is Non-Idempotent and Uses an Ambiguous Process Check<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:84-94`, `scripts/watchdog.sh:2-21` **Vulnerability Type**: Insufficiently hardened scheduled persistence mechanism **Risk Level**: Medium ### Vulnerable Code ```bash # SKILL.md:84-94 # Copy watchdog to your server (replace YOUR_SERVER and YOUR_KEY) scp scripts/watchdog.sh user@YOUR_SERVER:/opt/axon/watchdog.sh ssh user@YOUR_SERVER "chmod +x /opt/axon/watchdog.sh" # Add cron (every 5 min) ssh user@YOUR_SERVER "(crontab -l 2>/dev/null; echo '*/5 * * * * /opt/axon/watchdog.sh') | crontab -" ``` ```bash #!/bin/bash # Axon agent-daemon watchdog — run via cron: */5 * * * * /opt/axon/watchdog.sh # Usage: Set AXON_DIR, PRIVATE_KEY, and RPC below, then: crontab -e → add line above AXON_DIR="${AXON_DIR:-/opt/axon}" DAEMON="$AXON_DIR/tools/agent-daemon/agent-daemon" PK_FILE="$AXON_DIR/private_key.txt" RPC="${AXON_RPC:-https://mainnet-rpc.axonchain.ai/}" LOG="$AXON_DIR/watchdog.log" if ! pgrep -f "agent-daemon" > /dev/null 2>&1; then echo "$(date '+%Y-%m-%d %H:%M:%S') [RESTART] daemon not running" >> "$LOG" nohup "$DAEMON" \ --rpc "$RPC" \ --private-key-file "$PK_FILE" \ --heartbeat-interval 720 \ --log-level info \ >> "$AXON_DIR/daemon.log" 2>&1 & echo "$(date '+%Y-%m-%d %H:%M:%S') [RESTART] new PID: $!" >> "$LOG" else echo "$(date '+%Y-%m-%d %H:%M:%S') [OK] daemon running" >> "$LOG" fi ``` ### Technical Analysis The persistence mechanism is disclosed and directly supports the declared requirement to maintain periodic blockchain heartbeats. It is therefore not a hidden backdoor. However, its implementation has several security and reliability weaknesses: - Re-running the installation command appends duplicate cron entries. - No uninstall or cleanup procedure is supplied. - `pgrep -f "agent-daemon"` matches any process whose full command line contains that text, rather than the intended executable and instance. - The watchdog executes fixed files ...[truncated 1789 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make watchdog installation explicitly optional and explain that it creates cross-session persistence. 2. Make installation idempotent by checking for an existing uniquely tagged cron entry before adding one. 3. Provide documented disable and uninstall commands. 4. Prefer a hardened `systemd` service with: - A dedicated unprivileged user - `NoNewPrivileges=true` - Filesystem and capability restrictions - An explicit executable path - Controlled restart policy 5. If cron remains supported, use `flock` to prevent concurrent runs. 6. Track the daemon using a validated PID file and verify `/proc/<pid>/exe` resolves to the expected binary. 7. Require `/opt/axon`, the watchdog, the daemon, and key file to have restrictive ownership and permissions. 8. Verify daemon integrity before execution, such as with a pinned checksum. 9. Rotate logs to prevent indefinite disk consumption. 10. Isolate signing credentials from the general daemon process where technically possible. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (13)

External Model or Provider Selection

High
Category
Excessive Agency
Content
"""
Axon Agent Registration Script
Bypasses the official SDK due to ABI mismatch (see references/known-issues.md).
Usage: python3 register.py --private-key-file /path/to/key.txt --capabilities "nlp,coding" --model "claude-sonnet-4.6"
"""
import argparse
import sys
Confidence
90% confidence
Finding
Skill selects an external model or provider that may use a different account or billing plan than the operator expects. Undisclosed model switches can cause unexpected cost or quota consumption.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The README instructs users to provide a private key file directly to local scripts, but it does not include any warning about secure storage, file permissions, shell history, or the risk of exposing wallet credentials. In a blockchain context, compromise of the private key would allow full control of the wallet and loss of staked or liquid funds, so normalizing this workflow without safety guidance materially increases credential-handling risk.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The skill directs users to store an EVM private key in a local file and then pass that file to scripts and a long-running daemon, but it lacks a strong secret-handling warning. This increases the risk of credential theft through file leakage, shell history, backups, logs, permissive ownership, or compromise of the host running the daemon.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
## Prerequisites

- Server with Python 3.8+ and Go 1.21+
- EVM wallet private key saved to a file (e.g. `/opt/axon/private_key.txt`, chmod 600)
- Minimum 120 AXON balance (100 stake + 20 burn + gas buffer)
- `web3` Python package: `pip install web3`
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill instructs the user to perform an on-chain registration that stakes 100 AXON and notes that 20 AXON is burned permanently, but it does not present a clear warning/consent step immediately before the irreversible transaction. Because blockchain transactions are final, users may unintentionally incur permanent financial loss if they follow the instructions without understanding the consequences.

Session Persistence

Medium
Category
Rogue Agent
Content
go build -o tools/agent-daemon/agent-daemon ./tools/agent-daemon/

# Start daemon
nohup /opt/axon/tools/agent-daemon/agent-daemon \
  --rpc https://mainnet-rpc.axonchain.ai/ \
  --private-key-file /opt/axon/private_key.txt \
  --heartbeat-interval 720 \
Confidence
83% confidence
Finding
The skill starts a background daemon with nohup, creating a process that persists beyond the interactive session and continuously uses the wallet key for heartbeats. While operationally necessary for this blockchain agent, background persistence increases exposure if the host is compromised or if the daemon/binary is replaced or misconfigured.

Session Persistence

Medium
Category
Rogue Agent
Content
ssh user@YOUR_SERVER "chmod +x /opt/axon/watchdog.sh"

# Add cron (every 5 min)
ssh user@YOUR_SERVER "(crontab -l 2>/dev/null; echo '*/5 * * * * /opt/axon/watchdog.sh') | crontab -"
```

---
Confidence
86% confidence
Finding
The skill installs a recurring cron job on a remote server, which creates persistence by automatically executing a script every five minutes. In legitimate admin context this may be intended, but from a security perspective persistence mechanisms are sensitive because they can survive session termination and repeatedly run modified or compromised scripts.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This code accesses a highly sensitive credential by reading a private key from a user-supplied file and deriving an address from it. Although the file usage is visible in the CLI argument, there is no confirmation prompt, warning print, or comment/docstring explaining the sensitivity of this operation or advising safe handling.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
Several user-facing strings are hardcoded in Chinese, which imposes a specific language on users without offering a language choice or documenting that the tool is intended only for a Chinese-speaking context. This matches the policy category for language or locale restrictions without user opt-in.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code prints multiple user-facing messages in Chinese, including balance, errors, warnings, and success notices. Because the script does not provide a locale option or document a justified region-specific constraint, it forces a specific language on users and violates the language/locale policy criterion.

Session Persistence

Medium
Category
Rogue Agent
Content
#!/bin/bash
# Axon agent-daemon watchdog — run via cron: */5 * * * * /opt/axon/watchdog.sh
# Usage: Set AXON_DIR, PRIVATE_KEY, and RPC below, then: crontab -e → add line above

AXON_DIR="${AXON_DIR:-/opt/axon}"
DAEMON="$AXON_DIR/tools/agent-daemon/agent-daemon"
Confidence
85% 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.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script starts a long-running daemon with a private key file from disk, but provides no safeguards around secret storage, permissions, or operator warnings. In this context, the daemon appears to be an agent connected to an external RPC endpoint, so compromise of the key file or accidental insecure deployment could expose credentials used for blockchain or agent identity operations.

Session Persistence

Medium
Category
Rogue Agent
Content
if ! pgrep -f "agent-daemon" > /dev/null 2>&1; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') [RESTART] daemon not running" >> "$LOG"
    nohup "$DAEMON" \
        --rpc "$RPC" \
        --private-key-file "$PK_FILE" \
        --heartbeat-interval 720 \
Confidence
65% 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.

Static analysis

No suspicious patterns detected.