{"id":1282,"date":"2026-10-11T06:15:19","date_gmt":"2026-10-11T06:15:19","guid":{"rendered":"https:\/\/smartcryptosecurity.com\/?p=1282"},"modified":"2026-10-11T06:15:19","modified_gmt":"2026-10-11T06:15:19","slug":"critical-memory-corruption-bug-discovered-in-solidity-code-generator-affecting-versions-up-to-0-8-37-3","status":"publish","type":"post","link":"https:\/\/smartcryptosecurity.com\/?p=1282","title":{"rendered":"Critical Memory Corruption Bug Discovered in Solidity Code Generator Affecting Versions up to 0.8.37"},"content":{"rendered":"<p>A significant memory corruption vulnerability has been discovered in the Solidity compiler\u2019s default code generation pipeline. Reported by security researcher Shaheen Fazim on August 14, 2026, via the Ethereum Foundation&#8217;s bug bounty program, the flaw causes the <code>delete<\/code> operator to misbehave when applied to individual elements of memory-based <code>bytes<\/code> or <code>string<\/code> arrays. Rather than safely clearing only the designated single byte, the generated EVM assembly code overwrites an entire 32-byte word starting at that specific index. This unintended mass-clearing operation wipes out up to 31 subsequent bytes, either further down inside the same array or bleeding over into adjacent memory allocations if the deleted element resides near the array&#8217;s boundary.<\/p>\n<p>Assigned a &quot;low\/medium&quot; severity rating on the internal scale maintained by the Solidity development team, the defect exclusively impacts the traditional <code>evmasm<\/code> compilation pipeline. Contracts compiled using the modern IR (Intermediate Representation) pipeline remain completely unaffected by the issue. Furthermore, the vulnerability is triggered regardless of whether the compiler&#8217;s optimization routines are enabled or disabled. An exhaustive analysis of historical codebases revealed that the affected code path actually predates the very first official release of Solidity, meaning that all compiler versions up to and including version 0.8.36 harbor the bug. The issue has been officially addressed and patched in Solidity version 0.8.37.<\/p>\n<h2>Understanding the Scope and Affected Contracts<\/h2>\n<p>To gauge the real-world impact of the discovery, developers and security researchers scanned the Sourcify database, which contains roughly 870,000 verified smart contract compilations, searching specifically for the vulnerable source code pattern. The search yielded positive matches in only 17 distinct compilations involving just two unique functions. Further forensic analysis of these instances revealed that neither of the functions was actually exposed to risk; in both cases, the bytes cleared inside the array were either immediately discarded or deleted anyway, and the memory zones immediately following the arrays were either unallocated or safely bounded. Consequently, no deployed smart contracts in the wild are known to have suffered malicious exploitation or unintended state corruption from this flaw.<\/p>\n<p>Nevertheless, identifying whether a specific codebase is vulnerable requires careful verification of multiple conditions. A smart contract is only potentially exposed to the memory corruption flaw if all of the following criteria are met simultaneously: the contract must be compiled using an affected version of Solidity ranging from version 0.8.0 up to 0.8.36; the compilation must rely on the default <code>evmasm<\/code> backend pipeline rather than the IR pipeline; and the source code must explicitly invoke the <code>delete<\/code> operator on an index belonging to a dynamic <code>bytes<\/code> or <code>string<\/code> array stored specifically in memory. <\/p>\n<p>If a contract never applies the <code>delete<\/code> keyword to individual elements of memory-based byte or string arrays, it remains entirely safe. Notably, standard assignment statements\u2014such as writing <code>b[i] = 0<\/code> to a byte array\u2014bypass the flawed code path completely and execute exactly as intended, clearing precisely one byte without collateral damage. <\/p>\n<h2>Technical Details Behind Memory Allocation and the Defect<\/h2>\n<p>To fully comprehend why the bug occurs, it helps to examine how the Solidity compiler manages memory layout for variable-length data structures. While most data types in Solidity memory occupy neat, full 32-byte words, dynamic byte arrays (<code>bytes<\/code> and <code>string<\/code>) are handled differently. They consist of a 32-byte length header followed immediately by raw data bytes packed back-to-back without internal gaps. Memory allocation in Solidity operates by advancing a free memory pointer, meaning consecutive allocations sit flush against each other, separated only by optional padding.<\/p>\n<p>When the compiler generates code for array allocations, it frequently tacks on up to 31 zero bytes of padding at the end of a block to ensure that subsequent allocations align neatly on 32-byte word boundaries. Arrays created using constructs like <code>new bytes(n)<\/code> or initialized directly from literal strings are typically padded in this manner. However, unpadded memory layouts are generated by specific functions, including <code>bytes.concat<\/code>, <code>string.concat<\/code>, and the entire suite of <code>abi.encode<\/code> variants (<code>abi.encode<\/code>, <code>abi.encodePacked<\/code>, <code>abi.encodeWithSelector<\/code>, <code>abi.encodeWithSignature<\/code>, and <code>abi.encodeCall<\/code>). Unpadded arrays end precisely where the next allocation begins, leaving zero buffer space.<\/p>\n<p>When a developer writes <code>delete b[i]<\/code> on a memory byte array, the compiler is expected to execute the semantic equivalent of <code>b[i] = 0<\/code>. For regular assignments, the compiler correctly checks the element width and issues a single-byte store instruction (<code>mstore8<\/code>), ensuring only the targeted byte is overwritten with zero. However, the legacy code path responsible for handling the <code>delete<\/code> keyword on packed array elements historically bypassed this width check in the <code>evmasm<\/code> pipeline. Instead of issuing a single-byte store, it emitted a full 32-byte word store (<code>mstore<\/code>) starting directly at the offset of the chosen element.<\/p>\n<p>Because this 32-byte write initiates at the exact index of the array element rather than snapping to a 32-byte word boundary, it spills forward. The array&#8217;s length header, which sits safely ahead of the data block, is untouched, allowing the array to maintain its original length value. Yet, any internal cryptographic hashing operations, ABI encodings, or external data returns relying on the array&#8217;s contents will transparently read the newly corrupted, zeroed-out bytes.<\/p>\n<figure class=\"article-inline-figure\"><img decoding=\"async\" src=\"https:\/\/soliditylang.org\/assets\/logo-og-image.png\" alt=\"Memory Byte Array Element Delete Clears Whole Word Bug | Solidity Programming Language\" class=\"article-inline-img\" loading=\"lazy\" \/><\/figure>\n<h2>Corruption Inside and Beyond the Array Boundaries<\/h2>\n<p>The destructive reach of the faulty 32-byte write depends heavily on the index of the deleted element and how the array was originally allocated in memory. When an element is deleted deep inside the interior of an array, up to 31 subsequent elements following the target index are forcefully zeroed out. Unless the array happens to contain exclusively zeros past that point, this behavior alters the internal state of the data structure immediately.<\/p>\n<p>When the deletion targets elements sitting near the trailing edge of an array, the write operation can easily breach the array&#8217;s boundaries and spill directly into whatever data structure happens to occupy the next slot in memory. For padded arrays, the trailing padding bytes absorb a portion of the unintended zero-fill, limiting the external damage. For instance, an array of length 40 possesses 24 bytes of padding, meaning that deleting any of the final seven elements will cause the write to escape the array boundary by no more than seven bytes. Conversely, arrays whose lengths are exact multiples of 32 features zero padding, leaving the final 31 elements fully exposed to boundary leakage. For unpadded arrays, deleting any of the last 31 elements\u2014or even the very first element if the entire array is shorter than 31 bytes\u2014will invariably corrupt whatever memory allocation follows.<\/p>\n<p>When the overflow reaches an adjacent memory structure, the exact nature of the resulting corruption depends on the layout of that neighboring data. For left-aligned types like <code>bytesN<\/code>, the most significant bytes are wiped clean. For right-aligned types such as standard integers, memory pointers, and addresses, leading bytes within the target word are cleared. A minor write spill of 12 bytes or fewer might leave an Ethereum address intact, whereas a maximal 31-byte spill will obliterate almost any standard numerical variable, drastically altering its runtime value.<\/p>\n<h2>Practical Demonstration and Severity Assessment<\/h2>\n<p>A straightforward demonstration of the flaw involves declaring adjacent data structures in memory. Consider a contract containing a function that allocates a five-byte memory array, invokes <code>delete d[0]<\/code>, and returns the array. Under normal conditions, only the first byte should become zero, yielding the byte sequence representing <code>0x0002030405<\/code>. Due to the compiler bug in the <code>evmasm<\/code> pipeline, the execution instead emits <code>0x0000000000<\/code>, wiping out the entire array content. <\/p>\n<p>Similarly, if a function allocates a 32-byte memory array alongside a maximum-value 256-bit unsigned integer (<code>type(uint256).max<\/code>) and subsequently executes <code>delete b[31]<\/code>, the 31-byte overflow spills directly into the integer&#8217;s storage location in memory. Because integers are stored with their most significant bytes first, the overflow strips away all high-order bits, causing the variable to evaluate to a mere 255 instead of its expected maximum ceiling. Replacing the <code>delete<\/code> statement with an explicit assignment such as <code>b[31] = 0<\/code> avoids the issue entirely and preserves expected program logic.<\/p>\n<p>Security auditors note that because the compiler emits no warning flags and the Ethereum Virtual Machine executes the corrupted bytecode without triggering a runtime revert, diagnosing the bug can be exceptionally difficult in complex applications. The failure manifests as silent data corruption rather than a dramatic crash, though comprehensive unit testing covering array manipulation paths can successfully catch the anomaly. <\/p>\n<h2>The Fix and Recommended Actions<\/h2>\n<p>The resolution implemented by the Solidity core team in version 0.8.37 ensures that the <code>delete<\/code> code path properly consults the element width of packed collections, aligning its behavior with standard assignment operations. When clearing an element inside a packed byte or string array, the compiler now correctly emits a single-byte store (<code>mstore8<\/code>) rather than a full 32-byte word write, restoring complete semantic parity between the <code>evmasm<\/code> and IR compilation pipelines.<\/p>\n<p>Developers maintaining smart contract projects built on older versions of the Solidity compiler are strongly encouraged to audit their codebases for instances where the <code>delete<\/code> operator is applied to individual elements of memory-based <code>bytes<\/code> or <code>string<\/code> variables. Upgrading the project toolchain to Solidity version 0.8.37 or later eliminates the vulnerability at the compiler level. Alternatively, developers unable to upgrade immediately can refactor affected source code by replacing element deletions with explicit assignments, such as assigning zero directly to the target array index.<\/p>\n<p>The Ethereum Foundation and the Solidity development team expressed their gratitude to security researcher Shaheen Fazim for identifying the flaw, responsibly disclosing the vulnerability through the official bug bounty channels, and supplying a functional reproduction test case that enabled a swift and accurate patch.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A significant memory corruption vulnerability has been discovered in the Solidity compiler\u2019s default code generation&#8230;<\/p>\n","protected":false},"author":10,"featured_media":1281,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[366],"tags":[869,401,406,961,201,962,407,960,5,400,402,964],"class_list":["post-1282","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-smart-contract-auditing","tag-affecting","tag-auditing","tag-code","tag-corruption","tag-critical","tag-discovered","tag-generator","tag-memory","tag-security","tag-smart-contracts","tag-solidity","tag-versions"],"_links":{"self":[{"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=\/wp\/v2\/posts\/1282","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=\/wp\/v2\/users\/10"}],"replies":[{"embeddable":true,"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1282"}],"version-history":[{"count":0,"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=\/wp\/v2\/posts\/1282\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=\/wp\/v2\/media\/1281"}],"wp:attachment":[{"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1282"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1282"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1282"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}