hexblot / composer-remediate
Composer plugin that traces vulnerable dependencies to the packages you control and uses Composer's own solver to find the smallest verified upgrade that removes them.
Package info
github.com/hexblot/composer-remediate
Type:composer-plugin
pkg:composer/hexblot/composer-remediate
Requires
- php: ^8.1
- composer-plugin-api: ^2.0
- symfony/yaml: ^5.4 || ^6.4 || ^7.0 || ^8.0
Requires (Dev)
- composer/composer: ^2.9
- justinrainbow/json-schema: ^5.2 || ^6.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^10.5
Suggests
- ext-pdo_sqlite: Required to build or read a local advisory database (remediate db:build, --database-location)
- ext-zip: Required by remediate db:build to read the OSV and FriendsOfPHP archives
Provides
None
Conflicts
None
Replaces
None
README
From vulnerable dependency to verified Composer fix.
composer audit tells you which packages are vulnerable. composer remediate searches for the
least invasive composer update command that removes the vulnerability, proves each candidate with
Composer's own dependency solver, and recommends the best verified one. The search is bounded and
ranked, not exhaustive: the report says when a limit was hit.
$ composer remediate
CVE-2026-XXXXX symfony/http-foundation 6.4.21
Introduced by
root
└── drupal/core-recommended 11.4.2
└── symfony/http-foundation 6.4.21
Recommended remediation
drupal/core-recommended 11.4.2 -> 11.4.3 (3 packages updated, 0 added, 0 removed)
Composer validation
PASS
Recommended command
composer update drupal/core-recommended -W -m
Advisories come from the database this project publishes: a copy is kept at a fixed path under
Composer's cache directory, checked against the publisher on every run and verified by checksum, so
reports carry exploit data (FIRST EPSS, CISA KEV) and say where the advisory data has gaps. A plain run therefore
makes one small request to GitHub. --no-database asks your configured repositories instead, exactly
as composer audit does, and --offline uses the copy already on disk. See
Advisory database and
Privacy and network behaviour.
Status: released as 0.x on Packagist;
nothing is written to your project unless you ask for it with --apply. Most of the original roadmap
is now delivered: the search for the one
command that fixes every finding, --apply to run that command for you, and a GitHub Action that
opens a single pull request with the fixes applied. What is still to come is on the
roadmap.
It is tested against seventeen real historical projects, and the independent reviews and their rechecks are answered in the changelog, each finding with a test. Current state, fixtures and evidence: hexblot.github.io/composer-remediate.
Using it as a CI gate
The command exits 0 when the lock is clean, 1 when vulnerabilities have a verified fix, 2 when
at least one has no verified fix yet, and 3 to 5 for tool, advisory-data or network errors. A
typical gate fails on 1 (apply the recommended command), warns on 2, and keeps the HTML or JSON
report as an artifact:
composer global config --no-plugins allow-plugins.hexblot/composer-remediate true
composer global require hexblot/composer-remediate
composer remediate --no-dev --output=remediation-report.html --output=remediation-report.json
Add --fail-on high to let low and medium findings pass, --output=results.sarif for GitHub Code
Scanning annotations, or --output=sbom.cdx.json for a CycloneDX SBOM with the fixes attached.
Pin the version in CI. Before 1.0 a minor release may change exit codes, report fields or how the advisory database is chosen, so a pipeline that installs whatever is newest can change behaviour between two runs nobody touched. Install an exact version and move it on purpose:
composer global require hexblot/composer-remediate:0.11.0
A composer require --dev in a project is already pinned by its composer.lock. If you parse the JSON
report, validate it against the report-v<N>.schema.json for the schema_version you read; those
files never change once published.
For a project you do not trust, run the shipped composer-remediate binary instead of
composer remediate: it starts Composer with plugins and scripts disabled and never loads the
project's autoloader, so no code from the analysed project runs.
Ready-made GitHub Actions and GitLab CI jobs, and jq recipes for severity-based gates, are in the
CI integration guide. Every command
and option is listed in the CLI reference.
Development
PHP and Composer run inside ddev:
ddev start ddev composer install ddev composer --working-dir=tools/deptrac install # once: the architecture rules need PHP 8.2+ ddev composer check # phpstan + deptrac + phpunit
Changes under src go through a pull request, one branch per change; documentation and changelog
edits can go straight to main. While a pull request is a draft, CI runs a single job on PHP 8.4.
Marking it ready for review runs the tests against every supported version: PHP 8.1 to 8.5, and
Composer 2.4 to 2.9. The
contributing guide has the rest.
Documentation is built with MkDocs (pipx run --spec mkdocs --pip-args=pymdown-extensions mkdocs serve) and published from main to GitHub
Pages. The CLI reference and case-studies pages are generated (ddev composer cli-reference,
ddev composer case-studies) and checked in CI.
Sponsor
Development of Composer Remediate is sponsored by Lambda Twelve, which funds the maintainer's time and the tooling costs behind the work, including the AI assistance used during development. The project takes no money from users and has no commercial tier.
Acknowledgement
CVE Lite CLI is an OWASP project that gives JavaScript and TypeScript developers local-first, lockfile-based vulnerability scanning with copy-and-run fix commands and parent-aware guidance for transitive dependencies. Composer Remediate was inspired by that approach, applying it to Composer's dependency model and using Composer's own solver to prove each recommendation before it is shown.
License
MIT. See LICENSE.