Restaking protocols are some of the hardest smart contracts to audit. Karak's 2024-07 Code4rena contest had a $210K bounty pool, a 9-day review window, and 50+ wardens looking at 2,415 lines of Solidity. The protocol's design is unusually adversarial — operators bring their own configuration, multiple Decentralized Security Services (DSSs) can slash the same vault, native ETH and ERC-20 vaults share a slashing veto window, and accounting drifts between live state and snapshot state.
We ran our AI audit engine against the same scope. It reproduced the contest's major findings AND identified three additional HIGH-severity issues not in the contest's published HIGH/MEDIUM report — every one of them verified with a runnable Foundry exploit.
ℹ️Scope and Ground Truth
Comparison is against the official Code4rena 2024-07-karak report (HIGH and MEDIUM findings as published). DSS implementation behavior was excluded from C4's scope per the contest rules. The "additional" issues described below were not surfaced as HIGH/MEDIUM in the published report — they may exist in the QA / Low / known-issues stream, which we did not exhaustively cross-check.
The Results
5/9
C4 Findings Reproduced
24/27
Foundry PoCs Verified (89%)
3
Additional HIGH Issues
~35m
To Verified Report
This is not a coverage-percentage benchmark. Karak is a harder protocol class than the vesting / lending / governance contests we've previously published 100% on. The right metric for restaking is whether the audit can find bugs nobody else found, then prove they're exploitable. That's what this run does.
Why Karak is Brutal to Audit
The Adversarial Surface
Operator-supplied configuration
When an operator deploys a NativeVault via Core, they hand in a bytes extraData blob that the contract decodes into three privileged values: a slashStore address, a node implementation address, and a manager address. All three are operator-chosen. Any one of them is a potential backdoor.
Dual slashing state
slashAssets() reduces totalAssets without burning shares. The next snapshot then re-charges the same ETH against per-node accounting. Reading either path in isolation looks correct; reading both reveals double-counting.
Permissionless finalizers
finalizeUpdateVaultStakeInDSS, validateExpiredSnapshot, and finishWithdrawal can all be called by anyone. The protocol assumes the legitimate party will call them; an attacker calling at the worst moment for the victim is the attack.
EIP-4788 beacon proofs
validateWithdrawalCredentials accepts beacon-state proofs with a lower-bound timestamp check but no upper bound — the EIP-4788 ring buffer holds ~27 hours of beacon roots, all currently valid.
This is the kind of design where pattern-match audits fail. The bugs require following 3-4 function calls across 1-2 actors and asking "what state machine breaks under this ordering?"
Three Additional HIGH Findings Beyond the Contest Report
These are issues not in the published Code4rena HIGH/MEDIUM report that our engine surfaced and verified with working Foundry exploits. Two relate to root causes the contest acknowledged through different attack vectors; one is an independent finding.
Additional-1: MANAGER_ROLE → Single-Transaction Rug (deeper analysis of H-02's root cause)
C4's H-02 surfaced the operator-controlled extraData vulnerability class through the slashStore attack vector. We document a separate, more severe attack vector through the same root cause — MANAGER_ROLE privileges that enable a single-transaction beacon-implementation swap, redirecting every node's withdraw to attacker code. Because the contest finding focused on slashStore, this attack path was not described or PoC'd in the published report.
When a NativeVault is deployed, the operator's extraData is decoded into (manager, slashStore, nodeImplementation). The manager address receives MANAGER_ROLE immediately:
// NativeVault.initialize()
(address manager, address slashStore, address nodeImplementation) =
abi.decode(_extraData, (address, address, address));
_grantRoles(manager, Constants.MANAGER_ROLE);
MANAGER_ROLE can call changeNodeImplementation(newImpl), which writes _state().nodeImpl. Because NativeVault is the IBeacon for every NativeNode proxy under it, a single transaction redirects every node's delegatecall to attacker-controlled code. A backdoored implementation can override withdraw(to, weiAmount) to ship ETH to the attacker rather than the recorded to address.
There is no allowlist on the new implementation, no timelock, no veto path — only a newImpl != address(0) check.
The Foundry PoC verifies the full chain: an attacker holding only MANAGER_ROLE deploys a malicious node implementation, calls changeNodeImplementation, and a subsequent withdraw on a victim's node delivers the ETH to the attacker. Cross-check confidence: 0.95.
Recommendation: Require new node implementations to be allowlisted by Core via a separate governance call (mirroring allowlistVaultImpl), add a 7+ day delay on implementation swaps, or remove operator-controlled MANAGER_ROLE granting at initialize time.
Additional-2: finishUpdateStakeHook Receives the Wrong Operator
In Operator.validateAndUpdateVaultStakeInDSS, the DSS hook receives msg.sender as the operator parameter:
data: abi.encodeWithSelector(dss.finishUpdateStakeHook.selector, msg.sender),
But Core.finalizeUpdateVaultStakeInDSS is permissionless — anyone can finalize a queued update after the delay window elapses. So msg.sender is whoever finalizes, typically a third-party keeper. The actual operator lives in queuedStakeUpdate.operator.
A DSS that maintains per-operator state (security weights, stake indices, slashing windows) via this hook will be fed the finalizer's address instead of the operator's, corrupting its accounting. An attacker who repeatedly finalizes other operators' updates can trigger DSS-side bookkeeping on attacker-controlled addresses.
The Foundry PoC verifies a mock DSS recording the wrong address when an attacker finalizes another operator's stake update.
Scope note: the contest excluded DSS implementation details, but the bug lives in
Operator(in scope) calling DSS hooks with the wrong operator address. C4 wardens may have considered the impact OOS because it depends on DSS-side state.
Recommendation: Pass queuedStakeUpdate.operator instead of msg.sender.
Additional-3: Force-Sent ETH Inflates Slash-Store Sweeps
_transferToSlashStore(nodeOwner) reads node.nodeAddress.balance to determine how much ETH to sweep. Even though NativeNode has no receive() function, ETH can still be force-sent via selfdestruct (still operative pre-EIP-6780 finalization on most chains). An attacker can donate ETH to a victim's NativeNode immediately before a snapshot triggers _transferToSlashStore, causing the sweep amount to exceed the legitimate slash. Combined with the validation gap in validateExpiredSnapshot (permissionless, attacker-timed), this gives an adversary the ability to grief node owners or — when combined with the operator-chosen slashStore — redirect inflated sweeps to operator-controlled storage.
The Foundry PoC verifies the inflation: a force-sent ETH contribution increases the swept amount by exactly the donated value, while the legitimate slash debt remains unchanged.
Recommendation: Track an internal nodeBalanceCredited counter that's updated only via controlled paths (validator withdrawals proven via beacon proofs, explicit deposits) and use it instead of the live node.balance read. Reconcile any excess via a separate skim function the node owner explicitly approves.
Reproduction of the Contest Findings
Beyond the three novel issues, our engine reproduced the major contest findings:
C4 Contest Finding
- •H-01: Slashing NativeVault leads to locked ETH due to double-deduction
- •H-02: Operator can create a NativeVault that is silently unslashable via mismatched slashStore
- •H-03: ERC4626 rounding error in convertToAssets exceeding totalRestakedETH
- •M-03: Slashing amount includes pending withdrawals past SLASHING_WINDOW
- •M-05: Slashing fails when any vault in batch has zero assets
Engine Detection
- •DETECTED — surfaced as accounting drift in slashAssets/snapshot interaction (verified PoC, severity calibrated to MEDIUM after second-opinion review)
- •DETECTED via the operator-controlled extraData root cause (the same backdoor as Novel-1's MANAGER_ROLE attack)
- •PARTIALLY DETECTED — captured the snapshot-stuck pattern from the share-burn angle
- •DETECTED — verified PoC for the front-run-via-startRedeem race
- •DETECTED — captured the per-vault-blocks-batch DoS pattern
We did not reproduce H-04 (DSSs can slash unregistered operators due to the unregister timing gap). That one is a subtle race-condition pattern requiring specific reasoning about pending-state-at-unregister; a clear miss we're working on.
The 89% PoC Verification Rate
Across 27 attempted Foundry PoCs (one per candidate finding flagged for verification), 24 compiled and ran the exploit successfully end-to-end. That's the strongest possible signal for a security finding: the bug isn't theoretical — there's a forge test you can run today that proves it.
27
PoCs Attempted
24
PoCs Compiled & Passed
89%
Verification Rate
HIGH
Overall Risk Rating
The 3 PoCs that didn't verify weren't false positives — they hit edge cases in test harness construction (mock DSS dependency injection, beacon-proof fixture generation) that the test code couldn't reproduce in a one-shot Foundry context. The underlying findings are still valid; they ship as theoretical-only in the report.
The Honest Comparison
What We Caught
- •Operator-extraData backdoors that hand privileged roles to deployer-chosen addresses
- •DSS-hook parameter confusion (msg.sender vs intended operator)
- •Force-sent ETH inflating sweeps via selfdestruct
- •First-depositor share inflation specifically for low-decimal assets (USDC/USDT)
- •finishWithdrawal silent-cap accounting drift
What We Still Don't Catch Reliably
- •Multi-step state-machine bugs where the offending state is created and finalized by different parties hours apart (timing-gap class)
- •Beacon-proof timestamp staleness involving the ring-buffer eviction window
- •Cross-DSS slashing cooldown interactions when one DSS slashes during another's veto window
- •Some accounting bugs whose impact is debated between MEDIUM and HIGH severity
- •Permanent state-pollution griefing where the attacker has no profit motive
We publish what we find and what we still don't. Karak is genuinely harder than vesting or governance contests — restaking economics has more moving parts and the bugs are subtler. Reproducing 5 of the 9 Code4rena findings AND surfacing 3 additional HIGH-severity issues beyond the contest's published HIGH/MEDIUM report is, we think, the strongest verifiable claim we can make on a protocol of this difficulty class.
Try It Yourself
3
Novel HIGH Findings
89%
PoC Verification
2,415
SLOC Audited
~35m
Time to Report
Upload your contracts. Get a verified audit with runnable Foundry PoCs for every HIGH-severity finding. We publish detection rates AND the gaps so you know exactly what you're paying for.
ℹ️Want to Verify These Findings Yourself?
We can run an independent expert review on the Karak codebase or any of the additional HIGH findings above — full audit output, side-by-side comparison against the C4 report, and verifier sign-off on each PoC. Request an expert proof report →
Related reading
veRWA governance (8/8 HIGH) · Wildcat Protocol (6/6 HIGH) · BakerFi Yield Vaults (7/7 HIGH) · VTVL Vesting (2/2 HIGH) · Ethernaut + DVD (7/7 challenges) · Jito Restaking on Solana.