Skip to content

Releases: BlockRunAI/Franklin

v3.30.0 — native Polymarket betting (end-to-end)

Choose a tag to compare

@VickyXAI VickyXAI released this 11 Jul 04:27

Franklin gains the execution half of the prediction-market story. PredictionMarket researches the bet; the new PolymarketBet tool places, manages, and settles it — signing orders locally with the same `~/.blockrun/.session` key that pays x402 on Base.

  • New core tool PolymarketBet — full lifecycle parity with blockrun-mcp: setup / fund / buy / sell / orders / cancel / positions / redeem / withdraw (CLOB V2, Polygon).
  • Real-money safety — dry-run unless `confirm:true`, plus an interactive Confirm/Cancel user gate before any on-chain signing (`auto_approve` for headless). Per-order + session USD caps; bet stakes stay off the x402 `--max-spend` ledger — only the $0.01 fund fee is metered.
  • Ported byte-faithfully — 11-file module incl. the l1-auth ERC-7739 workaround, pinned to `@polymarket/clob-client-v2@1.0.8`; a golden-vector test guards the signing envelope. Polymarket-only; other venues stay research-only.

Verified: 513/513 local tests, tsc clean, functional smoke test. Design doc: `docs/plans/2026-07-10-franklin-native-polymarket-betting-design.md`.

v3.29.15 — spend-accounting integrity + prompt-injection containment (round-10)

Choose a tag to compare

@VickyXAI VickyXAI released this 25 Jun 00:57
43476f5

The bash-guard converged (rounds 7-9), so round-10 widened the audit to the non-bash surface — spend/budget, payment proxy, prompt-injection framing, persistence — and found higher-impact issues a narrow bash hunt never would.

Sev Finding Fix
🟠 HIGH Exa tools spend USDC invisibly to --max-spend — never recordUsage record each settled Exa charge like every sibling paid tool
🟠 HIGH Concurrent paid-tool spend escapes the ceiling on stream error/abort/model-switch failure path now folds the tool-spend delta; cap check trips on it
🟠 HIGH SearchX returns attacker tweet text UNFRAMED frameUntrusted on both return paths
🟡 MED VoiceStatus dumps remote-party transcript UNFRAMED frameUntrusted

Documented limitation: --max-spend is a per-round soft ceiling (checked after parallel tools settle); the on-chain wallet balance is the hard floor. Pre-dispatch budget gate deferred to avoid a hot-loop rewrite.

Tests pin the spend-accounting primitive, Exa recording, the failure-path fold, and SearchX/Voice framing. Local suite 510/510.

npm i -g @blockrun/franklin@3.29.15

v3.29.14 — security: brace-expansion wallet read + 6to4 SSRF (round-9)

Choose a tag to compare

@VickyXAI VickyXAI released this 25 Jun 00:15
9f1444a

A third convergence verify (re-attacking the round-8 quote-normalization & rtk-recursion fixes) confirmed 2 NEW classes. The find count is converging (7→6→5→2); survivors are increasingly exotic.

Sev Bypass Fix
🔴 CRITICAL cat {~,}/.bloc{k,}run/.{session,}brace expansion (4th shell primitive) reads the wallet EVM key, defeating directory+basename+glob guards at once comma/.. brace groups now opaque (prompt, like $VAR); deny patterns also run on a brace-collapsed copy
🟡 MEDIUM http://[2002:a9fe:a9fe::]/6to4 IPv6 embeds 169.254.169.254, survives WHATWG normalization decode & re-check like NAT64 / IPv4-mapped

The brace splice is reader-agnostic (grep/cut/cat). Regression tests pin both classes plus benign controls. Local suite 506/506.

npm i -g @blockrun/franklin@3.29.14

v3.29.13 — security: close 5 more single-command bypasses (round-8)

Choose a tag to compare

@VickyXAI VickyXAI released this 24 Jun 20:47
8d1bc18

A second 13-agent adversarial convergence verify of the 3.29.12 guards confirmed 5 NEW single-command bypass classes the round-7 fixes didn't anticipate — one critical (a fresh evasion of the wallet directory rule itself).

Sev Bypass Fix
🟠 HIGH rtk node evil.js — the rtk proxy blanket-allowed any wrapped command (wildcard RCE) strip rtk/rtk proxy and recurse; safety = wrapped command's
🔴 CRITICAL cat ~/.block''run/.sess''ion — empty-quote / backslash / ANSI-C splice reads the wallet EVM key deny patterns now run on a shell-normalized copy; $'…'/$"…" opaque
🟠 HIGH cat ~/.git-credentials & friends — gh hosts, cargo/rclone, Solana CLI keypair, keychain, shell history broadened credential-store denylist
🟡 LOW git branch -d / git tag -d — ref destruction via the read-only allowlist delete/rename/force prompt; read + create stay safe

The critical splice is notable: it defeats the wallet directory rule (.blockrun) itself — the shell strips ''/""/\ before opening the file, but the literal regex saw non-contiguous text. Now matched against a dequoted/unescaped normalization that mimics shell tokenization, closing the splice on all four key basenames (.session, .solana-session, .solana-session-key2, solana-wallet.json).

