Back to skill

Security audit

ClawPurse

Security checks for vulnerabilities and agentic risk

Overview

ClawPurse is a coherent local crypto wallet, but it handles wallet secrets and can perform high-impact staking actions with guardrail gaps that deserve review before installation.

Install only if you are comfortable giving this CLI access to a wallet that can move or stake real NTMPI. Avoid passing passwords or mnemonics on the command line, keep allowlist enforcement enabled, review staking commands manually, restrict ~/.clawpurse permissions, and update or audit dependencies before production use.

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

T09 · Insecure Skill Coding Practices

Error
Location
src/cli.ts:52
Finding
Wallet Passwords and Recovery Mnemonics Can Be Exposed Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `src/cli.ts:52-60`, `src/cli.ts:201-207` **Vulnerability Type**: Sensitive credential exposure through process arguments **Risk Level**: High ### Vulnerable Code ```typescript async function promptPassword(promptText: string): Promise<string> { // For now, use env var or argument - interactive prompt needs enquirer const password = process.env.CLAWPURSE_PASSWORD || getArg('--password'); if (!password) { console.error(`Error: Password required. Set CLAWPURSE_PASSWORD env var or use --password flag`); process.exit(1); } return password; } ``` ```typescript const mnemonic = getArg('--mnemonic') || process.env.CLAWPURSE_MNEMONIC; if (!mnemonic) { console.error('Error: Mnemonic required. Use --mnemonic or set CLAWPURSE_MNEMONIC'); process.exit(1); } ``` ### Technical Analysis The CLI explicitly accepts wallet passwords through `--password` and complete BIP-39 recovery phrases through `--mnemonic`. Process arguments are not an appropriate secret-transport mechanism because they may be recorded or exposed through: - Shell history files. - Process inspection utilities and `/proc` interfaces. - Audit and endpoint-monitoring systems. - CI/CD command logs. - Container or orchestration metadata. - Debug output and command wrappers. A recovery mnemonic grants full and generally irreversible control over the wallet. A disclosed password can be combined with access to `keystore.enc` to decrypt the mnemonic. Although environment variables are preferable to command-line arguments in some environments, they may also be exposed through process inspection, crash reports, or deployment configuration. The declared wallet functionality requires access to these secrets, but it does not require placing them in globally observable command-line metadata. ### Attack Path 1. A user or automated Agent executes a command such as: ```bash clawpurse import --mnemonic "word1 word2 ..." --password "wallet- ...[truncated 1038 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove support for `--password` and `--mnemonic` command-line arguments. 2. Implement a masked interactive password prompt using Enquirer or a dedicated secure-prompt library. 3. Accept mnemonics through a protected interactive prompt, an explicitly opened file descriptor, or standard input only when the caller confirms that stdin is not being logged. 4. Consider integration with operating-system credential stores for unattended operation. 5. Retain environment-variable support only when necessary for automation and display a clear warning that environment variables are not universally confidential. 6. Ensure documentation and examples no longer encourage secret-bearing command-line flags. 7. Add tests that reject `--password` and `--mnemonic` and verify that secrets do not appear in logs or error messages. 8. Minimize the lifetime of decrypted mnemonic and password values and avoid including them in exception contexts. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/receipts.ts:33
Finding
Transaction Receipt File Is Written Without Explicit Confidentiality Permissions<![CDATA[ ## Vulnerability Details **File Location**: `src/receipts.ts:33-37` **Vulnerability Type**: Insecure local storage permissions **Risk Level**: Medium ### Vulnerable Code ```typescript async function saveReceipts(receipts: Receipt[]): Promise<void> { const receiptsPath = getReceiptsPath(); await fs.mkdir(path.dirname(receiptsPath), { recursive: true }); await fs.writeFile(receiptsPath, JSON.stringify(receipts, null, 2)); } ``` ### Technical Analysis The receipt file is written without an explicit file mode. Its final permissions therefore depend on the process umask and on any permissions already associated with the file. This differs from the keystore and allowlist implementations, which request mode `0600`. The receipt records contain sender and recipient addresses, transaction amounts, timestamps, transaction hashes, gas usage, and optional memos. Blockchain addresses and hashes are public once known, but collecting them in a local file associates them with a specific local user and can disclose a complete financial activity profile. Memos may contain additional business or personal information. The write operation also replaces the file directly rather than using an atomic temporary-file-and-rename sequence. A crash during writing could corrupt the audit trail, although the primary confirmed security issue is the absence of explicit confidentiality permissions. ### Attack Path 1. ClawPurse runs under a permissive umask or writes to a pre-existing file with permissive permissions. 2. `~/.clawpurse/receipts.json` becomes readable by the user's group or by other local users. 3. Another local account or process reads the receipt file. 4. The attacker correlates wallet addresses, counterparties, payment amounts, timestamps, and memo contents. 5. The information may be used for financial surveillance, targeted phishing, extortion, or identification of high-value wallets. ### Impact Assessment The vulnerability exposes local financial metad ...[truncated 390 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create `~/.clawpurse` with mode `0700`. 2. Write `receipts.json` with mode `0600`: ```typescript await fs.writeFile(receiptsPath, data, { mode: 0o600 }); ``` 3. Explicitly apply `chmod(0o600)` to existing files because the `mode` option does not necessarily correct permissions on an already existing file. 4. Use an atomic write strategy: - Create a temporary file in the same protected directory. - Set mode `0600`. - Flush the file where appropriate. - Rename it atomically over the destination. 5. Consider encrypting receipt memos or allowing users to disable local memo retention. 6. Add permission tests under different umask values and verify both directory and file modes. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
src/staking.ts:102
Finding
Staking Operations Bypass Transaction Limits and Consistent Confirmation Controls<![CDATA[ ## Vulnerability Details **File Location**: `src/staking.ts:102-253`, `src/cli.ts:455-537` **Vulnerability Type**: Missing authorization guardrails for high-impact financial operations **Risk Level**: High ### Vulnerable Code The delegation path parses the amount and immediately signs the transaction without invoking `validateAmount`, applying `KEYSTORE_CONFIG.maxSendAmount`, checking an allowlist, or requiring confirmation: ```typescript export async function delegate( wallet: DirectSecp256k1HdWallet, delegatorAddress: string, validatorAddress: string, amount: string ): Promise<StakeResult> { const microAmount = parseAmount(amount); // Validate validator address if (!validatorAddress.startsWith('neutarovaloper')) { throw new Error(`Invalid validator address. Expected neutarovaloper prefix, got ${validatorAddress.slice(0, 15)}...`); } const client = await getSigningClient(wallet); const msg = { typeUrl: '/cosmos.staking.v1beta1.MsgDelegate', value: MsgDelegate.fromPartial({ delegatorAddress, validatorAddress, amount: { denom: NEUTARO_CONFIG.denom, amount: microAmount.toString(), }, }), }; const result = await client.signAndBroadcast( delegatorAddress, [msg], 'auto', 'Staked via ClawPurse' ); ``` The same pattern appears in undelegation and redelegation: ```typescript export async function undelegate( wallet: DirectSecp256k1HdWallet, delegatorAddress: string, validatorAddress: string, amount: string ): Promise<StakeResult> { const microAmount = parseAmount(amount); if (!validatorAddress.startsWith('neutarovaloper')) { throw new Error(`Invalid validator address. Expected neutarovaloper prefix, got ${validatorAddress.slice(0, 15)}...`); } const client = await getSigningClient(wallet); ``` ```typescript export async function redelegate( wallet: DirectSecp256k1HdWallet, delegatorAddress: string, srcValidatorAddr ...[truncated 4578 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a shared transaction-policy layer used by transfers, delegation, undelegation, and redelegation. 2. Apply strict amount validation before calling `parseAmount`. 3. Enforce explicit configurable limits for each staking operation, with conservative defaults. 4. Require a masked, interactive confirmation that displays: - Exact base and display amounts. - Source wallet. - Source and destination validators. - Estimated fees. - Unbonding consequences where applicable. 5. Do not treat a simple `--yes` switch as sufficient authorization for high-value unattended operations. Use scoped policy files, short-lived approval tokens, or transaction-specific signatures for automation. 6. Decode validator addresses with a canonical Bech32 implementation and verify the checksum, expected prefix, and payload length. 7. Optionally maintain a separate validator allowlist and block unknown validators by default for Agent deployments. 8. Reject same-validator redelegation locally. 9. Record staking receipts with the same protected audit controls used for transfers. 10. Add tests proving that excessive, zero, negative, malformed, and overprecision staking amounts are rejected and that confirmation thresholds cannot be bypassed accidentally. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (135)

Self-Modification

High
Category
Rogue Agent
Content
1. **Download this package** to your local machine
2. **Navigate** to your ClawPurse repository
3. **Drag and drop** all files from this package into your repository
   - Your OS will prompt to replace existing files
   - Click "Replace" or "Merge" for all conflicts
4. **Done!** All enhancements are now in your repo
Confidence
97% confidence
Finding
This is a self-modification pattern because the document tells the operator to replace existing repository files wholesale. That behavior can directly alter source code, tests, GitHub Actions, and web assets in one step, enabling persistent compromise or insertion of malicious logic if the package is untrusted or has been tampered with.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
If you need to start fresh:
```bash
# Remove all ClawPurse data (DESTRUCTIVE!)
rm -rf ~/.clawpurse

# Reinitialize
clawpurse init --password <new-password>
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
If you need to start fresh:
```bash
# Remove all ClawPurse data (DESTRUCTIVE!)
rm -rf ~/.clawpurse

# Reinitialize
clawpurse init --password <new-password>
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Known Vulnerable Dependency: brace-expansion==1.1.12 — 4 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-33750 (brace-expansion: Zero-step sequence causes process hang and memory exhaustion); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro) +1 more

High
Category
Supply Chain
Confidence
92% confidence
Finding
brace-expansion 1.1.12 is present and is reported vulnerable to multiple denial-of-service conditions from pathological brace patterns. Although this instance is in transitive dev tooling, many build, lint, or test paths may still process attacker-influenced glob patterns in CI or local automation, making it a real availability risk.

Known Vulnerable Dependency: minimatch==3.1.2 — 3 advisory(ies): CVE-2026-27904 (minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regu); CVE-2026-26996 (minimatch has a ReDoS via repeated wildcards with non-matching literal in patter); CVE-2026-27903 (minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adja)

High
Category
Supply Chain
Confidence
93% confidence
Finding
minimatch 3.1.2 is flagged for ReDoS via crafted glob patterns that trigger catastrophic backtracking. This is a genuine vulnerability class, and while it appears in development dependency paths here, attacker-controlled patterns in CLI, CI, or repository automation could still hang processes.

Known Vulnerable Dependency: js-yaml==3.14.2 — 4 advisory(ies): CVE-2026-84375 (js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources); CVE-2026-59869 (js-yaml: YAML merge-key chains can force quadratic CPU consumption); GHSA-5p4m-2wfm-xmqj (JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026) +1 more

High
Category
Supply Chain
Confidence
90% confidence
Finding
js-yaml 3.14.2 is affected by several CPU consumption issues involving malicious YAML constructs. Even though this specific copy is transitively included in dev tooling, YAML parsers are commonly fed project files or CI-provided content, so crafted input could cause denial of service during development workflows.

Known Vulnerable Dependency: picomatch==2.3.1 — 2 advisory(ies): CVE-2026-33672 (Picomatch: Method Injection in POSIX Character Classes causes incorrect Glob Mat); CVE-2026-33671 (Picomatch has a ReDoS vulnerability via extglob quantifiers)

High
Category
Supply Chain
Confidence
90% confidence
Finding
picomatch 2.3.1 is reported vulnerable to both incorrect glob matching and ReDoS from crafted extglob patterns. Because glob parsing is frequently reachable from developer tooling and repository automation, this is a genuine dependency weakness even if not obviously exposed at runtime.

Known Vulnerable Dependency: brace-expansion==2.0.2 — 4 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-33750 (brace-expansion: Zero-step sequence causes process hang and memory exhaustion); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro) +1 more

High
Category
Supply Chain
Confidence
91% confidence
Finding
brace-expansion 2.0.2 is also present and carries the same family of denial-of-service issues from malicious expansion patterns. As with the 1.x instance, this is primarily a tooling availability risk in this package-lock rather than a direct runtime compromise, but it remains a true vulnerability.

Known Vulnerable Dependency: browserslist==4.28.1 — 2 advisory(ies): CVE-2026-73088 (Browserslist: Uncaught crash / prototype write via untrusted browserslist-stats.); CVE-2026-73089 (Browserslist: Unbounded memory growth (no cache eviction) via distinct query res)

High
Category
Supply Chain
Confidence
82% confidence
Finding
browserslist 4.28.1 is flagged for crash/prototype-write and memory growth issues when handling untrusted stats or many distinct queries. Since this is part of build/development tooling rather than the wallet/CLI runtime shown here, the practical danger is reduced, but exploitation could still disrupt CI or developer environments.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"lint": "eslint src/",
    "lint:fix": "eslint src/ --fix",
    "type-check": "tsc --noEmit",
    "clean": "rm -rf dist/",
    "pretest": "npm run type-check",
    "security-check": "npm audit"
  },
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Possible Typosquatting: 'enquirer' resembles popular package 'inquirer'

High
Category
Supply Chain
Confidence
70% confidence
Finding
Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
### Coverage Not Generated

```bash
rm -rf coverage/
npm run test:coverage
```
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"Keystore has correct permissions (600)"
    
    # Clean up for next tests
    rm -rf "$HOME/.clawpurse"
}

