OMEGA V4 Security Audit · V0.7 GA
Full adversarial audit of the Covenant compiler before V0.7 public launch. Every finding is documented, reproducible, and public.
OMEGA V4 is Kairos Lab's internal adversarial audit framework. It is not a checklist. It's a mindset: assume every guarantee the compiler claims to enforce is a lie, and try to prove it. The question is never "does the source look right?" — it's "does the emitted bytecode contain the bytes the source promised?"
These findings share a pattern: the source looked correct, the tests passed, the contracts deployed — but the generated bytecode did not enforce the guarantee the source promised. Silent codegen failures are the worst class of bug.
Covenant's access control system lets developers write only(owner), when(condition), and given(proof) clauses on actions. These should emit a CALLER + EQ + ISZERO + JUMPI pattern targeting the revert path before any function body executes.
The IR builder accepted and type-checked the clause, but the emit_only_assert function was never called. Every deployed Covenant contract with an access control clause would silently accept calls from any address.
; withdraw_all() — NO ACCESS CHECK
JUMPDEST
PUSH1 0x00
SLOAD ; load balance
CALLER ; push msg.sender
; (transfer — no guard before it)
PUSH1 0x00
PUSH1 0x00
SSTORE ; clear balance
STOP
; withdraw_all() — GUARDED JUMPDEST CALLER ; msg.sender PUSH32 … ; stored owner SLOAD EQ ISZERO PUSH2 revert ; revert if ≠ JUMPI ; (transfer follows)
Fix: emit_only_assert in covenant-ir/src/builder.rs now emits LoadCaller → LoadPrincipal → Eq → Assert. The EVM backend lowers Assert to ISZERO + JUMPI → __revert__. Regression test in covenant-evm-backend/tests/guard_codegen.rs asserts every only() in source produces the CALLER + EQ + ISZERO + JUMPI pattern in the bytes.
Covenant supports UUPS upgradeable proxy patterns. An initializer action is supposed to be callable exactly once. But the bytecode had no re-init guard — initialize() could be called repeatedly, overwriting owner and treasury with attacker-controlled addresses.
Fix: emit_initializer_guard wraps every initialize action with a slot-based flag. The slot is keccak256("covenant.proxy.initializer.<ModuleName>") — EIP-7201 namespaced, unique per module. The bytecode reads the slot, reverts if already set, then sets it before executing the body. Phase 3 is terminal — no re-entry possible.
Cryptographic precompiles (FHE ops, Dilithium verify, ZK proof check) are invoked via STATICCALL. Two separate failures combined into a full bypass of post-quantum authentication:
CVN-013: The STATICCALL success flag was popped and discarded. A precompile that reverted (invalid input, out of gas) was treated as successful.
CVN-014: Before STATICCALL, the return memory slot was not zeroed. A failed STATICCALL left stale memory that MLOAD read as a nonzero value — interpreted as "signature verified".
Combined exploit: An attacker submits a forged Dilithium signature. The precompile reverts. The success flag is dropped. The MLOAD reads stale memory containing a nonzero value from a prior operation. Authentication succeeds. One transaction, deterministic in deployments with prior operations.
Bytecode differential: runtime bytecode grew from 835 → 1336 bytes. The ISZERO opcode count went from 9 → 47. That's 38 new safety checks, one per precompile call site. CI now asserts ISZERO count as a lower bound.
Covenant implements ERC-8228 (Cryptographic Amnesia Interface). Amnesia ceremonies have a strict four-phase state machine: idle → gathering → finalized → destroyed. Only phase reads were checked; phase transitions had no guards. An attacker could call destroy() at phase 0, jump to phase 3, and have is_destroyed() return true without a key ever having existed.
Downstream integrations (GDPR compliance, regulatory data erasure, institutional key destruction proofs) rely on is_destroyed() being trustworthy. With transitions unchecked, the state machine was decorative.
Fix: Every ceremony function now checks its required precondition phase via emit_assert_phase_eq(expected_phase). Phases are enforced at bytecode level via SLOAD + EQ + ISZERO + JUMPI. Phase 3 is terminal — no function takes phase 3 as a valid input state.
High findings caused incorrect or insecure behaviour without being fully exploitable in isolation. Several had been present since early compiler versions with no visible test failures.
| ID | Finding | Commit |
|---|---|---|
| KSR-CVN-015 | FheCmpNe and FheCmpLe dispatched to wrong precompile addresses — aliasing EQ and LT. Every encrypted != and <= returned an incorrect result. |
d378297 |
| KSR-CVN-016 | CSE optimizer collapsed distinct FheEncryptFresh calls. Two ciphertexts from "fresh" encryption were collapsed to one — the "fresh" guarantee was destroyed. |
f3a5277 |
| KSR-CVN-017 | Same CSE bug collapsed PqRand calls — post-quantum nonces reused across operations that required distinct randomness. |
f3a5277 |
| KSR-CVN-018 | Reentrancy lints didn't cover the ExternalCall opcode — cross-contract reentrancy went undetected by the linter. |
d88910c |
| KSR-CVN-019 | No EXTCODESIZE canary before CALL to external contracts — EOA and self-destruct patterns went undetected. |
5ee93a8 |
| KSR-CVN-020 | No 4-byte ABI selector prefix on precompile calldata — precompile ABI versioning not enforced at call sites. | 5ee93a8 |
| KSR-CVN-021 | @slot(N) annotation silently ignored — layout guarantees promised to developers were not enforced in emitted bytecode. |
0eb1ad8 |
| KSR-CVN-027 | External CALL and STATICCALL success flags discarded — same class as CVN-013, affecting user-invoked external calls. |
5eb1c38 |
Medium findings affected correctness and developer safety. Low and Informational findings strengthened tooling, diagnostics, and supply chain. All resolved before V0.7 GA.
KSR-CVN-022, 023 — Shamir / VDF hard-fail: Shamir Secret Sharing and Wesolowski VDF opcodes emitted broken stubs that silently succeeded without performing any cryptographic work. Rather than emit silent fiction, the compiler now hard-fails with E516/E517 for these opcodes until V0.8 chain support ships. "Deploy no code" beats "deploy broken code."
KSR-CVN-024, 025 — P4/P5 invariant detectors: Privacy invariants P4 (nonce reuse) and P5 (monotonicity) had no lint detectors in the security pass. Detectors added.
KSR-CVN-026 — FheBootstrap eliminated by DCE: Dead Code Elimination was removing FheBootstrap calls (which refresh FHE ciphertext noise budget) because they appeared to have no side effects. DCE now marks FHE refresh ops as side-effecting.
Storage / supply chain: @slot(N) collision detection wired (E423), annotation validation, PRECOMPILE_ABI_VERSION marker in bytecode, Cargo.lock pinning, per-chain version binding. Full list in covenant-audits.
only(owner) should produce CALLER + EQ + ISZERO + JUMPI. If it doesn't, the test fails — not because the source looked wrong, because the bytes are wrong.
Add(3,3), Eq(5,5)) would pass even if operands are reversed. We now test every binary op with asymmetric pairs (Sub(10,3) vs Sub(3,10), Lt(2,7) vs Lt(7,2)).
state = Phase2 in a function body doesn't protect you if the function can be called when state is Phase0. Every transition needs a precondition check compiled into bytecode — not documented in source, not enforced by convention.
STATICCALL has three failure modes: success flag, return data size mismatch, revert. Check all three. If any single check would have caught CVN-013 or CVN-014 alone, the exploit would have been impossible. That's what defense in depth means.
Shipping broken stubs is worse than shipping nothing. These features are deliberately disabled until they can be implemented correctly.
E516)shamir_split, shamir_recover, or @shamir_threshold will not compile. Full implementation requires Aster Chain support (V0.8).E517)vdf_eval or @vdf_locked will not compile. Same dependency on Aster SDK for chain-native VDF verification.--target-chain aster compiles to a placeholder artifact (COV7\x01 magic + metadata). Full bytecode emission requires Aster SDK GA. V0.7 artifacts are not deployable on-chain.The full OMEGA V4 report is public at github.com/Valisthea/covenant-audits. Every finding has a finding ID, severity, description, annotated bytecode PoC, remediation commit, and regression test. If OMEGA V4 missed something, that's a welcome problem — the bounty program is in the same repo.
QUICK INSTALL