Repository navigation
v0.2.0 — two exploit classes, and it finds the build itself
Two exploit classes now, and the command no longer needs to be told where the
build is.
What's new
A second exploit class. account-substitution-pda (FR-006): a program that
acts on an account of its own type without proving it belongs to the signer in
front of it. The attacker signs legitimately as themselves and hands in the
victim's account of the same type — the signature is real, it just authorises
the wrong account, which is what separates this from missing-signer. Cites
Wormhole, February 2022. On the fixture pair it moves 999,995,000 lamports on
the vulnerable half and is blocked on the fixed one.
The two halves emit byte-identical IDLs apart from the program address: the fix
is a require_keys_eq! inside the handler and shows nowhere in the IDL. A
verdict on this pair cannot have been read from metadata — there is nothing in
it to read.
--artifact is now optional. Without it the working copy is built and the
result cached by a SHA-256 of the sources and the locked dependencies, so a
repeat run with nothing changed skips the build: 59.8s cold against 0.135s warm
on the fixture, same verdict either way.
Sources are followed from the artifact, not searched for. The workspace is
found by walking up from the artifact rather than down from the scan root. A
scan of the vulnerable half used to cite line 41 of the fixed half — a
confident reference to the wrong line, which is worse than none.
Disagreement is now an answer. Where the artifact and the working copy
disagree — the program undeclared, one name at two addresses, or bytes unlike
what these sources build to — the run returns inconclusive with a reason and
exits 2. It never picks a half.
The workspace is read. Anchor.toml is parsed, so deployment is no longer
unknown for every scan; the value decides how much of a proof may be published
(FR-015). Every rule leans one way: anything the parser cannot fully read
resolves to unknown. Being wrong towards local publishes a mainnet exploit;
being wrong towards unknown costs a redaction nobody needed.
Fixed
- Replays no longer exhaust memory. litesvm 1.3.0 never frees an SVM's
native memory, so a process replaying many of them climbed until the
allocator aborted withstd::bad_allocat ~130 MB RSS with gigabytes free.
Two full scans, or a library walk over more than one scenario, hit it. Each
replay now runs in a child process that hands the leak back to the OS on exit. --artifactwas resolved against the scanned root, so
scan fixtures/x --artifact fixtures/x/artifactsdoubled the path.
Also
- Fixture reproducibility is now verified across machines. A cold
ubuntu-latestrunner with no build cache, installing the pinned toolchain
from scratch, produced all four hashes byte for byte. - A local demo runner that warms the build cache before a live showing, and
verifies the warm-up rather than assuming it.
What this release still does not have
BLOCKEDnever means safe. Two scenario classes, two fixture pairs. This tool
proves presence, never absence, and it always will.- No GitHub Action —
apps/actionis still a stub — no fork mode, no PoC
redaction.
Upgrading
Nothing to migrate. --artifact keeps working; it is now optional rather than
required.