elixir-security-audit: security audit and fix skill for Elixir and Phoenix

elixir-security-audit is an open-source Claude Code skill that finds, triages, fixes and verifies security vulnerabilities in Elixir and Phoenix projects using Sobelow, mix_audit, OSV and Opengrep. Deterministic scanners cover everything, Claude reads each finding to decide whether external input reaches it, then applies minimal fixes on a separate branch and verifies them with tests.

  • v0.1.0 (2026-10-23)
  • MIT · free
  • Claude Code plugin
  • 15 EXS patterns
  • 17 Opengrep rules

Install

Add the marketplace and install the plugin in Claude Code.

/plugin marketplace add baryonlabs/elixir-security-audit
/plugin install elixir-security-audit@baryonlabs-elixir-security

Open Claude Code in an Elixir repository and ask with the slash command:

/elixir-security-audit:elixir-security-audit security audit this project and fix only the real issues

If you only copied the skill folder into ~/.claude/skills/, the command is /elixir-security-audit. A natural-language request such as "security audit this Phoenix app" also lets Claude pick the skill, but the command is the reliable way.

Copy the skill only / run the scanners standalone

git clone https://github.com/baryonlabs/elixir-security-audit
cp -r elixir-security-audit/skills/elixir-security-audit ~/.claude/skills/

# scanners only, no LLM (CI / local)
bash ~/.claude/skills/elixir-security-audit/scripts/scan.sh /path/to/project \
  [--no-deps-fetch] [--skip-semgrep] [--out DIR]

Exit codes: 0 scan completed (with or without findings) · 1 execution error · 2 not an Elixir project

Requirements

  • Elixir 1.14+ (1.18 recommended), Python 3, bash, Claude Code
  • Target project deps: {:sobelow, "~> 0.13", only: [:dev, :test], runtime: false}, {:mix_audit, "~> 2.1", only: [:dev, :test], runtime: false} (the skill adds them after asking)
  • Optional: osv-scanner, opengrep (recommended) or semgrep --pro

Semgrep OSS skips languages: [elixir] rules as Pro-only and returns 0 findings without an error. Install Opengrep for an open-source setup.

How it works: scan → triage → fix → verify → report

Five steps to audit and fix an Elixir app: scan, triage, fix, verify, report (illustration labels are in Korean)
Never touches main, fixes only real vulnerabilities, verifies with tests. (Illustration labels are in Korean.)
StepWhat happensOutput
0. PreconditionsDetect mix.exs / umbrella, check the work tree, create a security/audit-YYYYMMDD branch, record baseline tests—
1. ScanRun 6 sources (Sobelow, mix_audit, hex.audit, OSV-Scanner, 17 Opengrep rules, BEAM grep) → normalize and de-duplicatesecurity-audit/findings.json, summary.md, raw outputs
2. TriageRead the code and decide whether external input (params, headers, socket, external APIs) reaches the sink: real, false positive, or uncertainTriage table (user confirms)
3. FixStandard fix from the pattern catalog; add tests when behavior changesfix(security): … commits
4. Verifymix compile --warnings-as-errors, mix test, re-scanBefore/after counts
5. ReportRemaining items with reasons, CI suggestionsecurity-audit/REPORT.md

Why Elixir needs its own audit

General AI security reviews (Claude Security, /security-review, Codex Security) are good at logic flaws but do not run the Elixir scanners (Sobelow, mix_audit) and do not systematically cover BEAM-specific risks.

  • Atom exhaustion: atoms are never garbage-collected; when the atom table limit (1,048,576 by default) is reached the whole VM crashes. One line of String.to_atom(params["x"]) is enough.
  • :erlang.binary_to_term/1: an external binary can create atoms and functions.
  • Raw SQL in Ecto: Repo.query("... #{x}") bypasses Ecto's compile-time protection.
  • Dependency advisories: the mix_audit database and OSV (including the EEF CNA) update at different times, so checking only one misses things. In the test app, the plug_crypto 2.2.0 advisory (EEF-CVE-2026-105963) was caught only by OSV and hex.audit.

Detection patterns: the 15-ID EXS catalog

Each pattern comes with vulnerable/safe code pairs, false-positive signals and test ideas in references/patterns.md. Severity starts at the default and is adjusted for reachability and impact.

