Safeguard
Compliance•

How do you read SPDX license expressions like MIT OR Apache-2.0?

OR means you choose a license, AND means all apply, WITH adds an exception. Here is how to read SPDX expressions in an SCA license report today.

Safeguard Security Team
6 min read

An SPDX license expression combines license identifiers with operators. OR means the recipient may choose one of the licenses, AND means all of them apply at once, WITH attaches a named exception, and a plus suffix means that version or any later one. An SCA license report that shows these strings is giving you real information.

Why SCA reports show expressions

A single package often cannot be described by one license name. SPDX handles that with license expressions, defined in Annex D of the specification. The spec gives two typical cases: software offered under a choice of licenses, such as GPL-2.0-only OR BSD-3-Clause, and a binary built from files under different licenses, such as LGPL-2.1-only AND BSD-3-Clause.

If your SCA tool flattens these into a single label, or splits them into separate findings, you can end up with a wrong policy result.

The four operators

OperatorMeaningExample
ORThe recipient picks one license from the choiceMIT OR Apache-2.0
ANDTerms of every listed license applyLGPL-2.1-only AND BSD-3-Clause
WITHA license plus a listed exceptionA license identifier WITH an exception identifier
+That version of the license or any later versionCDDL-1.0+

Parentheses set the order. The spec also says operators are matched case sensitively, so write them in capitals, and that there must be no space between an identifier and a trailing plus.

User-defined references use the LicenseRef- prefix. If you see one, the license text is not on the SPDX list, and someone has to read it.

How a policy should treat each form

Your allow list should be written against how the expression resolves, not against each word in it.

  • For OR, a policy can pass the package if at least one option is allowed. Record which option you rely on, so a later audit sees the choice.
  • For AND, every listed license must be allowed. One disallowed term fails the whole package.
  • For WITH, check the exception too. An exception changes the obligations of the base license, so do not treat the base name alone as the answer.
  • For LicenseRef, route it to a person. A tool cannot judge a custom text.

This is a policy-design aid, not legal advice. Have counsel confirm how your organization reads each license.

Test your tool in ten minutes

Make a small test repository with three dependencies whose metadata you know: one with an OR expression, one with AND, and one with a LicenseRef. Run the scan and check three things. Does the report show the full expression? Does the policy engine evaluate it as above? Does a LicenseRef end up in a review queue rather than a silent pass?

A worked example with four packages

Imagine your scan returns four packages, each with a license string.

PackageLicense expressionHow to read it
alphaMITOne license, permissive
betaMIT OR Apache-2.0You choose one of the two
gammaLGPL-2.1-only AND BSD-3-ClauseTerms of both apply
deltaLicenseRef-vendor-eulaA custom text, not on the SPDX list

Suppose your policy allows MIT, Apache-2.0, and BSD-3-Clause, and sends LGPL to review. Alpha passes. Beta passes, and you note that you rely on either option. Gamma goes to review because one of its two licenses is outside the allow list. Delta goes to a person, since a tool cannot judge a custom text.

If your tool had flattened beta to "MIT" and gamma to "BSD-3-Clause", the report would look clean while gamma carried an LGPL obligation. That is the failure to test for.

Step by step: write a policy that handles expressions

  1. List the licenses your organization has already approved, using SPDX identifiers rather than informal names.
  2. Decide the treatment of OR: pass if any option is approved, and record the chosen option.
  3. Decide the treatment of AND: pass only if every license is approved.
  4. Decide the treatment of WITH: look up the exception and approve it separately.
  5. Decide the treatment of LicenseRef: always send to review.
  6. Decide what happens to expressions the tool cannot parse: send to review, never pass silently.
  7. Write each decision into the policy document and the tool configuration, and keep them in sync.

Common parsing pitfalls

The specification sets small rules that tools sometimes get wrong. Operators are matched case sensitively, so "or" in lowercase is not a valid operator. There must be no space between an identifier and a plus sign. WITH needs spaces on both sides. Identifiers are matched case insensitively, but the canonical case on the SPDX list is preferred.

Older packages may carry informal strings such as "BSD" or "Apache 2", which are not valid SPDX identifiers. A good tool normalizes these where it can, and flags what it cannot. Ask how yours handles ambiguous names like "BSD", which could mean several different licenses.

Metadata is not the same as the license file

The license string in package metadata is declared by the maintainer. It can be missing, out of date, or different from the license text in the repository. For packages that matter to you, spot check the actual license file against the declared expression, and record the result.

Who should own the decision

Engineering can run the scan and enforce the policy, but the interpretation of a license belongs with someone qualified, usually counsel or a compliance owner. Engineering's job is to give them a clear list of expressions that need a decision, not to guess.

A note for SBOM consumers

SPDX and CycloneDX SBOMs can both carry license expressions. When you receive an SBOM from a supplier, run the same normalization before you apply your policy, so one set of rules covers internal and supplier components.

Try it yourself

Click through it at your own pace, or open it full screen.

Open a component and find where its license is shown. Compare that to the expression forms above.

Quick check

If a package says MIT OR Apache-2.0, do I have to comply with both?

No. OR is a choice. You can rely on either license, though it is wise to record which one you chose.

Is GPL-2.0-or-later the same as GPL-2.0+?

SPDX has both forms in different versions of its list, and the plus suffix is the older style for "or any later version". Check that your tool normalizes them to the same meaning.

What should a tool do with a license string it cannot parse?

It should flag the component for review rather than passing it silently. An unparsed string is missing information, not a clean result.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.