Think running composer update is good enough? Think again.
Composer audit scans your installed PHP packages against Packagist/GitHub advisories and spits vulnerabilities straight to your terminal.
It ships with Composer 2.4+ and exits non-zero when it finds issues, so you can fail builds in CI.
Run it before you push, after dependency changes, and schedule it in pipelines to catch problems early.
This post shows how to run a full audit, read the output, and fix or automate remediations so you stop shipping avoidable security bugs.
Running a Full Composer Audit to Check PHP Dependencies for Vulnerabilities

Composer’s composer audit command scans your installed PHP packages against known security advisories and spits out vulnerabilities right in your terminal. This feature landed in Composer 2.4 back in summer 2022. It queries Packagist’s Security Advisory API, which pulls data from GitHub Security Advisories and the FriendsOfPHP/security-advisories repository. You should be running this regularly. Before you push code, after updating dependencies, and automatically in CI/CD to catch problems early.
You’ll need Composer 2.4 or later. Running something older? Update first with composer self-update. When you fire up composer audit, Composer checks the versions in your vendor/ directory (or composer.lock) against the advisory database and returns a non-zero exit code equal to the number of vulnerabilities it finds. Zero exit code? You’re clean. This exit code behavior makes it perfect for automated enforcement. Your pipeline can kill the build if vulnerabilities show up.
Here’s how to run a full audit:
- Update Composer to at least version 2.4:
composer self-update - Navigate to your project directory where
composer.jsonandcomposer.locklive. - Run the audit command:
composer audit - Review the terminal output. It’ll list any advisories with package names, affected version ranges, CVE identifiers, and links to the full details.
- Check the exit code by running
echo $?(Linux/macOS) orecho %errorlevel%(Windows) right after. Non-zero means vulnerabilities were found.
By default, composer audit shows results in table format. You can switch this with --format=json for machine-readable output or --format=plain for simple text. For example, if you install guzzlehttp/guzzle version 7.4.4, you’ll get a vulnerability warning like “Found 1 security vulnerability advisory affecting 1 package” and it’ll tell you to run composer audit for the complete picture.
Understanding Composer Audit Output for PHP Dependency Security

When you run composer audit, you get the full advisory report with everything. If you ran composer update, composer require, or composer install --audit, you saw a shortened version that only shows advisory IDs and affected version ranges. Those abbreviated results come from package metadata and don’t actually hit the Security Advisory API. Want complete details including CVE identifiers, advisory titles, publication dates, and clickable links? Always run the standalone composer audit command.
Each line in the full audit output describes one vulnerability. You’ll see the package name (like symfony/http-kernel), a CVE identifier if one exists (like CVE-2023-12345), a short title summarizing the issue, a URL to the full advisory (usually on GitHub Security Advisories or the FriendsOfPHP repo), the affected version range, and the date the advisory was published or updated. Severity info might show up in the advisory title or in the linked report. Need to parse this data in a script? Use --format=json to get structured output with fields like advisoryId, packageName, affectedVersions, cve, and link.
| Field | Description | Example |
|---|---|---|
| Package | Fully qualified package name | guzzlehttp/guzzle |
| CVE | Common Vulnerabilities and Exposures identifier (if assigned) | CVE-2022-29248 |
| Affected Versions | Version constraint showing vulnerable releases | >=7.0.0,<7.4.5 |
| Advisory Link | URL to full write-up and mitigation steps | https://github.com/advisories/GHSA-xxxx-yyyy-zzzz |
Updating and Remediating Vulnerable Composer PHP Dependencies

