Skip to content

feat(kms/auth-eth): formal verification — Slither + Halmos + spec#689

Open
h4x3rotab wants to merge 2 commits into
foundryfrom
feat/auth-eth-formal-verification
Open

feat(kms/auth-eth): formal verification — Slither + Halmos + spec#689
h4x3rotab wants to merge 2 commits into
foundryfrom
feat/auth-eth-formal-verification

Conversation

@h4x3rotab
Copy link
Copy Markdown
Contributor

Layers a formal-verification stack on top of #252. Depends on #252 merging first — base is the foundry branch.

What

  • Slither static analysis (slither.config.json + four per-line // slither-disable-next-line justifications in DstackKms.sol). Baseline: 0 findings.
  • Halmos symbolic execution: 28 check_* properties across test/DstackApp.symbolic.t.sol and test/DstackKms.symbolic.t.sol. Each function's arguments are symbolic; properties cover owner gates, isAppAllowed decision tables, byte-exact TCB compare, disableUpgrades monotonicity, factory atomicity, both 5- and 6-arg initializer overloads. All pass.
  • docs/formal-verification.md — layered FV roadmap. SMTChecker (Layer 1) is deferred with rationale (forge's solc binaries lack z3 linkage).
  • docs/specification.md — normative pre/post/frame conditions, state invariants, cross-contract assumptions, adversarial scenarios, open spec questions for the team.

Both tools run locally (pipx install slither-analyzer halmos). Intentionally not in CI — symbolic execution is slow, solver-version-sensitive, and most valuable as an interactive design check rather than a PR gate.

Finding worth review

DstackKms.registerApp is permissionless by design (already confirmed-intentional). Halmos's first check_RegisterApp_OnlyOwner test failed and was rewritten to assert the actual permissive behavior. The downstream allowedOsImages whitelist + delegated isAppAllowed gate authorization, so registration alone confers no privilege.

Open product-level questions

The specification document ends with four decisions the team should pin down:

  1. Should renounceOwnership be overridden to revert?
  2. Should KMS track which appImplementation was current per app at deploy time?
  3. Should removeOsImageHash retroactively un-authorize already-running apps?
  4. Should gatewayAppId validate format?

How to verify

pipx install slither-analyzer halmos
cd kms/auth-eth
slither .                                          # 0 findings
halmos --contract DstackAppSymbolicTest            # 14 / 14
halmos --contract DstackKmsSymbolicTest            # 14 / 14
forge test --ffi                                   # 46 / 46 (unchanged from #252)

🤖 Generated with Claude Code

h4x3rotab and others added 2 commits May 19, 2026 09:03
Layers a verification stack on top of the Hardhat→Foundry migration:

- Slither static analysis with project-tuned suppressions
  (kms/auth-eth/slither.config.json): excludes naming-convention and
  solc-version detectors that hit OZ-idiom noise across our codebase,
  plus four per-line justified `// slither-disable-next-line` comments
  in contracts/DstackKms.sol (factory reentrancy-benign on
  deployAndRegisterApp's `new ERC1967Proxy`, named-return-forward
  unused-return on the IAppAuth delegation, two unindexed-event-address
  for backward compatibility with deployed log indexers). Baseline:
  0 findings.

- Halmos symbolic execution: 28 properties across
  test/{DstackApp,DstackKms}.symbolic.t.sol, each `check_*` function
  treats its arguments as symbolic. Owner-only mutations, isAppAllowed
  decision tables (including the byte-exact TCB compare), disableUpgrades
  monotonicity, factory atomicity + TCB flag propagation, both 5- and
  6-arg initializer overloads. All pass.

- docs/formal-verification.md is the layered roadmap (Slither → Halmos
  → optional Certora). SMTChecker (Layer 1) is deferred — forge's solc
  binaries lack z3 linkage and BMC alone gives zero useful output on
  OZ-upgradeable patterns. Halmos subsumes its coverage for our
  contracts.

Both tools run locally (pipx install). Intentionally not in CI —
symbolic execution is slow, solver-version-sensitive, and most valuable
as an interactive design check rather than a PR gate.

Findings worth review:
- DstackKms.registerApp is permissionless by design (no access control,
  only require !=0). Confirmed-intentional; the downstream
  allowedOsImages whitelist + delegated isAppAllowed gate authorization.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Normative pre/post/frame conditions, state invariants, cross-contract
assumptions, and adversarial scenarios for DstackKms + DstackApp,
independent of code. Each property cites the Halmos test that verifies
it; properties without a citation are explicit gaps.

Sections:
- Trust model (principals, environment, off-chain pipeline)
- Storage layout per contract with frame-condition rules
- Per-function pre/post/frame/events/reverts specs for the entire
  public surface
- Decision-table semantics for isAppAllowed
- State invariants INV-1 through INV-7 with verification status
- Adversarial scenarios: malicious registerApp + downstream gates,
  reentrancy structural-impossibility argument, gas-griefing,
  front-running, initializer selector collision
- Known verification gaps (cross-transaction invariants,
  universal-quantification over registered apps, KEVM bytecode-level)
- Open product-level questions for the team:
  1. Should renounceOwnership be overridden to revert?
  2. Should KMS track which appImplementation was current per app?
  3. Should removeOsImageHash retroactively un-authorize?
  4. Should gatewayAppId validate format?

Deliverable for any future external audit-firm engagement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@h4x3rotab h4x3rotab mentioned this pull request May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant