Back to skill

Security audit

Brouter Stake

Security checks for vulnerabilities and agentic risk

Overview

This skill is openly about staking real BSV, but it includes broad live money-moving and paid-oracle API instructions without enough guardrails.

Review before installing. Only use this with a Brouter account and token you are willing to let an agent use for real BSV staking or related API actions. Confirm the market, outcome, amount, and loss risk before any POST that stakes, creates markets, votes, publishes signals, claims faucet funds, or sends payment headers. Keep bearer tokens out of logs and treat the X-Payment and commit-reveal examples as documentation that needs stronger production safeguards.

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

T09 · Insecure Skill Coding Practices

Error
Location
references/api.md:270
Finding
Paid Oracle Signals Are Released Before On-Chain Payment Verification<![CDATA[ ## Vulnerability Details **File Location**: `references/api.md`, lines 270–308 **Vulnerability Type**: Payment-gate bypass caused by insufficient transaction verification **Risk Level**: High ### Vulnerable Code and Documentation ```javascript parts.push(Buffer.from('01', 'hex')); // prev txid (32 zeros — coinbase-style for off-chain proof) parts.push(Buffer.alloc(32)); // prev index (ffffffff) parts.push(Buffer.from('ffffffff', 'hex')); // empty script (OP_0) parts.push(Buffer.from('0100', 'hex')); // sequence parts.push(Buffer.from('ffffffff', 'hex')); // output count parts.push(Buffer.from('01', 'hex')); // value: priceSats as 8-byte LE const val = Buffer.alloc(8); val.writeBigUInt64LE(BigInt(priceSats)); parts.push(val); // locking script parts.push(Buffer.from([lockingScript.length])); parts.push(lockingScript); // locktime parts.push(Buffer.from('00000000', 'hex')); const txhex = Buffer.concat(parts).toString('hex'); const proof = { txhex, payeeLockingScript: payeeLockingScriptHex, priceSats }; return Buffer.from(JSON.stringify(proof)).toString('base64'); } // Usage const xPayment = buildXPayment('76a914...88ac', 50); ``` The documented processing behavior states: ```text On success (HTTP 200), the paid signal includes `payment_txid` confirming proof of payment was accepted. After accepting payment, Brouter polls the Anvil BSV node in the background to verify the txid has a real on-chain merkle proof (BEEF). This doesn't affect response time — data is served immediately on structural pass. ``` ### Technical Analysis The payment example constructs a transaction containing a zero-filled previous transaction ID and an `ffffffff` previous-output index. It does not reference a genuine spendable UTXO and does not contain a valid signature proving authorization to spend funds. Despite this, the documented service workflow releases paid signal data after only a structural validation pass. Verification that the transaction has a real on-chain ...[truncated 1925 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not release paid content until the submitted transaction has passed authoritative payment verification. 2. Verify that every transaction input references a real, unspent output and reject null, coinbase-like, nonexistent, or already-spent inputs. 3. Validate all input signatures and scripts under the applicable BSV consensus rules. 4. Confirm that the transaction pays at least the required amount to the exact server-issued locking script. 5. Bind each payment to the server-issued nonce, requested resource, amount, payee, and expiration time to prevent replay or cross-resource reuse. 6. Require successful broadcast and an acceptable SPV/BEEF proof before returning protected content. If zero-confirmation acceptance is necessary, use a documented risk engine and do not describe it as confirmed payment. 7. Track transaction IDs and payment nonces atomically so one transaction cannot unlock multiple resources unless explicitly permitted. 8. Replace the synthetic transaction example with a wallet-generated and cryptographically signed transaction using genuine spendable UTXOs. 9. Return a pending status while payment verification is incomplete, and disclose paid data only after verification succeeds. 10. Add regression tests covering zero-filled previous transaction IDs, missing signatures, nonexistent UTXOs, duplicate transactions, replayed nonces, underpayments, incorrect locking scripts, and transactions that never reach the network. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/api.md:369
Finding
Predictable Commit-Reveal Salt Allows Offline Vote Recovery<![CDATA[ ## Vulnerability Details **File Location**: `references/api.md`, lines 369–388 **Vulnerability Type**: Low-entropy cryptographic commitment example **Risk Level**: Medium ### Vulnerable Code and Documentation ```javascript crypto.createHash('sha256').update('yes' + 'mysecret').digest('hex') ``` The corresponding reveal example reuses the same static salt: ```json { "outcome": "yes", "salt": "mysecret" } ``` ### Technical Analysis A commit-reveal scheme conceals a participant's choice only when the salt is unpredictable and has enough entropy to resist offline guessing. The documented example uses the fixed string `mysecret`, while the committed outcome has a very small domain, normally only `yes` or `no`. Because commitment hashes are observable, another participant can calculate the two likely candidates: ```text SHA256("yes" + "mysecret") SHA256("no" + "mysecret") ``` A matching hash reveals the committed outcome before the reveal phase. More generally, users following the example with short human-generated salts remain vulnerable to dictionary and brute-force attacks. Simple concatenation is also not a robust encoding pattern. If variable inputs are permitted, concatenation without lengths or separators can create ambiguous preimages. Although the documented binary outcomes reduce that particular risk, domain separation and unambiguous encoding remain appropriate cryptographic hardening measures. ### Attack Path 1. A victim follows the documentation and creates a commitment using `mysecret` or another predictable human-generated salt. 2. An attacker observes the victim's commitment hash during the commit phase. 3. The attacker hashes each valid outcome with the example salt or a dictionary of likely salts. 4. The attacker finds a value matching the published commitment and learns the victim's outcome before reveal. 5. The attacker uses that information to adjust their own commitment, stake, or market strategy while the victim's vot ...[truncated 635 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Generate at least 128 bits of salt using a cryptographically secure random-number generator. For Node.js, use `randomBytes(32)` rather than a human-selected string. 2. Update the example to demonstrate secure generation and storage: ```javascript import { createHash, randomBytes } from 'crypto'; const outcome = 'yes'; const salt = randomBytes(32).toString('hex'); const commitmentHash = createHash('sha256') .update(`brouter:v1:${outcome}:${salt}`, 'utf8') .digest('hex'); ``` 3. Store the salt securely until the reveal phase. Warn users that losing the salt prevents a valid reveal and disclosing it early compromises secrecy. 4. Use domain separation and an unambiguous serialization format. A canonical encoded object or length-prefixed fields are preferable to raw string concatenation. 5. Clearly state that example strings such as `mysecret` must never be used in production. 6. Add client-side validation or SDK helpers that generate secure salts automatically. 7. Add tests proving that commitments differ across independently generated salts, even when the outcome is identical. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (12)

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill explicitly facilitates real-money staking of BSV sats, including examples that place bets, but it does not warn users that funds are deducted immediately and may be lost. In a transactional betting context, omission of a clear loss-risk warning can mislead users into taking irreversible financial actions without informed consent.

External Transmission

Medium
Category
Data Exfiltration
Content
curl -s "$BASE/api/markets?state=OPEN" | jq '.data.markets[] | {id, title, tier}'

# Take a position (minimum 100 sats)
curl -sX POST $BASE/api/markets/{market-id}/stake \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"outcome":"yes","amountSats":100}' | jq .
Confidence
92% confidence
Finding
This command performs an authenticated POST to an external API that places a real-money stake, causing immediate transfer of funds based on user-provided parameters. Because it is a live financial action, accidental, spoofed, or insufficiently confirmed execution could result in irreversible loss of funds.

External Transmission

Medium
Category
Data Exfiltration
Content
## Stake

```bash
curl -sX POST $BASE/api/markets/{market-id}/stake \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"outcome":"yes","amountSats":500}'
Confidence
92% confidence
Finding
This is another authenticated external POST example that directly executes a real-money staking transaction. In the context of a betting skill, the danger is elevated because the action is financially irreversible and could be triggered by misunderstanding, prompt injection into an agent workflow, or lack of user confirmation.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The onboarding example immediately performs registration, obtains a bearer token, and executes a real-money staking action without warning that the token is sensitive and the action can affect balances. In this skill context—real BSV staking—that omission is especially risky because an agent may replay the workflow automatically and expose credentials or spend funds without informed user approval.

External Transmission

Medium
Category
Data Exfiltration
Content
BASE=https://brouter.ai

# 1. Register (get your token + 5000 sats)
curl -sX POST $BASE/api/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name":"youragent","publicKey":"02your33bytepubkeyhex"}' | jq .
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
BASE=https://brouter.ai

# 1. Register (get your token + 5000 sats)
curl -sX POST $BASE/api/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name":"youragent","publicKey":"02your33bytepubkeyhex"}' | jq .
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
curl -s "$BASE/api/markets?state=OPEN" | jq '.data.markets[0].id'

# 3. Stake on a market (use token from step 1)
curl -sX POST $BASE/api/markets/{market-id}/stake \
  -H "Authorization: Bearer {your-token}" \
  -H "Content-Type: application/json" \
  -d '{"outcome":"yes","amountSats":100}'
Confidence
60% 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
96% confidence
Finding
The reference file documents capabilities to create markets and interact with oracle-driven resolution that go beyond the skill’s declared purpose of browsing and staking on markets. This scope expansion is dangerous because an integrating agent may expose higher-risk actions—such as creating binding market objects or invoking resolution-related workflows—without the user expecting those powers from the manifest.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
This section introduces monetized oracle publication, paid signal sales, and custom payment-header construction, which materially exceed a simple staking/browsing use case. The mismatch is dangerous because it can lead an agent to handle monetization flows, payment proofs, and token-authenticated publishing operations that were not disclosed in the skill metadata, increasing the chance of unintended fund movement, secret misuse, or unsafe automation.

External Transmission

Medium
Category
Data Exfiltration
Content
TOKEN=$(echo $RESP | jq -r '.data.token')

# 2. Claim faucet
curl -sX POST $BASE/api/agents/alice/faucet -H "Authorization: Bearer $TOKEN"

# 3. Create market
MID=$(curl -sX POST $BASE/api/markets \
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
| jq -r '.data.market.id')

# 4. Stake
curl -sX POST $BASE/api/markets/$MID/stake \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"outcome":"yes","amountSats":100}'
Confidence
60% 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

Low
Confidence
89% confidence
Finding
The skill instructs users to send bearer-token-authenticated requests to an external service but does not warn that account-linked identifiers, positions, and transaction metadata will be transmitted to brouter.ai. This creates a privacy and account-security concern, especially if users do not understand that authenticated actions can reveal identity, balances, or trading history.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
references/api.md:68