PHP2Shell: A Practical PHP Backport Guide for Debian
25 Oct 2026

PHP2Shell: In Ondřej’s Shoes – A Practical Guide from Upstream Patch to Debian Packages

A security update arrives, we install it, and work continues. That uneventful ending is what we want. It also makes it easy to overlook the people who made it possible. The PHP2Shell security emergency brought those people into the spotlight.

At CDNsun, we want to say thank you to two of them: Ondřej Surý and Remi Collet. Not because they work alone, or because every PHP installation depends directly on their repositories, but because their work represents something the Internet needs much more of: experienced people turning shared software into something others can reliably use.

The people behind the package names

Ondřej has been a Debian Developer since 2000 and has packaged PHP since PHP 5. His DEB.SURY.ORG project provides PHP packaging for Debian and Ubuntu. We are from Czechia too, and there is genuine pride in seeing a fellow Czech contribute so much to infrastructure used far beyond our borders.

Ondřej Surý, one of the people behind the PHP packages so many of us rely on.

Remi does similarly important work in another part of the Linux ecosystem. His RPM repository provides the PHP stack for Fedora and Enterprise Linux. His FAQ distinguishes that personal repository from his employer while explaining that PHP packaging is now his main job. The details matter: this is not a story in which all open-source work is unpaid. It is a mixture of professional commitment, personal initiative, sponsorship and community effort.

A package maintainer does much more than press a compile button. Someone has to reconcile dependencies, preserve integration with the operating system, accommodate extensions, investigate failures and make an update installable. When the change is urgent, those obligations do not disappear. There is simply less time in which to meet them.

Dependency-stack meme showing all modern PHP installs resting on supports labelled Ondrej and Remi.

An exaggeration, of course. The gratitude behind it is not.

An exaggeration, of course. The gratitude behind it is not. The joke works because we recognise the imbalance: a huge amount of useful software can rest on a surprisingly small number of people. But admiration should not become an expectation that those people will always be available.

PHP2Shell: a shared security response

The PHP Foundation’s account of the October 21, 2026 security release describes two related critical issues involving memory management and error handling. It also makes the collective effort clear: foundation-funded engineers, volunteers, the PHP security team, release managers and distributors all contributed.

That thanks extends to researchers at Calif, including Ryan A, Wiz, and OpenAI Codex Security, including Amy Burnett; and to OSTIF, Quarkslab and the Sovereign Tech Agency behind the earlier audit. Finding a problem, choosing a compatible remedy and delivering usable packages are different jobs. We need people doing all of them.

That is why celebrating Ondřej and Remi should widen the circle of recognition, not erase the people upstream of them. A working update is the result of that whole chain holding together.

What if Ondřej were at sea?

The boat scenario in The Atlantic’s interview with Ondřej prompted a practical question. Suppose an emergency arrived while he was at sea, away from the keyboard. Not that he missed this release: this is a hypothetical. People are entitled to be unavailable. What would an operator do if the needed package were not yet ready?

The best outcome is not that nobody ever goes sailing. It is that the work is supported well enough for them to go.

We tried a small part of that responsibility ourselves: adapting an upstream fix to an older PHP branch, building packages and comparing their behaviour with the distributor’s. A backport means carrying a fix into an older version without replacing that version with the newer one.

We chose PHP 5.6 as a laboratory target, structurally far removed from the PHP 7.4 upstream reference. The question was how to approach the work responsibly, not how to bypass the people already doing it.

How to build a backport yourself: the practical route

