If you write PHP code, you rely on code written by other people. Every composer require pulls in a packageâand every package pulls in its own dependencies. Before you know it, your application has a dependency tree hundreds of packages deep. That tree is your software supply chain, and if youâre not paying attention to its security, youâre carrying risk you didnât sign up for.
Supply chain attacks are not new, but theyâve accelerated dramatically in the last few years. The SolarWinds breach, the log4j debacle in the Java ecosystem, and the event-stream npm incident all share a common thread: attackers injected malicious code into widely used dependencies, and organizations downstream paid the price. PHP applications are just as vulnerable.
What Is a Software Supply Chain?
A software supply chain is everything your code depends on to function. For a typical PHP application, that includes:
- Composer packages pulled from Packagist or private repositories
- npm packages for your frontend assets
- Docker base images for development, testing, and production
- CI/CD tools and services your pipeline executes against
- Hosting platforms and infrastructure where your application runs
- Third-party APIs and SDKs your application consumes
Every link in that chain is a potential attack surface. Compromise any single link, and youâve compromised the entire application.
Why PHP Developers Should Care
PHP powers the web. WordPress, Laravel, Symfony, Drupal, Magentoâthe PHP ecosystem runs a massive portion of the internet. This makes PHP projects attractive targets. Attackers know that compromising a popular Composer package gives them access to thousands of downstream applications.
Real-World Examples
The PHP ecosystem has already seen supply chain attacks. In 2021, several typosquatted packages appeared on Packagist mimicking popular libraries. Attackers have also compromised WordPress plugin update servers to distribute backdoored plugins to millions of sites.
The lesson is simple: if you consume third-party code, you are trusting that codeâs maintainers, their infrastructure, and their own supply chains. Trust is necessary, but trust without verification is negligence.
Key Supply Chain Risks for PHP Projects
1. Compromised Dependencies
An attacker gains access to a package maintainerâs account or commits directly to a popular repository. They inject malicious code into a seemingly innocuous update. You run composer update, and suddenly your application is exfiltrating database credentials to a command-and-control server.
This isnât theoretical. Attackers have compromised legitimate packages across every major ecosystem. The composer install command you run every day is a vector if youâre not careful.
2. Typosquatting
Attackers publish packages with names that look like popular libraries: laravel vs laravel, monolog vs mon0log, guzzlehttp vs guzzlehttp. A developer mistypes a package name in composer.json or auto-completes the wrong suggestion, and the attackerâs code runs in production.
Packagist has improved its vetting process, but typosquatting remains a persistent threat. The burden is on you to verify exactly what youâre installing.
3. Dependency Confusion
Dependency confusion attacks exploit the way package managers resolve package names. If your internal composer.json references a private package name that also exists on Packagist, Composer might prioritize the public package over your private one. An attacker publishes a malicious package with the same name on Packagist, and your next build pulls their code instead of yours.
This attack vector has been demonstrated across npm, pip, and RubyGems. PHP projects using private repositories are not immune.
4. Build Pipeline Attacks
Your CI/CD pipeline has access to production credentials, deployment keys, and source code. If an attacker compromises your CI/CD toolingâthrough a malicious GitHub Action, a compromised Jenkins plugin, or a leaked API tokenâthey own everything your pipeline touches.
Build pipeline attacks are especially dangerous because they happen in an automated context. No human reviews every line of code that runs in CI. A malicious action in your deploy.yml workflow runs with full privileges, and you might not notice until itâs too late.
5. Docker Image Vulnerabilities
If you containerize your PHP application, your Dockerfileâs FROM php:8.1-fpm base image carries its own supply chain. Base images contain operating system packages, PHP extensions, and libraries, each with its own vulnerability history. A vulnerable version of libxml2 or curl in your base image is a vulnerability in your application.
OWASP Top 10 Supply Chain Security Risks
The OWASP Foundation published a Top 10 list for software supply chain security. These are the risks every developer should understand:
- Component Identification â Not knowing what dependencies you have
- Component Selection â Choosing insecure or malicious components
- Component Integrity â Installing modified or tampered components
- Component Updates â Using outdated or vulnerable versions
- Component Maintenance â Depending on abandoned or unmaintained packages
- Source Code Security â Compromised source code repositories
- Build Pipeline Security â Insecure CI/CD configuration
- Artifact Management â Insecure storage or distribution of build artifacts
- Deployment Infrastructure â Compromised hosting or deployment targets
- Operational Monitoring â Lack of visibility into supply chain threats
PHP developers should use this framework to audit their own projects. Where are you exposed?
Practical Mitigations for PHP Developers
Lock Your Dependencies
The single most impactful action you can take is to commit your composer.lock file to version control. The lock file pins every dependency to a specific version hash. When you deploy, every environment installs exactly the same code.
Without a committed lock file, running composer install on Monday might give you different packages than running it on Tuesdayâif a maintainer pushed a new version in between. Thatâs how compromised updates reach your production environment.
Verify Package Integrity with composer audit
Composer ships with a built-in audit command:
composer auditThis command checks your installed dependencies against the FriendsOfPHP/security-advisories database. It reports any packages with known vulnerabilities, including the CVE identifier and severity level.
Make composer audit part of your CI/CD pipeline. Fail the build if any known vulnerabilities are found:
# example for GitHub Actions
- name: Check for vulnerable dependencies
run: composer audit --format=json --no-interactiveUse the Security Advisories Database
The roave/security-advisories package acts as a meta-package that conflicts with any known-vulnerable version of common PHP libraries. Add it to your composer.json as a dev dependency and update it regularly:
composer require --dev roave/security-advisories:dev-masterIf any of your installed dependencies have known vulnerabilities, Composer will refuse to install them. This gives you a proactive defense against pulling in compromised or vulnerable code.
Audit Before You Require
Before adding a new dependency, vet it:
- How many installs does it have on Packagist?
- When was it last updated?
- Does it have a security policy?
- Does it have known vulnerabilities?
- Who maintains it? Is it a single person or an organization?
A package with 2,000 installs that hasnât been updated in three years is a security risk. A package maintained by a single person with no security policy is a bus-factor risk that becomes a security risk the moment that personâs account is compromised.
Scan Docker Images
If you use Docker, scan your images for known vulnerabilities. Tools like Docker Scout, Trivy, and Snyk can analyze your image layers and report CVEs in the base OS packages and installed PHP extensions.
Add image scanning to your CI/CD pipeline:
docker build -t my-app:latest .
trivy image my-app:latest --severity HIGH,CRITICALIf the scan reports critical vulnerabilities, rebuild with an updated base image or patch the affected packages.
Secure Your CI/CD Pipeline
Your CI/CD pipeline is a privileged environment. Treat it as such:
- Use fine-grained tokens instead of full-access credentials
- Pin GitHub Actions (or GitLab CI templates) to specific commit hashes, not version tags
- Audit third-party actions and templates before using them
- Never run
composer installornpm installwithout a lock file - Separate build credentials from deploy credentials
- Rotate secrets regularly
A compromised CI pipeline is a direct path to your production environment. Act like it.
Guard Against Dependency Confusion
To prevent dependency confusion attacks in PHP projects:
- Configure Composer to prefer your private repository over Packagist for internal packages
- Use distinct naming conventions for internal packages (e.g.,
prefix/internal-package) - Consider running a private Packagist instance or using Satis to host internal packages
- Verify the origin of every package in your dependency tree with
composer show --available
Implement Least Privilege in Build Systems
The token your CI pipeline uses to deploy should only have permission to deploy. It should not be able to:
- Modify repository settings
- Delete audit logs
- Access other environments
- List or rotate secrets
Similarly, the service account your application runs as should not be a root user inside its container. If a compromised dependency tries to write to the filesystem, the damage is limited by what the process user can access.
Sign Your Releases
Code signing provides cryptographic proof that a release was produced by you and hasnât been tampered with. If you distribute PHP packages or applications, sign them with a GPG key.
Tools like minisign and sigstore make signing accessible. If you consume packages, verify their signatures when available. The overhead is minimal, and the security benefit is significant.
Keep Everything Updated
This sounds obvious, but itâs worth stating: outdated dependencies are vulnerable dependencies. Attackers publish CVEs for a reason. The gap between a vulnerability being disclosed and you applying the fix is a window of opportunity.
Use automated dependency update tools:
- Dependabot â GitHubâs built-in dependency updater. Creates pull requests when new versions of your dependencies are released, including security updates.
- Renovate â Open-source bot that supports Composer, npm, Docker, and dozens of other ecosystems. Configurable schedules, grouping, and auto-approval.
- Composer Update Checker â The
local-php-security-checkertool from Enlightn scans your installed packages against the security advisories database without making external network calls, making it suitable for air-gapped environments.
Install one of these tools on every repository. Let automation handle the boring work of keeping dependencies current.
Building a Supply Chain Security Program
Individual actions are good. A program is better. Hereâs a framework for PHP teams:
Phase 1: Discovery
- Inventory every dependency across all your projects
- Identify direct and transitive dependencies
- Document all third-party services and integrations
- Map your CI/CD pipeline and its access controls
Phase 2: Assessment
- Run
composer auditon every project - Scan all Docker images for vulnerabilities
- Review CI/CD token permissions
- Check for abandoned or unmaintained packages
Phase 3: Remediation
- Update or replace vulnerable dependencies
- Remove unused dependencies (dead code canât be exploited)
- Rotate over-privileged tokens and credentials
- Pin CI/CD action versions and base image tags
Phase 4: Automation
- Add
composer auditto your CI pipeline - Enable Dependabot or Renovate on every repository
- Automate Docker image scanning
- Set up automated dependency update schedules
Phase 5: Monitoring
- Monitor security advisories for your dependencies
- Subscribe to the FriendsOfPHP security mailing list
- Watch your dependenciesâ GitHub repositories for security announcements
- Regularly review and update your threat model
The Bottom Line
Software supply chain security is not optional anymore. The attacks are real, the stakes are high, and the PHP ecosystem is squarely in the crosshairs.
You donât need to boil the ocean. Start with the basics: commit your lock file, run composer audit, vet your dependencies, and secure your pipeline. Once those are in place, layer on automation, scanning, and monitoring.
Your application is only as secure as its weakest dependency. Find that weakness before an attacker does.
This article is part of the Security Corner series, providing practical security guidance for PHP developers.