Skip to main content
Version: 1.4.0

Supply Chain Analysis (SCA)

Supply Chain Analysis (SCA) scans your project's dependency lock file for known vulnerabilities. It checks your pinned dependency versions against a regularly-updated advisory database and reports any packages that have known CVEs or security advisories.

info

SCA works entirely offline after the initial advisory database download. The advisory cache is stored at ~/.safe/advisories/ and is updated automatically on each run when an internet connection is available.


Quick Start

Run safe sca from your project root. SAFE will automatically detect a mix.lock (Elixir) or rebar.lock (Erlang) file in the current directory:

safe sca
tip

If both mix.lock and rebar.lock exist in the same directory, use --lock-file to specify which one to scan.


Usage

safe sca [--lock-file LOCK_FILE] [--advisories SOURCE] [--ignore-file PATH]
[--warnings-as-errors]

Arguments

Optional:

  • --lock-file LOCK_FILE Path to the lock file to scan. Supports both mix.lock (Elixir) and rebar.lock (Erlang). If omitted, SAFE looks for mix.lock or rebar.lock in the current directory.

  • --advisories SOURCE Override the default advisory source. Accepts:

    • A local directory path (e.g., ./my-advisories/) containing a packages/ subdirectory
    • A Git repository URL (e.g., https://github.com/org/advisories.git)

    Defaults to mirego/elixir-security-advisories, which syncs with the GitHub Security Advisory Database every 6 hours.

  • --ignore-file PATH Path to an SCA ignore file. Defaults to .safe/sca_ignore.json in the same directory as the lock file. See Suppressing SCA Findings for the file format.

  • --warnings-as-errors Treat warnings as errors. Non-hex/non-pkg dependencies (:git, :path, etc.) normally produce a warning; this flag causes the scan to exit with code 3 if any are found.


Examples

# Auto-detect lock file in current directory
safe sca

# Scan a specific lock file
safe sca --lock-file /path/to/mix.lock
safe sca --lock-file /path/to/rebar.lock

# Use a custom local advisory directory
safe sca --advisories ./my-advisories/

# Use a custom Git advisory repository
safe sca --advisories https://github.com/org/advisories.git

# Use a custom ignore file
safe sca --ignore-file /path/to/sca_ignore.json

# Fail if non-hex dependencies are present
safe sca --warnings-as-errors

Supported Lock Files

Lock fileEcosystemChecked dependencies
mix.lockElixir / Mix:hex packages only
rebar.lockErlang / Rebar3:pkg (Hex) packages only
info

Only dependencies fetched from the Hex package registry can be checked for vulnerabilities. Dependencies sourced from Git, local paths, or other non-Hex sources cannot be version-matched against the advisory database and will produce a warning instead.


Understanding the Output

When vulnerabilities are found:

Lock file: /your/project/mix.lock

Found vulnerable dependencies:

- hackney (1.18.0)
CVE: CVE-2024-12345
Severity: high
Title: Some Known Vulnerability
Fixed in: >= 1.19.0
More: https://github.com/advisories/GHSA-xxxx-xxxx-xxxx

Each vulnerable dependency lists:

  • The installed version
  • CVE identifier (if available)
  • Severity (e.g., low, medium, high, critical)
  • Advisory title
  • The minimum version that fixes the issue
  • A link to the full advisory

When the scan is clean:

Lock file: /your/project/mix.lock

No vulnerable dependencies found.

When advisories have been suppressed via the ignore file:

Ignored: 2 advisory(ies) for: hackney, oidcc (see .safe/sca_ignore.json)

When non-Hex dependencies are present:

3 non-hex dependencies found that cannot be checked for vulnerabilities:

- my_git_dep (git: tag: v1.0.0)
- my_path_dep (path: ../my_path_dep)
- my_branch_dep (git: branch: main)

Exit Codes

CodeMeaning
0No vulnerabilities found
1An error occurred during the scan
2One or more vulnerable dependencies found
3Non-Hex dependencies found and --warnings-as-errors is enabled

Advisory Database

The default advisory source is mirego/elixir-security-advisories, which re-publishes data from the GitHub Security Advisory Database for the Elixir/Erlang ecosystem. It is updated every 6 hours.

On first use, the repository is cloned to ~/.safe/advisories/elixir-security-advisories/. On subsequent runs, SAFE pulls the latest updates. If the network is unavailable, the cached data is used.

To use a custom advisory repository, it must follow the same structure:

packages/
<package-name>/
GHSA-xxxx-xxxx-xxxx.yml
...

Each YAML advisory file should contain fields such as id, package, title, description, severity, cve, link, first_patched_versions, and unaffected_versions.