T09 · Insecure Skill Coding Practices
- Location
conto-check.sh:231- Finding
Python Code Injection Through the Agent Name
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill has a coherent payment-policy purpose, but it gives agents financial and policy-admin authority with weak safeguards around credential setup, storage, endpoint validation, destructive policy changes, and final fund transfers.
Review this carefully before installing, especially if you would use an admin SDK key or let the agent move funds. Prefer a standard payment-approval key, avoid admin policy commands from chat, confirm every transfer yourself, keep CONTO_API_URL fixed to the real HTTPS Conto endpoint, and secure or rotate any SDK key written to ~/.hermes/.env.
conto-check.sh:231Python Code Injection Through the Agent Name
conto-check.sh:198Unauthenticated Local Callback Allows SDK Credential Injection
' + error.encode() + b'
You can close this window.
') with open('${TMPFILE}', 'w') as f: json.dump({'error': error}, f) elif sdk_key: self.wfile.write(b'You can close this window and return to your terminal.
') with open('${TMPFILE}', 'w') as f: json.dump({'sdkKey': sdk_key, 'agentId': agent_id, 'org': org}, f) else: self.wfile.write(b'No SDK key received.
') with open('${TMPFILE}', 'w') as f: json.dump({'error': 'No SDK key in callback'}, f) threading.Thread(target=self.server.shutdown).start() def log_message(self, *a): pass server = http.server.HTTPServer(('127.0.0.1', ${CALLBACK_PORT}), Handler) server.timeout = 300 try: server.handle_request() except: pass " & ``` ### Technical Analysis The temporary callback server accepts the first HTTP GET request and trusts the `sdkKey`, `agentId`, and `org` query parameters without authenticating the response. There is no cryptographically random state value, callback nonce, exact-path validation, origin binding, authorization-code exchange, or signature verification. Binding to ...[truncated 1599 chars]conto-check.sh:271SDK Key Is Stored Without Enforcing Restrictive File Permissions
conto-check.sh:27Configurable API URL Can Exfiltrate Bearer Credentials or Forge Policy Responses
README.md:220Unpinned npx Dependency Executes Mutable Remote Package Code
The declared description frames the skill as a payment policy checker, but the content also provisions agents, opens browser-based setup flows, stores SDK keys in ~/.hermes/.env, manages policies, and drives payment execution/confirmation. This mismatch can mislead users and reviewers about the real trust boundary and authority of the skill, increasing the chance that powerful wallet and credential operations are approved without informed consent.
The delete-policy operation interpolates an externally supplied policy_id directly into a privileged DELETE request, with no allowlisting, authorization narrowing, or secondary confirmation. In an agent setting, this enables parameter abuse: if the agent is induced to pass an attacker-chosen identifier while holding an admin key, it can delete arbitrary policies and disable spending protections.
delete-policy)
policy_id="${2:?policy_id required}"
_conto_request DELETE "/api/policies/$policy_id"
;;
get-rules)
The delete-rule operation directly embeds user-controlled policy_id and rule_id values into a destructive API path and executes immediately. In this context, an agent with admin credentials could be manipulated into deleting targeted protective rules, creating subtle policy bypasses that facilitate unauthorized payments while being harder to notice than full policy deletion.
delete-rule)
policy_id="${2:?policy_id required}"
rule_id="${3:?rule_id required}"
_conto_request DELETE "/api/policies/$policy_id/rules/$rule_id"
;;
setup)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
exit 1
fi
# Write to ~/.hermes/.env
HERMES_ENV="$HOME/.hermes/.env"
mkdir -p "$(dirname "$HERMES_ENV")"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
exit 1
fi
# Write to ~/.hermes/.env
HERMES_ENV="$HOME/.hermes/.env"
mkdir -p "$(dirname "$HERMES_ENV")"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
fi
# Write to ~/.hermes/.env
HERMES_ENV="$HOME/.hermes/.env"
mkdir -p "$(dirname "$HERMES_ENV")"
# Update or append CONTO_SDK_KEY and CONTO_API_URL in .env
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.
### 1. Sign up and install
Create an account at [conto.finance](https://conto.finance).
Install the skill from the well-known endpoint:
The README says the skill activates automatically when users mention policies or payments naturally, which is overly broad for a wallet-controlling agent. In this context, ambiguous or incidental conversation can trigger policy-management or payment-related actions unintentionally, increasing the risk of prompt-triggered financial operations or sensitive state changes.
The README instructs users to run npx tsx ... without pinning a specific package version. This makes the execution path depend on whatever version is resolved at runtime, which can change unexpectedly or be influenced by a compromised upstream package, leading to arbitrary code execution during testing.
The skill clearly expects shell, network, and local file-write capabilities but does not declare tool scope or allowed tools. That weakens least-privilege controls and can cause the agent runtime to grant broader capabilities than users expect, especially because the skill also persists credentials and performs payment-related API calls.
The mention of auto-execution in the mode comparison indicates the skill supports flows where approval directly leads to execution by a custody provider. Even if this is descriptive rather than imperative, it normalizes autonomous payment execution and increases risk when users may not realize a single API call can move funds.
| Question | Mode A | Mode B |
| ------------------------------- | ---------------------------------------------------------- | --------------------------------------------------- |
| Who holds the wallet keys? | Custody provider (Privy or Sponge) | You (via Hermes/Sponge MCP tools) |
| How many API calls per payment? | 1 (single call, auto-executes) | 3 (approve → transfer → confirm) |
| When to use? | Wallet `custodyType` is PRIVY or SPONGE in Conto dashboard | Wallet `custodyType` is EXTERNAL in Conto dashboard |
**Most Hermes setups use Mode B** — your agent controls the wallet via Sponge MCP tools and Conto acts as the policy gate before each transaction.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
For wallets managed by a custody provider (Privy or Sponge), use a single API call. Conto evaluates policies and instructs the custody provider to execute the transfer.
curl -sS -X POST "${CONTO_API_URL:-https://conto.finance}/api/sdk/payments/request" \
-H "Authorization: Bearer $CONTO_SDK_KEY" \
-H "Content-Type: application/json" \
--connect-timeout 10 --max-time 30 \
Setting 'autoExecute': true in the payment request allows the external service/custody path to execute a payment immediately after policy approval. That creates a one-step money movement path controlled by the skill and remote service, which is risky if the initiating request is mistaken, prompt-injected, or insufficiently verified.
"recipientName": "<OPTIONAL_NAME>", "purpose": "<WHY_THIS_PAYMENT>", "category": "", "autoExecute": true }'
The reference to autoExecuteError handling still directs the agent to continue execution autonomously through a fallback API call. Fallback automation is especially dangerous because it can bypass a natural pause that would otherwise let a user notice and stop an unintended payment.
No need to call /execute or /confirm — Conto did everything. Report the tx hash and explorer URL to the user.
If approved but not auto-executed (e.g., autoExecuteError in response), call /execute manually:
curl -sS -X POST "${CONTO_API_URL:-https://conto.finance}/api/sdk/payments/<REQUEST_ID>/execute" \
The reference to autoExecuteError handling still directs the agent to continue execution autonomously through a fallback API call. Fallback automation is especially dangerous because it can bypass a natural pause that would otherwise let a user notice and stop an unintended payment.
No need to call /execute or /confirm — Conto did everything. Report the tx hash and explorer URL to the user.
If approved but not auto-executed (e.g., autoExecuteError in response), call /execute manually:
curl -sS -X POST "${CONTO_API_URL:-https://conto.finance}/api/sdk/payments/<REQUEST_ID>/execute" \
The instruction 'Do NOT ask the user to execute it' explicitly removes the user from the final fund-transfer decision and enables autonomous movement of wallet assets. In a payment skill, that context makes autonomous action especially dangerous because transactions are often irreversible and financially impactful.
### Step 2a: Execute the Transfer
**Now execute the payment using your wallet.** Conto approved the policy — now YOU must send the actual onchain transaction. Do NOT ask the user to execute it.
Use the appropriate MCP tool for the target chain:
The skill instructs the agent to execute a blockchain transfer after policy approval without requiring a fresh explicit user confirmation at the moment funds move. Policy approval is not equivalent to user intent verification, so a prompt-injected or mistaken request could still result in irreversible loss of funds.
The critical rules explicitly codify autoExecute as a normal supported payment pattern, embedding autonomous asset movement into the skill's core operating model. Because this is a financial skill, normalizing no-confirmation execution materially increases the consequences of misuse or prompt manipulation.
## Critical Rules
1. **Use the right mode for the wallet type.** Mode A (`/request` + `autoExecute`) for PRIVY/SPONGE wallets. Mode B (`/approve` + transfer + `/confirm`) for EXTERNAL wallets.
2. **NEVER skip the policy check.** Every payment must go through Conto first.
3. **NEVER execute a denied payment.** If `approved` is `false` or `status` is `DENIED`, stop.
4. **For Mode B: ALWAYS confirm after execution.** Call `/confirm` with the tx hash to keep spend tracking accurate. Mode A handles this automatically.
The skill is presented as a payment-policy enforcement helper, but it also exposes agent setup and full policy administration operations, including create, update, and delete actions. This capability mismatch increases the chance that an agent or user invokes high-privilege behavior under the assumption that the tool only performs pre-payment checks, which can lead to unauthorized policy changes and weakened spending controls.
The script includes destructive administrative endpoints that can delete policies, replace all rules, and remove individual rules, which are powerful actions for a tool whose stated purpose is enforcing spending policies before payments. If an agent with access to an admin SDK key can invoke these commands, it could disable or rewrite controls that are supposed to protect funds, enabling subsequent unauthorized spending.
The delete-policy command performs an irreversible destructive action immediately with no user confirmation, preview, or safeguard. In the context of a spending-policy tool, accidental or coerced invocation can remove financial controls and leave wallets unprotected until policies are restored.
The delete-rule command deletes individual policy rules without confirmation or validation, which can silently weaken a policy while leaving the policy object itself in place. That makes the change easy to overlook and dangerous in this context because removing a single deny or limit rule may effectively bypass intended spending restrictions.
The script intentionally establishes session persistence by saving the SDK key under ~/.hermes/.env, allowing future commands to authenticate without repeating setup. In this financial-policy context, persistent credentials materially increase the blast radius of host compromise or accidental reuse because they may grant ongoing authority over approvals or policy administration.
exit 1
fi
# Write to ~/.hermes/.env
HERMES_ENV="$HOME/.hermes/.env"
mkdir -p "$(dirname "$HERMES_ENV")"
The setup flow persists the received SDK key to ~/.hermes/.env automatically, without an explicit warning, opt-in, or file-permission hardening. Persisting API credentials silently increases the risk of unintended long-term exposure to other local processes, users, backups, or later agent actions that read the environment file.
The README instructs users to ask the agent for its wallet address and notes that a wallet may be auto-provisioned, but it does not include an explicit privacy/safety warning. In a financial-agent context, exposing wallet addresses can aid profiling and targeted attacks, and silent or unclear wallet provisioning can surprise users about custody and onchain traceability.