Page loaded: A Patch You Can Actually Apply

Photo by Venti Views on Unsplash

Migration

A Patch You Can Actually Apply

When PHP2Shell landed, sites on a supported branch patched in an afternoon and everyone else started a migration. Angular draws the same line, and staying on the right side of it is the security plan.

Miguel Carino
Focus
Front-end web architecture, Angular, team leadership, and stakeholder communication
Experience
25+ years turning enterprise web complexity into maintainable products

On October 20, details of two critical PHP flaws leaked ahead of their planned disclosure. PHP moved its release up and shipped the fixes on October 21, and the pair became known as PHP2Shell. Both allow remote code execution. Security researchers also described a way to read server memory, which is where the passwords and API keys live. Plenty of site owners took their sites offline as a precaution while they patched.

What struck me was how differently that week went for different teams. For a site on a supported PHP branch, the fix was a patch release: bump the version, run the pipeline, restart the workers, go home. For a site still running a branch that support had already dropped, the same bug meant something else entirely. There was no release for it. There were minimal backports for people who build PHP from source, a list of config changes that PHP's own advisory says do not make an installation safe, and an upgrade across one or more major versions, started under deadline.

Same vulnerability. Two very different weeks.

The fix only fits current models

A security patch is a replacement part, and replacement parts are made for the models still in production. If your car is new enough, the dealer has the part on the shelf. If it isn't, you are now shopping for a car.

That is the mechanism under every story from that week. The PHP project fixed four branches: 8.5, 8.4, 8.3 and 8.2. Those are the branches it still supports. The cost of the fix was set long before the bug was found, by how far each site had drifted from that line. The bug itself was the same for everyone.

The stopgaps were real, and they still were not fixes. Cloudflare, Akamai and other security vendors pushed firewall rules to block the known payloads, and they helped. But a rule matches the attacks it knows about, and the advisory was clear that only updating closes the hole. Amazon's threat-intelligence honeypots also caught an attempt to exploit the flaws four days before the fix shipped. The window between "known to someone" and "patched by you" is not yours to set.

Angular draws the same line, just further out

It is tempting to read a PHP story as someone else's problem. An Angular app is mostly code that runs in the browser, after all. But Angular has its own version of that line, and an Angular app touches the server more than the label suggests.

Angular now ships a new major version about once a year. Through v22 it was every six months. From v22 on, each major gets twelve months of active support and then twelve months of long-term support, where only critical and security fixes land. Today v22 is active, v21 is in long-term support until June 2027, and v20 drops off the list on November 28. Everything from v2 to v19 is past the line now.

June gave a clean example. CVE-2026-50557 was a hole in Angular's sanitizer that let crafted markup get past it, a cross-site scripting risk. The fix shipped as patch releases for v19, v20 and v21, and in the v22 release candidate. The advisory lists no fix for v18 or older. An app on v21 took a patch bump. An app on v17 had the same bug and no patch from the Angular team waiting for it.

That way out is slower than it sounds, because the Angular CLI will not take it in one step. Point ng update at a version more than one major ahead and it stops:

npx ng update @angular/core@22 @angular/cli@22

On a v19 app, that prints "Updating multiple major versions of '@angular/core' at once is not supported. Please migrate each major version individually," and tells you to run the update for v20 first. Each hop runs its own migrations, and each one wants a build, a test run and a look at what changed. I have walked apps through six majors in a row this way. It works, and it is the right way to do it. It is also the last thing you want to be starting the morning an advisory drops.

And the browser is only part of the surface. An app that uses server-side rendering runs a Node server, with an Express stack under it and its own dependency tree. Every app has a build toolchain that installs hundreds of packages. This week, a routine audit of my own demo repo flagged denial-of-service fixes in qs, body-parser and brace-expansion, all of them pulled in by other packages rather than chosen by me. Each fix landed inside the versions the project already uses, so taking them was routine. That isn't guaranteed. When a maintainer stops patching an old line, the fix can mean a major upgrade first.

Four ways to live with the support window

Every team picks one of these, even teams that never decided to.

Stay on a supported major. Take each new major within a few months of release, one hop at a time, while the hop is small and the release notes are fresh. With a yearly cadence that is roughly one planned upgrade a year. Pair it with automated dependency updates and a CI run that actually exercises the app, so the small fixes arrive as routine pull requests. This is what I recommend for any app that is still being developed. It costs a steady, schedulable amount of work, and in return an advisory is a patch bump instead of a project.

Buy extended support. Vendors such as HeroDevs sell security patches for Angular versions the Angular team no longer supports, back to v4. For an app that is frozen, near retirement, or blocked by a dependency that will never move, that is a legitimate answer. It is the wrong default for an app with a future, though. You pay to stand still, and the distance to current Angular keeps growing underneath you.

Wall it off. Put the app behind a firewall, restrict who can reach it, and add rules as advisories land. That buys time, and the PHP week showed it is worth having. But a firewall inspects requests. It cannot repair a sanitizer that runs inside your users' browsers, and it only knows the attacks someone has already written rules for.

Freeze it and plan the rewrite. Sometimes the honest answer is that the app is being replaced. The risk is timing. A rewrite is a plan, and the next advisory is a date. If the rewrite is more than a few months out, one of the first three options still has to cover the gap.

Staying Current Is the Patch Plan

Nobody gets to choose when the next critical advisory arrives. What a team does choose, months earlier, is how far its app sits from the versions that will receive the fix. Keep that distance short and an emergency becomes a version bump and an afternoon. Let it grow and the emergency picks your upgrade schedule for you, starting that morning.

The patch is only useful if it fits.