Back to skill

Security audit

Archon Cashu

Security checks for vulnerabilities and agentic risk

Overview

This wallet skill mostly matches its stated Cashu/Archon purpose, but it has serious review-worthy gaps around wallet backups, dependency execution, and high-impact payment actions.

Review this carefully before installing. Do not run backup.sh unless the backup is fixed to encrypt locally before any IPFS upload, and avoid using the LNbits auto-pay and unpinned npx workflows with real funds until dependency pinning, confirmations, and validation are added.

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/cashu/backup.sh:63
Finding
Unencrypted Cashu Wallet Backup Uploaded to IPFS<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cashu/backup.sh`, lines 63-99 **Vulnerability Type**: Plaintext exposure of sensitive wallet data **Risk Level**: Critical ### Vulnerable Code ```bash # Step 1: Export wallet data # Copy wallet database if [ -d "$CASHU_WALLET_DIR" ]; then cp -r "$CASHU_WALLET_DIR" "$BACKUP_DIR/cashu-wallet" else echo "⚠️ No wallet directory at $CASHU_WALLET_DIR" rm -rf "$BACKUP_DIR" exit 1 fi # Step 2: Record balance for verification BALANCE=$($CASHU_BIN balance 2>&1 || echo "unknown") echo "$BALANCE" > "$BACKUP_DIR/balance.txt" # Step 3: Record metadata cat > "$BACKUP_DIR/metadata.json" << EOF { "timestamp": "$TIMESTAMP", "date": "$(date -Iseconds)", "balance": "$BALANCE", "mint": "$CASHU_MINT_URL", "wallet_dir": "$CASHU_WALLET_DIR", "hostname": "$(hostname)", "sha256": "$(find "$BACKUP_DIR/cashu-wallet" -type f -exec sha256sum {} \; | sha256sum | cut -d' ' -f1)" } EOF # Step 4: Create tarball TARBALL="/tmp/cashu-backup-${TIMESTAMP}.tar.gz" tar -czf "$TARBALL" -C "$BACKUP_DIR" . # Step 5: Upload to IPFS and store CID in vault echo "🔐 Uploading encrypted backup to IPFS..." # Add to IPFS IPFS_RESULT=$(curl -s -X POST "http://localhost:5001/api/v0/add" \ -F "file=@${TARBALL}" 2>/dev/null) ``` ### Technical Analysis The script copies the complete Cashu wallet directory and creates a gzip-compressed tar archive. Compression does not provide confidentiality, and no encryption command or authenticated-encryption operation occurs before the archive is submitted to the local IPFS API. The comment at line 3 and the status message at line 95 describe the backup as encrypted, but the implementation uploads plaintext wallet contents inside a compressed archive. This misleading security claim can cause users to upload sensitive wallet material under the false assumption that it is cryptographically protected. IPFS is content-addressed and designed for distribution and r ...[truncated 1403 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Encrypt the archive locally before making any IPFS request. Use authenticated encryption, such as age, a properly configured OpenPGP implementation, or AES-GCM through a reviewed library. 2. Store the encryption key outside the archive and outside the public CID metadata. Prefer a recipient public key or a hardware-backed secret. 3. Verify that the output is an encrypted container before upload and fail closed if encryption fails. 4. Never upload the plaintext archive, even temporarily. 5. Replace the misleading “encrypted backup” message with an accurate status message and document IPFS replication and retention risks. 6. Require explicit user confirmation before the first remote or distributed backup unless a separately reviewed noninteractive policy has been configured. 7. Consider limiting the backup to the minimum files required for recovery rather than copying the complete wallet directory. 8. Implement and test a restore workflow that validates authenticity and integrity before extracting wallet data. ]]>

T08 · Insecure Dependencies

