Security 9 min read

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.

Matt King
Matt King
May 21, 2026
Last updated: May 21, 2026
The Intercom PHP Hack: How a Composer Plugin Stole Credentials From Thousands of Developers

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:

  1. 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.
  2. Executed obfuscated JavaScript code via the downloaded Bun binary.
  3. Exfiltrated credentials from the developer's environment, including:
    • GitHub personal access tokens (from ~/.config/gh/hosts.yml and environment variables)
    • SSH private keys (from ~/.ssh/)
    • Cloud provider credentials (AWS, GCP, Azure config files)
    • All environment variables present at install time

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.

Free security check

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.

18% have debug mode on
72% missing security headers
12% have exposed .env
Scan My App Free No signup required. Results in 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.

Stay Updated on Laravel Security

Get actionable security tips, vulnerability alerts, and best practices for Laravel apps.