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.
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
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_FILEPath to the lock file to scan. Supports bothmix.lock(Elixir) andrebar.lock(Erlang). If omitted, SAFE looks formix.lockorrebar.lockin the current directory. -
--advisories SOURCEOverride the default advisory source. Accepts:- A local directory path (e.g.,
./my-advisories/) containing apackages/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.
- A local directory path (e.g.,
-
--ignore-file PATHPath to an SCA ignore file. Defaults to.safe/sca_ignore.jsonin the same directory as the lock file. See Suppressing SCA Findings for the file format. -
--warnings-as-errorsTreat warnings as errors. Non-hex/non-pkg dependencies (:git,:path, etc.) normally produce a warning; this flag causes the scan to exit with code3if 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 file | Ecosystem | Checked dependencies |
|---|---|---|
mix.lock | Elixir / Mix | :hex packages only |
rebar.lock | Erlang / Rebar3 | :pkg (Hex) packages only |
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
| Code | Meaning |
|---|---|
0 | No vulnerabilities found |
1 | An error occurred during the scan |
2 | One or more vulnerable dependencies found |
3 | Non-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.