Audit Command

The audit command lists known security advisories affecting your installed dependencies. It works on both composer.lock and package-lock.json, like composer audit / npm audit, but in a single pass and with whatsdiff's output formats. cli-audit.png

Usage

whatsdiff audit [options]

Options

Comparison Options

  • --from - Commit, branch, or tag to compare from (enables diff mode)
  • --to - Commit, branch, or tag to compare to (diff mode; defaults to HEAD)
  • --at - Audit the lockfile at a specific commit, tag, or branch instead of the working tree

Output Options

  • --format, -f - Output format: text (default), json, or markdown
  • --no-fix - Skip the suggested-fix version lookup (faster, no extra registry calls)

Filtering Options

  • --include - Audit only specific package managers (comma-separated: composer, npmjs)
  • --exclude - Exclude specific package managers (comma-separated: composer, npmjs)

Failure Options

  • --fail-on - Severity threshold for non-zero exit: low (default), medium, high, critical, or none
  • --allow-unrated - Do not trip --fail-on for advisories whose severity has not been rated upstream yet

By default, advisories with an unrated severity are treated as meeting any threshold (fail-safe). Pass --allow-unrated if you would rather not block on advisories that are still pending a CVSS score.

Cache Options

  • --no-cache - Disable caching and force fresh data retrieval from advisory registries

Option Conflicts

  • --at cannot be used with --from or --to
  • --include and --exclude are mutually exclusive

What It Does

The audit command:

  1. Reads composer.lock and/or package-lock.json from the working tree (or from a specific ref if --at is given).
  2. Resolves the installed version of each package and queries the corresponding registry for known security advisories.
  3. Filters advisories by affected version range to only report those that actually impact your installed versions.
  4. Computes the lowest safe upgrade for each vulnerable package (skipped with --no-fix).
  5. Displays results in your preferred format (text, JSON, or markdown).

The command supports three modes:

  • Current state (default) - audit the working-tree lockfiles.
  • Point-in-time (--at) - audit the lockfile as it existed at a specific commit, tag, or branch.
  • Diff mode (--from / --to) - report only advisories that are newly introduced between two refs. Useful in PR pipelines to surface vulnerabilities a change introduces without re-flagging pre-existing ones.

Example Output

$ whatsdiff audit

2 vulnerable packages, 4 security advisories

  symfony/cache  v8.0.5 → fixed in v8.0.12
      CVE-2026-45073  SQL Injection in PdoAdapter::doClear() via Unsanitized $prefix
  symfony/yaml   v8.0.1 → fixed in v8.0.12
      CVE-2026-45304  YAML Parser Exponential Memory Allocation via Recursive Collection-Alias Expansion ("Billion Laughs")
      CVE-2026-45305  YAML Parser ReDoS via Catastrophic Backtracking in Parser::cleanup() Regex
      CVE-2026-45133  YAML Parser Stack Exhaustion via Unbounded Recursion in Nested Blocks, Sequences, and Mappings

Legend: ○ rating pending (4)

Severity bullets are colored in interactive terminals (red for critical/high, yellow for medium, cyan for low, gray for unrated), and CVE IDs are rendered as clickable hyperlinks where supported.

Examples

Basic Usage

Audit the current working-tree lockfiles:

whatsdiff audit

JSON Output for CI/CD

Output in JSON format for parsing in scripts:

whatsdiff audit --format=json

Markdown Output

Generate a markdown report for a PR description or release notes:

whatsdiff audit --format=markdown > security-report.md

Audit at a Specific Commit or Tag

Audit the lockfile as it existed at a released version:

whatsdiff audit --at=v2.3.0

Diff Mode - New Advisories Between Refs

Only report advisories that were newly introduced between two refs:

whatsdiff audit --from=v2.2.0 --to=v2.3.0

Fail Only on High or Critical Findings

Useful in CI when you want to allow low/medium advisories without blocking the build:

whatsdiff audit --fail-on=high

Audit a Single Ecosystem

Only audit Composer packages, skipping package-lock.json:

whatsdiff audit --include=composer

Skip the Fix-Version Lookup

