Precompile Summary

PropertyValue
Address0x04
NameIDENTITY
Gas15 base + 3 per 32-byte word of input (rounded up; ceil(len / 32))
InputArbitrary bytes (any length)
OutputByte-for-byte identical copy of the input
BehaviorReturns exactly the input data unchanged. Historically used by Solidity and Vyper compilers for efficient memory-to-memory copying before MCOPY (EIP-5656, Cancun). The precompile performs no cryptography or parsing; it is a consensus-defined memcpy exposed at a fixed address.

Threat Surface

The IDENTITY precompile is deceptively simple: it copies bytes from input to output. That simplicity hides a large implicit attack surface, because callers rarely “choose” to use 0x04 directly—compilers emit CALLs to IDENTITY as part of routine ABI decoding, memory shuffles, and other lowering steps. Any incorrect assumption about whether the call succeeded, what gas remains, or what bytes occupy the output buffer can translate into logic bugs that look like “weird memory” rather than “precompile failure.”

At the protocol level, IDENTITY still occupies a slot in every client’s precompile table. Bugs are rare because the operation is trivial, but the blast radius of a wrong implementation would have been enormous in the pre-Cancun era, when compilers depended on it heavily for memory operations. Today, Cancun-era bytecode tends to use MCOPY instead, shrinking direct reliance on 0x04 but leaving legacy bytecode, older toolchains, and explicit 0x04 calls in play.

Economic and denial-of-service angles are secondary: IDENTITY is intentionally cheap per word, so contracts that pipe user-controlled blobs through compiler-generated or hand-written identity calls may face gas griefing (large copies, memory expansion on the caller). Finally, EIP-7666 and broader “EVM-ify the precompile” discussions introduce long-term semantic risk for any contract that assumes 0x04 remains a precompile forever.


Smart Contract Threats

T1: Vyper compiler — unchecked IDENTITY CALL success (CVE-2025-21607) (High)

The Vyper compiler used the IDENTITY precompile for some memory operations but did not check the success return value of the CALL to 0x04. An attacker can craft tight gas conditions so the precompile call fails (for example, out of gas during the sub-call). Failure is silent from the compiler’s perspective if the generated code does not branch on success: execution may continue while the output buffer retains stale or uninitialized memory, which is then treated as if it were freshly copied data.

Impact is constrained in part by the 63/64 gas rule: after an expensive or failing inner call, only a fraction of gas may remain, limiting what complex logic can follow. Nevertheless, in edge cases stale memory can feed later arithmetic, storage writes, or control flow—classic “confused deputy” semantics at the memory layer rather than the token layer.

Why it matters: This is a compiler correctness bug, not a flaw in the Ethereum IDENTITY specification itself, but it demonstrates that treating IDENTITY as infallible is unsafe at the bytecode level.

T2: Gas griefing via large data copying (Low)

Gas for IDENTITY is 15 + 3 per 32-byte word of input, which is inexpensive relative to many alternatives. A contract that allows an untrusted party to influence how much data is copied through identity-like paths (whether via compiler lowering or explicit calls) may be forced to pay for large memory expansion and repeated copies—for example, in a loop—turning IDENTITY into part of a resource exhaustion or griefing strategy.

Why it matters: IDENTITY is rarely the sole bottleneck; memory growth and surrounding logic usually dominate cost. Still, cheap duplication enables griefing patterns when combined with unbounded user input sizes.

T3: Deprecation and semantic drift (MCOPY, EIP-7666) (Informational)

EIP-7666 discusses replacing the IDENTITY precompile with EVM bytecode built around MCOPY, reducing long-term consensus maintenance surface. Compilers post-Cancun increasingly emit MCOPY for memory copies. Contracts that directly call 0x04 or depend on specific gas schedules for identity-shaped operations may face behavioral or costing differences across forks, clients, or future hard forks—even if observational equivalence (“bytes out == bytes in”) is preserved.

Why it matters: Low severity for typical users today; higher relevance for toolchain authors, formal verification, and cross-chain bytecode that assumes 0x04 is forever a precompile.


Protocol-Level Threats

P1: Consensus and client implementation surface (EIP-7666 direction)

Even the simplest precompile must be implemented identically in every execution client. EIP-7666 proposes EVM-ifying IDENTITY to shrink that surface. Until any such change is finalized and deployed, IDENTITY remains a shared dependency for correct chain replay.

P2: Historical blast radius (pre-Cancun compiler reliance)

Before MCOPY (Cancun), Solidity and Vyper relied heavily on IDENTITY for efficient memory operations. A hypothetical client bug (wrong offset, wrong length, wrong gas accounting, wrong returndata handling) could have caused widespread silent data corruption across many contracts without a single “malicious” Solidity line—only divergent EVM behavior.

P3: Warm access to 0x04 (EIP-2929)

