19 Oct 2026, Mon

Solidity Compiler Bug Discovered: Memory Byte Array Element Deletion Overwrites Extra Data

On August 14, 2026, developer Shaheen Fazim reported a critical bug within the Solidity code generator via the Ethereum Foundation’s official bug bounty program. The vulnerability concerns how the compiler handles the delete operator when it is applied to specific elements of bytes and string arrays residing in contract memory. Instead of safely and precisely clearing only the targeted index, the generated bytecode instructs the EVM to write 32 zero bytes starting directly at that element. This unintended 32-byte sweep corrupts adjacent data inside the array, and when the operation targets elements near the tail end of the array, it spills over to overwrite whatever data structures happen to be allocated immediately afterward in memory.

According to the core development team, the equivalent explicit assignment—such as writing b[i] = 0—remains entirely unaffected by this flaw and correctly clears just a single byte. The bug has been assigned a severity rating of low-to-medium on the internal scale maintained by the Solidity team. It exclusively impacts the default evmasm compilation pipeline, leaving the newer IR (Intermediate Representation) pipeline completely safe. Furthermore, developers do not need to enable the Solidity optimizer for the bug to manifest; it occurs naturally under standard compilation profiles due to flaws inherent in the code emission stage itself.

Affected Versions and Scope of the Vulnerability

Investigation into the codebase revealed that the affected code path predates the very first official release version of Solidity. Consequently, every version of the compiler up to and including version 0.8.36 is susceptible to the issue. The Solidity team resolved the defect with the rollout of version 0.8.37.

To gauge the real-world impact of the bug, the development team conducted a comprehensive scan of the Sourcify database, which contains roughly 870,000 verified smart contract compilations. They searched for the specific source pattern capable of triggering the memory corruption. Out of nearly a million verified compilations, the vulnerable pattern surfaced in just 17 instances, which collectively comprised only two distinct functions. Upon closer inspection, neither of those functions was actually rendered exploitable or functionally broken by the bug. At the time of disclosure, no deployed smart contracts in the wild are known to have suffered malicious exploitation or unintended data corruption as a result of this issue.

For a smart contract to be vulnerable, a specific set of conditions must simultaneously align. First, the contract must be compiled using an affected version between 0.8.0 and 0.8.36 while relying on the default evmasm code generation pipeline. Second, the source code must explicitly apply the delete operator to an index of a memory-allocated bytes or string array. If a contract never performs element-level deletions on in-memory byte arrays or string values, it faces zero risk from this vulnerability.

The compiler team provided several crucial clarifications regarding these conditions. Only element-level deletions trigger the flaw; executing delete b on an entire array routes through a completely separate code path and functions properly. Additionally, the array must reside in memory. Byte arrays stored permanently in contract storage utilize an entirely different mechanism and remain completely unaffected, while calldata arrays cannot be targeted by the delete operator at all. Furthermore, arrays whose individual elements naturally occupy a full 32-byte word in memory—such as bytes1[] memory—are unaffected because bytes and string are the only types that tightly pack their elements back-to-back without word-aligned gaps.

Technical Internals of Memory Byte Arrays

To understand why the bug occurs, it is helpful to examine how Solidity manages memory layouts. Most data types in Ethereum memory consume full 32-byte words. Dynamic bytes arrays serve as a prominent exception: they consist of an initial 32-byte length descriptor followed immediately by the raw data bytes packed continuously without padding. Solidity allocates memory sequentially by advancing the free memory pointer, meaning consecutive allocations sit directly flush against one another, separated only by necessary word-alignment padding.

In standard scenarios, arrays created via expressions like new bytes(n) or initialized from literal values are padded with up to 31 zero bytes at the end so that any subsequent memory allocation begins neatly on a fresh 32-byte word boundary. These are known as padded arrays. However, the legacy evmasm pipeline does not apply this trailing padding to the results of certain operations, including bytes.concat, string.concat, and various ABI encoding helpers like abi.encode, abi.encodePacked, and abi.encodeCall. Arrays generated by these methods end precisely where the next memory allocation begins, creating unpadded arrays where a trailing write can easily bleed across allocation boundaries.