Run faster by skipping the suggested-fix resolution:

whatsdiff audit --no-fix

Force Fresh Data

Bypass the cache and reload advisories from the registries:

whatsdiff audit --no-cache

Output Formats

Text (default)

Human-readable output with colored severity bullets, package name and installed version, a suggested fix version, and a legend at the bottom counting advisories by severity. CVE IDs are rendered as clickable hyperlinks in terminals that support OSC 8.

JSON

Machine-readable output suitable for scripts and CI integrations. Sample (trimmed to a single advisory):

{
    "mode": "current",
    "from": null,
    "to": null,
    "summary": {
        "vulnerable_packages": 2,
        "total_advisories": 4,
        "by_severity": {
            "critical": 0,
            "high": 0,
            "medium": 0,
            "low": 0,
            "unknown": 4
        },
        "max_severity": "unknown"
    },
    "audits": [
        {
            "name": "symfony/cache",
            "type": "composer",
            "installed_version": "v8.0.5",
            "suggested_fix_version": "v8.0.12",
            "max_severity": "unknown",
            "advisories": [
                {
                    "advisory_id": "PKSA-z7t6-zt6p-wtng",
                    "cve": "CVE-2026-45073",
                    "title": "CVE-2026-45073: SQL Injection in PdoAdapter::doClear() via Unsanitized $prefix",
                    "link": "https://symfony.com/cve-2026-45073",
                    "affected_versions": ">=8.0.0,<8.0.12",
                    "severity": "unknown"
                }
            ]
        }
    ]
}

In diff mode, mode is "diff" and from / to hold the resolved commit hashes.

Markdown

A markdown report with a summary table and one section per severity, suitable for pasting into PR descriptions or issues:

# Security Audit

## Summary

| Severity | Count |
|----------|-------|
| Unknown  | 4     |

## Unknown

### symfony/cache (`v8.0.5`)

**Fix available:** upgrade to `v8.0.12`

| ID                                                       | Severity | Title                                                                            |
|----------------------------------------------------------|----------|----------------------------------------------------------------------------------|
| [CVE-2026-45073](https://symfony.com/cve-2026-45073)     | Unknown  | CVE-2026-45073: SQL Injection in PdoAdapter::doClear() via Unsanitized $prefix   |

Exit Codes

The command uses standard exit codes for integration with scripts and CI/CD pipelines:

Exit Code Status Description
0 SUCCESS No advisories meet the --fail-on threshold
1 FAILURE At least one advisory meets or exceeds the threshold, or invalid options were passed
2 ERROR Lock file missing, network/registry error, or git error

Pass --fail-on=none to always exit 0 regardless of findings (useful when you only want the report).

Use Cases

1. CI/CD - Fail the Build on High or Critical Advisories

Block deployments when a serious vulnerability is detected, while tolerating low/medium ones:

name: Security Audit

on: [pull_request, push]

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0  # Need full history for diff-mode runs

      - name: Install whatsdiff
        run: composer global require whatsdiff/whatsdiff

      - name: Audit dependencies
        run: whatsdiff audit --fail-on=high

Tighten or loosen the gate by changing --fail-on (critical, high, medium, low, or none).

2. Pull Request - Only Report Newly Introduced Advisories

In a PR pipeline, use diff mode to surface only the vulnerabilities a change introduces, ignoring pre-existing ones already present on main:

- name: Audit new advisories vs main
  run: |
    whatsdiff audit \
      --from=origin/main \
      --to=HEAD \
      --format=markdown \
      --fail-on=medium \
      > new-advisories.md

- name: Comment on PR
  uses: marocchino/sticky-pull-request-comment@v2
  with:
    path: new-advisories.md

This keeps PR feedback focused on what the author actually changed.

Supported Lock Files

  • composer.lock (PHP/Composer)
  • package-lock.json (JavaScript/npm)

Both files are audited automatically if present in your project. Use --include or --exclude to scope the audit to a single ecosystem.

Related Commands

  • Use analyse to see all dependency changes (not just vulnerable ones)
  • Use check to verify a single package