EHO Musings

EHO Musings

Archives
Log in
Subscribe
October 23, 2026

No legacy bug goes unpunished

I was kind of doing a victory lap this morning as I was reading about the PHP vulnerabilities that are causing massive patching across the world's web properties. Literally a week ago, I turned on the Webflow version of the non-profit website I had been building and at the same time turned off the WordPress version. Guess what? WordPress is a PHP core on top of which a bazillion PHP plugins have been built.

The history and details of these related issues are detailed in this PHP Foundation posting.

But this tidbit from one of the two patched issues just leaped off the page at me:

CVE-2026-109618 stems from how PHP responds to an out-of-memory condition. PHP previously used a mechanism called longjmp() to exit the current operation when memory ran out. In some situations, that sudden exit could leave request data partly initialized. PHP’s later shutdown process could then read or act on the invalid data, opening a path to remote code execution. Link

longjmp()!! O.M.G.

For those of you who did not grovel in the "C" runtime in the 1980's and early 1990's (like, that's all of you) setjmp() and longjmp() were often called "non-local goto". You would call setjmp and it would preserve the stack pointer and relevant register state. When you needed to go back there you would simply call longjmp and poof, you were executing the code immediately following the original setjmp call.

Back in the day we (yes, including me) built crude forms of exception handling in "C" with setjmp/longjmp. I made a sort of name for myself in front of the head of engineering for the (at the time) powerhouse software company Borland by building and describing such a system. It was an elegant mechanism to simulate exception handling in "C", taking cues from the emerging newfangled language called C++.

The problem with setjmp/longjmp was, most often, no semblance of orderly cleanup was performed when you did a "beam me up, Scotty" transport from execution at one point to execution back at the setjmp origin. You could theoretically arrange to do "pre-clean-up" before calling longjmp or "post-clean-up" at the destination, but in practice: a) it was very difficult to reason about the state that you had in memory at the time you called longjmp (what are all the things you are going to skip); and b) most people simply didn't bother.

This means that invocation of longjmp can easily lead to shattered state. And shattered state is the air that cybersecurity vulnerabilities breathe. The only reasonable thing to do in the face of, say, unrecoverable out of memory (OOM) conditions or situations where state consistency cannot be guaranteed is Linux-style _exit() (or TerminateProcess() on Windows). Which is more or less what the patch for this part of PHP2Shell (as this coterie of vulnerabilities is known) entails. They also have orderly remediation in application-defined memory scarcity cases. In both cases, the longjmp call was eliminated.

This led me to think about all of the talented young software engineers currently working in the industry. For perfectly valid reasons, if one of these talented new engineers sees longjmp() in a legacy code base, they are liable to think, "hmm, what is that?" A grizzled veteran looks at longjmp and immediately says, OMFG, we have to fix that. Because we lived through all the razor blade cuts that our past sins gave us. It's almost like seeing longjmp in a code base gives us PTSD.

This brings up a new kind of security asymmetry.

Attacker: Find a single failure path that enables a vulnerability.

Defender: Establish overall system security by gaining confidence across all relevant execution paths.

The attacker needs one counterexample. The defender needs a sufficiently complete understanding of the entire system. Or carefully designed boundaries which reduce the need to completely understand the underlying subsystem complexities. It's not like we can just "hire all the graybeards" to fix the bugs, Y2K-style. The institutional knowledge that is disappearing isn't just "oh, this API does that thing with X side effect". It's the intuition for recognizing dangerous architectural patterns before they become a known vulnerability. A cyber model can find a use-after-free vulnerability. Recognizing that an entire error recovery mechanism depends on an unachievable global invariant (clean state) is a whole 'nother kettle of fish.

PHP2Shell illustrates two disturbing problems:

  • Institutional knowledge required to recognize dangerous architectural patterns is disappearing.
  • Even when that knowledge survives, the system may have become so complicated that remediation is prohibitively difficult.

