agentleFS
ccpowerpackccpowerpack/claude-code-skills/skills/dependency-audit/SKILL.md

dependency-audit

Skill0 starsChanged 4 months agoMITView on GitHub

Vet a new dependency (or a dependency-heavy diff) before it lands. Proves the package exists with the exact spelling on the official registry BEFORE any install, then checks health and supply-chain risk. Use for "should I add this package", "audit these deps", "is this library safe", "review this package.json/requirements.txt/go.mod/Cargo.toml change", or whenever an LLM-suggested import points at a package you have not personally verified exists.

  • Reads credentials
  • Installs packages

42 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use api-audit, container-audit and 8 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • gmanch94Skill

    api-audit

    Guides a structured API portfolio audit — from discovery through primary-source-verified inventory, shortcomings analysis, prioritized recommendations, executive summary, and options analysis. Enforces primary-source discipline, cross-file consistency, and advisor review gates. Use when auditing an API portfolio, evaluating a vendor's developer ecosystem, or producing defensible technical analysis of an API set.

    Also in 3 projects that use this

  • grichaSkill

    container-audit

    Audit local Docker images and running containers for hardening issues before deploy — privileged flags, root users, stale base images, missing resource limits. Use for pre-deploy container review.

    Also in 3 projects that use this

  • conorluddySkill

    performance-profiling

    Instruments integration and performance analysis workflows for iOS apps. Use when profiling CPU usage, memory allocation, network activity, or energy consumption. Covers Time Profiler, Allocations, Leaks, Network instruments, and performance optimization strategies.

    Also in 3 projects that use this

  • OpenAISkill

    threat-model

    Use when Codex is already in the threat-modeling phase of a security scan, the user explicitly invokes $threat-model, or the user explicitly asks to create, update, or persist a repository threat model. Do not use as the primary trigger for full PR, commit, branch, patch, or repository scans.

    Also in 4 projects that use this

  • renfei-designSkill

    a11y-audit

    Audit Figma designs for WCAG accessibility issues — color contrast, minimum font size, touch target sizing, and missing text alternatives. Use when asked to check accessibility, audit contrast ratios, find a11y issues, verify WCAG compliance, or review designs for accessibility problems. Scans nodes, analyzes offline, and annotates issues in Figma.

    Also in 3 projects that use this

  • OpenAISkill

    security-scan

    Use for a standard, single-pass security audit of an entire repository or a scoped path, package, folder, or submodule with no diff to review. This is the default repository scan. Do not use for PR, commit, branch, or working-tree diffs, or for deep, multi-pass scans.

    Also in 4 projects that use this

The file

We split this skill into the rules it gives an agent

4 rules. 0 are common, 3 are distinctive, and 1 is very specific to this project.

  • 0

    Common

    Most of the 39 edited versions we read keep these.

  • 3

    Distinctive

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    If the name does not resolve → stop.

    line 30
  2. Distinctive:

    No justification line → the dependency does not land.

    line 51
  3. Distinctive:

    When the change is a big lockfile delta rather than one new import, don't hand-check hundreds of lines — bound the work:

    line 89
  4. Very specific:

    Do not emit the install command until every listed package reads ADOPT.

    line 143

“Common” is measured: kept by at least 6 in 10 of the 39 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Dependency Audit

You are deciding whether a dependency earns its place in the tree. The cardinal rule: you may not run an install command until you have proven the package exists on the official registry with the exact spelling you intend to install. Model-suggested package names are a supply-chain attack surface: LLMs hallucinate plausible names, and attackers pre-register those exact names as malware (slopsquatting). The install command is where a typo becomes a breach — so verification comes strictly before it.

Second rule: every new direct dependency needs a one-line justification against writing it yourself. A left-pad-sized need does not justify a tree-sized liability.

Phase 1 — Existence & typosquat gate (do not emit an install command before this passes)

For the exact string you plan to install, confirm it resolves on the official registry and is the package you think it is. Run the check for the ecosystem, paste the real output.

