Back to skill

Security audit

Spark Bitcoin L2 Proxy for AI Agents

Security checks for vulnerabilities and agentic risk

Overview

This skill is coherent and disclosed, but it gives an autonomous agent bearer-token access to Bitcoin wallet operations and its sample client can send that token to any configured proxy URL.

Install only if you control the proxy endpoint, use HTTPS, and can enforce a trusted host for PROXY_URL. Do not give an autonomous agent an admin token; use the narrowest role, set low per-transaction and daily limits, test with small amounts, monitor logs, and keep a token revocation path ready.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:412
Finding

Unvalidated Proxy URL Can Expose the Wallet Bearer Token

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 412–429 and 515–516
Vulnerability Type: Improper validation of a security-sensitive network destination
Risk Level: High

Vulnerable Code

javascript
constructor(baseUrl, token) {
  this.#baseUrl = baseUrl.replace(/\/$/, '');
  this.#token = token;
}

async #request(method, path, body = null) {
  const options = {
    method,
    headers: {
      'Authorization': `Bearer ${this.#token}`,
      'Content-Type': 'application/json',
    },
  };
  if (body) {
    options.body = JSON.stringify(body);
  }

  const response = await fetch(`${this.#baseUrl}${path}`, options);
  const result = await response.json();

  if (!result.success) {
    throw new Error(result.error || 'Request failed');
  }
  return result.data;
}
javascript
const agent = new SparkProxyAgent(
  process.env.PROXY_URL,
  process.env.PROXY_TOKEN
);

Technical Analysis

The provided client obtains the proxy endpoint from the externally configured PROXY_URL environment variable and sends the sensitive PROXY_TOKEN to that endpoint in an HTTP Authorization header. The constructor only removes a trailing slash; it does not parse or validate the URL, enforce HTTPS, reject embedded credentials, or restrict the destination to a trusted host.

The documentation instructs users to use HTTPS, but this is advisory and is not enforced by the sample implementation. Consequently, a malformed, plaintext, or attacker-controlled proxy URL will receive the bearer token whenever any client method makes a request.

This credential grants wallet capabilities according to its assigned role. A read-only token exposes wallet information, while pay-only or admin tokens can authorize financial operations. Server-side transaction and daily limits reduce potential loss but do not prevent credential disclosure or unauthorized use within those limits.

The separately flagged L402 helper at lines 334–353 does not directly trans ...[truncated 1907 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse the configured endpoint with new URL(baseUrl) and reject invalid URLs.
  2. Require url.protocol === 'https:'; permit plaintext HTTP only through an explicit development-only option that cannot be enabled in production.
  3. Maintain an explicit allowlist of trusted proxy hostnames or require the expected hostname to be supplied through a protected deployment configuration.
  4. Reject URLs containing embedded usernames or passwords.
  5. Normalize the validated origin rather than concatenating an unchecked string.
  6. Configure redirects manually or disable them. Never forward the Authorization header when a redirect changes the origin.
  7. Consider certificate or public-key pinning in controlled deployment environments where the runtime supports it.
  8. Use the narrowest token role and enforce low maxTxSats and dailyBudgetSats values.
  9. Avoid using administrative tokens in autonomous agents.
  10. Validate configuration during client construction and fail closed before making any request.

Example hardening:

javascript
constructor(baseUrl, token, allowedHosts = []) {
  const url = new URL(baseUrl);

  if (url.protocol !== 'https:') {
    throw new Error('PROXY_URL must use HTTPS');
  }

  if (url.username || url.password) {
    throw new Error('PROXY_URL must not contain credentials');
  }

  if (allowedHosts.length > 0 && !allowedHosts.includes(url.hostname)) {
    throw new Error('Untrusted proxy host');
  }

  this.#baseUrl = url.origin;
  this.#token = token;
}

The request implementation should additionally reject cross-origin redirects or reissue redirected requests without the bearer credential only after explicit trust validation.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

YARA rule 'ransomware_behavior': Ransomware-like patterns (mass encryption, ransom notes) [malware]

Critical
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · SKILL.md (reported line 3)May include surrounding context.

md
---
name: sparkbtcbot-proxy
description: Use a Spark Bitcoin L2 wallet proxy for AI agents via HTTP API. Check balances, send payments, create invoices, pay L402 paywalls — all without holding the mnemonic. Use when user mentions "Spark proxy," "wallet API," "L402," "proxy payment," "bearer token auth," or wants secured Bitcoin capabilities for an agent.
argument-hint: "[Optional: specify operation - balance, pay, invoice, l402, transfer, or setup]"
homepage: https://github.com/echennells/sparkbtcbot-proxy
source: https://github.com/echennells/sparkbtcbot-proxy
requires:
  env:
    - name: PROXY_URL
      description: HTTPS URL of your deployed sparkbtcbot-proxy instance (e.g., https://your-app.vercel.app)
      sensitive: false
    - name:

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% 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).

Content

Scanner excerpt · SKILL.md (reported line 60)May include surrounding context.

md
5. **Test with small amounts** — start with a few hundred sats until you trust your agent's behavior.

6. **Have a revocation plan** — know how to revoke tokens via `DELETE /api/tokens` if an agent is compromised.

## Token Roles

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 90)May include surrounding context.

Get Balance

bash
curl -H "Authorization: Bearer $TOKEN" \
  "$PROXY_URL/api/balance"

Static analysis

No suspicious patterns detected.