Security 10 min read

Composer Audit: Find and Fix PHP Dependency Vulnerabilities

Learn how to run composer audit to detect security vulnerabilities in your PHP dependencies, fix them with composer update, and automate audits in your CI/CD pipeline.

Matt King
Matt King
March 7, 2026
Last updated: March 27, 2026
Composer Audit: Find and Fix PHP Dependency Vulnerabilities

The average Laravel application pulls in 80 to 120 Composer packages. Each one is a potential entry point for attackers if a vulnerability is disclosed and you do not update in time. In 2025 alone, over 400 PHP package vulnerabilities were added to the Security Advisories Database.

composer audit is the built-in tool for catching these before they reach production. This guide covers everything you need to know: how it works, how to fix what it finds, how to automate it in CI/CD, and how it compares to other tools like Dependabot.

What composer audit does

Composer audit was introduced in Composer 2.4. It reads your composer.lock file and checks every installed package against the PHP Security Advisories Database, which aggregates CVEs from the National Vulnerability Database, GitHub Security Advisories, and package maintainer reports.

composer audit

Here is what typical output looks like:

Found 2 security vulnerability advisories affecting 2 packages:

+-------------------+------------------------------+
| Package           | symfony/http-foundation      |
| CVE               | CVE-2024-5678                |
| Title             | Request validation bypass    |
| URL               | https://...                  |
| Affected versions | >=5.0.0, <5.4.5             |
| Reported at       | 2024-03-15T00:00:00+00:00   |
+-------------------+------------------------------+

+-------------------+------------------------------+
| Package           | guzzlehttp/guzzle            |
| CVE               | CVE-2023-9101                |
| Title             | SSRF in HTTP request handler |
| URL               | https://...                  |
| Affected versions | >=6.0.0, <6.5.3             |
| Reported at       | 2023-11-02T00:00:00+00:00   |
+-------------------+------------------------------+

If no vulnerabilities are found, it returns exit code 0. If vulnerabilities exist, it returns a non-zero exit code, which makes it easy to use as a gate in automated pipelines.

How to fix vulnerabilities

Option 1: Update specific packages

The safest approach is to update only the affected packages:

composer update symfony/http-foundation guzzlehttp/guzzle

This updates just those packages (and their dependencies) to the latest versions allowed by your composer.json constraints. Run composer audit again to confirm the fix.

Option 2: Update all packages

If you are comfortable updating everything:

composer update

This is faster but carries more risk of breaking changes. Always run your test suite after a bulk update.

Option 3: When you cannot update

Sometimes a fix requires a major version bump that would break your application. In that case:

  1. Check if the vulnerability actually affects your usage. Read the CVE description carefully. A vulnerability in a feature you do not use may be lower priority.
  2. If you must stay on the current version, consider adding a workaround (input validation, WAF rule, or middleware) while you plan the upgrade.
  3. Document the decision. A suppressed vulnerability should be a conscious, tracked choice, not something that gets forgotten.

Handling version constraints

If composer update does not resolve a vulnerability, your composer.json constraints may be too tight. For example, if you require "symfony/http-foundation": "^5.4" and the fix is in 6.0, you need to update the constraint:

{
    "require": {
        "symfony/http-foundation": "^6.0"
    }
}

Then run composer update symfony/http-foundation and test thoroughly, since major version bumps often include breaking changes.

Output formats

Composer audit supports multiple output formats for different use cases:

# Human-readable table (default)
composer audit

# JSON for CI/CD parsing and dashboards
composer audit --format=json

# Plain text for simple scripts
composer audit --format=plain

# Only check production dependencies
composer audit --no-dev

The JSON format is particularly useful for integrating with security dashboards or Slack notifications:

composer audit --format=json | jq '.advisories | length'
# Returns: 2

Automating composer audit in CI/CD

GitHub Actions

Add this to your workflow to block PRs and deployments with known vulnerabilities:

name: Security Audit

on:
  push:
    branches: [main, develop]
  pull_request:
  schedule:
    - cron: '0 8 * * 1'  # Every Monday at 8am

jobs:
  security-audit:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'

      - name: Install dependencies
        run: composer install --no-interaction --prefer-dist

      - name: Run security audit
        run: composer audit --format=json