EcosystemExistence checkSquat/typo check
npmnpm view <pkg> version time.created homepage repositoryCompare to the intended repo; watch for scope confusion (@org/pkg vs pkg), hyphen/underscore swaps, added js/2 suffixes
PyPIpip index versions <pkg> or curl -s https://pypi.org/pypi/<pkg>/json | jq '.info.name, .info.home_page, .urls[].upload_time'Underscore vs hyphen normalize the same on PyPI, but the import name differing wildly from the repo is a flag; check .info.author and project URLs point to the real project
Cargocargo search <pkg> then curl -s https://crates.io/api/v1/crates/<pkg> | jq '.crate.repository, .crate.downloads'Look-alike names with swapped words; verify repository is the canonical source
Gocurl -s "https://proxy.golang.org/<module>/@v/list" (module path lowercased)The module path is the identity; a different host/org path is a different package. Verify the path matches the real repo
RubyGemsgem info <name> -r or curl -s https://rubygems.org/api/v1/gems/<name>.json | jq '.name, .source_code_uri, .downloads'Underscore/hyphen swaps; verify source_code_uri
Mavencurl -s "https://search.maven.org/solrsearch/select?q=g:<group>+AND+a:<artifact>&rows=1&wt=json" | jq '.response.numFound'groupId is the trust anchor — a familiar artifactId under an unfamiliar groupId is a different, untrusted publisher

Gate conditions — all must hold before install:

  • The exact name resolves (non-empty, non-404).
  • The repository/homepage points at the project you actually intend (not a fresh empty repo).
  • First-publish date and version history are consistent with a real project (a "popular utility" published 6 days ago with one version is a squat until proven otherwise).

If the name does not resolve → stop. Do not "npm install and see." A non-existent name suggested by a model is the exact slopsquat trigger. Re-derive what the code actually needs and find the real package by reading docs, not by guessing spellings.

Common squat patterns to eyeball the name against (any hit means slow down and confirm identity):

PatternLegitSquat
Char swap / typorequestsreqeusts, request
Separator swappython-dateutilpython_dateutil published by someone else
Added filler wordcrossenvcross-env clone, colourama vs colorama
Scope/namespace drop@types/nodetypes-node
Look-alike homoglyphlodash1odash, l0dash
Suffix/version baitaxiosaxios-js, axios2

Phase 2 — "Do we even need it?" gate

For each new direct dep, write one line: what it does that's not worth writing ourselves.

  • Is the used surface one function? (is-odd, left-pad, a UUID v4, a debounce) → inline it; don't take the tree.
  • Does something already in the lockfile cover it? Grep existing deps first.
  • Does the stdlib cover it? (crypto.randomUUID, Array.prototype.flat, pathlib, net/http.)

No justification line → the dependency does not land.

Phase 3 — Health signals

Pull these and judge the package as a maintained artifact, not a snapshot.

  • Last release date — abandoned (>18mo, open CVEs) or churning-too-fast?
  • Maintainer count / bus factor — single maintainer + your prod critical path = risk to log.
  • Download trend — flat-tiny or suspiciously spiking (post-typosquat)?
  • Open critical issues / unpatched advisories — npm audit, pip-audit, cargo audit, govulncheck.
  • Install scripts present? — npm view <pkg> scripts for preinstall/postinstall; these run arbitrary code at install time.
  • Transitive dep count — npm view <pkg> dependencies / check the lockfile delta. 4 lines of need pulling 60 packages is a no.
  • Repo ↔ registry match — is the published artifact built from the repo you're reading? (provenance/attestations if available.)

Reading an install script before you trust it — when Phase 4 flags postinstall/preinstall or a setup.py that runs code, actually open it (npm view <pkg> dist.tarball then extract, or read the sdist). Red flags: base64/hex blobs decoded and eval'd, curl/wget to an IP or pastebin, writes to ~/.ssh / ~/.npmrc / env dumps, child_process/os.system spawning shells, obfuscated one-liners. A legit build script compiles native code or copies files — it does not phone home or read your credentials.

Phase 4 — Supply-chain risk table

Classify the package on these axes; each "yes" raises the bar for landing it.

RiskHow to detectWhy it matters
Install-time scriptsnpm view <pkg> scripts; pip sdist with setup.py running codeCode executes on install, in CI and dev machines, before your tests ever run
Native buildsgyp/node-gyp, build.rs, C extension in sdistCompiles arbitrary C at install; breaks reproducibility; needs toolchain in prod images
Network at runtimegrep the package for outbound calls, telemetryPhones home; exfiltration surface; availability coupling
License familynpm view <pkg> license; check SPDXCopyleft (GPL/AGPL) in a proprietary codebase is a legal landmine; verify against your policy

Phase 5 — Pin it so the vetted artifact is the one that installs