Error
Location
scripts/cashu/backup.sh:25
Finding
Execution of Unpinned Registry Packages Through npx<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cashu/backup.sh`, line 25; `scripts/cashu/receive.sh`, lines 15-18 **Vulnerability Type**: Mutable third-party dependency execution **Risk Level**: High ### Vulnerable Code From `scripts/cashu/backup.sh`: ```bash if [ -z "$VAULT_DID" ]; then # Check if vault exists by name in aliases VAULT_DID=$(npx --yes @didcid/keymaster resolve-alias "$VAULT_NAME" 2>/dev/null || true) fi ``` From `scripts/cashu/receive.sh`: ```bash # Step 1: Refresh notices npx --yes @didcid/keymaster refresh-dmail 2>/dev/null || true # Step 2: Get all dmails as JSON DMAILS=$(npx --yes @didcid/keymaster list-dmail 2>/dev/null) ``` ### Technical Analysis The scripts invoke `npx --yes @didcid/keymaster` without an exact package version, a committed lockfile, or an integrity constraint. If the package is not already available locally, `npx` may retrieve and execute the version currently resolved by the configured npm registry. The `--yes` option removes the interactive installation prompt. Consequently, a future package release, compromised maintainer account, compromised registry response, or unsafe registry configuration can change the code executed by these reviewed scripts without changing the project itself. The downloaded package runs with the invoking user's privileges and inherits the process environment. In these workflows, that environment may include `ARCHON_WALLET_PATH`, `ARCHON_PASSPHRASE`, and other wallet-related configuration loaded by `config.sh`. ### Attack Path 1. An attacker compromises the package publishing account, registry, or package distribution path, or causes an unsafe package version to be resolved. 2. A user invokes the backup or receive workflow. 3. `npx --yes` downloads or resolves the mutable `@didcid/keymaster` package without additional approval. 4. Package lifecycle behavior or CLI code executes with the user's operating-system privileges. 5. The compromised code reads inherited ...[truncated 683 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `@didcid/keymaster` to an exact reviewed version rather than relying on the registry's current resolution. 2. Add a package manifest and committed lockfile containing integrity hashes. 3. Install dependencies during a controlled setup phase and invoke the fixed local binary, for example through `node_modules/.bin`, rather than allowing runtime downloads. 4. Use `npm ci` against the reviewed lockfile and disable lifecycle scripts where compatible with the dependency. 5. Verify package provenance and signatures when the package ecosystem supports them. 6. Run the dependency with the smallest possible environment. Do not expose `ARCHON_PASSPHRASE` or unrelated wallet credentials to commands that do not require them. 7. Consider sandboxing the command with restricted filesystem and network access. 8. Treat dependency download or integrity failure as a hard error instead of silently continuing. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cashu/backup.sh:15
Finding
Predictable and Insufficiently Protected Temporary Wallet Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cashu/backup.sh`, lines 15-17 and 57-92 **Vulnerability Type**: Unsafe temporary file and directory handling **Risk Level**: High ### Vulnerable Code ```bash # Backup config CASHU_WALLET_DIR="${CASHU_WALLET_DIR:-$HOME/.cashu}" VAULT_NAME="${CASHU_VAULT_NAME:-cashu-wallet-vault}" BACKUP_DIR="/tmp/cashu-backup-$$" ``` ```bash mkdir -p "$BACKUP_DIR" echo "📦 Backing up cashu wallet..." echo " Wallet dir: $CASHU_WALLET_DIR" echo " Vault: $VAULT_DID" # Step 1: Export wallet data # Copy wallet database if [ -d "$CASHU_WALLET_DIR" ]; then cp -r "$CASHU_WALLET_DIR" "$BACKUP_DIR/cashu-wallet" else echo "⚠️ No wallet directory at $CASHU_WALLET_DIR" rm -rf "$BACKUP_DIR" exit 1 fi # Step 2: Record balance for verification BALANCE=$($CASHU_BIN balance 2>&1 || echo "unknown") echo "$BALANCE" > "$BACKUP_DIR/balance.txt" # Step 3: Record metadata cat > "$BACKUP_DIR/metadata.json" << EOF { "timestamp": "$TIMESTAMP", "date": "$(date -Iseconds)", "balance": "$BALANCE", "mint": "$CASHU_MINT_URL", "wallet_dir": "$CASHU_WALLET_DIR", "hostname": "$(hostname)", "sha256": "$(find "$BACKUP_DIR/cashu-wallet" -type f -exec sha256sum {} \; | sha256sum | cut -d' ' -f1)" } EOF # Step 4: Create tarball TARBALL="/tmp/cashu-backup-${TIMESTAMP}.tar.gz" tar -czf "$TARBALL" -C "$BACKUP_DIR" . ``` ### Technical Analysis The backup directory is derived from the process ID, and the archive name is derived from a timestamp. Both are predictable in a shared temporary directory. The script uses `mkdir -p` rather than atomically creating a unique directory with `mktemp`. It also does not establish a restrictive `umask` or explicitly assign owner-only permissions to the temporary directory and archive. Actual exposure depends on the host's existing umask and temporary-directory protections, but the script does not enforce the confidentiality requirements appropriate for complete wallet ...[truncated 1434 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Set `umask 077` before creating any wallet backup files. 2. Create the temporary directory atomically: ```bash BACKUP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/cashu-backup.XXXXXXXX")" ``` 3. Create the archive through a securely created temporary file rather than a predictable timestamp name. 4. Verify that temporary paths are owned by the current user and are not symbolic links before writing. 5. Register cleanup immediately after creating temporary resources: ```bash cleanup() { rm -rf -- "$BACKUP_DIR" rm -f -- "${TARBALL:-}" } trap cleanup EXIT INT TERM HUP ``` 6. Explicitly apply owner-only permissions to directories and files, such as mode `700` for directories and `600` for archives. 7. Encrypt sensitive data before it is written to a persistent temporary archive. 8. Where practical, keep intermediate data in a private runtime directory or process it as a stream to minimize plaintext data at rest. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (25)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill markets DID-derived cryptographic locking but the reported behavior uses DID only as a messaging or routing identifier and sends unlocked Cashu tokens over dmail. That is a security-significant mismatch because users may believe only the intended DID holder can redeem funds when the implementation may actually deliver bearer tokens through a less restricted channel.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill markets DID-derived cryptographic locking but the reported behavior uses DID only as a messaging or routing identifier and sends unlocked Cashu tokens over dmail. That is a security-significant mismatch because users may believe only the intended DID holder can redeem funds when the implementation may actually deliver bearer tokens through a less restricted channel.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill markets DID-derived cryptographic locking but the reported behavior uses DID only as a messaging or routing identifier and sends unlocked Cashu tokens over dmail. That is a security-significant mismatch because users may believe only the intended DID holder can redeem funds when the implementation may actually deliver bearer tokens through a less restricted channel.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The header says the wallet proofs are encrypted before backup, but the implementation only copies the wallet directory, creates a tar.gz, and uploads it to IPFS with no encryption step. Because Cashu wallet contents can directly enable spending, publishing plaintext backups can expose funds and sensitive wallet metadata to anyone who obtains the archive or CID.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
echo "🔄 Minting $AMOUNT sats from $CASHU_MINT_URL..."

