For the complete documentation index, see llms.txt. This page is also available as Markdown.

74423 sc insight boundary valid nitro attestations are rejected by timestamp validation

Submitted on Apr 22nd 2026 at 13:25:47 UTC by @Razkky for Audit Comp | Base Azul

  • Report ID: #74423

  • Report Type: Smart Contract

  • Report severity: Insight

  • Target: https://github.com/base/contracts/tree/v8.1.0/src/multiproof

  • Impacts:

Description

Summary

NitroEnclaveVerifier documents attestation timestamp validity as inclusive:

  • attestation is not too old when timestamp + maxTimeDiff >= block.timestamp

  • attestation is not from the future when timestamp <= block.timestamp

However, the implementation rejects both equality boundaries:

uint64 timestamp = journal.timestamp / 1000;
if (timestamp + maxTimeDiff <= block.timestamp || timestamp >= block.timestamp) {
    journal.result = VerificationResult.InvalidTimestamp;
    return journal;
}

As a result, a valid attestation journal is returned as InvalidTimestamp when:

  • journal.timestamp / 1000 == block.timestamp

  • journal.timestamp / 1000 + maxTimeDiff == block.timestamp

This can cause TEEProverRegistry.registerSigner to revert with AttestationVerificationFailed even though the attestation satisfies the verifier's documented validity rule.

Vulnerability Details

The timestamp validation comment in NitroEnclaveVerifier._verifyJournal states:

But the actual check uses <= and >= as invalid conditions:

For the documented rule to hold, only strictly old or strictly future attestations should be rejected:

The current implementation rejects the exact equality cases that the documentation says are valid.

Impact

Valid Nitro enclave attestations can be incorrectly rejected as InvalidTimestamp. This can block otherwise valid signer registration through TEEProverRegistry.registerSigner.

The relevant integration path is:

Use strict invalidity checks so the documented valid boundaries are accepted:

This matches the documented invariant:

  • timestamp + maxTimeDiff >= block.timestamp

  • timestamp <= block.timestamp

Also consider reviewing TEEProverRegistry.registerSigner, which uses a similar inclusive cutoff for MAX_AGE:

If the intended policy is to reject exact-boundary timestamps, the comments should be updated to make the exclusive validity window explicit.

Proof of Concept

Add the PoC below to contracts/test/multiproof/NitroEnclaveVerifier.t.sol inside the existing NitroEnclaveVerifierTest contract.

They mock only the external RiscZero verifier call. The production NitroEnclaveVerifier.verify and _verifyJournal logic is executed.

Run the following command to execute the PoC:

Expected output on the vulnerable code:

Was this helpful?