Summary
SgxVerifier.registerInstance() is permissionless and registers an attacker-supplied Ethereum address taken directly from the SGX quote's reportData. It trusts whatever IAttestation.verifyParsedQuote(...) returns. In AutomataDcapV3Attestation, the application-enclave identity check (MRENCLAVE / MRSIGNER — i.e. "is this quote actually from the Taiko prover program?") is only performed when checkLocalEnclaveReport == true, and that flag defaults to false (storage zero-init) with no toggleLocalReportCheck() call anywhere in script/ or deployments/.
This is filed for input/clarification from @smtmfft on the live trust model — I could not determine the on-chain value of the flag from the repo, and the evidence is contradictory (see below). If the flag is on in production, this is sound and the only ask is to make the invariant enforced rather than operator-dependent. If it is off, it is a live key-forgery path against the SGX leg.
Code references
contracts/layer1/verifiers/SgxVerifier.sol:113-124 — registerInstance() is external with no access control; registers address(bytes20(_attestation.localEnclaveReport.reportData)) after only require(verified, ...).
contracts/layer1/automata-attestation/AutomataDcapV3Attestation.sol:407-415 — MRENCLAVE/MRSIGNER are checked only inside if (checkLocalEnclaveReport) { ... }.
contracts/layer1/automata-attestation/AutomataDcapV3Attestation.sol:37 — bool public checkLocalEnclaveReport; (defaults false).
contracts/layer1/automata-attestation/AutomataDcapV3Attestation.sol:143-146 — toggleLocalReportCheck() is the only way to enable it; grep finds no call in script/ or deployments/.
contracts/layer1/verifiers/SgxVerifier.sol:182-188 — _isInstanceValid() (proof time) only checks the address matches the stored instance and the validity window. It never re-checks MRENCLAVE/MRSIGNER.
Why this matters
If checkLocalEnclaveReport is false on the live attestation contract(s), an attacker can:
- Run any SGX enclave (their own program, not raiko/gaiko) that signs a
reportData containing an Ethereum key they control.
- Obtain a genuine Intel DCAP quote for it (it is a real enclave, just not the Taiko one).
- Call
registerInstance(...) permissionlessly — it passes, because without the MRENCLAVE/MRSIGNER check, steps 3–8 only prove "this is a real Intel SGX quote with acceptable TCB", not "this is the Taiko prover".
- Sign arbitrary "SGX proofs" for any state transition with their key.
On mainnet's MainnetVerifier (SGX and ZK, 2-of-N) this defeats the SGX leg but not the ZK leg, so it is not instant fund loss. Under any 1-of-N AnyVerifier wiring it would be total compromise.
Important operational note: because _isInstanceValid never re-validates MRENCLAVE, flipping the flag on does not retroactively invalidate an instance already registered while it was off. Remediation (if the flag is currently off) would also require enumerating instances[0..nextInstanceId) and deleteInstances(...) for any key not attributable to a genuine raiko/gaiko enclave.
Questions / requests for @smtmfft
- Is
checkLocalEnclaveReport == true on the live SGXRETH_ATTESTER / SGXGETH_ATTESTER attestation contracts today? (Governance proposals 0004/0009/0010 call setMrEnclave(...) to populate the trusted set, which only matters if the check is enabled — hence the contradiction with the default and the missing toggle.)
- If yes: is there appetite to enforce this as an invariant rather than rely on operator configuration? e.g. a deploy/governance-time assertion that the flag is set after SGX configuration, or moving the MRENCLAVE allowlist into
SgxVerifier itself so SGX trust is self-contained rather than depending on an optional flag in the vendored Automata library.
- If no (flag is off): this should be treated as a live high-severity exposure — confirm and we can prioritize enabling the check + auditing/cleaning the existing instance set.
Suggested direction (pending clarification)
- Operational: verify the live flag; if off, audit & prune registered instances, populate the trusted MRENCLAVE/MRSIGNER set, then enable the check.
- Code: make "ship with the check off" fail loudly (init-time default
true or a post-configuration assertion), so a zero-value default can never silently disable enclave-identity verification.
Found during a recursive audit of the core protocol contracts and their dependencies.
Summary
SgxVerifier.registerInstance()is permissionless and registers an attacker-supplied Ethereum address taken directly from the SGX quote'sreportData. It trusts whateverIAttestation.verifyParsedQuote(...)returns. InAutomataDcapV3Attestation, the application-enclave identity check (MRENCLAVE / MRSIGNER — i.e. "is this quote actually from the Taiko prover program?") is only performed whencheckLocalEnclaveReport == true, and that flag defaults tofalse(storage zero-init) with notoggleLocalReportCheck()call anywhere inscript/ordeployments/.This is filed for input/clarification from @smtmfft on the live trust model — I could not determine the on-chain value of the flag from the repo, and the evidence is contradictory (see below). If the flag is on in production, this is sound and the only ask is to make the invariant enforced rather than operator-dependent. If it is off, it is a live key-forgery path against the SGX leg.
Code references
contracts/layer1/verifiers/SgxVerifier.sol:113-124—registerInstance()isexternalwith no access control; registersaddress(bytes20(_attestation.localEnclaveReport.reportData))after onlyrequire(verified, ...).contracts/layer1/automata-attestation/AutomataDcapV3Attestation.sol:407-415— MRENCLAVE/MRSIGNER are checked only insideif (checkLocalEnclaveReport) { ... }.contracts/layer1/automata-attestation/AutomataDcapV3Attestation.sol:37—bool public checkLocalEnclaveReport;(defaultsfalse).contracts/layer1/automata-attestation/AutomataDcapV3Attestation.sol:143-146—toggleLocalReportCheck()is the only way to enable it;grepfinds no call inscript/ordeployments/.contracts/layer1/verifiers/SgxVerifier.sol:182-188—_isInstanceValid()(proof time) only checks the address matches the stored instance and the validity window. It never re-checks MRENCLAVE/MRSIGNER.Why this matters
If
checkLocalEnclaveReportisfalseon the live attestation contract(s), an attacker can:reportDatacontaining an Ethereum key they control.registerInstance(...)permissionlessly — it passes, because without the MRENCLAVE/MRSIGNER check, steps 3–8 only prove "this is a real Intel SGX quote with acceptable TCB", not "this is the Taiko prover".On mainnet's
MainnetVerifier(SGX and ZK, 2-of-N) this defeats the SGX leg but not the ZK leg, so it is not instant fund loss. Under any 1-of-NAnyVerifierwiring it would be total compromise.Important operational note: because
_isInstanceValidnever re-validates MRENCLAVE, flipping the flag on does not retroactively invalidate an instance already registered while it was off. Remediation (if the flag is currently off) would also require enumeratinginstances[0..nextInstanceId)anddeleteInstances(...)for any key not attributable to a genuine raiko/gaiko enclave.Questions / requests for @smtmfft
checkLocalEnclaveReport == trueon the liveSGXRETH_ATTESTER/SGXGETH_ATTESTERattestation contracts today? (Governance proposals 0004/0009/0010 callsetMrEnclave(...)to populate the trusted set, which only matters if the check is enabled — hence the contradiction with the default and the missing toggle.)SgxVerifieritself so SGX trust is self-contained rather than depending on an optional flag in the vendored Automata library.Suggested direction (pending clarification)
trueor a post-configuration assertion), so a zero-value default can never silently disable enclave-identity verification.Found during a recursive audit of the core protocol contracts and their dependencies.