# Step 1: Request invoice via cashu CLI (captures the quote ID)
INVOICE_OUTPUT=$($CASHU_BIN invoice "$AMOUNT" --no-check 2>&1)
BOLT11=$(echo "$INVOICE_OUTPUT" | grep -oP 'lnbc[a-z0-9]+' | head -1)
QUOTE_ID=$(echo "$INVOICE_OUTPUT" | grep -oP '(?<=--id )[A-Za-z0-9_-]+' | head -1)
Confidence
85% confidence
Finding
Using the cashu CLI with --no-check disables validation during invoice/quote retrieval, which can cause the script to trust unverified output before extracting and paying a BOLT11 invoice. In this skill's context, that is more dangerous because the script immediately automates payment via LNbits, so a malicious or misconfigured mint/CLI response could induce payment for an unvalidated invoice or incorrect quote.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The core send flow creates an unlocked Cashu token and places it directly into the dmail body, despite the skill being described as supporting DID-derived P2PK-locked payments. In this skill context, that mismatch is especially dangerous because users are likely to trust the DID integration for recipient binding, but the token is actually transferable to any party who sees it, enabling theft through message interception, mailbox compromise, terminal logging, or accidental disclosure.

Session Persistence

Medium
Category
Rogue Agent
Content
## Setup

