March 28, 2021 — php.net infrastructure. Two commits landed in the php-src repository hosted on the PHP project's self-managed Git server, attributed to two of the most trusted names in the language's history: Rasmus Lerdorf, the creator of PHP, and Nikita Popov, a longtime core maintainer. Neither had written them. The commits carried a small, precisely placed backdoor capable of remote code execution on any server running the tampered build — a supply chain compromise that struck at the source of a language running an estimated 75%+ of the web's server-side codebase at the time.
The incident was caught fast, contained before it reached a tagged release, and never confirmed to have compromised a production PHP installation. But it forced the PHP project to abandon two decades of self-hosted git infrastructure and remains one of the clearest public case studies of what happens when an attacker gets write access to a language runtime's canonical source tree.
What Happened
On the evening of March 28, 2021, two commits appeared on the git.php.net server's copy of php-src, the canonical repository for the PHP interpreter itself. The commit metadata impersonated Rasmus Lerdorf and Nikita Popov — using their names and email addresses — giving the changes the outward appearance of routine, trusted maintainer activity. Popov spotted the anomaly almost immediately: reviewing the commit log, he found two commits he had no memory of authoring, one of which modified ext/pcre/php_pcre.c, a core extension shipped in virtually every PHP build.
The team's own postmortem quickly ruled out the initial assumption of individually compromised maintainer accounts. Git commit authorship is trivially spoofable — anyone with push access to a repository can set author metadata to any name and email — so the presence of Lerdorf's and Popov's names in the commit log was not evidence their credentials had been stolen. What it did indicate was more troubling: something with write access to the git.php.net server infrastructure itself, not merely to one contributor's laptop, was able to push directly to a repository with no code review gate on that path.
The Backdoor Mechanism
The malicious diff was small and disguised as an innocuous typo fix, a classic technique for slipping a payload past a quick visual scan. It added a check against the HTTP_USER_AGENTT header — a deliberate misspelling of User-Agent designed to look like developer sloppiness rather than intent — and, if the header's value contained the string zerodium, passed the content of the REMOTE_ADDR header directly into zend_eval_string(), PHP's function for evaluating a string as executable PHP code.
In practice, that meant any attacker who knew the trigger phrase could send a single crafted HTTP request to a server running the tampered PHP build and have arbitrary PHP code executed with the permissions of the web server process — a textbook backdoor, hidden in three lines inside a core extension used by nearly every PHP deployment on earth. The reference to Zerodium, a commercial exploit acquisition broker, appears to have been either a taunt, a false-flag misdirection, or dark humor on the attacker's part; it was never substantiated as a genuine connection to that company.
Because ext/pcre ships compiled into the default PHP binary on most distributions, a successful, undetected merge into a tagged release would have handed a working, near-universal RCE backdoor to anyone who knew the magic string — reachable via a single unauthenticated HTTP header, no authentication or complex chaining required.
Detection and Response
The compromise was caught at the earliest possible stage: in the source repository, before the change was ever merged into a release branch or shipped in a tagged PHP version. No evidence emerged that any production PHP release, package, or downstream distribution ever shipped the backdoored code. That distinction — caught in the repo versus caught in a shipped artifact — is the entire reason this incident is remembered as a near-miss rather than a mass-exploitation event.
The PHP team's response was swift and structurally significant rather than merely reactive:
- The malicious commits were reverted within hours of discovery.
- Direct push access to
git.php.netwas suspended while the team investigated. - The root cause of the server compromise itself was never conclusively identified publicly — investigators could not pin down exactly how the attacker obtained write access to the git server, which is itself a notable data point about the limits of forensic visibility on self-hosted infrastructure without hardened audit logging.
- Most consequentially, the PHP project announced it would end self-hosted git.php.net as the system of record and migrate canonical development to GitHub, adopting pull-request-based review as a mandatory gate for all future changes to
php-src.
That last decision is the incident's lasting legacy. The PHP maintainers concluded that the trust model underpinning direct-push access to a self-run git server — however long it had worked without incident — was no longer a defensible way to protect a dependency this deeply embedded in the internet's infrastructure. GitHub's authentication hardening, required reviews, and audit trail were judged a materially stronger control than what the project could maintain on its own hosting.
Why This Matters for Software Supply Chains
The PHP incident is instructive for reasons that go well beyond one language ecosystem's git hosting choice:
Source-level compromise beats artifact-level compromise, every time, from an attacker's perspective. Backdooring a build pipeline or a shipped binary gets you one poisoned artifact. Backdooring the source repository of a language runtime gets you a payload that redistributes itself through every build, every packager, every CI pipeline, and every downstream consumer that pulls from that tree — with the implicit trust of the project's name attached. This is the same structural logic behind later, more damaging events like the SolarWinds and XZ Utils compromises: the earlier in the supply chain an attacker plants a change, the more legitimate distribution channels launder it on their behalf.
Commit authorship is not authentication. Git's author/committer fields are metadata, not cryptographic proof of identity. Any organization relying on "the commit says it's from a trusted maintainer" as a security control — rather than signed commits, enforced code review, or branch protection — is trusting a field an attacker with repository write access can set to anything. The PHP project's shift to GitHub with mandatory PR review was, functionally, a move from an honor-system trust model to an enforced one.
A single mistyped header string was the entire attack surface. The backdoor's trigger condition depended on nothing more than an HTTP header value matching a string. There was no privilege escalation, no memory corruption, no exotic technique — just a conditional branch quietly inserted into hot-path code that almost nobody reads line-by-line during routine maintenance. That simplicity is exactly why it's dangerous: low-sophistication backdoors hidden in high-trust code paths are often harder to catch than sophisticated exploits, because reviewers aren't looking for them.
Detection depended on a human noticing something felt wrong, not on tooling that would have flagged the change automatically. Nikita Popov's recollection that he hadn't written those commits is what broke the incident open. A different maintainer, a busier week, or a more subtly placed change could plausibly have let this slip through — a sobering thought given how close-run the actual outcome was.
Lessons for Defenders
Security teams evaluating their own exposure to this class of incident should be asking a few concrete questions: Which repositories in your dependency tree still allow direct, unreviewed pushes to a branch that feeds production builds? Do you have any automated control that would catch a functionally anomalous change — a header-triggered code evaluation, an unexpected network call, an unusual eval-style construct — introduced into a widely-used dependency, or does detection depend entirely on a maintainer's memory? And if a backdoor like this landed in one of your thousands of transitive dependencies today, would your organization have any way of knowing whether the vulnerable code path was actually reachable from your application, or would you be stuck patching blindly across your entire fleet?
How Safeguard Helps
Incidents like the PHP git server compromise underscore why supply chain defense has to start well before a vulnerable or backdoored package reaches a build. Safeguard's Griffin AI continuously analyzes upstream dependency changes and flags anomalous patterns — unexpected eval-style constructs, unusual conditional logic tied to network input, and other markers consistent with intentionally obfuscated backdoors — rather than relying solely on published CVE feeds that lag behind fast-moving incidents like this one. Safeguard's reachability analysis then determines whether a flagged code path in a dependency like ext/pcre is actually invoked by your application at runtime, letting teams triage a component-level compromise by real exposure instead of patching every service that merely references the affected library. Continuous SBOM generation and ingest give security teams an accurate, queryable inventory of exactly which services run which version of which dependency, so a disclosure like this one can be answered in minutes rather than days of manual auditing. And when a fix is warranted, Safeguard's auto-fix PRs push the remediated dependency version directly into affected repositories, closing the gap between disclosure and patched production code before an opportunistic attacker can act on public knowledge of the exposure.