Account Demolisher
Security

Audit and review status

The state of the external audit, the internal pre-audit review and its remediation by severity and status, the FxDAO removal, and the dependency posture.

External audit

An independent external audit of Account Demolisher has not been performed yet. The app tells you so: whenever it is on mainnet, from the build default, a restored selection or a switch, the browser has to acknowledge that the code has not had an independent audit before the app operates (src/components/layout/AppShell.tsx, src/components/layout/MainnetConfirm.tsx). The notice follows the network the app has selected, not the one a signing request names, so a co-signer on /sign sees it whenever their browser is on mainnet without an acknowledgement.

When the external audit runs, its findings and their resolutions are published on this page.

Internal pre-audit review

Before the external audit, the codebase went through an internal review at commit 764d808 (2026-10-02):

  • Seventeen area reviewers read every line of src/ (136 files, 32,341 lines), the Docker, CI and release configuration, package.json, public/, every page of this documentation, the root markdown, and every file under tests/ and scripts/qa/, recording the exact line ranges read.
  • An independent verifier tried to refute each finding against the code and the installed library sources, and where possible proved it with a scratch script, a focused test, or a read-only testnet or mainnet query. Verifiers also reported issues the reviewers missed.
  • A completeness pass compared the coverage against the file tree and sent six further reviewer and verifier pairs into cross-cutting areas: the sign-time guards, slippage, fail-open error handling, secret and token data flow, concurrency, and drift between discovery and execution.
  • 483 raw findings: 479 survived verification and 4 were refuted. They were merged into 259 distinct issues, one per root cause, and two more found while fixing were added, for 261.
  • Nothing was signed or submitted on mainnet during the review.

Each code fix that changed behavior was made with a regression test written to fail first. Refactors and dead-code removals were checked with the type checker and the existing test suites, and documentation-only issues against the code. A separate reviewer checked every fix.

Severity scale

SeverityMeaning
CRITICALLoss or stranding of the account owner's funds, key or secret compromise, or signing something the owner did not intend
HIGHA close fails or misreports for a realistic account, a security control is bypassed, or success is reported falsely
MEDIUMA real bug with a narrower trigger or recoverable impact, or misleading UI on a money path
LOWAn edge case, robustness, minor UX or accessibility
INFOCode quality, dead code, stale comments, or documentation drift with no runtime impact

Results

The counts below are the review's tracking file as of this revision of the documentation:

SeverityIssuesFixedNot a bug
CRITICAL880
HIGH39390
MEDIUM64640
LOW1251232
INFO25250
Total2612592
  • Fixed: 259 issues, every one confirmed by an independent check against the code after the fix landed.
  • Not a bug: 2 issues the fix work showed were already handled.

What the CRITICAL fixes changed

IssueNow
Allow-listed DeFi steps signed simulation-recorded authorization trees without checking nested callsEvery DeFi step is held to the exact authorization tree its call needs (src/lib/soroban/defi-auth-guard.ts)
Retry after a failed forward could report success while the balance sat in the mediatorA forward that did not land ends forward_pending, and Retry runs it
A merge whose confirmation was lost could lead Retry to re-mint the mediator and strand the balanceSubmissions are journaled by hash and looked up before anything is signed again; a funded mediator is adopted
The mediator token's 15-minute lifetime could run out before the mergeA new flow is minted right before the funding batch, and tokens renew through /api/mediator/reissue
Two-pass Soroban builds reused one account object and submitted at the wrong sequenceEvery build gets its own copy of the account at the same sequence, so a probe build never advances the real one
Aquarius discovery failed open when its API and event scan both came back emptyA protocol that cannot be read records an error, and the merge guard refuses on it
Blend discovery read only the V2 backstopBoth backstops are read, and V1 pools resolve to the V1 backstop
A shared-account signing request could merge around open Soroban positionsA signing request is refused while the plan holds any step besides the classic close, or discovery reported an error, and the bundle is checked again before submit

FxDAO

FxDAO was a supported protocol and is no longer, because the protocol shut down on chain. The evidence, gathered on 2026-10-06:

  • The mainnet vaults contract CCUN4RXU5VNDHSF4S4RKV4ZJYMX2YWKOH6L4AKEKVNVDQ7HY5QIAO4UB now runs a wasm whose interface exports only evict and upgrade.
  • Its CoreState.panic_mode is true.
  • VaultsInfo shows total_vaults = 0 and total_col = 0 for USD, EUR and GBP.
  • The contract's data on stellar.expert holds only the instance entry, so no vault record remains, live or archived.
  • The six testnet FxDAO contracts the app had pinned no longer exist.

There are no FxDAO positions left to unwind, so the app no longer discovers them or plans exits for them, and the allow-list carries no FxDAO entries. The FxDAO stablecoins already issued (about 17,504 USD, 3,857 EUR and 3,110 GBP by the debt counters) are ordinary balances: a close sells them for XLM, returns them to their issuer, or asks you, like any other credit balance.

Dependency posture

Runtime dependencies are pinned by the committed pnpm-lock.yaml and installed with --frozen-lockfile. CI and the release workflow both run pnpm audit --prod --audit-level high and fail on any high or critical advisory in the production tree. The production tree carries none.

Two overrides in pnpm-workspace.yaml remove advisories that the upstream version ranges would otherwise ship:

  • axios 1.20.0 under the Stellar SDK 16 copy that @blend-capital/blend-sdk pins, which would otherwise ship axios 1.18.0.
  • jayson 5.0.0 under @solana/web3.js 1, which drops the uuid 8 and stream-json 1 copies that jayson 4 carries.

No advisory is suppressed. On 2026-10-12, pnpm audit --prod reports one advisory below the gate, and pnpm audit without --prod, which adds the development dependencies, reports one more:

AdvisoryPackageTreeSeverityWhy it stays
GHSA-848j-6mx2-7j84elliptic 6.6.1ProductionLowNo patched release exists. It sits under @hot-wallet/sdk, which only the Stellar Wallets Kit's HOT Wallet module uses; the app does not load that module, and signs with ed25519 through the Stellar SDK
GHSA-vfj7-8cjw-p6xmbraces 3.0.3Development onlyHighNo patched release exists: 3.0.3 is the latest braces release. It arrives through eslint-config-next > @next/eslint-plugin-next > fast-glob > micromatch > braces and runs only while ESLint lints the repository. The plugin expands only the settings.next.rootDir patterns of the lint configuration, which this repository does not set. The production image installs with --prod and does not contain it

ESLint stays on 9.39.5, the last 9.x release, while the latest is 10.12.0. eslint-config-next 16.4.0 depends on eslint-plugin-react ^7.37.0, and that plugin's latest release, 7.37.5, declares the peer range ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7, which leaves ESLint 10 out. ESLint 10 support is tracked upstream in jsx-eslint/eslint-plugin-react#3977, open on 2026-10-12. ESLint is a development tool and is not in the production image.

The toolchain is Node.js 24 LTS and pnpm 12, with Stellar SDK 17, Next.js 16.4 and React 19.3.

On this page