The recurring lesson: text-classifying shell commands for auto-approval is a denylist treadmill. The canonicalized isWalletKeyPath guard on the file/media tools is the primary wallet protection; the bash-guard is the best-effort shell net and now fails toward prompting on quoting, expansion, wrappers, and anything it can't statically resolve.

Regression tests pin all five classes plus benign controls. Local suite 504/504.

npm i -g @blockrun/franklin@3.29.13

v3.29.12 — security: close 6 convergence-verify single-command bypasses (round-7)

Choose a tag to compare

@VickyXAI VickyXAI released this 24 Jun 20:24
20cb44f

An 8-agent adversarial convergence verify of the 3.29.11 guards confirmed 6 more single-command holes (2 critical). Round-7 fixes them at the root, with the never-published 3.29.11 media-write fix folded in.

Unifying principle: a bash segment is auto-approved ("safe") only when its full effect is statically visible — any runtime indirection the classifier can't see now forces a prompt.

Closed this release

Sev Bypass Fix
🔴 CRITICAL BASH_ENV=./evilrc ls — env-var prefix exec/loader hijack (LD_PRELOAD, DYLD_*, PERL5OPT, NODE_OPTIONS, PATH, IFS) only a locale/display allowlist (LANG, LC_*, TZ, TERM) may prefix a safe command
🔴 CRITICAL cat $HOME/.bl*/.s*$VAR-rooted glob wallet-key read parameter expansion treated as opaque like $(...)
🟠 HIGH git status > ~/.bashrc — redirect write on git/npm/cargo/bun redirect check now runs for every segment
🟡 MEDIUM cat ~/.ssh/id_rsa — host-credential reads (~/.aws, ~/.gnupg, gcloud, .npmrc, .pgpass, .netrc) mirrors the Write tool's dangerous-path block
🟡 MEDIUM git config core.pager "node evil.js" — config/remote writes (exec hook) safe only in get/list / read form
🟡 MEDIUM metadata.google.internal — SSRF cloud-metadata hostnames (*.internal, instance-data, NAT64) denied by name

Plus (folded-in 3.29.11): media tools (ImageGen/VideoGen/MusicGen/BrowserX) now apply the isWalletKeyPath guard to output_path, and bash-guard splits on newline/CR/lone-& separators.

The canonicalized isWalletKeyPath guard on the file/media tools remains the primary wallet protection; the bash-guard is the best-effort shell net and now prompts on anything it can't statically reason about.

Regression tests pin all six classes plus benign controls. Local suite 500/500.

npm i -g @blockrun/franklin@3.29.12

Franklin 3.29.10 — close the 3.29.9 guard bypasses

Choose a tag to compare

@VickyXAI VickyXAI released this 24 Jun 19:43
bcf5616

An adversarial bypass-hunt of the v3.29.9 security guards (and a re-review of the fixes) found 25 bypasses in the guards themselves — root cause: matching shell text / exact strings instead of canonicalizing. All closed.

  • SSRF — redirect bypass (critical). The guard checked only the initial host, but fetch follows redirects, so a public URL that 302s to 169.254.169.254/127.0.0.1 sailed through. WebFetch + reference-image now follow redirects manually, re-validating the host on every hop. Also: IPv4-mapped IPv6, trailing-dot, and a false-positive blocking public fc*/fd* hosts.
  • Wallet key — directory rule. Filename matching was trivially obfuscated (.solana""-session, .\solana-session, globs, unlisted key files). Any reference to ~/.blockrun in a shell command now prompts; the file Read/Write/Edit tools have a separate canonicalized guard. Case-insensitive on macOS/Windows.
  • bash-guardgh api mutations in every form (--method=POST/-XDELETE/-ftitle=v); find -exec/-delete/-fprint/-fprintf/-fls; tee/xargs removed; coreutil writers (sort -o, tree -o, uniq IN OUT, yq -i) and >|/>&FILE redirects now prompt.

The file Read/Write/Edit tools remain the primary canonicalized guard; bash-guard is the best-effort shell net (non-trust mode). New regression tests pin every bypass. Local suite 490/490.

See CHANGELOG.md.

Franklin 3.29.9 — security hardening (round-5)

Choose a tag to compare

@VickyXAI VickyXAI released this 24 Jun 18:41
bdc6046

A fifth review round (fresh non-money angle) found 13 issues — four HIGH security holes around the wallet. Each finding was adversarially verified. All fixed. Local suite 484/484.

Security — wallet exposure (HIGH)

  • franklin proxy now binds loopback only (was 0.0.0.0 — the x402 payment proxy was reachable from the LAN).
  • The wallet key store (~/.blockrun/.session/.solana-session/solana-wallet.json) is now refused by the agent's Write/Edit/Read tools.
  • bash-guard no longer auto-approves cat-ing the wallet key or xargs; gh api mutations (-X DELETE/POST/PUT) now prompt.

