Skip to main content

Audit status

This page is the honest read on the security posture of the current SealedIP deployment.

Prototype build, testnet only

The current deployment is unaudited. It runs on Story Aeneid testnet (chain id 1315), with testnet WIP, against contracts that were deployed and redeployed multiple times during the CDR Hackathon (May 27 to June 5, 2026). Do not assume mainnet security guarantees.

What's on-chain

ItemValue
SealedAuction0xb41B87f2E58E3f6139d6B6D2323C7AdFd47FC9ee
AuctionRevealCondition0x1A3cCd475CCFb47D1353f62F3bca6DEfAC3D69bC
CDR (Story system contract)0xCCCcCC0000000000000000000000000000000005 (not verified on Storyscan)
Source licenseMIT
Solidity version0.8.26
Optimizer runs200

What's covered by tests

43 Foundry tests passing across three suites.

BidPayload

  • Encoding / decoding round-trip preserves all fields
  • recoverSigner returns the correct address for valid signatures
  • recoverSigner rejects tampered amounts
  • recoverSigner rejects tampered nonces
  • High-s signatures rejected (EIP-2 low-s enforcement)
  • Invalid payload length reverts with InvalidPayloadLength
  • Invalid signature length reverts with InvalidSignatureLength

AuctionRevealCondition

  • checkReadCondition returns false before the deadline
  • checkReadCondition returns false at deadline but before trigger
  • checkReadCondition returns true once deadline elapsed AND auction triggered
  • register reverts when called by a non-registrar
  • register succeeds when called by the registrar

SealedAuction — creation and reserve

  • createAuction emits AuctionCreated event and stores record
  • Rejects past deadlines (DeadlineInPast)
  • submitEncryptedReserve stores ciphertext and sets reserveHasCiphertext
  • submitEncryptedReserve reverts on double-write (ReserveAlreadyWritten)
  • submitEncryptedReserve reverts when called by non-seller (NotSeller)

SealedAuction — bidding

  • allocateBidSlot pulls deposit and allocates a CDR vault slot
  • Reverts past deadline (BiddingClosed)
  • Reverts on zero deposit (ZeroDeposit)
  • submitEncryptedBid blocks non-bidder writes (NotBidder)
  • Blocks double-write of ciphertext (CiphertextAlreadyWritten)

SealedAuction — trigger / settle

  • trigger flips state at deadline only (DeadlineNotReached revert otherwise)
  • settle picks highest valid bid, verifies reserve reveal, mints license, pays out, refunds losers
  • settle skips amount-exceeds-deposit attacks
  • settle skips bad signatures
  • settle skips slots without ciphertext
  • settle reverts with InvalidReserveReveal on a bad reserve reveal when reserveHasCiphertext is true
  • No-winner path (no bid clears reserve) refunds all deposits and emits AuctionExpiredNoWinner

Run locally:

cd contracts && forge build && forge test

Source-line coverage for production contracts is gated at 90%:

npm run coverage

Verified live end-to-end on Aeneid

Beyond the Foundry suite, the full lifecycle has been run against the real CDR threshold network on testnet: list, seal reserve, two sealed bids, trigger, CDR threshold-decryption of both bids AND the sealed reserve, and an atomic settle that mints a Story PIL license to the winner. This exercises the one leg the Foundry tests mock: real CDR decryption at settle.

StepOn-chain evidence (auction #2)
Trigger0xe18035c9ef7cc4cd2d15ca46ffa7ad49fd9240bea25c1ca45549b321dd3ab89c
CDR decrypt bid A (0.5 WIP)read tx 0xf4a3f7c1a75ad2d020f86c024ee5428c43b2f10ac17c4faf2b70f8b442393b57
CDR decrypt bid B (1.0 WIP)read tx 0x2540b9b58b34ef1e2843e85c01d3c3b4f5bb2f1ef04b19168c811837f632a116
CDR decrypt sealed reserve (0.1 WIP)read tx 0x57a79e48b5593ddef982e604c7d7fe4776649304a0ba52d6b6456bb71bb0e8f3
Settle0x15003bbcfad735a4222cc2b20e7684d8906c8f1c75e14d9374b111f9c4e5be04 (status 1)
Outcomewinner bidder B at 1.0 WIP; license token #72662 minted to the winner

The harness is sdk/scripts/live-settle-test.ts (places two bids, then runs the orchestrator: wait, trigger, decrypt every vault, settle). Every hash above is checkable on Storyscan.

What's NOT covered by tests

  • Gas-limit boundary tests — what happens when settling with hundreds of bidders
  • Reentrancy fuzzing — manual code review covers the patterns, but no fuzz suite
  • End-to-end with real CDR (automated) — the Foundry suite mocks the CDR contract. The real CDR network has been exercised manually and settles correctly (see Verified live end-to-end), but there is no automated integration suite against live CDR
  • Story Protocol contract behavior changes — if Story redeploys PILicenseTemplate or changes the mint signature, settle could revert. No automated integration tests run against live Story contracts.
  • Floor-0 default edge cases — the behavior when no reserve is sealed is tested; extreme bid values near zero are not fuzz-tested.

Static analysis

No automated static analysis (Slither, Mythril, Echidna) has been run on the contracts. These are typically the first step of a professional audit.

What passing tests don't prove

The tests verify the documented behavior of the contract. They do not prove:

  • Threshold cryptography correctness. The TDH2 implementation lives in CDR, not SealedIP. We trust CDR's implementation.
  • Validator set integrity. A colluding validator set can defeat the protocol regardless of contract correctness.
  • Off-chain encryption service correctness. The encryption service is a TypeScript wrapper around a Rust WASM module. Bugs there could leak plaintext.
  • Front-end correctness. The marketplace UI handles wallet flows; bugs there could mislead users.
  • PIL terms semantics. We mint a Story PIL license at settle. The legal effect of that license depends on Story Protocol's enforcement, not ours.
  • CDR reveal-integrity. The contract verifies the seller and bidder signatures on revealed amounts, but cannot verify that the revealed amount matches what was originally encrypted in the CDR vault.

Path to audit-readiness

If you wanted to deploy SealedIP to mainnet, the things to do first:

  1. Static analysis pass — Slither and Mythril against SealedAuction.sol and BidPayload.sol. Address findings.
  2. Reentrancy reordering — move state transitions before external calls in settle() (currently state is written after transfers).
  3. Gas-limit fuzzing — fuzz settlement with varying bid counts; document the practical max or add a pull-payment fallback.
  4. Real-CDR integration tests — run end-to-end against an Aeneid CDR fork.
  5. Independent audit — engage a security firm familiar with threshold-crypto-adjacent systems.

None of this is hard. It is not in scope for the hackathon.

Reporting issues

See Reporting vulnerabilities for the disclosure path.