Using Composer Audit to Find Security Issues
In the African savanna, a herd of elephants moves with purpose across the plains. Each step echoes with accumulated wisdom — the matriarch has memorized water sources, safe passages, and predator territories over decades. When drought approaches, this knowledge isn’t merely helpful; it’s the difference between survival and catastrophe. A young elephant that strays from the herd’s wisdom might drink from a contaminated waterhole or wander into territory guarded by a pride of lions.
Similarly, your PHP application’s dependencies form an ecosystem you must navigate with accumulated security knowledge. Each third-party library you install carries potential risks — unknown vulnerabilities that may have been discovered since your last update. Without systematic scanning, you’re essentially wandering blind, hoping none of your dependencies contain security flaws that could compromise your entire application.
In this article, we’ll show you how to use composer audit, a built-in Composer command that provides the accumulated security knowledge of that experienced matriarch — guiding you safely through the complex landscape of PHP dependencies. We’ll walk through everything from basic usage to automation, so you can integrate security scanning into your regular workflow.
Prerequisites
Before we begin, let’s establish what you’ll need:
- Composer 2.4 or later: The
auditcommand was introduced in Composer 2.4. If you’re using an older version, you’ll need to upgrade Composer first. - A
composer.lockfile: Composer Audit analyzes the locked versions in yourcomposer.lockfile, not only the requirements incomposer.json. This means you need to have runcomposer installat least once. - PHP 7.2 or later (for Composer 2.x): Composer itself requires PHP 7.2+, though your project may use any PHP version.
You can verify your Composer version by running:
composer --version
If you see something like Composer version 2.4.x or higher, you’re ready to proceed.
Tip: If you need to upgrade Composer, you can typically run
composer self-update. On some shared hosting environments, you might need to use a version manager likemiseto manage your Composer version.
Understanding Dependency Vulnerability Scanning
Modern PHP applications rely heavily on third-party packages — often dozens or hundreds of them. While this accelerates development, it also introduces security risks: a vulnerability in a single dependency can potentially compromise your entire application.
Dependency vulnerability scanning addresses this by automatically checking your project’s dependencies against databases of known security issues, such as the GitHub Advisory Database and the PHP Security Advisories Database. These databases are maintained by security researchers and the open source community, tracking newly discovered vulnerabilities as they’re reported.
The scanning process compares your exact dependency versions (from composer.lock) against the list of vulnerable versions in these databases. When a match is found, you’re alerted to the issue along with details about the affected package and recommended fixes.
Introducing composer audit
Since Composer 2.4, the audit command has provided built-in security vulnerability scanning directly in your Composer workflow. This command analyzes your composer.lock file and reports any known vulnerabilities in your installed package versions.
Command Usage
Let’s examine the basic syntax and options for composer audit:
composer audit [options]
The simplest form, with no options, scans your project’s dependencies and outputs any vulnerabilities it finds:
$ composer audit
Note: The
auditcommand reads yourcomposer.lockfile from the current working directory. Make sure you’re in your project’s root directory when running this command.
When no vulnerabilities are detected, you’ll see output like this:
No security vulnerability advisories found
When vulnerabilities are found, Composer displays them in a formatted table with details about each advisory.
Understanding the Audit Report
Let’s look at what a typical vulnerability report contains:
Found 1 security vulnerability advisory
+-------------------+------------------------------------------------------------------+
| Package | monolog/monolog |
| CVE | CVE-2022-12345 |
| Title | Improper Handling of Line Breaks in SMTP Handler |
| URL | https://github.com/advisories/GHSA-xxxx-yyyy-zzzz |
| Affected versions | >=2.0.0,<2.3.2 |
| Reported at | 2022-10-01 12:00:00 |
+-------------------+------------------------------------------------------------------+
Let’s examine each field:
- Package: The name of the vulnerable library — in this case
monolog/monolog. This tells you exactly which dependency needs attention. - CVE: The Common Vulnerabilities and Exposures identifier. This is a standardized reference number that you can search for additional information from other sources. Not all advisories have a CVE; some may use a GitHub Security Advisory (GHSA) identifier instead.
- Title: A brief description of the vulnerability. This gives you an initial sense of the issue’s nature — is it a SQL injection risk? An information disclosure problem? A denial-of-service vector?
- URL: A link to the full advisory. You should always click through to read the complete details, which typically include technical explanation of the vulnerability, its severity rating, and sometimes proof-of-concept exploits.
- Affected versions: The version range that’s vulnerable. In our example,
>=2.0.0,<2.3.2means all versions from 2.0.0 up to (but not including) 2.3.2 are affected. Any version 2.3.2 or higher is safe from this particular vulnerability. - Reported at: When the vulnerability was publicly disclosed. This helps you understand how long the vulnerability has been known — a vulnerability disclosed last week may be less concerning than one from several years ago (assuming you haven’t been able to update yet).
Warning: The presence of a vulnerability doesn’t necessarily mean your application is exploitable. Many vulnerabilities require specific conditions or configurations to be exploitable. However, you should treat all reported vulnerabilities seriously and assess your exposure based on your application’s specific usage of the vulnerable package.
Alternatives to Composer Audit
While composer audit is convenient and integrated directly into Composer, it’s not the only option for security scanning. Let’s briefly examine some alternatives you might consider.
Roave Security Check (formerly SecurityAdvisories): Before composer audit existed, many developers used the roave/security-advisories package. This package is a Composer “metapackage” that deliberately conflicts with vulnerable package versions, causing composer update to fail if you try to install a vulnerable package. You add it as a dev dependency in your composer.json. While effective, it requires manual updates to stay current and doesn’t provide as detailed reporting as the built-in audit command.
GitHub Dependabot: If you host your code on GitHub, Dependabot automatically monitors your dependencies and creates pull requests when security updates are available. It works by analyzing your dependency configuration and checking against the GitHub Advisory Database. Dependabot is generally recommended as a complementary tool — it’s proactive but doesn’t replace running an audit in your CI pipeline.
Third-Party Services: Commercial tools like Snyk, WhiteSource, and PHP Security Checker offer more advanced features including continuous monitoring, remediation advice, and integration with issue trackers. These are particularly valuable for enterprise environments with compliance requirements.
Static Analysis Tools: Tools like PHPStan with security extensions or Psalm with security plugins can detect some security-related code patterns (e.g., SQL injection vulnerabilities) that composer audit doesn’t cover. These analyze your code directly rather than your dependency versions.
Generally speaking, we recommend using a layered approach: composer audit for dependency version vulnerabilities, Dependabot for automated notifications, and static analysis for code-level security issues. This gives you comprehensive coverage.
Resolving Vulnerabilities: A Step-by-Step Workflow
When composer audit identifies a vulnerability, you need to update the affected package(s) to a secure version. Let’s walk through a systematic approach.
Step 1: Identify a Safe Version
The audit report includes the “Affected versions” field, which tells you which versions are vulnerable. To find a safe version, you need to choose a version that falls outside that vulnerable range.
For example, if the report shows >=2.0.0,<2.3.2, any version >=2.3.2 is considered safe from this vulnerability. You’ll want to check the package’s changelog or release notes on Packagist or GitHub to see what version patches were released.
# View package information including available versions
composer show monolog/monolog --all
Tip: Sometimes the vulnerable version constraint comes from a dependency of one of your direct dependencies. In such cases, you might not be able to update the vulnerable package directly — you’ll need to update the parent package that requires the vulnerable version. Composer’s dependency visualization can help:
composer depends monolog/monolog.
Step 2: Update the Package
Once you’ve identified a safe version, update the package using composer update. It’s generally best to update one vulnerable package at a time so you can isolate changes and test thoroughly:
# Update a specific package and its dependencies
composer update monolog/monolog --with-dependencies
The --with-dependencies flag ensures that any dependencies needed by the updated package are also updated if necessary. This is often important for resolving version conflicts that can arise when one package’s requirements change.
Warning: Updating packages can introduce breaking changes, especially if the update involves a major version jump (e.g., from 1.x to 2.x). Always read the package’s upgrade guide or changelog before updating to understand potential breaking changes. Then test your application thoroughly.
Step 3: Verify the Fix
After updating, run composer audit again to verify that the vulnerability has been resolved:
$ composer audit
No security vulnerability advisories found
If vulnerabilities remain, you may need to update additional packages or adjust your approach. Sometimes a package’s dependencies also need updating to resolve all issues.
Step 4: Test Your Application
With dependencies updated, run your application’s test suite to ensure the upgrades haven’t introduced any regressions:
# Run your test suite (adjust command as needed for your framework)
$ ./vendor/bin/phpunit
If you don’t have an automated test suite, you should manually exercise the functionality that uses the updated packages. Pay particular attention to areas where the vulnerable package is used.
Step 5: Commit the Changes
Once you’ve verified that the vulnerability is fixed and your application works correctly, commit the updated files to version control:
$ git add composer.json composer.lock
$ git commit -m "Update monolog/monolog to 2.3.2 for CVE-2022-12345"
It’s good practice to reference the CVE or advisory identifier in your commit message so future maintainers understand why the update was necessary.
Automating Audits with CI/CD
Manually running composer audit is a good start, but for continuous security, you should automate it. Integrating it into your Continuous Integration (CI) pipeline ensures that new vulnerabilities are caught before they reach production.
Note: The
composer auditcommand was introduced in Composer 2.4. If you’re using an older CI environment that hasn’t been updated, you’ll need to upgrade Composer in your CI configuration first.
GitHub Actions Example
Here’s a straightforward workflow that runs on every push to your main branch:
name: Security Audit
on:
push:
branches: [main, master]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
tools: composer:v2
- name: Install Dependencies
run: composer install --no-dev --prefer-dist --no-progress --no-interaction
- name: Run Composer Audit
run: composer audit --no-interaction
Notice we’ve added the --no-interaction flag to ensure the command doesn’t hang waiting for input in the CI environment. This workflow will automatically fail if any security vulnerabilities are detected, preventing the vulnerable code from being merged or deployed.
GitLab CI Example
For GitLab CI, you’d create a .gitlab-ci.yml file:
composer_audit:
image: composer:2
script:
- composer install --no-dev --prefer-dist --no-progress --no-interaction
- composer audit --no-interaction
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
Other CI Systems
The pattern is similar for other CI systems like Jenkins, CircleCI, or GitHub Codespaces. The key points are:
- Install dependencies (use
--no-devfor production deployments) - Run
composer auditwith--no-interactionfor automated environments - Let the build fail if vulnerabilities are found
Warning: Running
composer auditin CI only checks the versions in yourcomposer.lockagainst currently known vulnerabilities. It doesn’t prevent new vulnerabilities from being introduced after the audit runs. For continuous protection throughout your dependency lifecycle, consider combiningcomposer auditwith Dependabot or similar tools that monitor for new advisories after deployment.
Troubleshooting Common Issues
Let’s address some challenges you might encounter.
”No security vulnerability advisories found” but I know there are vulnerabilities!
First, verify that your composer.lock file actually contains the packages you think it does:
$ composer show -l
Second, composer audit relies on data from the PHP Security Advisories Database. This database is updated regularly, but if your Composer cache is old, you might not have the latest advisory data. Try clearing Composer’s cache:
composer clear-cache
composer audit
Tip: You can also update the security advisories database explicitly:
composer update --no-dev friendsofphp/security-advisories. Note that this package is typically installed as a dev dependency and is updated automatically when you runcomposer update.
The audit command is not recognized
If you get Command "audit" is not defined, you’re using Composer version older than 2.4. You’ll need to upgrade:
composer self-update
If you’re on a shared host where you can’t update the global Composer, consider using a version manager like mise to manage your PHP and Composer versions per-project.
Composer hangs or times out
On slower connections or with large dependency trees, the initial advisory database download might time out. You can try:
- Ensure you have adequate network connectivity
- Run
composer audit --no-pluginsto disable plugins that might interfere - Increase Composer’s process timeout:
export COMPOSER_PROCESS_TIMEOUT=2000
Vulnerabilities in transitive dependencies I can’t control
Sometimes the vulnerability exists in a package that’s several levels deep in your dependency tree. You might not be able to update it directly because its version is constrained by a parent package. In these cases:
- Check if the parent package has a newer version that resolves the constraint
- Consider filing an issue or pull request with the maintainer of the parent package
- As a last resort, you can use
composer replaceto override the vulnerable package, though this requires careful testing
Warning: Overriding dependencies with
composer replacecan create compatibility issues. Only use this approach if you understand the package’s API and compatibility requirements. It’s generally better to work with upstream maintainers to get a proper fix released.
Conclusion
In the African wilderness, the herd’s accumulated wisdom enables survival through drought and danger. Similarly, composer audit gives you that accumulated security knowledge — automatically checking your dependencies against known vulnerabilities so you can act before threats materialize.
Key takeaways for maintaining secure PHP applications:
- Run
composer auditregularly, ideally in your CI pipeline on every push or at least daily on your main branch - Address vulnerabilities promptly — the longer you wait, the more time attackers have to exploit known issues
- Use a layered security approach: combine
composer auditwith tools like Dependabot and static analysis - Understand the limitations:
composer auditonly catches known vulnerabilities with published advisories; zero-day vulnerabilities won’t appear until they’re reported - Keep Composer itself updated to benefit from the latest security features and advisory database
By making security scanning a routine part of your development workflow, you significantly reduce your application’s attack surface and build more robust, resilient software. The matriarch’s wisdom protects the herd — let composer audit protect your application.
Further Reading
Sponsored by Durable Programming
Need help with your PHP application? Durable Programming specializes in maintaining, upgrading, and securing PHP applications.
Hire Durable Programming