Notes / Audits and snapshots

Solana -- Marinade Liquid Staking scored, 2026-09-18

Audits and snapshots2026-09-18Chain: Solana

Source: chains/solana/data/scored_targets_2026-09-18-marinade-liquid-staking.md in the repository, rendered here without changes. Source file

Closes two open points at once from scouted_targets_2026-09-17-run2.md (target #3, upper-bound composite 54): "decode State.admin_authority" and Methodology gap H1 ("legacy serum-style multisig has no timelock field, needs to be written into METHODOLOGY.md"). Both apply to this one target, so this pass closes them together.

Of the original 16 scouted targets, Marinade was the only one still carrying a clean "(upper bound)" tag with no config-admin path decoded -- Meteora DLMM/DAMM v1 (targets #5/#6) remain deliberately un-promoted for a different reason (no public source to confirm a specific number, reaffirmed by the 2026-09-18 adversarial review of the previous batch), not a backlog item.

Result#

DimensionadminKeymultisigtimelock
Program upgrade (legacy multisig, Path A)601000
State.admin_authority (council governance, Path B)706970
Combined (min per dimension)60690

compositeScore = 45 (down from the published upper bound of 54).

Two full-power paths, both re-derived live every run#

Path A -- program upgrade authority. A 2021-era "serum-style" multisig (marinade-finance/multisig, program msigmtwzgXJHj2ext4XJjCDmpbcMuufFb5cHuwg6Xdt, a verbatim fork of the now-archived project-serum/multisig template -- the multisig PROGRAM's own upgrade authority was burned in 2021, so the multisig program itself is immutable; only the Marinade program it controls is still live). Multisig account magrsHFQxkkioAy45VWnZnFBBdKVdy2ZiRoRGYT9Wed, 6-of-13, any owner can sign (no permission bitmask), and there is no timelock field anywhere in the struct -- confirmed against the real source (marinade-finance/multisig@v0.7.0's execute_transaction only checks did_execute and sig_count >= threshold), not merely absent from the decoded bytes. Signer PDA re-derived with seeds [multisig_pubkey], bump = the on-chain nonce field (253, not searched for) -- exact match to the live program-upgrade authority 551FBXSXdhcRDDkdcb3ThDRg84Mwe5Zs6YjJ1EEoyzBp.

Path B -- State.admin_authority. NOT a multisig at all: a Realms/SPL-Governance native-treasury PDA (42VJbDihcS81YJPbuhHnHgvo1ehu42j8VK9sNwrnAarR) of a dedicated Governance record in Marinade's own DAO deployment (GovMaiHfpVPw8BAM1mbdzgmSZYDw2tdP32J2fapoQoYs, realm "Marinade DAO", governance M5Fg6GipNvPzWgXNr5wj1EDcp8GB9J53cgyE7YGYLbL). This specific Governance record has COMMUNITY (MNDE token-holder) voting structurally DISABLED (community_vote_threshold = Disabled) -- only its COUNCIL can vote (council_vote_threshold = YesVotePercentage(50%)).

The council mint's entire 5-token supply sits, as expected for spl-governance's normal deposit-pooling design, in the realm's own pooled Governing Token Holding PDA -- this is NOT evidence of concentration in one wallet, it's the standard mechanism (independently re-derived and confirmed: this exact PDA, seeds ["governance", realm, council_mint]). The real voters are one level deeper, in each member's own TokenOwnerRecordV2, enumerated LIVE (not hardcoded) via sol_read.list_token_owner_records: 5 distinct owners, 1 token each, a genuine one-seat-per-member council. A 50% YesVotePercentage threshold over 5 equal-weight seats is ceil(0.50 * 5) = 3 -- an effective 3-of-5 council, using the exact same ceil(pct * total_weight) method this project's own data/finding_2026-09-17-spl-governance-shared-instance- controller.md already established and calibrated (there: a 60% threshold over 7 seats -> 5-of-7).

The judgment call: full-power, not bounded, and why#

admin_authority gates ChangeAuthority (single signature, no timelock, can reassign itself and every other top-level authority field on State at will) and ConfigMarinade (reward_fee, hard-capped <=10% by an in-code constant the admin cannot itself raise -- clearly bounded on its own).

The full-power case rests on a TRANSITIVE path: ChangeAuthority lets admin_authority instantly self-grant validator_system.manager_authority, which then gates SetValidatorScore and EmergencyUnstake/PartialUnstake -- the ability to force-redirect up to 100% of ALL depositors' currently-staked SOL away from one validator per epoch. Found by the adversarial review below, stronger than first written here: the per-epoch movement cap admin_authority also controls via ConfigMarinade has NO enforced ceiling at all (config_marinade.rs explicitly comments out the >=100% check) -- not "raisable to 100%," there is no upper bound to raise it to.

No instruction moves user PRINCIPAL to an admin-controlled address -- the only value admin can extract is the same hard-capped reward-fee skim, so this is not a fund-custody bypass. But validator selection is the primary counterparty/slashing-risk determinant for a liquid-staking protocol, the closest real analogue this target has to METHODOLOGY.md 6.2's own full-power example of a "price source": it lets one signature redirect where real, live, already-deployed user value is exposed, not merely which fees get skimmed. This is disclosed, not silently decided -- score_marinade's own docstring lays out the counter-argument (a reviewer who weighs "SOL never technically leaves a Marinade-owned account" more heavily may reasonably classify this as bounded instead) and exactly which instructions that disagreement should be argued from.

Methodology gap H1, closed#

The legacy serum-style multisig shape (owners: Vec<Pubkey>, threshold: u64, nonce: u8, owner_set_seqno: u32, no timelock field, signer PDA = [multisig_pubkey] with bump = the stored nonce) is structurally identical, for scoring purposes, to Squads v3 (fixed threshold-of-members, zero enforced delay) -- it reuses that same formula rather than needing a new _score_full_power_path kind. No new branch was added; this closes the gap by documenting the reuse, not by writing new code.

Cross-exposure, live-detected#

Owner 8HVYKgq2PA4SCDuPZSfHBH1aupTBJYPVru6kq3UfuSX9 sits on BOTH the 6-of-13 program-upgrade multisig AND holds one of the 5 council seats gating admin_authority -- one compromised key reaches both full-power paths on this single target. Live-detected via the same _signers-set mechanism as every other cross-exposure finding in this file, not assumed from the scouting pass.

Verification#

Adversarial review, 2026-09-18#

3-dimension review before commit (legacy-multisig/Path-A/Path-B facts; council census and threshold derivation; the full-power judgment call and cross-exposure), each finding independently re-verified by a separate reviewer instructed to try to refute it. 14 reviewers, 11 findings, 9 confirmed (mostly "matches exactly"), 2 flagged for disposition and applied above: the council-threshold denominator fix (deposit sum -> live mint supply, with an abort-on-divergence guard) and the max_stake_moved_per_epoch wording fix (no enforced ceiling at all, not "raisable to 100%" -- the review found the ORIGINAL docstring UNDERSTATED the real risk, not overstated it). A third finding proposing to reframe the full-power docstring around METHODOLOGY.md 6.2's "move user funds" clause instead of its "price source" clause was itself refuted on independent re-check -- "price source" is one of 6.2's own three enumerated full-power examples, not a weaker external analogy, and the docstring already explicitly raises and rejects the "moves funds" framing before choosing it (no instruction moves user principal to an admin-controlled address). No change to composite (45) from either of the two real fixes.

Reproduction#

python3 -c "
import sys; sys.path.insert(0, 'chains/solana')
from scorers import score_marinade
r = score_marinade('https://api.mainnet-beta.solana.com')
print(r['label'], r['compositeScore'])
for n in r['notes']: print(' -', n)
"

Not an audit, not investment advice. All notes ยท Back to the dashboard.