Once composer audit flags a package, you need to update it to a safe version. Check the “Affected Versions” range in the audit output to see which releases are vulnerable, then look for a newer version outside that range. You can update a single package with composer update vendor/package or adjust the version constraint in composer.json and run composer update. Say guzzlehttp/guzzle 7.4.4 is vulnerable and 7.4.5 fixes it. Update your constraint to "guzzlehttp/guzzle": "^7.4.5" and run composer update guzzlehttp/guzzle.
Use composer outdated to see which packages have newer releases. This command lists your installed version, the latest version your constraints allow, and the latest version overall. It doesn’t check for vulnerabilities. It just shows available upgrades. Pair it with composer audit to both identify security issues and find safe upgrade targets. Watch out for semantic versioning. A caret constraint like ^2.3 allows updates to 2.x but blocks 3.0, which reduces breaking changes. If the vulnerability’s in a transitive dependency (a package required by one of your direct dependencies), you might need to update the parent package or use composer why vendor/package to trace where it’s coming from.
Remediation steps:
- Update the package:
composer update vendor/packageto grab the latest allowed version. - Tighten the constraint: Edit
composer.jsonto require a minimum safe version (like^2.5.1) then runcomposer update. - Check transitive dependencies: Use
composer why vendor/packageto see which direct dependency pulls in the vulnerable package. - Replace abandoned packages: Composer 2.7+ warns about abandoned packages in audit output. Switch to the suggested replacement as soon as you can.
- Force a newer version: If a parent package is slow to update, you can sometimes override with a higher minimum in your own
composer.json. - Review breaking changes: Before jumping to a new major version, read the package’s changelog or upgrade guide so you don’t break things at runtime.
Integrating Composer Audit into CI/CD for Ongoing PHP Dependency Security

The best way to enforce dependency security is to run composer audit in every CI/CD pipeline and fail the build if it finds vulnerabilities. Because composer audit exits with a non-zero code when it discovers advisories, most CI systems (GitHub Actions, GitLab CI, Jenkins, CircleCI) will automatically mark the step as failed. You can run the check after installing dependencies with composer install --no-dev (to skip dev packages) and then run composer audit as a separate step, or use composer install --audit to get an abbreviated scan during install.
Set up a scheduled job to run audits even when you’re not actively deploying. A common pattern is running composer audit every two hours in a cron-triggered pipeline. For critical applications handling sensitive data or high traffic, consider running it every hour. This way, if a new advisory drops for a package you already have installed, you’ll know within a short window. Combine automated audits with alert notifications. Send Slack messages, email, or PagerDuty alerts when the audit step fails so your team can respond fast.
CI/CD implementation steps:
- Add a dependency install step in your pipeline:
composer install --no-dev --prefer-dist - Run the audit command:
composer auditor usecomposer install --auditto get an abbreviated scan during install. - Check the exit code: Most CI systems fail automatically on non-zero exit. No extra scripting needed.
- Optionally filter output format: Add
--format=jsonif you want to parse results and send structured alerts. - Schedule regular scans: Configure a cron job or scheduled pipeline to run
composer auditevery 1 to 2 hours. - Set up notifications: Route audit failures to Slack, email, or incident management tools so the team gets alerted immediately.
Differences Between Composer Audit and Composer Outdated for PHP Projects

composer audit and composer outdated do different jobs and you should use both for complete dependency hygiene. composer audit checks your installed packages against a vulnerability database and reports security advisories. It only cares about known exploits and won’t tell you about newer versions unless they’re relevant to fixing a CVE. composer outdated lists every package that has a newer release, showing your current version, the latest version your constraints allow, and the absolute latest version. It doesn’t mention security at all. It’s purely a version-tracking tool.
Run composer outdated regularly to stay current with bug fixes, performance improvements, and new features. Then run composer audit to catch any packages with disclosed vulnerabilities. If a package shows up in both lists, prioritize the security update first. composer audit tells you the issue is urgent, and composer outdated tells you which version to target.
Comparison:
- Purpose:
composer auditreports vulnerabilities.composer outdatedshows available updates. - Data source:
composer auditqueries Packagist’s Security Advisory API.composer outdatedreads package metadata from Packagist’s main API. - Exit code:
composer auditexits non-zero when vulnerabilities are found.composer outdatedalways exits zero (it just displays information). - Use case: Use
composer auditto enforce security policies in CI. Usecomposer outdatedto plan maintenance and keep dependencies fresh.
Using Additional Tools and APIs Alongside Composer Audit for Stronger PHP Dependency Security