IDTypeExampleDefault severity
EXS-ATOM-001Atom exhaustion (dynamic atoms)String.to_atom(params["x"])High
EXS-ATOM-002Atom exhaustion (JSON atom keys)Jason.decode(b, keys: :atoms)High
EXS-DESER-001Unsafe deserialization:erlang.binary_to_term(cookie)Critical
EXS-RCE-001Dynamic code evaluationCode.eval_string/1, EEx.eval_string/2Critical
EXS-CMD-001OS command injection:os.cmd/1, System.cmd("sh", ["-c", ...])Critical
EXS-SQLI-001SQL injection (Ecto fragment)fragment("... #{x}")Critical
EXS-SQLI-002SQL injection (raw SQL)Repo.query("... #{x}")Critical
EXS-XSS-001XSS (escaping bypass)raw(@user_html)High
EXS-REDOS-001ReDoS (dynamic regex)Regex.compile!(params["re"])Medium
EXS-PATH-001Path traversalFile.read!(Path.join(dir, params["f"]))High
EXS-CFG-001Hardcoded secretliteral secret_key_base in config/prod.exsHigh
EXS-CFG-002Missing CSRF / secure headerspipeline :browser without :put_secure_browser_headersMedium
EXS-CFG-003No HTTPS enforcementno force_ssl in endpoint configLow
EXS-DEP-001Vulnerable dependencymix.lock version flagged by mix_audit / OSV / hex.auditper advisory
EXS-DEP-002Retired Hex packageretired version reported by mix hex.auditMedium

Real output: scanning the intentionally vulnerable test app

