On 28 March 2021, two malicious commits were pushed to php-src, the source code of the PHP language, on the project's self-hosted git.php.net server. They were made in the names of PHP creator Rasmus Lerdorf and core developer Nikita Popov and added a backdoor that would run any PHP code sent in a crafted HTTP header, with a comment mentioning the exploit broker Zerodium. Maintainers spotted and reverted both commits within hours, and no PHP release shipped the backdoor. The project moved its canonical repositories to GitHub, where write access requires two-factor authentication. On 6 April Popov reported that the server itself was probably not compromised. The attacker had pushed over HTTPS using password authentication against the php.net user database, and "it is possible that the master.php.net user database leaked." The identities abused were developers' passwords, so we class this as a human-identity breach, flagged as such on our hub.
Key takeaways
- Two commits pushed to php-src on 28 March 2021, under the names of Rasmus Lerdorf and Nikita Popov, added a remote code execution backdoor triggered by a crafted HTTP header.
- The maintainers' update of 6 April says the pushes were authenticated with php.net account passwords over HTTPS, a path that bypassed the project's key-based gitolite set-up, and that the php.net user database may have leaked.
- Both commits were reverted within hours, PHP 8.0.4 and 7.4.17 were delayed two weeks as a precaution, and no PHP release contained the backdoor, according to PHP.Watch.
- PHP moved its canonical repositories to GitHub with 2FA required, reset all php.net passwords and moved password storage to bcrypt.
- The identity lesson: a forgotten password path into a build-critical system undoes every stronger control around it, whether the account belongs to a person or a machine.
At a glance
| Organisation | The PHP project (php-src on git.php.net) |
|---|---|
| When | Malicious commits pushed and disclosed on 28 March 2021; cause updated by the maintainers on 6 April 2021 |
| Attacker | Unknown; the backdoor code carried a comment naming the exploit broker Zerodium, but no source attributes the attack |
| Entry point | HTTPS pushes to git.php.net using password authentication against the master.php.net user database |
| Identities abused | php.net developer accounts and passwords, with commits made in the names of two core maintainers |
| Impact | Backdoor committed to the PHP source tree and reverted within hours; no release affected; patch releases delayed two weeks |
| Category | Human identity (not listed as an NHI or AI agent breach). Incident class: human-identity breach (developer account passwords used to push malicious commits) |
What happened
PHP is used by almost 80% of websites, according to W3Techs figures cited by The Record, and until March 2021 its source code lived on the project's own Git server, git.php.net, with GitHub acting only as a mirror. On Sunday 28 March, Popov told the PHP internals mailing list that two malicious commits had been pushed to php-src "from the names of Rasmus Lerdorf and myself." At that point, he wrote, "everything points towards a compromise of the git.php.net server". The Record reported that the backdoor was first spotted by Czech software engineer Michael Voříšek.
PHP.Watch described the change. The first commit, attributed to Lerdorf, added code that would execute whatever was contained in a User-Agentt HTTP header, along with the text "REMOVETHIS: sold to zerodium, mid 2017". Popov reverted it. About seven hours later a second commit under Popov's own name reintroduced the backdoor, and maintainer Levi Morrison reverted that. According to The Record, the code would have let attackers "execute their own malicious PHP commands on victims' servers" had it reached production.
The project's response was immediate and structural. GitHub repositories "which were previously only mirrors, will become canonical," Popov wrote, and contributors would need to join the php organisation on GitHub, where "Membership in the organization requires 2FA to be enabled." The upcoming PHP 8.0.4 and 7.4.17 releases were delayed by two weeks while the code was checked.
The cause turned out to be different from the first assumption. In his update of 6 April, Popov wrote: "We no longer believe the git.php.net server has been compromised. However, it is possible that the master.php.net user database leaked." The pushes had bypassed gitolite, the key-based access layer, because git.php.net also accepted changes over HTTPS with password authentication backed by the master.php.net user database. The Register reported Popov's view that "I'm not sure why password-based authentication was supported in the first place," and that the logs showed a few guesses at usernames followed by immediate successful authentication. The master.php.net system was rebuilt as main.php.net on PHP 8, with parameterised queries, all passwords reset and "Passwords are now stored using bcrypt." The Register noted that the explanation fell short of a full analysis, and how the attacker obtained the passwords has not been confirmed.
Timeline
| Date | Event |
|---|---|
| 28 March 2021 | Two malicious commits are pushed to php-src under the names of Rasmus Lerdorf and Nikita Popov and reverted within hours. |
| 28 March 2021 | Popov announces the incident and makes the GitHub repositories canonical, with 2FA required for write access. |
| 29 March 2021 | The Record and PHP.Watch report the backdoor; PHP 8.0.4 and 7.4.17 are delayed by two weeks. |
| 6 April 2021 | Popov reports that the server was probably not compromised and that the master.php.net user database may have leaked; all php.net passwords are reset. |
| 7 April 2021 | The Register reports the update and the password-based HTTPS push path. |
How it happened: the identity attack path
- Parallel password path. Alongside key-based gitolite access, git.php.net accepted Git pushes over HTTPS with Digest authentication against the master.php.net user database, a path Popov had not known about, according to The Register.
- Developer passwords obtained. The attacker authenticated as php.net users, most likely with passwords from a leaked copy of that database, according to the maintainers. This has not been confirmed.
- Impersonated commits. The attacker pushed commits that named Rasmus Lerdorf and Nikita Popov as authors, relying on trust in their names.
- Backdoor in source. The commits added code that would execute attacker-supplied PHP sent in a crafted HTTP header.
- Detection and lockdown. Maintainers reverted the commits, moved to GitHub with 2FA and reset every php.net password.
Impact
- Confirmed: two malicious commits entered the php-src repository and were reverted within hours; no PHP release contained the backdoor.
- Operational: PHP 8.0.4 and 7.4.17 were delayed two weeks, git.php.net and svn.php.net were made read-only and development moved to GitHub.
- Suspected: a leak of the master.php.net user database containing developer account credentials, which the maintainers called possible but not proven.
- Potential: had the backdoor shipped, any server running the affected PHP build could have been taken over with a single HTTP request.
What this means for NHI governance
This is a human-identity breach, flagged as such on our breach hub: the accounts used were developers' php.net logins, and the commits were dressed up as the work of two well-known maintainers. We include it because it sits squarely in the software supply chain that NHI programmes are meant to protect. The source tree of a language runtime is upstream of millions of servers, and the controls that decide who can change it, and how they authenticate, are the same whether the pusher is a person, a bot or a CI pipeline.
The deeper lesson is about forgotten authentication paths. PHP had a key-based access layer, but an older password route into the same repository stayed open behind it, tied to a user database on ageing code. Attackers look for that kind of side door, and the same pattern appears with machine credentials: a deploy key or token that still works after everyone thought it was retired. Inventorying every way into a build-critical system, removing password logins and requiring signed commits and MFA closes it. The XZ Utils backdoor later showed the other route, a trusted maintainer identity built up over years. See our CI/CD Pipeline Identity Security Guide and MFA Guide.
Recommendations
- Remove password authentication from source control. Allow pushes only with SSO and MFA, SSH keys or short-lived tokens, and audit for legacy HTTPS or Digest endpoints. See our MFA Guide.
- Inventory every path into build-critical repositories. List each protocol, credential type and identity that can write, and close the ones nobody owns. See our CI/CD Pipeline Identity Security Guide.
- Require signed commits and verify them. A commit that names a maintainer should prove it came from that maintainer's key, so impersonation stands out.
- Store passwords with modern hashing and reset them after any suspected leak. PHP moved to bcrypt and reset every account. See our Password Security Guide.
- Review changes to critical code before they reach a release. Branch protection and mandatory review would make a direct push like this fail.
- Retire self-hosted infrastructure you cannot secure. PHP's own conclusion was to move to a platform with enforced 2FA rather than rebuild its server.
Frequently asked questions
Was PHP hacked in 2021?
Yes. On 28 March 2021 an attacker pushed two commits containing a backdoor to the official php-src repository on git.php.net, under the names of Rasmus Lerdorf and Nikita Popov. Both were reverted within hours and no PHP release contained the backdoor.
How did the attacker push the malicious PHP commits?
The PHP maintainers concluded the attacker used password authentication over HTTPS, a route into git.php.net backed by the master.php.net user database, rather than breaking into the server. They said the user database may have leaked; how the passwords were obtained has not been confirmed.
Did the PHP backdoor affect my servers?
Not through official releases. According to PHP.Watch, no released version of PHP contained the backdoor, and PHP 8.0.4 and 7.4.17 were delayed two weeks so the code could be checked. Only code built directly from the repository while the commits were present would have included it.
Related NHI Mgmt Group resources
XZ Utils Backdoor 2024 · ua-parser-js npm Hijack 2021 · Codecov Breach 2021 · CI/CD Pipeline Identity Security Guide · MFA Guide
How NHI Mgmt Group can help
Every software supply chain depends on a small number of identities that can change trusted code, human and non-human. We help teams map those identities and the paths they use, remove legacy authentication and put signing, MFA and review in front of release. See our NHI and AI agent security training.
References
- PHP internals mailing list (Nikita Popov): Changes to Git commit workflow (28 March 2021)
- The Record: Hackers backdoor PHP source code after internal repo hack (29 March 2021)
- PHP.Watch: git.php.net server compromised, move to GitHub, and delayed updates (29 March 2021)
- PHP internals mailing list (Nikita Popov): Update on git.php.net incident (6 April 2021)
- The Register: Update on PHP source code compromise: User database leak suspected (7 April 2021)