test_wallet_import() {
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"Keystore has correct permissions (600)"
    
    # Clean up for next tests
    rm -rf "$HOME/.clawpurse"
}

test_wallet_import() {
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"Keystore has correct permissions (600)"
    
    # Clean up for next tests
    rm -rf "$HOME/.clawpurse"
}

test_wallet_import() {
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"Keystore has correct permissions (600)"
    
    # Clean up for next tests
    rm -rf "$HOME/.clawpurse"
}

test_wallet_import() {
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"Keystore has correct permissions (600)"
    
    # Clean up for next tests
    rm -rf "$HOME/.clawpurse"
}

test_wallet_import() {
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"Keystore has correct permissions (600)"
    
    # Clean up for next tests
    rm -rf "$HOME/.clawpurse"
}

test_wallet_import() {
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"Keystore has correct permissions (600)"
    
    # Clean up for next tests
    rm -rf "$HOME/.clawpurse"
}

test_wallet_import() {
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"Keystore has correct permissions (600)"
    
    # Clean up for next tests
    rm -rf "$HOME/.clawpurse"
}

test_wallet_import() {
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"Keystore has correct permissions (600)"
    
    # Clean up for next tests
    rm -rf "$HOME/.clawpurse"
}

test_wallet_import() {
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"Keystore has correct permissions (600)"
    
    # Clean up for next tests
    rm -rf "$HOME/.clawpurse"
}

test_wallet_import() {
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"Keystore has correct permissions (600)"
    
    # Clean up for next tests
    rm -rf "$HOME/.clawpurse"
}

test_wallet_import() {
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Hidden Instructions

High
Category
Prompt Injection
Content
<main id="main">

    <!-- HERO -->
    <section class="hero">
      <div class="container">
        <div class="hero-badge">Infraestructura de micropagos de código abierto en Neutaro</div>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
</div>
    </section>

    <!-- GATEWAY FEATURES -->
    <section id="gateway-features">
      <div class="container">
        <span class="section-label">Gateway 402</span>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Static analysis

No suspicious patterns detected.