SAFE - Security Analysis For Elixir


Security Audit For Erlang and Elixir A Mix task that brings [SAFE](https://safe-docs.erlang-solutions.com/) security vulnerability scanning to Elixir/Mix projects. ó

Installation

Add the plugin to your mix.exs dependencies:

defp deps do
[
{:mix_safe, "~> 1.0", only: [:dev, :test], runtime: false}
]
end

Then fetch dependencies:

mix deps.get

Usage

mix safe <subcommand> [options]

Subcommands

SubcommandDescription
fingerprintRun the SAFE fingerprint phase
analyseRun the SAFE analysis phase
scaScan dependencies for known vulnerabilities (Supply Chain Analysis)
downloadDownload the SAFE binary without running a scan
versionPrint the plugin version and the SAFE binary version
helpPrint usage information

Licensing

CapabilityLicense requirementCost
fingerprint + analyseRequires a SAFE licenseFree for open source projects
scaNo license requiredFree for everyone

The analyse phase (and the fingerprint step that feeds it) runs the full SAFE static analysis engine, which requires a SAFE license. The license is free for open source projects.

Dependency scanning via sca is completely free for everyone and needs no license.

Typical workflow

1. Fingerprint your project

$ mix safe fingerprint
* checking your project's structure
* Discovered 1 app(s): [:my_app]
{
"output": ["stdio", "file"],
"version": "1.1",
"project": {
"name": "my_app",
"apps": [{"name": "my_app", "app_file": "mix.exs", "additional_includes": []}],
"paths": ["_build/dev/lib/my_app/ebin"]
}
}
Would you like to proceed with this configuration? [y/N]: y
* running SAFE fingerprint
* SAFE fingerprint complete

2. Analyse for vulnerabilities

$ mix safe analyse
* Using config from .safe/config.json
* running SAFE analysis
* SAFE analysis complete - no vulnerabilities found

3. Scan dependencies for known vulnerabilities

$ mix safe sca
* running SAFE SCA
* SAFE SCA complete - no vulnerabilities found

Options:

FlagDescriptionDefault
--lock-file PATHPath to mix.lock or rebar.lockauto-detected
--advisories SOURCEAdvisory source: GitHub URL, local dir, or git URLmirego/elixir-security-advisories
--ignore-file PATHPath to SCA ignore file.safe/sca_ignore.json
--warnings-as-errorsTreat warnings (e.g. non-hex deps) as errorsoff

Exit codes: 0 clean, 1 error, 2 vulnerabilities found, 3 warnings treated as errors.

To suppress specific findings, create .safe/sca_ignore.json:

{
"ignored_dependencies": [
{"package": "hackney", "advisory_ids": ["*"], "reason": "Not exploitable"},
{"package": "oidcc", "advisory_ids": ["GHSA-xxxx-xxxx-xxxx"]}
],
"ignored_non_hex_packages": ["my_git_dep", "my_path_dep"]
}

Binary management

The SAFE binary is downloaded automatically on first use and stored at:

<project_root>/_build/safe/safe

The resolved version is pinned in safe.lock at the project root (commit this file to version control). On later runs the binary is not re-downloaded as long as the file is present.

Skipping the download

mix safe download

Useful in CI pipelines where you want to cache the binary separately from the scan step.

Configuration file

mix safe fingerprint generates .safe/config.json in the project root.

{
"output": ["stdio", "file"],
"version": "1.1",
"project": {
"name": "my_app",
"apps": [
{
"name": "my_app",
"app_file": "mix.exs",
"additional_includes": []
}
],
"paths": ["_build/dev/lib/my_app/ebin"]
}
}

You can edit this file before re-running. If it exists when mix safe fingerprint is called, the plugin will ask whether to reuse it.

Umbrella projects

Umbrella projects are supported. Each child app under apps/ contributes one entry to the apps list, and paths is set to the longest common prefix of all child ebin directories.

Exit codes

CodeMeaning
0Success / no vulnerabilities found
1Error (download failure, bad config, unsupported platform, …)
2Vulnerabilities found