Zealynx NewsletterWeek 02 · June 3, 2026

Last week the contract was the bug. This week the contract was fine and the key wasn't.

A weekly view from inside the audit queue: one finding worth your attention, one exploit autopsied at the line-of-code level, a tooling note, what we published on the blog this week, and an Academy update.

01Finding of the week

One signer key that can move reserves is a High-severity finding.

Last week's finding was about wallet UX: the user could not read what they signed. This week's finding is one layer down, and it is the one most teams still file under "ops, not our problem." The Gravity Bridge drain on May 30 is the reason it is now our problem, on the report, with a severity attached.

The pattern is not new. Researchers attribute the Gravity loss to a compromised validator or orchestrator signing key, not a flaw in the contract. The same root cause showed up in the Kelp DAO and Resolv incidents earlier this year, where the audited code was not the weak point. When an auditor signs off on contract logic and the protocol still loses reserves to a single key, the scope was wrong, not the code. So we are widening the scope.

High-severity: insufficient privileged-role controls on the destination chain. Any signer key, orchestrator address, or validator set that can authorize a large withdrawal or state update without a timelock and a meaningful multisig threshold (2-of-n is a floor, not a target) is a High-severity finding, scored the same as a missing access-control modifier in the contract itself. A single key that can move reserves is a single point of failure, and we now write it up as one. Remediation: HSM or MPC custody for signer keys, an on-chain rotation procedure, invariant tests that explicitly simulate a key compromise rather than assuming the key holds, and a rate-limit or circuit-breaker that treats an outsized outflow as anomalous by default rather than waiting for a validator to notice at 02:00 UTC on a Saturday.

Bridges get audited as contract plus key custody plus monitoring, or they do not get audited.

02Exploit of the week, autopsied

Gravity Bridge, $5.4M, the contract verified everything except whether it should.

Date
May 30, 2026, early UTC
Loss
~$5.4M ($4.3M USDC, 274 WETH ~$553K, $434K USDT, 14.164 PAXG ~$64K)
Chain
Ethereum mainnet (bridge contract), Ethereum to Cosmos via IBC
Vector
Suspected privileged signing-key compromise (researcher-attributed, not yet confirmed by postmortem)
Attacker EOA
0x7B58...da1F9
Laundering
Portion routed via ChangeNow and Binance; ~2,102 ETH (~$4.23M) still held
Bridge status
Halted by validators and orchestrators; ~$11.5M TVL pre-drain
Context
PeckShield counted 8 major bridge exploits totaling ~$328.6M in May alone

A note on what is and isn't confirmed

Gravity has acknowledged the incident, halted the bridge, and opened an investigation. It has not published a postmortem, so the exact entry point is unconfirmed. On-chain analyst Specter flagged the unusual withdrawals first and read the pattern as a signing-key compromise; PeckShield and Cyvers corroborated the asset breakdown and the laundering trail. We are autopsying the attributed mechanism, not a confirmed source diff, and we will say so plainly. The engineering lesson holds regardless of which key leaked.

What the bridge verified correctly

Gravity locks assets on Ethereum and mints mirror tokens on Cosmos, with a validator set signing off on every cross-chain move. By the available accounts, the signature checks did exactly what they were written to do. The withdrawal that drained the reserves carried cryptographically valid authorization. There was no reentrancy, no validation bypass in the message handler, no forged signature. From a contract-only review, the verification logic passed. This is the inverse of last week's Verus autopsy, where the bug was a missing equality check in the code. Here the code may have been correct and the attacker simply held a key that let them speak with the contract's full authority.

What the bridge did not have

There was no second factor on a large privileged release. A valid signature was sufficient; nothing stood between "signature verifies" and "tokens leave." No timelock to delay an outsized withdrawal long enough for a human to cancel it. No threshold that required a second independent approval for a transfer of that size. No on-chain rate limit that treats a withdrawal of a large share of TVL as anomalous by default. The illustrative shape of the gap, written as a generic bridge release function rather than Gravity's actual source:

function releaseFunds(Withdrawal calldata w, bytes calldata sig) external {
    // verified correctly: the signature is valid
    require(verifySigner(sig, w), "bad sig");

    // missing: a valid signature is the only gate on a large release
    // missing: require(timelockElapsed(w) && secondApproval(w));
    // missing: require(w.amount <= dailyLimit, "rate limit");

    token.transfer(w.recipient, w.amount);
}

The test we would have written

For a closed contract you fuzz the logic. For a bridge you also have to fuzz the threat model, and "a signer key is compromised" is part of that model, not an edge case outside it. The property is not "do signatures verify." It is "a single compromised privileged actor cannot move reserves without a delay or a second approval."

function invariant_singleKeyCannotDrain() public {
    // handler grants the fuzzer one privileged signer
    // and lets it attempt arbitrary releases
    assertTrue(timelockActive || secondApprovalRequired);
    assertLe(releasedThisWindow, rateLimitForWindow);
}

An invariant harness that hands the fuzzer one valid signer and still cannot drain the contract is the whole engagement for a bridge's operational boundary. If it can drain on the first round, the timelock and the rate limit are the fix, and they are cheaper than the postmortem.

Why this is the other half of the bridge problem

Look at the same week. Verus (May 18, $11.5M) was a code-level binding bug: valid signatures over a payout the contract should have rejected. Alephium (May 30, ~$815K) was a backend flaw that fed guardians forged events to sign, so the signatures were valid over invalid data. Gravity (May 30, $5.4M) is the third shape: valid signatures from a key that should never have been in the attacker's hands. Three different entry points in two weeks, one architecture. A bridge is two systems with a contract in the middle, and the contract has to enforce equivalence between the sides and survive the loss of its own privileged keys. Auditing only the Solidity covers one of those and leaves the protocol exposed on the other.

03Tooling note

Scaffolding privileged-key invariants with Krait and Foundry.

Last week the Krait boundary tag was cross-domain, for the Verus-class "for every output, an equivalent input" property. This week we used the same scaffolder against the other half of the bridge threat model. Point Krait at a contract that exposes a privileged release path and it generates a Foundry harness where the handler is granted a compromised signer, then tries to drain. The properties it pre-declares are the two that Gravity did not have: a release requires a timelock or a second approval, and no single window can exceed a rate limit.

$ krait scaffold-invariants --contract Bridge.sol --boundary privileged-key
$ forge test --match-contract BridgeOpsInvariants -vvv
$ krait explain-failure ./out/failure.trace

The difference fr the cross-domain tag is the threat model the handler assumes. cross-domain assumes honest signers and fuzzes the value binding; privileged-key assumes a signer is hostile and fuzzes what they can do with valid authorization. Krait runs as a Claude Code skill on the engineer's machine at zero API cost. If you ship a bridge and you are not running the question "what happens when a signer key is compromised" as a test, the Gravity post-mortem will run it for you.

04From the Zealynx blog

Bridge-relevant reading from the Zealynx archive.

05Academy update

New in the Academy: Share to earn Lynx.

Zealynx Academy just shipped Share to earn Lynx: you now earn Lynx points when you share your progress, on top of the points you already earn for building and auditing. The Academy is still fully free, no paywall, no premium tier. The newest features land first on the updates page.

06Housekeeping

The Ethereum Foundation's $1M audit subsidy program (run with Areta, covering up to 30% of audit cost via monthly cohorts) is still open, and if you would rather have Zealynx cover the audit directly, our Round 02 grants are open below.