plugins/elixir-phoenix/skills/deps-audit/SKILL.md
Audit Hex deps for supply-chain security risk — bidi chars, compile-time exec, maintainer changes, typosquats, CVEs. Use after mix deps.update, when checking if a package upgrade is safe, or reviewing mix.lock PR diffs.
npx skillsauth add oliver-kriska/claude-elixir-phoenix phx:deps-auditInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Non-mutating supply-chain audit for Hex packages. Runs an 8-rule MVP catalogue
against changed packages, enriches with Hex API metadata, wraps existing tools
(mix hex.audit, mix_audit, OSV-Scanner), and emits a triage table.
mix deps.update or mix deps.get brought in new versionsmix.lock (pre-merge gate)--preview <pkg>).claude/deps-audit/last-run.json — its absence
is evidence the audit didn't actually run.mix_audit / osv-scanner — even if asked. Detect,
warn with install instructions, skip cleanly if missing. If the user
says "install it," respond with the install command (e.g.,
mix deps.add mix_audit --only dev) and do not execute it. The
audit skill is non-mutating; mix.exs / mix.lock are off-limits
regardless of consent.rule_id, severity, file:line, snippet, message. No
handwaving.(old, new) pairs
resolved.hex-deps-triager agent runs only when score
10 (1 BLOCK or 3+ WARNs), and its verdicts are advisory — never auto-suppress a finding without human review.
| Mode | Trigger | Old source | New source |
|------|---------|-----------|-----------|
| B (default) | /phx:deps-audit | git show HEAD:mix.lock | working mix.lock |
| C (PR) | /phx:deps-audit --base main | git show <ref>:mix.lock | working mix.lock |
| A (preview) | /phx:deps-audit --preview httpoison | locked version | Hex API latest |
See ${CLAUDE_SKILL_DIR}/references/operating-modes.md for full resolver logic.
Default = full 8-rule scan with streaming progress. --quick opts out
to CVE + retirement only. See ${CLAUDE_SKILL_DIR}/references/execution-flow.md.
Parse the mix.lock Erlang term format for both old and new sources. Emit a
list of {pkg, old_version, new_version} tuples. Surface
new-only and removed-only packages separately (a removed package is not
audited; a brand-new package gets old_version = nil and skips diff-only
rules).
See ${CLAUDE_SKILL_DIR}/references/diff-resolver.md for shell + mix run -e snippets per mode and the JSON output contract.
For each (pkg, old, new):
mix hex.package fetch <pkg> <old> --unpack -o ${AUDIT_TMPDIR}/tarballs/<pkg>/<old>/
mix hex.package fetch <pkg> <new> --unpack -o ${AUDIT_TMPDIR}/tarballs/<pkg>/<new>/
All ephemeral artifacts live under ${AUDIT_TMPDIR} (driver-owned, removed
on exit). See ${CLAUDE_SKILL_DIR}/references/audit-tmpdir.md and
${CLAUDE_SKILL_DIR}/references/tarball-fetcher.md.
| # | Rule | Sev | Method |
|---|------|-----|--------|
| 1 | Bidi Unicode control chars in .ex/.exs/.erl | BLOCK | grep |
| 2 | Code.eval_* / :erlang.apply with non-literal MFA at module scope | BLOCK | AST (Sourceror or regex+scope) |
| 3 | System.cmd / :os.cmd / Port.open at compile time | BLOCK | AST |
| 4 | :erlang.binary_to_term/1 on literal without :safe | BLOCK | AST |
| 5 | New :git/:path dep in mix.exs (vs old) | BLOCK | AST diff |
| 6 | Maintainer change between versions | BLOCK | Hex API |
| 7 | Base64 blobs >256 chars outside priv/static/, test/fixtures/, assets/ | WARN | regex |
| 8 | Levenshtein ≤2 from top-500 + download delta >1000× | BLOCK | Hex API + fuzzy |
Full catalogue (35 rules, MVP marked) in ${CLAUDE_SKILL_DIR}/references/heuristics.md.
Bash + mix run -e implementations for all 8 MVP rules in
${CLAUDE_SKILL_DIR}/references/rules-impl.md (single-pass NEW + diff rules +
Hex API rules, with run_all_rules master loop).
mix hex.audit — retired-package check, always availablemix_audit — CVE check via GHSA, if installed (else warn + skip; do NOT install)osv-scanner — CVE check via OSV.dev, if installed (else warn + skip; do NOT install)See ${CLAUDE_SKILL_DIR}/references/external-tools.md for detection, output parsing, and severity mapping per tool.
GET /api/packages/:name — owners, downloads, inserted_atGET /api/packages/:name/releases/:version — per-release publisherdays_since_publish, owner_age_days, download_velocityCap at 5 req/sec. Per-run cache under ${AUDIT_TMPDIR}/hex-api/.
See ${CLAUDE_SKILL_DIR}/references/hex-api.md for endpoint contracts,
caching strategy, Rule 6/8 detection, and Levenshtein implementation.
hex_vet.exs ledger (if present)If hex_vet.exs exists at project root, vetted-version findings are
downgraded to INFO. Unvetted versions retain their severity.
Lock-vs-ledger disagreement: lock wins. See the deps-vet skill's
hex-vet schema doc for the "Lock-vs-ledger disagreement" section.
Use /phx:deps-vet <pkg> <version> (separate skill) to add entries.
When run with DIFFERENTIAL=1 (default), findings that existed in the
OLD tarball are downgraded to INFO. Net-new signals reach the renderer
at full severity. See ${CLAUDE_SKILL_DIR}/references/differential.md.
For packages where the aggregate score exceeds 10, the
hex-deps-triager sonnet agent reads finding + diff windows and
produces structured verdicts (confidence, verdict, rationale,
fp_reasons[]). A context-supervisor (haiku) consolidates verdicts
across packages into triage/consolidated.md. Main skill reads only
the consolidated file.
See ${CLAUDE_SKILL_DIR}/references/llm-triage.md.
Per-package weighted sum: BLOCK = 10, WARN = 3, INFO = 1. Risk band: 0 clean · 1–5 low · 6–15 medium · 16+ high.
Output:
pkg | old → new | risk | findings | diff.hex.pm | maintainer-change plus a per-package detail section for any non-clean row..claude/deps-audit/last-run.json. The Phase 3 gate reads this; an audit that doesn't write it is a no-op for the gate. Always emit, even on clean runs.--json flag emits JSON to stdout instead of markdown. See
${CLAUDE_SKILL_DIR}/references/output-renderer.md for table format,
sidecar schema, exit-code rubric, and --quiet mode.
mix.lock, mix.exs, or any project file (non-mutating)mix deps.{get,update,compile} via deps-audit-gate.sh. See references/hook.md./phx:compound after BLOCK findings — corpus self-feeds.--sarif <path> and gate CI via --ci.${CLAUDE_SKILL_DIR}/references/heuristics.md — full 35-rule catalogue${CLAUDE_SKILL_DIR}/references/rules-impl.md — bash + mix run -e for the 8 MVP rules${CLAUDE_SKILL_DIR}/references/operating-modes.md — Mode A/B/C resolver${CLAUDE_SKILL_DIR}/references/diff-resolver.md — shell snippets, lock parser${CLAUDE_SKILL_DIR}/references/tarball-fetcher.md — fetch wrapper, parallel cap, cache prune${CLAUDE_SKILL_DIR}/references/external-tools.md — mix_audit, osv-scanner wrappers${CLAUDE_SKILL_DIR}/references/hex-api.md — endpoint contracts, rate limit, Rule 6/8${CLAUDE_SKILL_DIR}/references/output-renderer.md — markdown, JSON v1, exit codes, SARIF${CLAUDE_SKILL_DIR}/references/testing.md — smoke runner, fixture matrix${CLAUDE_SKILL_DIR}/references/differential.md / llm-triage.md — Phase 2 NDJSON subtract + triager${CLAUDE_SKILL_DIR}/references/semgrep.md / yara.md — Phase 2 precision layers (soft deps)${CLAUDE_SKILL_DIR}/references/cassettes.md / sarif.md / hook.md / ci-integration.md — Phase 3 surface${CLAUDE_SKILL_DIR}/references/trusted-publishers.md / skill-checklist.md — upstream + eval${CLAUDE_SKILL_DIR}/references/audit-tmpdir.md — Phase 5 per-run ephemeral storage contract${CLAUDE_SKILL_DIR}/references/execution-flow.md / differential-cve.md — Phase 5 default scan + CVE difftools
Scope or freeze which files Claude can edit during debugging, a refactor, or review. Use when edits should stay in specific dirs, or for a read-only investigate lock. Backed by a sentinel + PreToolUse hook.
development
Ash Framework — resources, actions, policies, aggregates, calculations, AshPhoenix.Form, LiveView, migrations. Use when generating resources via mix ash.codegen, editing changes, checks, types, validations, or domain code interfaces.
development
Reduce mix output noise (5-15% token savings) by installing rtk filters that compress mix test/credo/dialyzer/compile output before it reaches Claude. Use when long mix output floods context.
development
Narrow bare rescue in Elixir so real errors like KeyError and typos propagate instead of being swallowed. Use to audit rescues and refactor error handling.