{"id":1540,"date":"2026-10-13T22:15:16","date_gmt":"2026-10-13T22:15:16","guid":{"rendered":"https:\/\/smartcryptosecurity.com\/?p=1540"},"modified":"2026-10-13T22:15:16","modified_gmt":"2026-10-13T22:15:16","slug":"critical-solidity-memory-corruption-bug-discovered-in-code-generator-affecting-versions-up-to-0-8-37","status":"publish","type":"post","link":"https:\/\/smartcryptosecurity.com\/?p=1540","title":{"rendered":"Critical Solidity Memory Corruption Bug Discovered in Code Generator Affecting Versions Up to 0.8.37"},"content":{"rendered":"<p>A significant vulnerability has been uncovered within the Solidity code generator, impacting all historical versions of the Ethereum smart contract programming language up to and including version 0.8.36. The bug, which specifically involves the way memory-based byte arrays handle element deletions, causes the compiler to inadvertently overwrite adjacent memory slots. While security teams have rated the vulnerability as low to medium severity due to specific preconditions required for exploitation, the flaw highlights deep-seated nuances in how the Ethereum Virtual Machine (EVM) assembly pipeline manages raw memory layout.<\/p>\n<p>The issue was formally brought to light on August 14, 2026, when developer Shaheen Fazim submitted a bug report through the official Ethereum Foundation bug bounty program. Fazim\u2019s report included a working reproducer that demonstrated how applying the <code>delete<\/code> keyword to a specific element within a memory-located <code>bytes<\/code> array triggers an unexpected 32-byte zero write. Instead of clearing only the targeted byte index, the generated bytecode blasts a full word of zeros starting at that exact element. <\/p>\n<p>This unexpected behavior leads to collateral damage, clearing up to 31 bytes of data immediately following the deleted element. Depending on the array&#8217;s positioning, this over-allocation write can either corrupt subsequent elements within the same dynamic array or, when applied near the tail end of the structure, bleed past the array&#8217;s boundaries to overwrite whatever data resides in the adjacent memory allocation. Interestingly, the standard assignment equivalent, such as setting <code>b[i] = 0<\/code>, remains entirely unaffected by this flaw and correctly clears a single byte as intended.<\/p>\n<p>According to the core development team, the vulnerability is strictly confined to the default <code>evmasm<\/code> compilation pipeline. The newer IR (Intermediate Representation) pipeline remains unaffected by the defect, and the use of the Solidity optimizer is neither required to trigger the bug nor capable of mitigating its faulty semantics. The vulnerable code path itself is exceptionally old, predating the very first official public release of Solidity. <\/p>\n<p>To gauge the real-world impact of the vulnerability, security researchers scanned the Sourcify database, analyzing roughly 870,000 verified smart contract compilations for the specific source pattern known to trigger the defect. The scan revealed that the problematic pattern appeared in only 17 distinct compilations, which collectively housed just two unique functions. Further manual analysis confirmed that neither of those functions was actually susceptible to malicious or accidental exploitation; in both instances, the corrupted bytes were either discarded or fell within harmless, unused memory regions. At the time of disclosure, no deployed production contracts are known to have been compromised or affected by the bug.<\/p>\n<p>Which Contracts Are Affected?<\/p>\n<p>For a smart contract to be vulnerable to this memory corruption issue, a precise combination of conditions must be met simultaneously. First, the contract must be compiled using the default <code>evmasm<\/code> pipeline rather than the IR pipeline. Second, the source code must apply the <code>delete<\/code> operator specifically to an element inside a memory-resident <code>bytes<\/code> or <code>string<\/code> array. <\/p>\n<p>If a contract never invokes <code>delete<\/code> on an individual element of a memory-based byte array or string, it is completely immune to the bug. Furthermore, developers must look closely at how arrays are typed and structured. Only packed byte arrays\u2014specifically <code>bytes<\/code> and <code>string<\/code> types in memory\u2014are affected, because they pack their individual elements tightly back-to-back without word-boundary padding. In contrast, arrays whose elements each occupy a full 32-byte memory word, such as <code>bytes1[] memory<\/code>, are entirely unaffected.<\/p>\n<p>The distinction between data locations is also vital. Byte arrays residing in contract storage are managed by a completely separate and correct compilation code path, rendering them safe. Similarly, calldata arrays cannot have the <code>delete<\/code> operator applied to them in any capacity. <\/p>\n<p>The vulnerability also extends to <code>string<\/code> values, albeit through an indirect mechanism. While direct index deletion like <code>delete s[i]<\/code> will fail to compile for a memory string <code>s<\/code>, developers frequently convert strings into byte views using <code>bytes(s)<\/code>. Executing <code>delete bytes(s)[i]<\/code> operates directly on the underlying memory representation of the string, thereby triggering the exact same code generator flaw.<\/p>\n<p>Technical Details<\/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<p>To fully understand why the bug occurs, one must examine how Solidity manages memory allocation. Most data types in Ethereum memory consume full 32-byte words. Dynamic byte arrays are the primary exception, consisting of an initial 32-byte length header followed immediately by the packed byte data. Solidity allocates memory sequentially by advancing a global free memory pointer, meaning consecutive allocations sit flush against one another, separated only by optional padding.<\/p>\n<p>When the compiler generates code for array allocations, it typically adds up to 31 zero bytes of padding at the end of the data so that any subsequent memory allocation cleanly starts on a fresh 32-byte word boundary. These are classified as padded arrays. However, certain modern constructs\u2014including <code>bytes.concat<\/code>, <code>string.concat<\/code>, and the entire suite of <code>abi.encode<\/code> variants\u2014produce unpadded arrays whose data ends precisely where the next allocation begins, leaving no buffer whatsoever.<\/p>\n<p>When a standard value is stored in memory, its alignment depends entirely on its type. Left-aligned types like <code>bytesN<\/code> start at the beginning of a word, while right-aligned types such as integers, addresses, and memory pointers sit at the tail end of the word, padded by leading zeros. Byte arrays, however, require single-byte granularity (<code>mstore8<\/code>) because their elements are individual bytes. <\/p>\n<p>The root cause of the bug lies in a divergence between standard assignment and the <code>delete<\/code> keyword within the evmasm pipeline. While an assignment like <code>b[i] = 0<\/code> correctly routes through a single-byte store operation, the <code>delete<\/code> path mistakenly executes a full 32-byte word write starting at the element&#8217;s memory address. Because this write does not align with a word boundary, it spills forward, overwriting the targeted element along with up to 31 subsequent bytes. Because the array&#8217;s 32-byte length header located at the front of the structure is never touched, the array retains its original length declaration. Consequently, subsequent operations\u2014such as calculating a <code>keccak256<\/code> hash, performing ABI encoding, or returning data to an external caller\u2014silently process the corrupted byte stream.<\/p>\n<p>Example and Observed Behavior<\/p>\n<p>A clear demonstration of this behavior can be observed in a simple contract containing sequential memory declarations. In functions where a short byte array is allocated, executing a delete operation on the first index unexpectedly clears all subsequent bytes in that word. Similarly, when a delete is performed on the final element of a padded or unpadded array that sits flush against another data structure, the 32-byte write overflows into the neighboring memory space.<\/p>\n<p>In tests conducted with affected compiler versions, deleting an element near the end of a 32-byte memory array (<code>new bytes(32)<\/code>) cleanly overwrites the most significant bytes of an adjacent uint256 variable stored in memory. For instance, an integer initialized to its maximum possible value (<code>type(uint256).max<\/code>) sees its upper 31 bytes zeroed out, causing the function to return 255 instead of the expected maximum integer. Replacing the <code>delete<\/code> statement with a direct assignment (<code>b[i] = 0<\/code>) bypasses the faulty code path and yields the correct output.<\/p>\n<p>Severity Assessment and Remediation<\/p>\n<p>Because the compiler emits no warnings and the EVM does not encounter a runtime revert when the memory corruption occurs, detecting the bug can be challenging. The manifestation of the flaw appears as silent data corruption rather than an explosive failure, though unit tests checking exact byte array contents can catch internal array corruptions.<\/p>\n<p>The Ethereum Foundation and Solidity core developers have addressed the vulnerability in Solidity version 0.8.37. The fix aligns the <code>delete<\/code> code path with the assignment path, forcing the compiler to issue a precise single-byte store (<code>mstore8<\/code>) rather than a full-word store when clearing elements within packed byte arrays. <\/p>\n<p>Developers maintaining smart contracts using any version of Solidity up to 0.8.36 are strongly encouraged to audit their codebases for instances where the <code>delete<\/code> keyword is applied to elements of memory-based <code>bytes<\/code> or <code>string<\/code> variables. Upgrading the compiler toolchain to version 0.8.37 or later completely resolves the vulnerability, restoring expected semantics to memory byte array manipulations. <\/p>\n<p>The Solidity team extended their gratitude to Shaheen Fazim for discovering and responsibly disclosing the vulnerability through the Ethereum Foundation&#8217;s bug bounty program, praising the clarity of the provided reproduction test cases that enabled a swift patch.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A significant vulnerability has been uncovered within the Solidity code generator, impacting all historical versions&#8230;<\/p>\n","protected":false},"author":27,"featured_media":1539,"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-1540","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\/1540","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\/27"}],"replies":[{"embeddable":true,"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1540"}],"version-history":[{"count":0,"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=\/wp\/v2\/posts\/1540\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=\/wp\/v2\/media\/1539"}],"wp:attachment":[{"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1540"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1540"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/smartcryptosecurity.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1540"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}