{"id":1324,"date":"2026-10-11T22:49:20","date_gmt":"2026-10-11T22:49:20","guid":{"rendered":"https:\/\/wyominginvest.com\/?p=1324"},"modified":"2026-10-11T22:49:20","modified_gmt":"2026-10-11T22:49:20","slug":"critical-solidity-vulnerability-discovered-in-memory-byte-array-deletions-affecting-versions-up-to-0-8-37","status":"publish","type":"post","link":"https:\/\/wyominginvest.com\/?p=1324","title":{"rendered":"Critical Solidity Vulnerability Discovered in Memory Byte Array Deletions Affecting Versions Up to 0.8.37"},"content":{"rendered":"<p>On August 14, 2026, developer Shaheen Fazim identified and reported a critical vulnerability within the Solidity code generator via the Ethereum Foundation\u2019s bug bounty program. The defect concerns how the compiler handles the <code>delete<\/code> operator when applied to an individual element of a <code>bytes<\/code> or <code>string<\/code> array located in memory. Instead of safely and precisely clearing only the specified index, the generated code incorrectly writes 32 zero bytes starting at that exact element. This unintended 32-byte zero-write spills over past the target index, wiping out up to 31 subsequent bytes either within the same array or\u2014when the deletion occurs near the boundary of the array\u2014leaking into adjacent, independently allocated memory structures. Interestingly, the equivalent manual assignment operation, such as <code>b[i] = 0<\/code>, remains entirely unaffected and correctly clears precisely one byte.<\/p>\n<p>Ethereum Foundation maintainers assigned this vulnerability a severity rating of low-to-medium on their internal scale. Crucially, the bug is strictly isolated to the default <code>evmasm<\/code> compilation pipeline, while the newer IR (Intermediate Representation) compilation pipeline remains completely secure and unaffected. Furthermore, invoking the Solidity optimizer is neither necessary to trigger the flaw nor capable of preventing it, as the issue stems directly from the code generation phase itself, and the optimizer merely preserves the faulty semantics. <\/p>\n<p>Historical analysis of the codebase reveals that the affected code path predates the very first publicly released version of Solidity. Consequently, every single version of the compiler up to and including version 0.8.36 suffers from the defect. The issue has been formally patched and resolved in Solidity version 0.8.37. To gauge potential real-world impact, developers scanned the Sourcify database, which catalogs roughly 870,000 verified smart contract compilations. The analysis uncovered the vulnerable source pattern in exactly 17 compilations, containing only two distinct functions\u2014neither of which actually exposes real-world vulnerability under runtime conditions. At present, no deployed smart contracts are known to have suffered malicious exploitation or unintended data corruption as a result of this bug.<\/p>\n<p>Which Contracts Are Affected?<\/p>\n<p>A smart contract is deemed vulnerable only if a specific set of rigorous technical conditions are met simultaneously. First, the contract must be compiled using an affected version of Solidity, ranging from the earliest legacy versions up to 0.8.36. Second, the compilation must utilize the default <code>evmasm<\/code> code generation pipeline rather than the IR pipeline. Third, the source code must explicitly invoke the <code>delete<\/code> operator on an element of a memory-resident <code>bytes<\/code> or <code>string<\/code> array. <\/p>\n<p>While the first two conditions can be easily verified by inspecting compiler configurations and source files, evaluating the third condition requires deep architectural reasoning regarding the exact memory layout produced by the compiler. Because memory layout optimization can be complex, developers whose code satisfies the first two criteria are strongly advised to treat their contracts as potentially affected rather than attempting to definitively rule out memory overlap. Contracts that never apply the <code>delete<\/code> keyword to an individual element of a memory-based <code>bytes<\/code> or <code>string<\/code> type face zero risk.<\/p>\n<p>It is vital to understand that neither the activation of the optimizer nor the targeted Ethereum Virtual Machine version alters whether the bug manifests. The defect is structurally embedded in the bytecode emitted by the code generator. Additionally, whole-array deletions\u2014such as executing <code>delete b<\/code> on an entire array\u2014route through a completely different code path and execute with absolute correctness. The vulnerability is strictly confined to element-level deletions on dynamic byte arrays residing in memory. <\/p>\n<p>Storage-based byte arrays utilize an entirely separate implementation pathway and remain entirely unaffected, while calldata arrays cannot have the <code>delete<\/code> operator applied to them under any circumstance. Furthermore, arrays whose elements naturally occupy a full 32-byte word in memory, such as <code>bytes1[] memory<\/code>, are completely immune; the flaw exclusively affects <code>bytes<\/code> and <code>string<\/code> types because they pack their individual byte elements tightly back-to-back without word-alignment padding. Although direct index deletion like <code>delete s[i]<\/code> is not permitted for a <code>string memory<\/code> variable, developers frequently cast strings to <code>bytes<\/code> via explicit type conversion, writing <code>delete bytes(s)[i]<\/code>, which successfully triggers the exact same underlying memory corruption bug.<\/p>\n<p>Technical Details<\/p>\n<p>To understand why this memory corruption occurs, one must examine how Solidity manages memory allocation. Most data types in Solidity memory occupy full 32-byte words. Dynamic byte arrays (<code>bytes<\/code>) serve as a prominent exception, consisting of an initial 32-byte length descriptor followed immediately by the raw underlying data bytes packed tightly back-to-back without internal gaps. Solidity allocates memory sequentially by advancing a global free memory pointer, meaning consecutive allocations sit flush against one another. Consequently, any write operation that overruns the boundaries of one allocation spills directly into whatever data structure resides immediately afterward.<\/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>Most dynamically allocated byte arrays, such as those created using <code>new bytes(n)<\/code> or instantiated directly from literal values, are followed by up to 31 zero bytes of padding to ensure that subsequent memory allocations cleanly align on a 32-byte word boundary. These are classified as padded arrays. Conversely, the <code>evmasm<\/code> pipeline leaves certain allocations completely unpadded\u2014specifically the results of <code>bytes.concat<\/code>, <code>string.concat<\/code>, and various <code>abi.encode<\/code> variants including <code>abi.encodePacked<\/code>, <code>abi.encodeWithSelector<\/code>, <code>abi.encodeWithSignature<\/code>, and <code>abi.encodeCall<\/code>. In these unpadded arrays, the data ends precisely where the next memory allocation begins.<\/p>\n<p>Because memory byte array elements are single bytes, updating or clearing them normally requires a single-byte store operation (<code>mstore8<\/code>) rather than a full 32-byte word store (<code>mstore<\/code>). The compiler correctly employs <code>mstore8<\/code> for standard assignments like <code>b[i] = 0<\/code>. However, the internal implementation path for the <code>delete<\/code> operator in the <code>evmasm<\/code> pipeline fails to consult the element width, mistakenly treating the target as a standard full-word type. When <code>delete b[i]<\/code> is executed, the generated bytecode issues a full 32-byte zero write originating from the memory address of the targeted element and extending forward. Because this write starts at the specific index rather than aligning to a 32-byte word boundary, it stretches far beyond the intended byte.<\/p>\n<p>The array&#8217;s length descriptor, situated safely before the data payload, remains untouched, meaning the array preserves its original length value. However, any subsequent operations that read the array&#8217;s contents\u2014such as computing a <code>keccak256<\/code> hash, performing ABI encoding, or returning the byte sequence to an external caller\u2014will operate directly on the corrupted, zeroed-out memory space.<\/p>\n<p>The extent of the corruption depends heavily on the index of the deleted element and how the array was initially allocated. When developers delete an element within the interior of an array, the subsequent 31 bytes within that same array are forcefully overwritten with zeros. Unless those subsequent indices already contained zero bytes, the array&#8217;s data is immediately and permanently altered. <\/p>\n<p>When deletion targets one of the final 31 elements of a padded array, the trailing padding absorbs part of the 32-byte write. For arrays whose lengths leave a full 31 bytes of padding, no overflow occurs. But for arrays whose lengths are exact multiples of 32\u2014leaving zero padding\u2014deleting the final elements causes the zero-write to bleed directly into the subsequent memory allocation. For unpadded arrays, deleting any of the last 31 elements invariably bleeds into the next memory allocation, and for arrays shorter than 31 bytes, this includes even the very first element.<\/p>\n<p>Example<\/p>\n<p>A clear demonstration of this behavior involves a contract declaring adjacent memory structures. In a test contract containing functions that delete an element from a short byte array and a final element from a padded 32-byte array seated next to a structure holding a maximum-value integer, invoking the vulnerable functions under the <code>evmasm<\/code> pipeline yields corrupted outputs. For instance, clearing the first element of a five-byte array results in all five bytes being zeroed out instead of just the first. Similarly, clearing the final element of a 32-byte array overwrites the leading 31 bytes of an adjacent integer structure, drastically altering its numerical value. Replacing these delete statements with explicit assignments correctly preserves the integrity of the surrounding memory.<\/p>\n<p>Severity Assessment and Remediation<\/p>\n<p>The Solidity compiler emits no warnings when compiling vulnerable code, and transactions do not revert at runtime, making this bug particularly insidious to diagnose in production environments. Nevertheless, because internal array corruption typically surfaces during standard test suites that inspect modified arrays, developers have a reasonable window to catch such anomalies. <\/p>\n<p>The practical likelihood of encountering catastrophic memory overwrite in real-world deployments is low, as demonstrated by the extensive Sourcify code scan. The Ethereum Foundation recommends that all developers utilizing Solidity versions up to 0.8.36 immediately upgrade their toolchains to version 0.8.37 or higher. For projects unable to upgrade immediately, developers should audit their codebases to ensure that the <code>delete<\/code> operator is never applied to individual elements of memory-based <code>bytes<\/code> or <code>string<\/code> arrays, opting instead for explicit zero-assignment statements like <code>b[i] = 0<\/code> or transitioning compilation to the secure IR pipeline.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>On August 14, 2026, developer Shaheen Fazim identified and reported a critical vulnerability within the Solidity code generator via the Ethereum Foundation\u2019s bug bounty program. The defect concerns how the compiler handles the delete operator when applied to an individual element of a bytes or string array located in memory. Instead of safely and precisely<\/p>\n","protected":false},"author":15,"featured_media":1323,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[366],"tags":[1014,952,401,951,201,953,949,950,5,400,402,1051,948],"class_list":["post-1324","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-smart-contract-auditing","tag-affecting","tag-array","tag-auditing","tag-byte","tag-critical","tag-deletions","tag-discovered","tag-memory","tag-security","tag-smart-contracts","tag-solidity","tag-versions","tag-vulnerability"],"_links":{"self":[{"href":"https:\/\/wyominginvest.com\/index.php?rest_route=\/wp\/v2\/posts\/1324","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wyominginvest.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wyominginvest.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wyominginvest.com\/index.php?rest_route=\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/wyominginvest.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1324"}],"version-history":[{"count":0,"href":"https:\/\/wyominginvest.com\/index.php?rest_route=\/wp\/v2\/posts\/1324\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wyominginvest.com\/index.php?rest_route=\/wp\/v2\/media\/1323"}],"wp:attachment":[{"href":"https:\/\/wyominginvest.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1324"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wyominginvest.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1324"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wyominginvest.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1324"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}