While composer audit covers most use cases, you can layer in extra tools for defense in depth. The roave/security-advisories package is a popular complement. It’s a meta-package that defines conflict rules for every known vulnerable version in the FriendsOfPHP advisory database. Add it to your require-dev section and Composer will refuse to install or update to a vulnerable version. This blocks bad packages before they land in your vendor/ directory, while composer audit reports issues after installation. Think of roave/security-advisories as a preventive control and composer audit as a detective control.
The Symfony CLI includes a security:check command (formerly the standalone Local PHP Security Checker) that scans composer.lock and reports advisories. It’s useful as a second opinion or if you prefer Symfony’s output format. You can also bring in third-party services like Snyk, which scans your repository, monitors your dependencies continuously, and sends alerts when new CVEs drop. Snyk’s GitHub Action can run on every pull request and add inline comments with remediation advice.
Building custom tooling or dashboards? Query the Packagist Security Advisory API directly at https://packagist.org/api/security-advisories/. Pass a packages parameter with a list of package names and an optional updatedSince Unix timestamp to fetch only recent changes. The API returns JSON with advisory IDs, affected version ranges, and links to full reports. This is the same endpoint composer audit uses under the hood.
| Tool | Approach | Best For |
|---|---|---|
| roave/security-advisories | Conflict rules block vulnerable versions during install/update | Preventing bad installs in development and CI |
| Symfony security:check | Scans composer.lock and reports advisories | Quick local checks and alternative CI validation |
| Snyk | Continuous monitoring with alerts and PR comments | Proactive alerts and cross-project visibility |
Troubleshooting Issues When Running Composer Audit on PHP Dependencies

If composer audit isn’t working right, start by checking your Composer version. The audit command and related flags were added in Composer 2.4. If you’re on 2.3 or earlier, run composer self-update and try again. Network issues are another common problem. The audit queries Packagist’s API over HTTPS, so if your CI runner or local machine is behind a restrictive firewall or proxy, the request might time out or fail silently. Check your network logs and make sure outbound HTTPS to packagist.org is allowed.
Sometimes you’ll see an advisory listed for a version that doesn’t match what you have installed. This happens when the advisory’s affected version range is written broadly or when you’re looking at the abbreviated audit output from composer install --audit instead of the full composer audit report. Always run the full command to get exact version constraints and links. If you think an advisory is a false positive, verify your installed version with composer show vendor/package and compare it against the advisory’s affected range. You can also clear Composer’s cache with composer clear-cache and re-run the audit to rule out stale metadata.
Troubleshooting steps:
- Upgrade Composer: Run
composer self-updateto make sure you’re on Composer 2.4 or later. - Check network access: Verify your machine or CI runner can reach
packagist.orgover HTTPS. - Clear the cache: Run
composer clear-cacheand trycomposer auditagain. - Run full audit instead of abbreviated: If you only saw advisory IDs during
composer update, runcomposer auditto get complete details. - Verify installed versions: Use
composer show vendor/packageto confirm the version and compare it against the advisory’s affected range to rule out false positives.
For edge cases like private packages or internal forks, remember that composer audit only knows about advisories published to Packagist or GitHub Security Advisories. If you maintain proprietary packages, you’ll need to publish your own advisories or use an internal scanning tool that understands your private repository structure.
Best Practices for Maintaining Secure PHP Dependencies with Composer Audit

