Run composer audit with the locked option in CI. It checks the packages in composer.lock against security advisories, returns exit code 1 if it finds packages matching your dependency policies, and exit code 0 when there are no issues. Add no-dev if you only ship production packages.
What the command does
The Composer documentation describes audit as checking installed packages against dependency policies. It looks for security advisories and also detects abandoned and malware-flagged packages. By default it uses the Packagist.org API, or other repositories if you configure them.
By default it audits what is installed. The locked option changes that: it audits packages from the lock file, regardless of what is currently in the vendor directory. In CI that is what you want, since the lock file is the reviewed record.
Options that matter
| Option | Effect |
|---|---|
| locked | Audit the lock file, not the vendor directory |
| no-dev | Skip require-dev packages |
| format | table (default), plain, json or summary |
| abandoned | ignore, report or fail |
| ignore-severity | Skip advisories of a given severity, repeatable |
A CI step
composer audit --locked --no-dev --format=json
Run the step on every pull request and on a schedule. Advisories are published after code is merged, so a scheduled run catches new findings in code that has not changed.
Choosing how strict to be
- Start by failing on any advisory in production packages.
- Run a second, informational job for dev packages, since they run in your build but not in production.
- Set abandoned to report first. Switch it to fail once you have cleaned up, so new abandoned packages are noticed.
- Use ignore-severity sparingly, and write the reason in the pull request that adds it.
What audit does not tell you
A clean result means no matching advisory is known right now. It does not say your code reaches a vulnerable function, and it does not cover code copied into your repository. Treat it as one input.
Keeping the lock file honest
Composer says to commit composer.lock to your project repository so everyone shares the same versions. For libraries it is not necessary to commit it. Running install with a lock file uses the exact versions listed in it, while update fetches the latest allowed versions and rewrites the lock file.
Quick check
What exit code means audit found something?
Exit code 1 means it found packages matching dependency policies or failed because of missing required packages. Exit code 0 means no issues.
Does audit read composer.lock by default?
No. By default it audits installed packages. Add the locked option to audit the lock file instead.
Safeguard's dependency scanning and policies can sit next to composer audit as a second check, with gates on pull requests. Try the free scan on a PHP repository.
Sources
Last reviewed: 19 October 2026.