The IDENTITY precompile address 0x04 is always warm after Berlin (EIP-2929). A CALL to 0x04 therefore pays 100 gas for warm address access rather than the 2600 cold-access cost. This is not a vulnerability by itself, but it affects gas scheduling tests, fuzzing bounds, and exploits that depend on exact gas left (including scenarios related to T1).


Edge Cases

CaseBehavior / notes
Empty inputReturns empty returndata (0 bytes).
Zero-length CALL / empty calldataReturns empty output; still charges base gas appropriate to the call path.
Very large inputIDENTITY gas scales linearly with input length (per 32-byte word, ceiling). Memory expansion on the caller and surrounding logic usually dominate total cost.
Input length not a multiple of 32 bytesExact copy: no padding, no truncation; output length equals input length.
OOG during precompileFrom the caller’s perspective, the inner call can fail; correctness requires checking CALL success and the actual returned size, not assuming memcpy occurred.

Real-World Exploits

ItemNotes
CVE-2025-21607Vyper compiler issue: failure to check IDENTITY CALL success; primary documented security incident tied to IDENTITY misuse at the toolchain layer.
Protocol-level “IDENTITY hacks”No major, public incident class of direct exploitation of Ethereum’s 0x04 implementation analogous to cryptographic precompile bugs; risk has manifested as compiler / codegen and gas-scheduling issues.
Implicit usageHeavy indirect use via Solidity / Vyper lowering (e.g., patterns involving abi.decode, memory moves, and legacy memcpy lowering)—increases dependence on correct success handling and returndata semantics.

Attack Scenarios

Scenario A — Silent failure / stale buffer (Vyper-style codegen pattern)

Illustrative Solidity showing the class of error: treating returndata as valid without checking CALL success. Real compilers emit varied bytecode; this is a minimal mental model only.

// ILLUSTRATIVE: direct low-level call to 0x04 without checking success.
// Bug class: stale memory if the call fails (e.g., insufficient gas).
pragma solidity ^0.8.0;
 
contract IdentityUnsafeSketch {
    function copyViaIdentity(bytes calldata data) external pure returns (bytes memory out) {
        assembly {
            let len := data.length
            out := mload(0x40)
            mstore(out, len)
            let dst := add(out, 0x20)
            calldatacopy(dst, data.offset, len)
            // Reserve scratch space for return (same buffer abused in buggy patterns)
            let success := staticcall(gas(), 0x04, dst, len, dst, len)
            // BUG: ignoring `success` — may use stale `dst..dst+len`
            mstore(0x40, add(dst, len))
        }
    }
}

Scenario B — Gas griefing via repeated large copies

// ILLUSTRATIVE: attacker supplies large payload; victim pays memory + call overhead.
pragma solidity ^0.8.0;
 
contract IdentityGriefSketch {
    event Done(uint256 words);
 
    function pump(bytes calldata blob) external {
        uint256 iterations = 8; // illustrative bound
        bytes memory acc = blob;
        for (uint256 i; i < iterations; i++) {
            acc = abi.encode(acc); // grows buffer; real griefing often pairs user input with loops
        }
        emit Done(acc.length / 32);
    }
}

Mitigations

MitigationApplies to
Check CALL / STATICCALL success and validate returndata length matches expected copy length.Any hand-written assembly; audits of compiler output around identity calls.
Cap user-controlled copy sizes; use pagination or merkleized data instead of copying full blobs on-chain.Contracts that decode or relay large calldata.
Test under marginal gas (property tests / fuzzing) for codegen that uses 0x04.Toolchains and high-assurance contracts.
Upgrade compilers and redeploy / verify builds after security advisories (e.g., CVE-2025-21607).Vyper projects and mixed-language monorepos.
Prefer modern bytecode where lowering uses MCOPY (Cancun+) for memory moves, reducing reliance on 0x04 for new deployments.New development on Cancun-enabled chains.

Compiler / EIP-based protections

SourceProtection / direction
Vyper (post-advisory)Address unchecked IDENTITY paths via patches tied to CVE-2025-21607; rebuild and verify bytecode.
Solidity / Vyper (Cancun+)MCOPY lowering reduces frequency of identity precompile use for plain memory copies.
EIP-7666 (proposal)Potential EVM bytecode replacement for IDENTITY to align implementation with core EVM primitives and reduce precompile table risk.

Severity Summary

IDTitleSeverity
T1Unchecked IDENTITY CALL (CVE-2025-21607, Vyper)High
T2Gas griefing via large copyingLow
T3Deprecation / MCOPY / EIP-7666 semantic driftInformational
P1Client consensus surface; EIP-7666 directionInformational (protocol maintenance)
P2Historical blast radius (pre-Cancun)Informational / retrospective
P3Warm 0x04 (EIP-2929) gas accountingInformational

AddressNameRelationship
0x02SHA256Adjacent precompile range; cryptographic hashing vs. passthrough copy.
0x03RIPEMD-160Adjacent precompile range; same “fixed address, fixed gas schedule” family.
0x05MODEXPNext precompile; large-input / gas-complexity contrast with trivial IDENTITY.