PkgRadar

Docs

Gate malicious dependencies in your CI — in minutes.

PkgRadar checks every dependency against our static scan corpus before it's installed and fails the build on a malicious one. Start with a free key (25 scans / mo, no card), drop one step into your pipeline, and you're protected.

1. Get an API key

Sign in (Google or a magic link — no password), then create a key from Dashboard → Keys. Keep it in CI as a secret, e.g. PKGRADAR_TOKEN.

2. Add the gate to your pipeline

GitHub Actions — one step. It auto-detects your lockfiles and fails the job on a high-risk dependency:

- name: PkgRadar gate
  uses: PkgRadar/pkgradar-cli@v1
  with:
    token: ${{ secrets.PKGRADAR_TOKEN }}
    fail-on: high

GitLab CI — include the hosted template and set your token:

include:
  - remote: 'https://pkgradar.com/templates/pkgradar.gitlab-ci.yml'

pkgradar:
  extends: .pkgradar-base
  stage: test

# Add PKGRADAR_TOKEN under Settings > CI/CD > Variables

Any other CI — install the prebuilt CLI binary and run the gate:

curl -sSfL https://pkgradar.com/install.sh | sh
pkgradar gate --lockfile package-lock.json --fail-on high

See the full CLI reference for install options (prebuilt binaries for Linux/macOS, or build from source), supported lockfiles, flags, and exit codes.

3. How the gate decides

Each dependency resolves to a verdict — high (block), review (inspect), or low (pass). The gate returns HTTP 200 when the build is allowed and 422when it's blocked; --fail-on (or fail_on in a .pkgradar.yml) chooses whether you block on high only or also on review. Already-known dependencies are served from a shared cache, so only genuinely new releases cost a scan. For the precision/recall behind the verdicts, see accuracy; for what the detectors look for, see methodology.

The gate fails open by default.If PkgRadar is unreachable or a scan times out, the build is allowed through rather than blocked — a PkgRadar outage won't block your pipeline. To fail closedinstead (block when we can't verify), set fail_open: false in .pkgradar.yml or pass --no-fail-open.

4. Diff mode on pull / merge requests

On a PR or MR pipeline you usually only care about what the change adds. Pass --baseline <ref> and the gate compares the lockfile against that ref and only gates newly-added or version-bumped dependencies— existing, already-reviewed deps don't re-trigger or re-spend scans. The GitHub Action and GitLab template wire this automatically on merge-request pipelines, so you typically don't set it by hand.

Exit codes & verdicts

The CLI and gate return predictable, CI-friendly exit codes. This is the canonical table — the CLI and firewall pages defer to it:

Exit codeMeaning
0Pass — every dependency cleared the fail-on threshold (or was allowlisted / waived).
1Blocked — at least one dependency breached the threshold (a high, or a review when fail_on: review).
2Usage / config error caught before running — missing token, bad spec, or an unknown flag.
3Runtime error — an invalid/rejected token, an unparseable lockfile, or a network/TLS failure reaching the gate. With fail-open (the default) a network failure still passes the build; a rejected token or bad lockfile surfaces here regardless.

A verdict of high blocks by default, review is a single weaker signal for a human look, and low passes. See accuracy for what each verdict means.

Troubleshooting

“Build passed but packages were not scanned”

The gate fails open, so it passes the build but logs a ::warning:: (GitHub) / WARNING (GitLab) line explaining why nothing was checked. The two common causes:

“PKGRADAR_TOKEN is not set”

The gate couldn't read your API key. On GitHub, confirm the secret is wired into the step (token: ${{ secrets.PKGRADAR_TOKEN }}). On GitLab, watch for the Protected-variable trap: a variable marked Protected is only injected on protected branches/tags, so it disappears on ordinary MR pipelines. Un-protect PKGRADAR_TOKEN (or run the gate only on protected refs). Mint or rotate keys at Dashboard → Keys.

A package you trust is flagged (false positive)

Add a waiver to .pkgradar.ymlnext to your lockfile. A waiver still scans and reports the package but doesn’t block on it — and it’s auditable (reason, reviewer) and can expire:

waivers:
  - package: "sharp"
    versions: ">=0.33.0, <0.34.0"   # optional semver range; omit = all versions
    reason: "native build; reviewed internally"
    reviewer: "[email protected]"      # optional
    expires: "2026-09-01"            # optional (YYYY-MM-DD); waiver stops applying after this

Prefer a waiver over allowlist: an allowlist entry bypasses the scan entirely (nothing is reported), whereas a waiver keeps the finding visible and leaves an expiry/reviewer trail. See the CLI reference for the full .pkgradar.yml schema, and please report genuine false positives to [email protected] — valid cases become permanent corpus entries (see accuracy).

Timeouts or network errors

By default the gate fails openon a timeout or unreachable backend: the build proceeds and a warning is logged, so an outage on our side can't block your pipeline. Tune the budget with timeout_ms in .pkgradar.yml. If you would rather block when we can't verify a dependency, set fail_open: false or pass --no-fail-open to fail closed.

Check a package directly

No setup needed — the public API returns a verdict for any package:

# the verdict lives at .report.risk (low / review / high) with .report.score
curl -s 'https://pkgradar.com/api/public/pkg?ecosystem=npm&name=lodash' \
  | jq '.report.risk, .report.score'

Or look one up on the package lookup.

From your AI assistant (MCP)

Check packages before you install or recommend them, right inside Claude Code, Cursor, or any MCP client:

claude mcp add pkgradar -- npx -y @pkgradar/mcp

Details on the MCP server page.

Need a hand?

Email [email protected] for setup or volume questions, or open a ticket from your dashboard. See pricing for plans and quotas.