The Intercom PHP Hack: How a Composer Plugin Stole Credentials From Thousands of Developers
On April 30, 2026, attackers compromised intercom/intercom-php on Packagist (20.7 million lifetime installs). The malicious version auto-executed as a Composer plugin, downloading Bun and exfiltrating GitHub tokens, SSH keys, and environment variables. Here is what happened and how to protect yourself.
On April 30, 2026, attackers successfully compromised the intercom/intercom-php package on Packagist, one of the most widely installed PHP client libraries with over 20.7 million lifetime installs. For roughly two hours, anyone running composer install or composer update in a project depending on this package was silently pulling down a credential-stealing payload. Around 1,800 developers are estimated to have been caught in the window. This post walks through exactly what happened, how to check if you were affected, and what you can do right now.
The attack has been attributed to the "Mini Shai-Hulud" campaign, the same threat actor that previously targeted npm and PyPI ecosystems. GitHub Advisory GHSA-gr3r-crp5-qrrm covers the disclosure.
Timeline of the Attack
| Time (UTC) | Event |
|---|---|
| 20:53 | Attackers push a malicious commit from a compromised GitHub service account. Version 5.0.2 is tagged and published to Packagist. |
| ~21:00 onwards | Developers running composer install or composer update begin pulling the compromised version. |
| ~22:30 | Suspicious activity is flagged through automated scanning. |
| 22:37 | The malicious commit is reverted and version 5.0.2 is yanked from Packagist. |
The attack window was approximately 1 hour and 44 minutes. That is a tight window, but Packagist's scale means thousands of installs can happen in that time.
How the Attack Worked
This attack exploited a legitimate Composer feature rather than a dependency confusion trick or a typosquat.
Composer Plugins: The Attack Vector
Composer has a plugin system that allows packages to hook into the install lifecycle. A package can declare itself as a composer-plugin type in its composer.json, and Composer will execute its code automatically during installation.
The attacker modified intercom/intercom-php version 5.0.2 to declare itself as a Composer plugin:
{
"name": "intercom/intercom-php",
"type": "composer-plugin",
"extra": {
"class": "Intercom\\ComposerPlugin"
}
}
This single change tells Composer: run this class's activate() method the moment you install this package.
The Payload
Once Composer executed the plugin class, it performed the following steps:
- Downloaded the Bun JavaScript runtime from a remote server. Bun is a legitimate, modern JS runtime, which helped avoid detection by security tooling looking for known malicious binaries.
- Executed obfuscated JavaScript code via the downloaded Bun binary.
- Exfiltrated credentials from the developer's environment, including:
- GitHub personal access tokens (from
~/.config/gh/hosts.ymland environment variables) - SSH private keys (from
~/.ssh/) - Cloud provider credentials (AWS, GCP, Azure config files)
- All environment variables present at install time
- GitHub personal access tokens (from
The exfiltration was performed over HTTPS to an attacker-controlled endpoint, making it difficult to distinguish from normal outbound traffic.
Most developers run composer install on their local machine or in a CI/CD pipeline that has elevated credentials attached. A CI runner often has access to secrets needed to deploy, push to registries, or interact with cloud infrastructure. This makes the attack surface much larger than just one developer's laptop.
Am I Affected?
You are potentially affected if you installed or updated dependencies in a project that depends on intercom/intercom-php between 20:53 and 22:37 UTC on April 30, 2026.
Check your composer.lock
grep -A 2 '"intercom/intercom-php"' composer.lock
If you see "version": "5.0.2", you installed the compromised version.
Check for the Bun binary
find /tmp ~/.local /var/tmp -name "bun" -type f 2>/dev/null
which bun
If you find a bun binary you did not intentionally install, treat the system as compromised.
What to Do If You Installed the Compromised Version
Assume all credentials that were accessible during the install are compromised. Do not wait to confirm exfiltration before rotating.
1. Rotate GitHub tokens
Go to github.com/settings/tokens and revoke all personal access tokens. Check for any new deploy keys or OAuth authorisations added to your repositories.
2. Rotate SSH keys
Remove your existing public keys from GitHub, GitLab, or any servers they are authorised on. Generate new keypairs:
ssh-keygen -t ed25519 -C "your_email@example.com"
3. Rotate cloud credentials
For AWS, rotate IAM access keys and check CloudTrail for unexpected API calls. For GCP and Azure, do the equivalent in their IAM consoles.
4. Rotate application secrets
Rotate anything that was in your .env file or shell environment at the time of install: APP_KEY, database passwords, payment gateway keys, third-party API tokens.
5. Audit for persistence
Check cron jobs, systemd timers, shell profile files, and SSH authorized_keys for additions you do not recognise:
crontab -l
cat ~/.ssh/authorized_keys
How to Protect Against Composer Plugin Attacks
Lock down the allow-plugins config
Since Composer 2.2, you can whitelist which packages are allowed to run as plugins:
{
"config": {
"allow-plugins": {
"pestphp/pest-plugin": true,
"phpstan/extension-installer": true
}
}
}
With this set, intercom/intercom-php attempting to register as a plugin would have been blocked.
Run Composer in CI with restricted permissions
Avoid attaching powerful credentials to the environment where composer install runs. Use short-lived tokens scoped to what the install actually needs.
Pin exact versions in composer.lock
Commit your composer.lock and do not allow Composer to update it in production deployments:
composer install --no-interaction --prefer-dist --optimize-autoloader
Monitor for unexpected processes during CI
Add a step to check for unexpected processes or filesystem changes after the install step. Even a simple diff of the filesystem before and after composer install can surface anomalies.
The Bigger Picture: Cross-Ecosystem Supply Chain Attacks
The Mini Shai-Hulud campaign is a reminder that no package ecosystem is immune. This same threat actor previously planted malicious packages in npm and PyPI before turning to Packagist.
The pattern is consistent across ecosystems:
- Compromise a legitimate, trusted account rather than publishing a new unknown package.
- Use native extension points (npm lifecycle scripts, PyPI's setup.py, Composer plugins) to execute code automatically on install.
- Target developer credentials rather than end-user data. Developer machines and CI runners hold keys to repositories, cloud infrastructure, and production environments.
For PHP developers specifically, the Composer plugin system has historically received less security scrutiny than npm's postinstall hooks. The allow-plugins config exists precisely for this reason, but adoption is far from universal.
Protect Your Laravel Application
Supply chain attacks introduce compromised code at the dependency layer, but the misconfigurations and exposed endpoints that give attackers more to work with once they are in are detectable from outside your application.
Run a free StackShield scan on your application to catch exposed .env files, debug mode left on in production, unprotected admin interfaces, and the kinds of issues that turn a compromised dependency into a full breach.
Is your Laravel app exposed right now?
34% of Laravel apps we scan have at least one critical issue. Most teams don't find out until something breaks. Our free scan checks your live application in under 60 seconds.
Frequently Asked Questions
What happened with the intercom/intercom-php package?
On April 30, 2026, attackers compromised the intercom/intercom-php package on Packagist via a compromised GitHub service account. They pushed a malicious version (5.0.2) that declared itself as a Composer plugin, which auto-executes during installation. The payload downloaded the Bun JavaScript runtime and ran obfuscated code that exfiltrated GitHub tokens, SSH keys, cloud credentials, and environment variables. The attack window was approximately 2 hours.
How do I check if I installed the compromised version?
Run "grep -A 2 intercom/intercom-php composer.lock" in your project directory. If you see version 5.0.2, you installed the compromised version. Also check for an unexpected Bun binary on your system with "find /tmp ~/.local -name bun -type f".
What should I do if I was affected?
Assume all credentials accessible during the install are compromised. Rotate GitHub tokens, SSH keys, cloud credentials (AWS, GCP, Azure), and all application secrets from your .env file. Check for persistence mechanisms: review cron jobs, SSH authorized_keys, and shell profile files. Update to a safe version of the package.
How can I prevent Composer plugin attacks?
Use the allow-plugins config in your composer.json to whitelist which packages can run as Composer plugins. Only run "composer install" (not "composer update") in production. Review any PRs that modify composer.json repository entries. Run Composer in CI with restricted permissions and short-lived tokens.
Related Articles
Laravel Session Security: Cookies, Hijacking & config/session.php
A deep dive into Laravel session security. Learn how cookie flags, session drivers, and config/session.php settings protect against hijacking, fixation, and sidejacking attacks.
SecurityAutomated Security Testing in Laravel CI/CD Pipelines
How to add security gates to your Laravel CI/CD pipeline with GitHub Actions. Covers dependency scanning, static analysis, secret detection, and automated security monitoring.
SecurityLaravel Content Security Policy: Configure CSP Without Breaking Your App
Only 22% of Laravel apps have a Content Security Policy. Learn how to implement CSP with spatie/laravel-csp, handle Livewire and Vite nonces, and avoid the mistakes that break production.
Compare StackShield
Security Checklists
Laravel Production Deployment Security Checklist
A comprehensive security checklist for deploying Laravel applications to production. Covers environment config, server hardening, access control, and monitoring.
20 itemsLaravel API Security Checklist
Secure your Laravel API endpoints against common vulnerabilities. Covers authentication, input validation, rate limiting, and response security.
Stay Updated on Laravel Security
Get actionable security tips, vulnerability alerts, and best practices for Laravel apps.