
Shields against supply-chain, slopsquatting, and typosquatting attacks from dependencies and code.
cargo install sloppy-joe
The LiteLLM supply chain attack (March 2026) compromised a package with 97M monthly downloads. Attackers stole publishing credentials, pushed malicious versions that harvested SSH keys, cloud credentials, and K8s secrets. sloppy-joe's default 72-hour version age gate would have blocked both poisoned versions — they were discovered within hours, well before the gate would have opened. If you run
sloppy-joe checkin CI, this attack fails. Full analysis
AI code generators hallucinate package names ~20% of the time. Attackers register those names and wait. sloppy-joe catches them in CI before npm install or pip install runs.
# Install (single static binary, no runtime dependencies)
cargo install sloppy-joe
# Or download an auditable binary archive from GitHub Releases
# https://github.com/brennhill/sloppy-joe/releases
# Fast local guardrail — auto-detects ecosystem from manifest files
sloppy-joe check
# Strict online scan (recommended before push / release)
sloppy-joe check --full
# Strict CI-oriented scan
sloppy-joe check --ci
# Check a specific directory
sloppy-joe check --dir ./my-project
# Check only npm dependencies
sloppy-joe check --type npm
# Check the Python runtime plus selected groups/extras
sloppy-joe check --python-groups dev,test --python-version 3.12
sloppy-joe check --python-extras docs --python-platform linux --python-version 3.12
# Enforce canonical rules and org standards via config
sloppy-joe check --config /etc/sloppy-joe/config.json
# Config from a URL (useful in CI — no secrets to manage)
sloppy-joe check --config https://raw.githubusercontent.com/yourorg/security-configs/main/sloppy-joe.json
# JSON output for CI pipelines
sloppy-joe check --json
# Review exact maintainer-change exceptions with evidence
sloppy-joe check --review-exceptions
# Create and register a safe per-repo config outside the repo
sloppy-joe init --register
# Create an ecosystem-specific greenfield starter policy
sloppy-joe init --greenfield --ecosystem npm
# Print review-only bootstrap suggestions for an npm or Cargo repo
sloppy-joe init --from-current
# Or write/register those suggestions safely outside the repo
sloppy-joe init --from-current --register
# Or write a config manually to a secure path outside the repo
sloppy-joe init > /secure/location/sloppy-joe.json
nix profile install github:brennhill/sloppy-joe
Scan modes:
sloppy-joe check runs the fast local guardrail. It always enforces manifest parsing, lockfile/sync, provenance, and unsupported-source policy. If dependency or policy state changed, or the last successful full scan is older than 24 hours, it recommends sloppy-joe check --full.sloppy-joe check --full runs the strict online scan and refreshes the recorded successful full-scan state.sloppy-joe check --ci runs the same strict coverage as --full, with CI-oriented intent.sloppy-joe check evaluates the runtime profile by default. If scoped dependencies exist, it warns and tells you to pass explicit --python-groups, --python-extras, --python-platform, and/or --python-version flags for CI/build parity.sloppy-joe check output always reminds you to use --ci or --full for CI and production gating.Exit codes: 0 = no blocking issues found in the selected mode, 1 = blocking issues found, 2 = runtime error.
Supports: JavaScript (npm, pnpm, Yarn, Bun), Python, Rust, Go, Ruby, PHP, JVM (Gradle/Maven), and .NET — auto-detected from manifest files.
Ecosystem guides: see docs/ecosystems/README.md for the current trust model, supported features, and fail-closed limits for each ecosystem.
| Ecosystem | Required manifest | Trusted lockfile / project state |
|---|---|---|
| JavaScript / npm | package.json | package-lock.json or npm-shrinkwrap.json; legacy npm v1 blocked by default |
| JavaScript / pnpm | package.json | pnpm-lock.yaml |
| JavaScript / Yarn | package.json | yarn.lock |
| JavaScript / Bun | package.json | bun.lock |
| Python | pyproject.toml, requirements*.txt, Pipfile, setup.cfg, or setup.py | trusted Poetry path uses poetry.lock, trusted uv path uses uv.lock, and fully hash-locked pip-tools is trusted only when the committed requirements graph binds --index-url and any --extra-index-url values exactly; repo-visible Python indexes can be allowlisted via trusted_indexes.pypi; trusted Python modes evaluate one selected install profile at a time (runtime by default, explicit groups/extras/platform/arch/version via CLI); legacy manifests allowed with warnings by default |
| Rust | Cargo.toml | Cargo.lock |
| Go | go.mod | go.sum required for external deps |
| Ruby | Gemfile | Gemfile.lock |
| PHP / Composer | composer.json | composer.lock |
| JVM / Gradle | build.gradle or build.gradle.kts | gradle.lockfile |
| JVM / Maven | pom.xml | warning-only: no trusted project-local lockfile path yet |
| .NET / NuGet | .csproj | packages.lock.json |
Config sources: local file path, HTTPS URL, or SLOPPY_JOE_CONFIG env var. Config is never read from the project directory (see CONFIG.md for why).
Onboarding: use the bootstrap mode that matches the repo:
sloppy-joe init --greenfield --ecosystem <eco> prints an ecosystem-specific starter policy for new projects. Today, greenfield presets are implemented for npm, pypi, and cargo; other ecosystems fail with a “not supported yet” error. Add --register to write it outside the repo and register it safely.sloppy-joe init --from-current inspects the current repo and prints review-only bootstrap suggestions. Today, --from-current is implemented only for repos whose first-party code is npm and/or cargo; other ecosystems fail closed with a “not implemented yet” error. Add --register to write and register the generated config.sloppy-joe init with no mode prints a neutral manual template.Single binary. 8 ecosystems. 16 attack types. Zero false positives on generative checks. Config that AI agents can't tamper with.