If the next emergency arrives before a ready-made package does, where do you start? This is the sequence we followed. It is a beginner’s map of the work, from an empty lab machine to packages you can test, not a claim that adapting security-sensitive C code is a one-command job.

  1. Prepare a separate build machine. Start with a clean virtual machine or spare server, not the live server you need to protect. Match the operating-system release and CPU architecture of the packages you want to produce. We used Debian on amd64. Choose a machine with several CPU cores, enough RAM for parallel compilation, and room for dependencies, unpacked sources and separate build results.
  2. Install the compilation and packaging tools. On Debian, the shopping list includes build-essential for the compiler and make, dpkg-dev and devscripts for Debian packaging, sbuild, schroot and debootstrap for an isolated builder, and quilt, Git and download tools for managing patches and sources. The Debian package-building guide explains the toolchain. The package’s own build dependencies, libraries and development headers, come next; installing a compiler alone is not enough.
  3. Create the clean build environment. Configure a separate sbuild environment for the target Debian release and architecture. This is a small, clean filesystem in which the package is compiled, rather than a collection of libraries accumulated on your everyday machine. Configure its package sources so the dependencies declared by the PHP source package can be resolved. The sbuild documentation covers this setup. Keep the environment so both the original and modified source can use the same recipe.
  4. Download the exact source package you intend to repair. Do not simply fetch whichever source your package manager currently calls “latest.” For our original revision 103, the inputs were the source descriptor (.dsc) (we intentionally don’t provide link), the original PHP source archive, and the matching Debian packaging archive (we intentionally don’t provide link). Keep all three together. Check their recorded checksums and available publisher-authentication evidence, then preserve an untouched copy.
  5. Unpack and build the unchanged version first. Use dpkg-source -x with the descriptor to unpack the complete source, including the distributor’s existing patches. Inspect debian/control for build dependencies and debian/rules for the build recipe. Give the original descriptor to your configured sbuild builder and save its logs and resulting .deb files. This establishes that your toolchain can build the original before a new patch enters the picture.
  6. Establish a working test baseline. Install the selected original packages in a disposable test environment, with the PHP extensions and execution modes you need. Test the command-line interpreter and actual HTTP handling, then run the applicable PHP tests using the source tree’s run-tests.php driver. Download the same-version original vendor packages from the repository archive and test those in a separate copy of the same environment too, if available. Our rebuilt and vendor baselines agreed on all 12,186 individual test results. That comparison gave the later changes a meaningful reference.
  7. Fetch the upstream fix and adapt it to the old code. Our reference was Avoid state corruption via bailout, authored by Arnaud Le Blanc and committed by Ilija Tovilo; its patch is downloadable. Compare each affected function with its older counterpart. Locate the matching allocation, error-handling and cleanup paths, then check the old data structures and APIs. A PHP 7.4 patch is not automatically a PHP 5.6 patch. AI can help navigate those differences, but this is the step that needs C-code understanding and review.
  8. Record the adaptation as a separate package patch. Work in a copy of the original source. Put the resulting patch in debian/patches, add it to debian/patches/series, and update debian/changelog with a distinguishable local version. We used 5.6.40-104~cdnsun1. Preserve the existing distributor patches. Recreate the source package with dpkg-source --build and check that a fresh extraction contains the intended changes.
  9. Build the modified source into Debian packages. Pass the new descriptor to the same configured builder, with a separate results directory. Retain the .deb packages, build logs, .changes file and .buildinfo file. Together they record what was produced and the build environment. Our builds each produced 77 Debian packages; we selected 19 PHP runtime packages for testing rather than installing every output indiscriminately.
  10. Install in a fresh test environment and compare. Keep the original and modified packages separate. Use the same extensions, configuration, test selection and fixtures, and compare individual outcomes, not just the total number of failures. Exercise the real web execution mode as well as CLI, then confirm it still works after the suite. We ultimately compared four variants: original and updated, each locally (our) built and vendor (Ondřej) provided.

What our rehearsal showed

Across the four variants, our selected suite recorded 12,186 individual test results per full run. Its shared language and extension tests ran primarily through CLI, separate integration checks exercised PHP in Apache and PHP-FPM through Apache. The updated pair showed very close regression agreement (our build passed one additional test in the full run).

The adaptation also made the maintainer’s judgement calls tangible. The older array implementation had different internal rules, and the mitigation intentionally disabled session upload-progress reporting. These were changes to understand, not obstacles to conceal.

One stage remains unfinished: we did not create or run targeted fail-before/pass-after security checks for this vulnerability against either our build or the updated vendor build. AI-access restrictions paused that next stage. We may revisit targeted checks and PHP hardening in a later article.

Give the people holding it up more support

Walking a little way in a maintainer’s shoes left us with more appreciation, not a replacement story. AI assistance does not remove the responsibility to understand a change, weigh compatibility costs and decide what evidence is sufficient. Nor does one experiment reproduce years of answering reports, maintaining infrastructure and preparing the next release.

Ondřej says much of his packaging work happens in his spare time. His project offers GitHub sponsorship and Open Collective donations, alongside a commercial support ecosystem. Remi’s Merci / Thanks page is a place to support and acknowledge his work; his FAQ explains that donations help pay for build hardware, hosting and connectivity.

Supporting the PHP Foundation helps sustain work on the language itself. For organisations that depend on this ecosystem, we think recurring support should be part of the infrastructure budget, not an occasional response to a frightening headline.

From all of us at CDNsun: thank you, Ondřej and Remi, and thank you to the researchers, maintainers, security teams, release managers, sponsors and community members alongside you. The best outcome is not that nobody ever goes sailing. It is that the work is supported well enough for them to go.

Leave a Reply

Your email address will not be published. Required fields are marked *