What was proven: the decision logic
The core of Shugo is one pure function,evaluate(), that takes a snapshot of a policy plus a requested pull and returns Allow or Deny(reason). It has no accounts, no CPI, and no Solana runtime in it, which is what makes it possible to check exhaustively with Kani, a bit-precise model checker for Rust.
The property proven is a biconditional: evaluate() returns Allow if and only if every check passes.
u64 caps and amounts, all i64 timestamps, all possible destination bytes — not a sampled set of test cases.
Result
What the proof does not cover
These limits are as important as the result.It does not prove 'no more than the cap in any window-length interval'
It does not prove 'no more than the cap in any window-length interval'
That property is false for Shugo and is not claimed. The window is fixed, not sliding, so an agent can pull up to the cap at the end of one window and again at the start of the next — up to 2× the cap across a boundary. See Velocity Caps.
It covers evaluate(), not the whole program
It covers evaluate(), not the whole program
The proof covers the decision function. It does not cover account validation in
execute_pull, the CPI into S&A, the write-back of the updated window total, PDA derivation, or signer checks. Those are exercised by the integration tests below, which are behavioral checks of specific scenarios, not exhaustive proofs.It says nothing about S&A or the Solana runtime
It says nothing about S&A or the Solana runtime
Both are assumed correct. S&A has its own audit; Shugo inherits its guarantees and its risks.
Integration tests
Seven tests run both compiled programs side by side in LiteSVM — Shugo’s program and the real, unmodified Subscriptions & Allowances binary — so the CPI between them executes under real runtime semantics rather than being mocked.SUBSCRIPTIONS_SO_PATH pointing at its .so).
A bug the tests missed once
The first devnetcreate-policy run failed with S&A error 136, StaleSubscriptionAuthority. The SDK had passed a hardcoded 0 as the authority’s generation ID. A real authority’s ID is the slot it was created in, so on a live cluster that value is huge; every test had passed anyway because LiteSVM’s clock starts at slot 0, which made the wrong value accidentally correct. The SDK now uses S&A’s sentinel for same-transaction creation, and the test suite sets a realistic slot so this class of bug can’t hide again. It’s listed here because a security page that only reports successes isn’t worth much.
(1).png?fit=max&auto=format&n=qzWg2aQwcoMXkrks&q=85&s=7bd9594b6c05a51ce5a41a26f4cb7e42)
(1).png?fit=max&auto=format&n=qzWg2aQwcoMXkrks&q=85&s=f7ad867613529ca7109dfe0b0dabd815)