Security is a habit, not a one-time task. Run composer audit locally before every commit and in CI on every push. Commit your composer.lock file to version control so everyone on the team and your CI pipeline installs the exact same versions. This makes audit results consistent and prevents “works on my machine” surprises. Set up scheduled scans (every 1 to 2 hours) to catch newly disclosed vulnerabilities even when you’re not actively deploying code.
Keep your dependencies lean. The fewer packages you depend on, the smaller your attack surface and the easier it is to audit and update. Review your require and require-dev sections regularly and remove anything you no longer use. When a package gets flagged as abandoned, replace it quickly. Composer 2.7+ will exit non-zero during audit if you depend on an abandoned package, and you can configure this behavior in composer.json if you need more flexibility.
Best practices:
- Run
composer auditin CI and fail builds on non-zero exit to enforce security gates. - Commit
composer.lockso everyone uses the same versions and audit results are reproducible. - Schedule regular audits (every 1 to 2 hours) to catch new advisories between deployments.
- Keep Composer itself updated with
composer self-updateto get the latest audit features and security fixes. - Use
composer outdatedalongside audit to find safe upgrade targets and keep dependencies current. - Minimize dependencies by removing unused packages and avoiding bloated libraries.
- Replace abandoned packages as soon as Composer flags them. Don’t wait for a security issue.
- Integrate
roave/security-advisoriesin development to block vulnerable versions before they’re installed.
Final Words
In the action, we ran a full composer audit, parsed its output, and walked through safe updates and CI gating so vulnerabilities don’t slip into production.
You learned when to use Composer 2.4+, how to read CVE and severity details, and practical remediation steps for direct and transitive packages. The guide also covered troubleshooting and extra tools to strengthen scans.
Keep composer audit php dependencies in your regular workflow and CI; it catches issues early and makes upgrades less painful.
FAQ
Q: What does composer audit do and when should I use it?
A: The composer audit command checks your PHP dependencies for known vulnerabilities by querying Packagist’s Security Advisory API; use it after dependency changes, before releases, and in CI for continuous checks.
Q: What Composer version is required to run composer audit?
A: Composer audit requires Composer 2.4 or newer; the feature landed in summer 2022, so update with composer self-update before running if you’re on an older release.
Q: How do I run composer audit (quick steps)?
A: To run composer audit, ensure Composer 2.4+, cd to your project root, run composer audit, use –format=json for automation, and note non-zero exit codes equal the number of findings.
Q: What does a non-zero exit code from composer audit mean?
A: A non-zero exit code from composer audit means vulnerabilities were found; the exit code equals the count of reported issues, letting CI fail builds automatically.
Q: What information appears in composer audit output and when should I use –format=json?
A: Composer audit output includes package, CVE (if present), advisory title, link, affected ranges, and dates; use –format=json when you need machine-readable results for automation or triage.
Q: How should I remediate vulnerable packages reported by composer audit?
A: To remediate, run composer outdated to find updates, adjust version constraints, run composer update vendor/package safely, consider patching or swapping abandoned libraries, and retest before deploying.
Q: How do I handle transitive vulnerabilities found by composer audit?
A: To handle transitive vulnerabilities, run composer why to trace which package requires it, update the parent package, open an upstream PR, or vendor/replace the transitive dependency if needed.
Q: How can I integrate composer audit into CI/CD pipelines?
A: Integrate composer audit by running it in your pipeline, fail on non-zero exit codes, schedule regular scans (hourly or every few hours for critical apps), and use –format=json for alerts.
Q: What’s the difference between composer audit and composer outdated?
A: Composer audit checks for security advisories; composer outdated lists newer package versions. Use audit for safety checks and outdated when planning upgrades—together they guide secure maintenance.
Q: What extra tools should I use with composer audit for stronger PHP dependency security?
A: Use tools like roave/security-advisories to block installs, Snyk or Symfony PHP Security Checker for deeper scans, and Packagist’s advisory API for supplemental feeds and automation.
Q: What common issues occur when running composer audit and how do I fix them?
A: Common issues include outdated Composer, network blocks to Packagist, stale cache, and false positives; fix by composer self-update, ensuring network access, clearing cache, and using –locked or updating constraints.
Q: What are best practices for maintaining secure PHP dependencies with composer audit?
A: Best practices include running composer audit locally and in CI regularly, committing composer.lock, pruning unused deps, replacing abandoned packages quickly, and automating alerts for critical findings.