A key fact is that the underlying architectural defect had been recognized in 2024, two years before researchers demonstrated a working exploit. Because no known exploit path was established at the time, and architectural remedies were complex, fixing the issue was postponed. On August 11, 2026, researchers responsibly disclosed a working remote code execution to the PHP foundation. On October 21 (after some drama concerning premature disclosure), patched distributions started shipping. These dates illustrate a critical conundrum. The path that the PHP Foundation took was defensible. In 2024. I, myself, have deferred bugs because "that execution path isn't known to be possible." Or it is rare enough for the risk to be acceptable. But what was deferrable in 2024 is no longer deferrable in 2026. In the intervening two years, the vulnerability had not changed. What had changed was the economics of discovering and demonstrating exploitability.

We can no longer afford to treat the absence of demonstrated exploitability as sufficient justification for deferring the correction of known high-consequence architectural security defects.

We must elevate architectural weaknesses that violate fundamental safety invariants because AI has sharply reduced the cost of discovering and exploiting them. The security research that led to the exploit disclosure in August was AI-assisted (using GPT 5.6-Sol). The vulnerability was present in 2024. The emergency arrived in 2026. In the future, the gap will be measured in months or weeks.

Here's the other thing about intuition. Last year, during the frenetic art-making, fund-raising annual event for the non-profit I volunteer for, I had to update our website, written in WordPress by a third-party web development firm. I just could not understand the stack of things I was dealing with. WordPress this, Elementor that, plugin X, it was (to me) an incomprehensible mess. And I could see that even with "more experience" with the system I was not going to gain enough "mid-level understanding" to do threat assessment. Turns out WordPress is a core (centered around PHP) with many PHP plugins piled on top. So, there is not just combinatorial complexity with a mass of legacy plugins, the interactions between them are undocumented and opaque. And opacity is the enemy of security analysis. I wanted to move to Webflow because it had a clean and simple content management system (CMS). What I gained in addition was very little abstraction above raw CSS and JavaScript for the application code I was writing. Which makes both development easier (I can have Opus help me) and the whole system much more comprehensible. It doesn't make Webflow security nirvana (nothing is) but comprehensibility is the oxygen by which we can breathe easier at night (security-wise).

The numbers are getting downright scary. Anthropic's disclosure dashboard on October 2nd reports:

  • 6,157 vulnerabilities across 591 open-source projects disclosed to maintainers;
  • 6,123 findings independently reviewed by security firms of which 5,674 were confirmed valid;
  • only 516 known to have been patched. (and patch availability does not mean the fixes have been deployed).

The prior "security economics" required human black hat and white hat security engineers to probe systems and, basically, get lucky turning a vulnerability into an exploit. It was time-consuming and difficult. In the "age of Mythos", the economics have shifted disastrously. Now models can create exploits from discovered vulnerabilities at "AI model speed". The asymmetric imbalance is powerfully in the favor of attacks:

  • Discovery accelerates while remediation remains constrained by humans (even when agentic-assisted), regression and compatibility testing and deployment;
  • Attackers can scale exploration across legacy codebases where institutional knowledge is rapidly deteriorating;
  • Architectural defects become system liabilities because simply patching one vulnerability often does not address the underlying system design defect.

We cannot simply "patch vulnerabilities until our fingers fall off." We must improve and change the architecture so that establishing and maintaining security becomes tractable. Webflow establishes a simple contract between the content management system and the application DOM that is easy to understand and implement. The PHP vulnerability required that the error-handling maintain consistent state, not just fix a particular bug. That is an architectural change, which is a more robust improvement than a simple patch. Architectural remediation eliminates entire classes of failures. Point fixes address one bug. Finally, explicit security boundaries (that are properly enforced) reduce the amount of internal complexity that must be understood.

We have accumulated decades of software engineering debt under one set of vulnerability-discovery economics, but now we have to service that debt under an entirely different set.

Which leads to the question:

Can we continue to afford to continuously patch these myriad legacy systems?

The experienced veterans have retired, but the code hasn't.

Don't miss what's next. Subscribe to EHO Musings:
Older → Architectural coherence is at risk
Powered by Buttondown, the easiest way to start and grow your newsletter.