Composer 2.9 and 2.10: Security Blocking, Better Repo Management, and What PHP Developers Need to Know
Composer 2.9 and 2.10 bring automatic security blocking, a new repo CLI command, and malware filtering. Here's what changed and how to use it.
If Composer is the beating heart of the PHP ecosystem, the 2.9 and 2.10 releases are the kind of quiet upgrade that deserves more attention than they usually get. There are no flashy new language features here. What you get instead is a Composer that is meaningfully safer, more ergonomic to use, and better equipped for the dependency management reality most teams actually face. If you are still running an older 2.x release, this is a good moment to understand what you have been missing.
Automatic Security Blocking (2.9)
The headline addition in Composer 2.9 is something that should have existed years ago: automatic blocking of packages with known security advisories. Previously, the composer audit command would report vulnerabilities in your installed packages, but running composer update would happily install a version with a known CVE if it satisfied your version constraints. That is no longer the default behavior.
In 2.9, Composer now checks for security advisories during install and update operations and blocks installation of flagged versions automatically. This protection is on by default. If you hit a case where you need to override it (say, a vulnerability exists but does not affect your usage), you can configure the behavior via the audit.block-insecure config key:
# Disable automatic blocking globally (not recommended)
composer config audit.block-insecure false
# Or set it in composer.json directly
composer config --json extra.composer-audit '{"block-insecure": false}'
There is also a separate option for abandoned packages. Abandoned packages are not blocked by default, but you can opt in:
composer config audit.block-abandoned true
This is worth enabling on projects that need strong provenance guarantees. Abandoned packages are not inherently insecure, but they represent a maintenance liability that teams should be making a conscious choice about, not discovering accidentally.
One practical note: the blocking behavior applies to update, but you can use the --no-audit flag when you genuinely want to bypass the check in a controlled way, such as during a CI step that runs the audit as a separate, explicitly reported gate:
composer update --no-audit
composer audit --format=json > audit-report.json
The composer repo Command (2.9)
Before 2.9, managing repositories meant editing composer.json by hand or using composer config repositories.name ... with a syntax that many developers had to look up every time. Composer 2.9 ships a proper repo subcommand that gives you a clean CLI interface for the whole lifecycle.
# List all configured repositories
composer repo
# Add a VCS repository
composer repo add my-private-lib vcs https://github.com/myorg/private-lib
# Add a Composer-type repository (like a private Packagist)
composer repo add internal composer https://packages.mycompany.com
# Remove a repository
composer repo remove internal
# Update the URL of an existing repository
composer repo set-url my-private-lib https://github.com/myorg/private-lib-v2
This is genuinely useful for teams that manage multiple private repositories or switch between environments with different repository sources. The underlying JSON structure for repositories also changed: in 2.9, repositories are stored as a JSON array rather than an object, which improves readability and makes merge conflicts easier to resolve.
Lock File Conflict Recovery (2.9)
Anyone who has worked on a feature branch that ran composer update while another branch did the same knows the resulting composer.lock conflict is annoying. The file is enormous, and the only conflict is usually in the content-hash field at the top.
Composer 2.9 handles this automatically. If only the content-hash property is in conflict (with git conflict markers present), Composer can recover on its own:
# Composer reads the lock file and ignores the conflict markers
# in content-hash, then regenerates it correctly
composer update --lock
You can also just re-run an update of the specific package that caused the divergence. Composer will detect the conflicted-but-recoverable state and do the right thing. This is a small quality-of-life improvement that eliminates a category of manual intervention that felt like busywork.
Minimal Changes Updates (2.9)
Another useful addition is the --minimal-changes flag for full updates:
composer update --minimal-changes
When performing a full composer update (i.e., no specific package names listed), this flag tells Composer to only update packages that are actually required to satisfy changed constraints. Everything else that can stay pinned, stays pinned.
This is valuable in projects with strict stability requirements or when you need to update a specific constraint in composer.json but want to limit the blast radius of the resulting update. Instead of getting a full dependency refresh, you get a targeted one.
Malware Filter Lists (2.10)
Composer 2.10, which began rolling out in May 2026, builds on the security foundation of 2.9 with an important addition: malware filter lists. This is distinct from vulnerability advisories (which cover CVEs and known exploits in legitimate packages) and instead targets packages where malware has been detected and confirmed.
When using Composer 2.10 or newer, composer audit will surface packages that have been flagged for malware. More significantly, composer update will automatically exclude those flagged versions from consideration. The intent is to protect developers from supply chain attacks where a package is compromised after an attacker gains access to a maintainer account.
# Check your current installation against security advisories and malware flags
composer audit
# JSON output for CI integration
composer audit --format=json
# Check a lock file without installing anything
composer audit --locked
The malware filter list is maintained by Packagist and updated independently from the normal release cycle, so you get continuous protection as new threats are identified, not just at the point when you next update Composer.
Upgrading and Checking Your Version
If you installed Composer globally with the standard method, upgrading is straightforward:
composer self-update
# Upgrade to a specific channel
composer self-update --stable
composer self-update --2 # stay on 2.x branch
# Check current version
composer --version
For projects using Docker or CI images that pin a specific Composer version, check the pinned version in your Dockerfile or workflow and bump it. The Composer Docker image (composer:2) tracks the latest stable automatically, but composer:2.8 or similar pinned tags will not.
A Note on the composer audit Workflow
With security blocking now a first-class feature, the composer audit command deserves a permanent place in your CI pipeline even if you have not added it yet. The typical pattern looks like this:
# In your CI workflow (GitHub Actions, GitLab CI, etc.)
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: Security audit
run: composer audit --no-interaction
The audit command exits with a non-zero status if it finds advisories, which will fail your build. For teams that want to treat advisories as warnings rather than build failures during initial rollout, you can inspect the exit code or use || true with a separate reporting step, but the goal should be to get to a state where composer audit passing is a hard requirement.
The Bigger Picture
What makes the 2.9 and 2.10 releases significant is not any single feature but the direction they signal. Composer is moving toward being a security-aware package manager rather than a package resolver that optionally knows about security. That is the right direction. PHP’s ecosystem has had robust tooling for static analysis and testing for years. The package management layer catching up on security ergonomics makes the full toolchain meaningfully stronger.
If your project is still on Composer 2.7 or 2.8, the upgrade path is smooth and the payoff in reduced security exposure and improved daily ergonomics is real. Run composer self-update, review your audit output, and add the security check to CI if it is not there yet.
Sources
- Composer 2.9 Release - Packagist Blog
- Composer 2.9 Introduces Security Improvements and New Repository Tools - The Drop Times
- Composer 2.9 lands on Upsun PHP Images - Upsun Docs
- Composer 2.9.6 Perforce Driver Security Fix - Packagist Blog
- Composer Releases - GitHub
- What’s New in Private Packagist, May 2026 - Packagist Blog