# How OSV-Scanner License Scanning Works with SPDX Allowlists

> Learn how OSV-Scanner performs license scanning using SPDX allowlists and boolean logic to identify violations. Get actionable insights for your project.

- Repository: [Google/osv-scanner](https://github.com/google/osv-scanner)
- Tags: how-to-guide
- Published: 2026-04-25

---

**OSV-Scanner evaluates package license expressions against user-provided SPDX allowlists using boolean logic, flagging violations when `spdx.Satisfies` returns false for any detected license identifier.**

The `google/osv-scanner` CLI tool provides license compliance auditing by comparing detected package licenses against SPDX allowlists. This functionality parses complex SPDX expressions containing `AND`, `OR`, and `WITH` operators, validating them against standardized identifiers to identify policy violations during software composition analysis.

## Parsing the --licenses Flag and Allowlist Validation

The license scanning workflow begins with CLI argument processing in [`cmd/osv-scanner/internal/helper/flags.go`](https://github.com/google/osv-scanner/blob/main/cmd/osv-scanner/internal/helper/flags.go). The `allowedLicencesFlag` definition (lines 21-24) accepts either a boolean for summary mode or a comma-separated list of SPDX identifiers that constitute the allowlist.

When the scan initializes, `GetScanLicensesAllowlist` in [`cmd/osv-scanner/internal/helper/getters.go`](https://github.com/google/osv-scanner/blob/main/cmd/osv-scanner/internal/helper/getters.go) (lines 13-30) transforms the raw flag value into a Go `[]string`. Before the actual scan begins, each identifier undergoes validation through `spdx.Unrecognized` in [`internal/spdx/verify.go`](https://github.com/google/osv-scanner/blob/main/internal/spdx/verify.go) (lines 5-13). This helper lower-cases entries and compares them against the built-in `spdx.IDs` map, causing an early error if any identifier is not a valid SPDX license ID.

The parsed allowlist is then stored in `osvscanner.ScannerActions` via `GetCommonScannerActions` (lines 35-48), populating the `ScanLicensesAllowlist` field that the core scanner will reference during analysis.

## Evaluating SPDX Expressions Against Allowlists

For each detected package, OSV-Scanner extracts raw SPDX strings from lock-files and copies them into `pkg.Licenses` as `models.License` types within [`pkg/osvscanner/vulnerability_result.go`](https://github.com/google/osv-scanner/blob/main/pkg/osvscanner/vulnerability_result.go) (lines 17-22).

The critical evaluation logic resides in [`internal/spdx/satisfies.go`](https://github.com/google/osv-scanner/blob/main/internal/spdx/satisfies.go). The `Satisfies` function (lines 52-62) tokenizes SPDX license expressions—for example `MIT OR Apache-2.0`—and builds an abstract syntax tree (AST). It then invokes `node.satisfiedBy` to check whether the parsed expression is satisfied by any identifier in the user-provided allowlist. This architecture supports complex logical operators including `AND`, `OR`, `WITH`, and parenthetical groupings.

## Detecting and Recording License Violations

When `Satisfies` returns `false` for a license expression, the scanner appends the offending license to `pkg.LicenseViolations` (lines 28-33 of [`vulnerability_result.go`](https://github.com/google/osv-scanner/blob/main/vulnerability_result.go)). Packages containing at least one violation are automatically forced into the final results by setting `includePackage = true`, ensuring policy breaches cannot be filtered out accidentally.

After the scan completes, the allowlist and summary flag are stored in `ExperimentalAnalysisConfig.Licenses` (lines 89-96). This configuration object enables reporters to render compliance data appropriately. For instance, [`internal/output/table.go`](https://github.com/google/osv-scanner/blob/main/internal/output/table.go) (lines 53-55) checks `len(licenseConfig.Allowlist) > 0` to determine whether to display the "license allowlist" column in tabular output.

## Practical Usage Examples

The following commands demonstrate common allowlist workflows:

```bash

# Generate a summary of all detected licenses without filtering

osv-scanner scan . --licenses

# Enforce an allowlist—only MIT or Apache-2.0 are permitted

osv-scanner scan . --licenses=MIT,Apache-2.0

# Combine allowlist validation with JSON output for CI pipelines

osv-scanner scan . \
    --format json \
    --licenses=MIT,Apache-2.0 \
    --output-file compliance-report.json

```

Under the hood, the comma-separated values become `[]string{"MIT", "Apache-2.0"}`. The scanner evaluates each package's license expression against this slice, and the resulting JSON output includes a `license_violations` field for any package failing the check.

## Summary

- The `--licenses` flag accepts either a boolean for summary mode or a comma-separated list of valid SPDX identifiers.
- **Invalid SPDX IDs** are rejected during initialization by `spdx.Unrecognized` before any scanning occurs.
- **SPDX expressions** containing `AND`, `OR`, and `WITH` operators are parsed into an AST and evaluated against the allowlist via `spdx.Satisfies`.
- Violations are recorded in `pkg.LicenseViolations`, forcing affected packages into the final output.
- Results are enriched with `ExperimentalAnalysisConfig.Licenses` for rendering by table, JSON, HTML, and other reporters.

## Frequently Asked Questions

### What SPDX license formats does OSV-Scanner support?

OSV-Scanner supports standard SPDX license identifiers as defined in the SPDX specification, including simple identifiers like `MIT` or `Apache-2.0`, as well as complex expressions using `AND`, `OR`, and `WITH` operators with parenthetical grouping. The validator in [`internal/spdx/verify.go`](https://github.com/google/osv-scanner/blob/main/internal/spdx/verify.go) ensures all allowlist entries match the official SPDX ID registry.

### How does the allowlist evaluate compound license expressions?

The `spdx.Satisfies` function in [`internal/spdx/satisfies.go`](https://github.com/google/osv-scanner/blob/main/internal/spdx/satisfies.go) tokenizes compound expressions and constructs an abstract syntax tree. For an expression like `MIT OR Apache-2.0`, the scanner returns true if either identifier appears in the allowlist. For `MIT AND Apache-2.0`, both must be present in the allowlist for the package to pass compliance.

### What happens if I provide an invalid SPDX ID in the allowlist?

The command aborts during flag parsing with an error message. The `GetScanLicensesAllowlist` function calls `spdx.Unrecognized` to filter the provided identifiers against the `spdx.IDs` map, and any unrecognized values trigger an immediate exit before the scan begins.

### Where do license violations appear in the output?

Violations appear in the `license_violations` field of the package data. When using the table reporter ([`internal/output/table.go`](https://github.com/google/osv-scanner/blob/main/internal/output/table.go)), the output includes a dedicated column showing allowlist status when `--licenses` is configured with specific identifiers. JSON and HTML reporters read `ExperimentalAnalysisConfig.Licenses` to include both the configured allowlist and any detected violations in their respective formats.