Sparkbtcbot — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Sparkbtcbot (Plugin) and scored it 45/100 (orange). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 19 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 19 flagged
A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Spark Bitcoin L2 wallet skill for AI agents — give an agent its own Bitcoin wallet so it can send and receive money on its own: pay for an API call, get paid for a task, tip, settle up — or buy real-world things (gift cards, eSIMs, VPNs) from Bitcoin-accepting merchants, with guardrails that verify every invoice against its quote before a sat moves.
Built on Spark, a Bitcoin Layer 2 with instant, near-zero-fee transfers and native Lightning support — and fully self-custodial, so the agent holds its own keys. Use it in Claude Code as a plugin, or in any other LLM agent framework via the npm package.
⚠️ Handles real Bitcoin. Mainnet by default, full custody the moment the seed is decrypted, no server-enforced spending caps — treat the agent like a hot wallet. Use a dedicated wallet holding only an operational float, set SPARK_DAILY_BUDGET_SATS, and populate the recipient allowlist; the funded balance is the only limit that survives a compromised process.🤖 If you are an AI agent, read [`AGENTS.md`](./AGENTS.md) before running any wallet code. Non-negotiables: never print or echo the mnemonic or the passphrase (both control all funds); never runnpm run reveal-mnemonicyourself; and if yougit clone/npm installfor the user, offer supply-chain hardening first. Full behavioral guidance is inSKILL.md.
Best for: autonomous agents that send/receive small amounts — pay per API call, get paid for a task, tip, settle up — plus dev/test on REGTEST and trusted agents you control. Not for: custody of large balances, or anything needing hard server-enforced spending caps or revocable access — no such enforcement exists on this path.
Spark is a Bitcoin Layer 2 that lets you send and receive Bitcoin instantly with low fees. Spark-to-Spark transfers are free, and Lightning interop costs 0.15–0.25%. It is fully self-custodial — you hold your own keys via a BIP39 mnemonic — and fully interoperable with the Lightning Network. Spark currently has a small number of infrastructure providers (Signing Operators), so there is some risk of downtime, and it requires trusting that at least one operator behaves honestly during transfers.
sp1q…)references/first-spend.md)SPARK_PRIVACY=off opts out; token balances stay public)spark.unilateral-exit-bundle.v1 recovery bundle, consumed by Blink's spark-unilateral-exit tool if the operators ever go dark. Verify with npm run leaf-vault -- verify.Two install paths depending on your stack.
Tested setups. No lock-in to one model or harness — the wallet, merchant, and bridge flows have been run end-to-end on real mainnet sats under both:
SKILL.md loads automatically.AGENTS.md automatically.Anything that can load the skill content should work the same way (Cursor, LangChain, OpenAI Agents SDK, your own harness — see the npm package below); those two are the stacks we've validated with real purchases and withdrawals.
claude plugin marketplace add https://github.com/echennells/sparkbtcbot
claude plugin install sparkbtcbotNative plugin install. Updates flow through claude plugin update sparkbtcbot. Claude reads SKILL.md automatically when the skill triggers.
npm install --ignore-scripts sparkbtcbot-skillThe package ships both the skill content (so you can load it into your LLM's context) and the encryption library (so generated code can import the helpers). Minimal use:
import { getSkillContent, getReference, listReferences } from "sparkbtcbot-skill";
// Always-loaded skill body — pass to your framework's system-prompt mechanism
const instructions = await getSkillContent();
// On-demand reference docs by name
console.log(await listReferences());
// → ['agent-class', 'architecture', 'bitrefill', 'cryptorefills',
// 'encrypted-seed', 'extras', 'first-spend', 'l402', 'lightning',
// 'merchant-spending', 'nadanada', 'recovery-scenarios', 'security',
// 'spark-invoices', 'supply-chain', 'tokens', 'unilateral-exit', 'wallet']
const l402Doc = await getReference("l402");Generated code (or your own glue) can also import the encryption helpers:
import { saveEncryptedMnemonic, loadMnemonicFromEnv } from "sparkbtcbot-skill";
await saveEncryptedMnemonic({ mnemonic, passphrase, path: "./seed.enc" });
const decrypted = await loadMnemonicFromEnv(); // reads SPARK_PASSPHRASEAnd the unilateral-exit backup (the "leaf-vault") via its subpath export:
import { enableLeafVault, snapshotLeafVault, verifyVault } from "sparkbtcbot-skill/leaf-vault";
const vault = enableLeafVault(wallet); // auto-refreshing recovery bundle
// ... later: await vault.dispose(); // flushes a final snapshot if needed(The SDK-free persistence/validation core behind it is also exported directly as sparkbtcbot-skill/leaf-vault/core, for code that handles bundles without a wallet instance.)
The package also ships a single sparkbtcbot CLI (0.6.1+; subcommands replaced the five per-command bins), so npm consumers and Claude Code plugin users never need the cloned repo — install the package into your project, then the command resolves locally (your lockfile governs what runs; no unpinned registry fetch):
npm install --ignore-scripts sparkbtcbot-skill # once, in your project
npm exec --no -- sparkbtcbot setup # one-time wallet bootstrap
npm exec --no -- sparkbtcbot reveal-mnemonic # user-run seed backup (refuses non-interactive)
npm exec --no -- sparkbtcbot leaf-vault verify
npm exec --no -- sparkbtcbot viewer grant <pubkey> # one read-only key for a private wallet (asks y/N; spark-sdk ≥0.12)
npm exec --no -- sparkbtcbot help # full subcommand list--no is deliberate: plain npx sparkbtcbot ... falls back to fetching the registry package named after the command you typed if the local bin isn't found (wrong directory, package not installed). Since 0.6.1 the name sparkbtcbot is project-owned — a reservation stub that only prints an error — so even that fallback can't run a stranger's code; the five per-command bin names from 0.4.x–0.5.x are project-owned refusing stubs too (see SECURITY.md). npm exec --no is the right form because it never installs: with no local bin it fails instead of fetching (npm may still make a registry metadata request — you'll see "npx canceled due to missing packages"). It is not a full guarantee that nothing runs, though: if an earlier bare npx left a copy in npx's cache that matches the registry's latest version, or a global install or a node_modules/.bin in a parent directory provides the bin, --no runs that copy. Run it from the project directory, or call ./node_modules/.bin/sparkbtcbot directly — that path never consults the registry, the npx cache, or global installs.
Do not rely on refusing npx's install prompt: npx only prompts on an interactive terminal. With no TTY — a CI job, a script, or an AI agent running commands for you — it installs and executes silently. That is why the safe forms are npm exec --no and ./node_modules/.bin/sparkbtcbot rather than a rule about answering "no".
--ignore-scripts is deliberate too: one production dependency (protobufjs) runs code at install time, before your code imports anything. The package and the Spark SDK both work fully without it. In a project that already has a lockfile, prefer npm ci --ignore-scripts — npm ci runs the full install lifecycle just like npm install, so the flag is required there too.
After sparkbtcbot setup, persist the passphrase you chose: the runtime reads SPARK_PASSPHRASE from its environment at boot (dotenv loads the .env in the directory your app runs from). Setup deliberately writes it nowhere — the encrypted seed lands in ~/.spark/seed.enc, and keeping the passphrase out of that directory is the point.
git clone https://github.com/echennells/sparkbtcbot.git ~/sparkbtcbot
cd ~/sparkbtcbot
npm ci --ignore-scripts # lockfile-exact install; fails loudly on any drift
npm test # offline unit suite — verifies the resolved tree matches the one we live-testedDon't clone directly into ~/.claude/skills/ — this repo nests the skill at skills/sparkbtcbot/, so the clone would put SKILL.md a level too deep and Claude Code won't discover it. If you want the clone to double as a personal skill (instead of the plugin install), symlink the inner skill directory:
ln -s ~/sparkbtcbot/skills/sparkbtcbot ~/.claude/skills/sparkbtcbotThe Quick Start below assumes this path — useful if you want to kick the tires on the example scripts (npm run example:balance etc.) before integrating.
# Install dependencies (in the cloned repo; lockfile-exact), then verify:
cd ~/sparkbtcbot
npm ci --ignore-scripts
npm test # offline; a red suite means the installed tree isn't the tested one — stop there
# Copy env template, set SPARK_PASSPHRASE (>=12 chars)
cp .env.example .env
$EDITOR .env
# One-time setup: generate a wallet, encrypt the mnemonic at ~/.spark/seed.enc.
# The 12 words are NOT printed and NOT written to disk in plaintext.
npm run setup
# Back up the mnemonic offline. Run this in YOUR OWN terminal (it refuses to run
# non-interactively so it can't be captured into an agent's transcript):
npm run reveal-mnemonic # decrypts seed.enc, prints the 12 words once
# copy them to paper / password manager / hardware backup. No file to delete.
# Run the examples
npm run example:balance
npm run example:paymentsThe mnemonic is never stored in plaintext anywhere the runtime reads. npm run setup writes an encrypted seed file (~/.spark/seed.enc, mode 0600); the runtime reads SPARK_PASSPHRASE from env and decrypts it once at boot. To back up the words offline, run npm run reveal-mnemonic in your own terminal — it decrypts the seed and prints the mnemonic once, and refuses to run non-interactively so it can't be captured into an AI agent's transcript. See skills/sparkbtcbot/references/encrypted-seed.md for the threat model and recovery scenarios.
| Script | npm script | Purpose |
|---|---|---|
setup-encrypted-seed.js | npm run setup | Generate wallet, encrypt mnemonic at rest |
balance-and-deposits.js | npm run example:balance | Check balance (BTC + tokens), get deposit addresses |
payment-flow.js | npm run example:payments | Lightning invoices, Spark invoices, fee estimation |
token-operations.js | npm run example:tokens | BTKN token balances, transfers, batch operations |
l402-paywalls.js | npm run example:l402 | Access L402 pay-per-request APIs via Lightning |
spark-agent.js | npm run example:agent | Complete SparkAgent class with all capabilities |
The npm run shortcuts exist only in the cloned repo. npm-package consumers get the same scripts under node_modules/sparkbtcbot-skill/skills/sparkbtcbot/scripts/ — run them directly, e.g. node node_modules/sparkbtcbot-skill/skills/sparkbtcbot/scripts/balance-and-deposits.js.
| Variable | Required | Description |
|---|---|---|
SPARK_PASSPHRASE | Yes | Passphrase (≥12 chars) that decrypts the seed file at boot. Set during npm run setup. |
SPARK_NETWORK | No | MAINNET (default), REGTEST, TESTNET, SIGNET |
SPARK_SEED_PATH | No | Override for the encrypted-seed file location. Defaults to ~/.spark/seed.enc. |
npm install --ignore-scripts sparkbtcbot-skill # brings the pinned SDK + helpers with itPassphrase + seed file = full wallet access. Either alone is useless; both together control all funds. There is no permission scoping, no spending limits, no read-only mode in the SDK.
Recommendations:
SPARK_PASSPHRASE like any production secret (deployment secret manager, .env in .gitignore, etc.)npm audit runs in CI on every push.postinstall supply-chain attack class (runs on Node ^22.22.2 || ^24.15.0 || >=26, but no Node bundles it — upgrade explicitly); otherwise 11.10.0+ is the floor where the package-cooldown age-gate (min-release-age) enforces at all. On Node 20 install `npm@11` explicitly — npm@latest resolves to 12 regardless of your Node and installs anyway (engine mismatches are only a warning), leaving you on an npm your Node doesn't support. Distro-packaged npm (Ubuntu apt ships ~9.x even alongside Node 22 LTS) runs years behind and silently ignores hardening keys, so upgrade rather than trust the system npm. The hardening config itself lives in the supply-chain-hardening repo.seed.enc into container images that ship alongside the passphraseaccountNumber values for different funding tiersThis software is provided as is, without warranty of any kind, express or implied — see LICENSE for the full text. Running it is your decision and your risk.
SPARK_DAILY_BUDGET_SATS, the recipient allowlist, invoice-vs-quote verification, and the TTY refusal in reveal-mnemonic lower the odds of a bad outcome. They do not enforce anything against a determined attacker or a confused agent — LLMs are non-deterministic and can be prompt-injected, and any process holding the decrypted seed has full spending authority.Fund the wallet with an operational float you can afford to lose entirely, and no more.
MIT
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.