The schedule trigger is important. New CVEs are disclosed constantly, and a Monday morning audit catches anything published over the weekend, even if no code changed.

GitLab CI

security-audit:
  stage: test
  script:
    - composer install --no-interaction --prefer-dist
    - composer audit
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_PIPELINE_SOURCE == "schedule"'

Bitbucket Pipelines

pipelines:
  default:
    - step:
        name: Security Audit
        caches:
          - composer
        script:
          - composer install --no-interaction --prefer-dist
          - composer audit

Composer audit vs Dependabot vs Snyk

Feature composer audit Dependabot Snyk
Cost Free (built-in) Free (GitHub) Free tier / paid
When it runs On demand / CI Continuously Continuously
Auto-fix PRs No Yes Yes
Database PHP Security Advisories GitHub Advisory Database Snyk Vulnerability DB
PHP-specific Yes Yes Yes
License scanning No No Yes
Container scanning No No Yes

Our recommendation: Use them together. Composer audit in CI catches vulnerabilities at deploy time. Dependabot catches them between deployments and opens fix PRs automatically. They complement each other.

Setting up Dependabot for PHP

Create .github/dependabot.yml in your repository:

version: 2
updates:
  - package-ecosystem: "composer"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10

Real-world example: Responding to a critical CVE

Here is a typical workflow when a critical vulnerability is disclosed:

  1. Your Monday morning CI schedule runs composer audit and fails
  2. You check the output and find a critical CVE in a package you use
  3. You run composer update package/name locally
  4. You run your test suite to verify nothing breaks
  5. You push the fix and the audit passes
  6. Production is updated within hours of the disclosure

For a recent real-world example, see our post on the Livewire RCE vulnerability (CVE-2025-54068), which was a critical remote code execution flaw that composer audit would have flagged immediately after the advisory was published.

Common issues and solutions

"No lock file found"

Composer audit requires a composer.lock file. If you do not commit your lock file (you should), generate one first:

composer install
composer audit

Old Composer version

Composer audit requires version 2.4 or later. Check your version and upgrade if needed:

composer --version
composer self-update

False sense of security

Composer audit only checks against known, disclosed vulnerabilities. It cannot find zero-day exploits or vulnerabilities that have not been reported to the database yet. It is one layer of defense, not the only one.

For a more complete picture of your application's security posture, combine composer audit with:

Summary

What Command
Run a basic audit composer audit
JSON output for CI composer audit --format=json
Skip dev dependencies composer audit --no-dev
Fix specific packages composer update package/name
Fix all packages composer update
Check Composer version composer --version

Run it locally. Run it in CI. Run it on a schedule. The five seconds it takes to run composer audit is nothing compared to the cost of deploying a known vulnerability to production.


Want continuous monitoring beyond just dependencies? Run a free StackShield scan to check your full external attack surface, including security headers, exposed files, DNS configuration, and more.

Frequently Asked Questions

What does composer audit do?

Composer audit scans your composer.lock file against the PHP Security Advisories Database and reports any packages with known vulnerabilities. It shows the CVE identifier, severity level, affected version, and the version that contains the fix.

How do I fix vulnerabilities found by composer audit?

Run composer update followed by the package names listed in the audit output. For example: composer update symfony/http-foundation guzzlehttp/guzzle. If a major version upgrade is needed and could break your code, pin to the latest safe minor version in your composer.json first, then run composer update.

Should I run composer audit in CI/CD?

Yes. Adding composer audit to your CI/CD pipeline ensures no deployment goes out with known-vulnerable dependencies. You can use the --format=json flag for machine-readable output and fail the build on any findings. Most teams add it alongside their test suite so it runs on every pull request.

What is the difference between composer audit and Dependabot?

Composer audit is a local CLI command that checks your lock file on demand or in CI. Dependabot is a GitHub service that monitors your repository continuously and opens pull requests when new vulnerabilities are disclosed. They complement each other: composer audit catches issues at deploy time, while Dependabot catches them between deployments.

Can composer audit check dev dependencies?

Yes, composer audit checks all dependencies in your lock file by default, including dev dependencies. You can exclude dev packages by running composer audit --no-dev if you only want to audit production dependencies.

Stay Updated on Laravel Security

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