Verifying a name means nothing if a later resolve pulls a different build. After a package clears:

  • Pin the exact version and hash. package-lock.json/yarn.lock, requirements.txt with == + --hash (or pip-compile/uv), Cargo.lock, go.sum, Gemfile.lock. Commit the lockfile in the same diff.
  • Prefer --frozen-lockfile / npm ci / pip install --require-hashes in CI so an attacker who later republishes the same version number (or a compromised registry) can't swap the bytes.
  • Turn off install scripts by default where you can (npm ci --ignore-scripts, then allowlist the few that genuinely need them) — this neutralizes the most common post-typosquat payload vector.
  • Record why a version, not latest. Floating ranges (^, ~, *) re-open the supply chain on every install; a pinned version is the artifact you actually audited.

Auditing a dependency-heavy diff (many deps at once)

When the change is a big lockfile delta rather than one new import, don't hand-check hundreds of lines — bound the work:

# What actually changed, direct vs transitive
git diff <base>..HEAD -- package-lock.json yarn.lock pnpm-lock.yaml requirements*.txt go.sum Cargo.lock
npm ls --all --depth=0            # or: pipdeptree ; cargo tree ; go mod graph
  • Separate direct from transitive. New direct deps get the full Phase 1–5 treatment. New transitive deps you scan for the loud risks: brand-new packages, install scripts, name look-alikes to known packages (classic squat vector for indirect deps).
  • Diff the count, not just the names. A one-line manifest change that adds 200 transitive packages is the finding — flag the blast-radius jump.
  • Run the ecosystem auditor on the delta: npm audit, pip-audit, cargo audit, govulncheck ./..., osv-scanner. Treat output as candidates to triage, not verdicts.
  • Any brand-new-and-popular transitive dep is the slopsquat signature — a package with a familiar name, published days ago, suddenly in your tree. Verify its identity even though nobody "chose" it.

Beyond typosquats — a package that exists and is real can still turn hostile. Existence checks don't catch: maintainer-account takeover pushing a malicious patch release, a formerly-good package sold to a new owner, or protestware triggered by locale/date. This is why Phase 5 pinning + hashes matter even for trusted names, and why a new patch version of an existing dep still deserves a glance at its diff/changelog before you bump it — not just new packages.

Worked example — agent-suggested package caught at the gate

An agent writes import requests_async_retry and suggests pip install requests-async-retry for "async HTTP with retries."

Phase 1:

$ pip index versions requests-async-retry
WARNING: No matching distribution found for requests-async-retry
$ curl -s https://pypi.org/pypi/requests-async-retry/json | jq .message
"Not Found"

Name does not resolve → gate fails, stop. This is the slopsquat danger zone: had a typosquatter registered that exact name last week with a postinstall payload, "just installing to check" would have run it. Do not try neighboring spellings blindly.

Re-derive the actual need: async HTTP client + retry/backoff. Read real docs → the maintained options are httpx (async client, exists since 2019, high downloads, clean repo) plus tenacity or httpx's transport-level retries.

$ curl -s https://pypi.org/pypi/httpx/json | jq '.info.name, .info.home_page, (.releases|keys|length)'
"httpx"
"https://github.com/encode/httpx"
100+

Verdict: drop the hallucinated name; adopt httpx, justified because a correct async connection-pooling + retry HTTP client is not worth hand-rolling.

Output contract

Deliver per package: existence-check output (pasted), the need-justification line (or "inline instead"), the health checklist with values, the risk-table classification, and a verdict ADOPT / INLINE / REJECT with the reason. Only after all packages are ADOPT do you present the install command. Use this verdict block:

pkg: <exact name>@<exact version>
exists: <yes — registry output pasted above>
need: <one line: why not inline>
health: last release <date> | maintainers <n> | transitive <n> | install-scripts <yes/no>
risk: <native/network/copyleft flags, or "none">
verdict: ADOPT | INLINE | REJECT — <reason>

Do not emit the install command until every listed package reads ADOPT.

Anti-patterns (hard no)

  • Running npm install / pip install before pasting the existence-check output for that exact name.
  • Trying alternate spellings of a name that didn't resolve instead of re-deriving the real package from docs.
  • Adding a dependency for a one-function need that inlines in under 30 lines.
  • Judging only the direct package and ignoring the transitive weight it drags in.
  • Treating a green npm audit as sufficient — it covers known CVEs, not abandonment, install scripts, or squats.
  • "It's popular so it's fine" without checking the repo↔registry match and publish history.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.