When a value narrower than 32 bytes is stored in memory, its alignment depends entirely on its type. Left-aligned values like bytesN types start at the first byte of a word, whereas right-aligned values such as integers, addresses, and memory pointers sit at the trailing end with leading zero bytes. Because individual byte array elements are single bytes, managing them normally requires a single-byte store instruction (mstore8) wherever the compiler tracks element widths. However, the deletion path bypassed this mechanism.

Memory Byte Array Element Delete Clears Whole Word Bug | Solidity Programming Language

The Root Cause in the Delete Path

When a developer writes delete x, Solidity assigns the zero value corresponding to that type, meaning delete b[i] should theoretically compile down to the exact same behavior as b[i] = 0. Both operations ultimately culminate in a memory store targeting the specific location of the array element. However, within the evmasm pipeline, these two actions diverged significantly under the hood.

While standard assignments correctly utilized single-byte store operations to overwrite just the target index, the delete code path mistakenly executed a full 32-byte word store (mstore) starting directly at the indexed byte. Because this write operation initiates at an arbitrary byte offset rather than aligned to a word boundary, the zero-fill spills far beyond the intended index. Although the array’s length field remains untouched—meaning the contract still perceives the array as having its original length—subsequent operations that read from the array, such as hashing via keccak256, performing ABI encoding, or returning the variable to an external caller, process the heavily corrupted byte sequence. The IR compilation pipeline did not suffer from this discrepancy because it correctly routed element deletions through the standard assignment store path.

The physical reach of this unintended zero-write depends heavily on the index of the deleted element and how the array was initially allocated. When a developer deletes an element located inside a padded array, the trailing padding absorbs part of the 32-byte write. For instance, if an array has 24 bytes of padding, deleting one of the final seven elements will cause the write to breach the array boundary and bleed into whatever memory allocation sits directly afterward. For unpadded arrays, deleting any of the final 31 elements immediately crosses the allocation boundary, regardless of the overall length of the array. For smaller unpadded arrays consisting of 31 bytes or fewer, this means every single index—including the very first element—will cause memory corruption beyond the array’s allocated space.

Practical Demonstration and Impact

To illustrate the vulnerability, consider a smart contract containing functions that perform element deletions on in-memory byte arrays situated next to other local variables. When compiling and executing such code using the default evmasm pipeline, the results diverge sharply from developer expectations.

In a test function clearing the first element of a small in-memory byte array, the 32-byte zero write wipes out not only the targeted index but also the subsequent four bytes belonging to the same array, reducing the entire sequence to zeroes. In another scenario where a 32-byte unpadded array is allocated directly alongside a large integer variable in memory, deleting the final element of the array causes the trailing bytes of the write to overwrite the most significant bytes of the adjacent integer. This transforms a maximum possible integer value into a minuscule number because the leading bytes have been systematically zeroed out. Replacing those delete statements with explicit assignments like d[0] = 0 avoids the bug entirely and produces the correct output.

Although the compiler emits no warnings and transactions do not revert at runtime when the bug is triggered, the silent data corruption can introduce subtle logic errors that are difficult to diagnose during testing. Nevertheless, the real-world probability of accidental exploitation remains low due to the strict alignment conditions required for the bug to manifest across memory boundaries.

Resolution and Recommendations

The Solidity core team successfully patched the vulnerability in version 0.8.37. The fix aligns the compiler’s delete code path with its standard assignment logic, ensuring that clearing a packed byte array element correctly triggers a single-byte store instruction rather than a full 32-byte word write. As a result, delete b[i] and b[i] = 0 now behave identically across all compilation pipelines.

Developers maintaining smart contracts written in Solidity are strongly advised to upgrade their compiler toolchains to version 0.8.37 or later. Projects that cannot immediately upgrade should carefully audit their codebase to verify whether any in-memory bytes or string manipulations rely on element-level delete operations, particularly when targeting arrays constructed via concatenation or encoding functions. The Ethereum Foundation and the Solidity development team expressed their gratitude to Shaheen Fazim for discovering the flaw and responsibly reporting it through the official bug bounty program.

Leave a Reply

Your email address will not be published. Required fields are marked *