Security — defense in depth

  • Web/search output is framed as UNTRUSTED data-not-instructions (prompt-injection containment, parity with MCP/skills).
  • SSRF guard on WebFetch + reference-image fetch (blocks loopback/private/metadata; FRANKLIN_ALLOW_PRIVATE_FETCH=1 to opt out).

Correctness & data integrity

  • sanitizeHistory adopted on reference-diff (orphan tool_results no longer 400 on strict mode); atomic stats writer + shape coercion; franklin migrate keeps http/sse url; MCP connect-timeout teardown; task cancel recycled-PID guard; brain concurrent-merge.

See CHANGELOG.md for full detail.

Franklin 3.29.8 — wallet spend-ceiling + paid-tool accounting (round-4 money audit)

Choose a tag to compare

@VickyXAI VickyXAI released this 24 Jun 14:23
d510d88

A fourth review round swept the paid-tool surface beyond the changed files. Headline: the --max-spend hard cap and several paid tools were blind to real USDC spend. All adversarially verified; the PR itself was then independently reviewed (which caught a concurrent-tool race in the ceiling fix, now closed).

Wallet spend ceiling (HIGH)

  • --max-spend now bounds TOTAL USDC, not just LLM tokens. Every paid tool (ImageGen/VideoGen/MusicGen, Exa, Surf, RealFace, Voice, Phone, Modal, DeFiLlama, RPC, Prediction) settled USDC through its own x402 path and counted $0 against the cap. A new live-spend accumulator is snapshotted before the stream (so mid-stream concurrent tools are captured, not raced past), netted against the LLM's own cost, and folded into the session total.
  • Charged-but-failed LLM calls now counted — a paid call whose stream then failed (timeout / mid-stream error / Esc) was never folded into the cap (and drift compounded across --resume).

Paid-but-invisible accounting

  • DeFiLlama, MultiChainRPC, PredictionMarket (now persisted), MusicGen, and panel-initiated phone Buy/Renew/List now record their settled USDC — were invisible to franklin stats.

Money-safety + correctness

  • $5 BuyPhoneNumber/RenewPhoneNumber now confirm via onAskUser.
  • VoiceStatus records once per invocation, not per 5s poll (was ≤420/call, evicting real spend history).
  • RiskEngine per-position cap values the held position at cost basis; over-sized closes flatten instead of throwing.

Contributor PR #89 (thanks @samsamtrum): Jupiter swaps no longer round a sub-precision amount up to one atomic unit; refined to floor excess precision and reject only true dust.

Local suite 479/479. See CHANGELOG.md for full detail.

Franklin 3.29.7 — finish the Exa wire-format fix + budget-safety follow-ups

Choose a tag to compare

@VickyXAI VickyXAI released this 24 Jun 07:04

Rollup release (npm went 3.29.4 → 3.29.7; 3.29.5/3.29.6 were never published). Headlined by completing the Exa wire-format fix and a three-round adversarial review that unified media-budget accounting.

Wallet / budget safety

  • Exa wire-format fix completed in the prefetch twin path. intent-prefetch.ts's own paid /v1/exa/answer call still read the dead body.data?.answer shape — it paid USDC, dropped the answer, and reported $0. Now reads both shapes via readExaAnswer (type-safe) and books the real cost.
  • Size-aware ImageGen + unified VideoGen/MusicGen budgets. Per-image/clip/track cost is resolved once (max of live catalog vs margin-adjusted static) and threaded through budget check, spend confirm, stats, and the content-budget record — closing a ~2–3× undercount on large image sizes and catalog-priced video (Seedance) / non-default music models.
  • Prefetch stock cost now reflects real spend (telemetry diff), so a 5-min cache hit no longer over-reports $0.001.

Recovery & robustness

  • Rate-limit/overload errors leaked as 200-OK text now auto-fall-back to another free provider (overloaded respects a user-pinned paid model); crash-safe persistence (fsync + orphan-.tmp cleanup); VoiceCall no-call_id guard.

Test integrity

  • Strengthened the paid Exa e2e to assert on tool-rendered markers (not the model's narrative); added paid ImageGen e2e + no-spend regression tests. Local suite 475/475.

See CHANGELOG.md for the full 3.29.5 / 3.29.6 / 3.29.7 detail.

Franklin Agent 3.28.3 — Node version guard

Choose a tag to compare

@VickyXAI VickyXAI released this 13 Jun 18:49

Old Node (< 20.19) crashed at startup with an opaque ERR_REQUIRE_ESM stack trace from deep inside rpc-websockets/uuid. The real requirement was always Node 20.19+ (require(esm)). 3.28.2's >=20.18.0 floor was one patch too low to actually run.

  • Runtime preflight guard. New dependency-free src/preflight.ts, imported before any other module, checks the Node version and on Node < 20.19.0 prints a clear upgrade message (nvm/fnm) and exits cleanly — no node_modules stack trace.
  • Correct engine floor. engines.node >=20.18.0>=20.19.0.
  • README updated to Node 20.19+ with the ERR_REQUIRE_ESM crash in the troubleshooting table.