Home / Smart Contract Auditing / Critical Solidity Memory Bug Discovered: Deleting Elements in Byte Arrays Can Overwrite Adjacent Data

Critical Solidity Memory Bug Discovered: Deleting Elements in Byte Arrays Can Overwrite Adjacent Data

A newly discovered security vulnerability in the Solidity code generator has exposed a major memory-management flaw affecting smart contracts compiled with versions up to and including 0.8.37. Identified by security researcher Shaheen Fazim on August 14, 2026, through the Ethereum Foundation’s bug bounty program, the defect causes the delete operation on memory-based bytes and string array elements to overwrite a full 32-byte word instead of clearing a single byte.

The flaw forces developers to review their codebase immediately, as it introduces unintended memory corruption that can silently alter execution states, corrupt data structures, and undermine contract logic without triggering compiler warnings or runtime exceptions.

Understanding the Vulnerability: The 32-Byte Overwrite

At the heart of the issue is a discrepancy in how the default evmasm code generation pipeline handles element-clearing operations compared to standard assignments. When a developer applies the delete operator to a specific index of a bytes or string array residing in memory—such as executing delete b[i]—the generated machine code writes 32 zero bytes starting precisely at the targeted index.

This behavior diverges sharply from the equivalent explicit assignment, b[i] = 0, which correctly targets and clears a single byte using a targeted single-byte store operation (mstore8). Because the erroneous delete operation initiates its 32-byte write sequence directly at the element’s offset rather than aligning to a standard 32-byte memory word boundary, it wipes out the intended element alongside up to 31 subsequent bytes.

Depending on the array’s contents and structure, this unintended zero-initialization propagates forward in one of two ways: it either corrupts neighboring elements within the same array or spills over past the array’s boundary into adjacent memory allocations.

Scope, Severity, and Affected Versions

The Ethereum Foundation has assigned this vulnerability a severity rating of low-to-medium on its internal scale, largely due to specific preconditions required for the bug to manifest and its low historical prevalence in the wild. The bug exclusively impacts the default evmasm compiler pipeline. Modern alternative setups utilizing the IR (Intermediate Representation) pipeline are completely unaffected, and the presence or absence of the optimizer does not influence whether the flaw is triggered.

The vulnerable code path has existed within the Solidity codebase since long before the language’s first official release. Consequently, all versions up to and including Solidity 0.8.36 are vulnerable. The issue has been officially resolved in Solidity 0.8.37, which patches the code generator to align the delete path with the correct single-byte store semantics used by assignments.

To gauge the real-world impact of the vulnerability, the development team scanned the Sourcify database, analyzing approximately 870,000 verified smart contract compilations for the specific source pattern. The scan identified the vulnerable pattern in only 17 compilations, encompassing just two distinct functions. Upon closer inspection, neither function was actually exploitable in a harmful manner; in both cases, the overwritten bytes were either subsequently discarded or landed in unallocated memory spaces, leaving no known deployed contracts compromised.

Which Contracts Are Affected?

A smart contract is susceptible to this memory corruption bug only if a specific set of conditions converges during execution. First, the contract must be compiled using an affected version of Solidity (v0.8.36 or earlier) paired with the default evmasm code generation pipeline. Second, the code logic must explicitly apply the delete keyword to an individual element of a dynamic byte array or string stored in memory—such as delete b[i] or via string-to-bytes conversions.

Several technical nuances dictate whether a particular implementation is safe. Whole-array deletions, such as executing delete b on an entire array, utilize a completely separate, unaffected code path and function correctly. Furthermore, arrays located in storage are handled differently and remain safe, while calldata arrays do not support the delete operation at all.

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

Data structures where each element naturally occupies a full 32-byte word in memory, such as bytes1[] memory arrays, are entirely immune. Only packed formats like bytes and string are vulnerable, because they pack their elements back-to-back without word-boundary gaps. Similarly, fixed-size byte arrays like bytesN types are unaffected because indexing them yields an isolated copy of the byte rather than a mutable reference into underlying memory.

Technical Details of Memory Corruption

To fully grasp how the bug operates under the hood, it is necessary to examine how Solidity manages memory allocation. Most data types in memory occupy full 32-byte words, but dynamic bytes and string arrays break this rule by storing a 32-byte length header followed immediately by packed data bytes. Solidity allocates memory sequentially by advancing a free memory pointer, meaning consecutive allocations sit flush against one another.

Compilers typically allocate memory in one of two states: padded or unpadded. Standard arrays created via new bytes(n) or literals are usually followed by up to 31 zero bytes of padding to ensure the next allocation begins cleanly on a word boundary. However, unpadded arrays—produced by operations like bytes.concat, string.concat, and various abi.encode functions—end abruptly where the next memory allocation begins.

When a delete operation targets an element within a padded array, the trailing padding bytes absorb a portion of the 32-byte zero-write. For instance, an array of length 40 possesses 24 bytes of padding, meaning that deleting one of the final seven elements causes the write to spill past the array’s boundary by no more than seven bytes. Conversely, unpadded arrays offer no such buffer; deleting any of the final 31 elements invariably overflows into whatever data structure happens to be allocated immediately afterward in memory.

When this overflow reaches into subsequent memory, the extent of the damage depends on the layout of the adjacent data type. For left-aligned values, the most significant bytes are wiped clean. For right-aligned values such as unsigned integers, addresses, or pointers, the leading bytes of the word are zeroed out. Depending on the size of the write and the width of the target variable, this can radically alter numerical values or zero out critical address references.

Practical Examples of Internal and External Corruption

A demonstration contract provided by the Solidity team illustrates how both internal and external memory corruption occur when consecutive declarations are allocated adjacently in memory.

In scenarios involving internal corruption, deleting an element near the beginning of a short, packed byte array clears not only the target index but also wipes out subsequent elements residing within the same allocated word. In scenarios involving external corruption, deleting the final element of a word-aligned byte array without padding causes the 32-byte zero-write to bleed directly into an adjacent variable—such as a uint256 integer stored immediately afterward.

In testing environments, this behavior manifests as unexpected return values. For example, an integer initialized to its maximum possible value can have its most significant bytes systematically zeroed out by a neighboring array deletion, transforming a critical cryptographic parameter or balance tracking variable into a fraction of its intended value. Because these modifications occur silently without reverting transaction execution or throwing errors, they present unique diagnostic challenges during auditing and debugging.

Recommended Actions for Developers

Smart contract developers maintaining codebases built on vulnerable versions of Solidity are strongly advised to audit their code for instances where the delete operator is applied to indexed elements of memory-based byte arrays or strings.

The most robust and immediate remediation is to upgrade the compiler toolchain to Solidity 0.8.37 or later, which completely eliminates the defect by enforcing correct single-byte store semantics on the delete execution path. Alternatively, developers unable to upgrade immediately can replace vulnerable element deletions with explicit assignments, such as substituting delete b[i] with b[i] = 0, which safely invokes the single-byte store mechanism.

Tagged:

Leave a Reply

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