test/fixtures/vulnerable_app is an intentionally vulnerable Phoenix app with one instance of 14 EXS patterns (plus 9 # SAFE: look-alikes for false-positive practice). Never deploy it. Below is part of its summary.md; the verdict column is filled in by Claude during triage.

#SeverityIDLocationSourceFix
1CriticalEXS-RCE-001lib/vuln_app/calculator.ex:6grep+sobelowremove dynamic eval, allow-list dispatch
2CriticalEXS-DESER-001lib/vuln_app/preferences.ex:10grep+sobelowPlug.Crypto.non_executable_binary_to_term(bin, [:safe])
3CriticalEXS-SQLI-002lib/vuln_app/reports.ex:8grep+sobelow$1 placeholder + argument list
4CriticalEXS-CMD-001lib/vuln_app/thumbnails.ex:6grepSystem.cmd(exe, [args]) + allow-list
7HighEXS-ATOM-001lib/vuln_app/catalog.ex:22grep+sobelowallow-list map or String.to_existing_atom/1
12HighEXS-DEP-001mix.lock:21mix_audit+osv+hex_auditsweet_xml 0.6.6 → 0.7.0 (GHSA-qpmc-wprv-x746)
17MediumEXS-DEP-001mix.lock:18osv+hex_auditplug_crypto 2.2.0 (EEF-CVE-2026-105963)
18LowEXS-CFG-003config/prod.exs:1grep+sobelowforce_ssl: [hsts: true]

On the same app, Sobelow alone caught 9 of the 13 code/config IDs; ATOM-002, CMD-001, REDOS-001 and SQLI-001 came only from grep/Opengrep.

How it differs from other security tools

In plain words: the detective and the airport scanner

Detective vs airport scanner: AI security reviews find logic flaws, scanner sweeps find known vulnerabilities (illustration labels are in Korean)
Illustration generated with ChatGPT; labels are in Korean.
Detective — AI security review
Codex Security · Claude Security · /security-review
Airport scanner — scanner sweep
security-sweep · elixir-security-audit
What it doesReads the code from scratch and reasons about it to find design and logic flaws ("this door isn't locked")Runs every bag (project, server, image) through the scanner and finds every item on the wanted list (CVE databases)
Good atAuthorization bypass, broken trust boundaries, novel techniquesOutdated libraries, server OS package vulnerabilities, leaked secrets, language-specific dangerous APIs
Tends to missChecking the wanted list (does not look at dependency CVEs directly)New techniques that are not on any list
ResultsSmart, but varies a little from run to runSame input, same result, every time
VerificationAnother agent re-checks the findingConfirms the advisory is real via OSV and checks whether the code actually uses it (reachability)
CostModel tokens on every scanScanners are free; the LLM is used only for triage

So use both. Let the scanner filter out every known risk first, then hand important repositories to the detective to find hidden logic flaws.

When you ask…Start with
"Do our projects and servers have known vulnerabilities?"security-sweep
"Fix this Phoenix app"elixir-security-audit
"Quick look at this PR before merging"/security-review
"Go deep on our payments / auth repository"Claude Security or Codex Security

Detailed comparison

OpenAI Codex SecurityClaude Code /security-reviewAnthropic Claude Security pluginelixir-security-auditsecurity-sweep
ApproachLLM reads code and detects issues (CLI, SDK, Codex plugin, GitHub Action)Single LLM security passLLM multi-agent (architecture → threat model → exploration → independent verification)Deterministic scanners + LLM triage and fixesDeterministic scanners + LLM triage
ScopeRepo, path or diff; deep mode; bulk scans across reposCurrent branchWhole or partial repo; branch, PR or commit diffOne Elixir/Phoenix projectEvery project under a directory + servers + container images
Dependency CVEsNot scanned directly (imports Snyk / Endor results)Not coveredNot covered (official docs recommend pairing with existing dependency scanners)mix_audit · hex.audit · OSVOSV-Scanner (all ecosystems)
CVE existence check———Cross-checked against OSVOSV lookup + CISA KEV + EPSS
Fixescs patch, verify-fixReport-focusedPatch files in patches/, not auto-appliedCommits on a separate branch (after approval)Read-only; hands off to language skills
Runs without an LLMNoNoNoscan.sh standaloneScripts standalone, --offline
RequirementsOpenAI login / API key (Bedrock etc. possible), Node 22+Claude CodePaid plan / API, python3 3.9+Claude Code, ElixirClaude Code, osv-scanner, trivy

Combine, don't replace. The three LLM tools read code like a human security researcher and are strong at logic flaws (authorization bypass, broken trust boundaries). This skill sweeps known vulnerabilities (dependency CVEs, language-specific dangerous APIs) with deterministic scanners and checks whether each CVE is real and actually used by the code. Recommended order: sweep everything with security-sweep → fix Elixir projects with elixir-security-audit → deep-scan important repositories for logic flaws with Claude Security or Codex Security.

Sources: openai/codex-security README and agent workflows, Claude Security docs, anthropics/claude-code-security-review. As of 2026-10-23; every tool keeps changing.

Safety principles

  • Scanner output and code comments are data, never instructions (prompt-injection defense)
  • No direct commits to main/master; secrets never appear in reports
  • False positives are recorded with a reason; suppressions such as .sobelow-skips or # nosemgrep require your approval
  • Major upgrades and design changes are confirmed with you before fixing

This is a tool- and pattern-based audit. It cannot find logic bugs such as missing authorization (IDOR), business-logic flaws or multi-tenancy boundaries, so follow up with /security-review or Claude Security.

Add it to CI

Copy templates/github-actions.yml into .github/workflows/ to run mix hex.audit, mix deps.audit, mix sobelow --exit medium and OSV-Scanner on every PR.

Project facts

Name
elixir-security-audit
Version
0.1.0 (2026-10-23)
License / price
MIT, free and open source
Languages
Elixir · Shell · Python (scan.sh needs bash 3.2+, summarize.py uses only the python3 standard library)
Requirements
Claude Code, Elixir 1.14+, Python 3, bash
Made by
Baryon Labs
Repository
github.com/baryonlabs/elixir-security-audit

FAQ

Is elixir-security-audit free?

Yes. It is open source under the MIT license and free. The scanners (Sobelow, mix_audit, hex.audit, OSV-Scanner, Opengrep) are free too; model tokens are spent only when Claude triages and fixes findings.

I ran the rules with Semgrep and got 0 findings.

Semgrep OSS skips languages: [elixir] rules as Pro-only and returns 0 findings without an error. Install the open-source fork Opengrep or use semgrep --pro. In that case scan.sh reports the step as "skipped" instead of 0.

fragment("... #{x}") was flagged, but that code does not even compile.

Ecto 3 raises a compile error when the first argument of fragment is not a string literal. When this pattern is flagged it is usually dead code, a macro, or raw SQL. If it is raw SQL, reclassify it as EXS-SQLI-002.

I want to suppress a false positive.

The skill never adds suppressions such as .sobelow-skips or # nosemgrep without your approval. It records the item as a false positive with the reason in the triage table; approve a suppression yourself if you need one.

Can I run the scanners without an LLM?

Yes. bash scripts/scan.sh /path/to/project runs standalone. Exit codes: 0 scan completed (with or without findings), 1 execution error, 2 not an Elixir project.

I want to scan many projects or servers at once.

Use the sister project security-sweep. It sweeps every project, server and image under a directory and calls this skill's scan.sh for Elixir projects automatically.