```bash
# Create config (edit with your paths)
./config.sh --create

# Edit the config
Confidence
60% 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.

Lp3

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding
The skill advertises shell-driven operations and explicitly references multiple executable scripts and external binaries, but it does not declare any tool scope such as permissions or allowed-tools. This creates an authorization ambiguity where an agent may invoke shell capabilities more broadly than users expect, increasing the risk of unintended command execution or privilege misuse.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The backup feature is presented as a simple operation without prominently warning that it exports wallet material to another storage domain ('vault'). For an ecash wallet, backups may contain sensitive secrets or proofs; users who are not warned about confidentiality and destination trust may unintentionally exfiltrate recoverable funds.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding
The script executes `npx --yes @didcid/keymaster` without pinning an exact package version or integrity, which means future runs may fetch and execute a changed or compromised package. In a wallet-backup workflow handling sensitive ecash data, that creates a supply-chain execution risk on the local host.

External Transmission

Medium
Category
Data Exfiltration
Content
if [ -z "$VAULT_DID" ]; then
        echo "Creating vault '$VAULT_NAME'..." >&2
        # Create vault via keymaster API
        VAULT_RESULT=$(curl -s -X POST "http://localhost:4226/api/v1/vaults" \
            -H "Content-Type: application/json" -d '{}')
        VAULT_DID=$(echo "$VAULT_RESULT" | jq -r '.did // empty')
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding
This backup flow performs IPFS publication of the wallet archive, which is more than a local vault backup and materially changes the exposure model. In the context of a Cashu wallet, undeclared publication is especially dangerous because backup artifacts may contain spendable proofs, balances, hostnames, and wallet paths.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The script transmits a wallet backup to IPFS without an explicit warning or confirmation that sensitive data is leaving the host. Since IPFS content addressing facilitates retrieval by CID and the script lacks encryption, users may unknowingly expose private wallet material and related metadata.

External Transmission

Medium
Category
Data Exfiltration
Content
echo "📌 IPFS CID: $IPFS_CID"
    
    # Store backup reference in vault via keymaster API
    STORE_RESULT=$(curl -s -X POST "http://localhost:4226/api/v1/vaults/$VAULT_DID" \
        -H "Content-Type: application/json" \
        -d "{\"key\": \"cashu-backup-${TIMESTAMP}\", \"value\": {\"cid\": \"$IPFS_CID\", \"timestamp\": \"$TIMESTAMP\", \"balance\": \"$BALANCE\", \"sha256\": \"$(sha256sum "$TARBALL" | cut -d' ' -f1)\"}}" 2>/dev/null)
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
90% confidence
Finding
The manual restore guidance instructs the user to extract a backup tarball directly into the wallet directory, which can modify or overwrite existing wallet files. For a destructive or irreversible operation, the file lacks any explicit warning, confirmation step, or comment advising users to back up or inspect the target directory first.

Session Persistence

Medium
Category
Rogue Agent
Content
# SECURITY: No default passphrase - must be set via ~/.archon.env or environment

create_default_config() {
    mkdir -p "$(dirname "$CONFIG_FILE")"
    
    # Check if passphrase is available
    if [ -z "$ARCHON_PASSPHRASE" ]; then
Confidence
60% 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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
# SECURITY: Passphrase sourced from ~/.archon.env, not stored here
# ARCHON_PASSPHRASE is inherited from environment
EOF
    chmod 600 "$CONFIG_FILE"
    echo "Created config at $CONFIG_FILE"
}
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
# SECURITY: Passphrase sourced from ~/.archon.env, not stored here
# ARCHON_PASSPHRASE is inherited from environment
EOF
    chmod 600 "$CONFIG_FILE"
    echo "Created config at $CONFIG_FILE"
}
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 script performs a live wallet send operation that creates a transferable Cashu token immediately from command-line inputs, with no interactive confirmation, dry-run step, or explicit warning to the user. In the context of an agent skill handling ecash, this increases the chance of accidental or unauthorized fund transfer if the script is invoked with the wrong DID, wrong amount, or by a higher-level agent flow without sufficient user consent.

External Transmission

Medium
Category
Data Exfiltration
Content
fi

echo "⚡ Paying invoice from LNbits..."
PAY_RESULT=$(curl -s -X POST -H "X-Api-Key: $LNBITS_ADMIN_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"out\": true, \"bolt11\": \"$BOLT11\"}" \
    "$LNBITS_HOST/api/v1/payments")
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
88% confidence
Finding
The script automatically redeems any Cashu-like token strings found in recent Nostr DMs by passing them directly to the wallet's receive command, without prompting the user or clearly warning that wallet state will be modified. In a wallet-management skill, this is risky because DMs are untrusted input and redemption can consume wallet resources, alter balances, or trigger acceptance of unwanted/spam tokens without deliberate user consent.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The script executes `npx --yes @didcid/keymaster` without pinning an exact package version, so each run may fetch and execute whatever version is currently published. In a wallet/payment workflow, a compromised or malicious upstream release could tamper with dmail contents, exfiltrate wallet-related data, or manipulate token handling before receipt.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
This second `npx --yes @didcid/keymaster` invocation has the same supply-chain risk: it may download and run an unpinned remote package at execution time. Because the script is used for receiving ecash-related messages, the skill context increases the danger: a hostile package update could interfere with inbox enumeration, harvest sensitive metadata, or alter payment-related behavior.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The script claims to send ecash in the Archon DID context, but it generates a plain Cashu token and transmits it over messaging without binding it to the recipient's DID or a P2PK lock. Anyone who gains access to the message contents in transit, logs, or recipient-side leakage can redeem the bearer token, so the implementation violates the expected security model and can mislead users into unsafe transfers.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script places a bearer-like Cashu token directly into the dmail message body, so anyone who can read, intercept, log, or later access that message may obtain the token material. Although the token is P2PK-locked and therefore harder to redeem without the recipient's private key, transmitting redeemable ecash over a messaging channel still creates a sensitive-data exposure path and may leak payment metadata or enable abuse if the lock is bypassed, misimplemented, or future tooling mishandles it.

Static analysis

No suspicious patterns detected.