Safeguard
Guides

How to Set Up Dependency Review on GitHub Pull Requests

GitHub's dependency-review-action can block PRs that introduce vulnerable or badly-licensed packages. Here is the exact configuration, plus the cases it silently misses.

Sofia Marchetti
Open Source Program Lead
5 min read

Dependency review is GitHub's pull-request gate that diffs the dependencies a PR adds or changes against the GitHub Advisory Database and your license policy, and it blocks the merge before a vulnerable package ever lands on your default branch. It is the cheapest supply-chain control most teams have not turned on: shift the check from "scan main nightly" to "stop it at the PR," and remediation cost drops from a ticket to a review comment. Setup takes about twenty minutes. Here is the whole thing, including the sharp edges.

What it actually does

When a PR touches a manifest or lockfile that the dependency graph understands — package-lock.json, requirements.txt, go.mod, pom.xml, Cargo.lock, and the rest of the supported list — GitHub computes the dependency diff: every package added, removed, or version-changed. The dependency-review-action then evaluates that diff against three things: known advisories (GHSA), your license allow/deny lists, and optionally a list of packages you have banned outright. It sees only the diff. Pre-existing vulnerabilities in the base branch do not fail the check, which is exactly the property that makes it politically survivable — developers are gated on their change, not on five years of inherited debt.

Enable the prerequisites

Dependency graph is on by default for public repos. For private repos: Settings → Security → Code security and analysis → enable Dependency graph. The review action is free for public repositories; private repositories need GitHub Advanced Security (the Code Security SKU, after GitHub split GHAS licensing in 2025).

Organization-wide, do this once from the org's Code security settings rather than repo by repo — new repositories inherit it and you avoid the coverage gaps that turn up in every audit.

Add the workflow

Create .github/workflows/dependency-review.yml:

name: Dependency review
on: pull_request

permissions:
  contents: read
  pull-requests: write   # needed for comment-summary-in-pr

jobs:
  dependency-review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/dependency-review-action@v4
        with:
          fail-on-severity: high
          comment-summary-in-pr: always
          deny-licenses: GPL-3.0, AGPL-3.0
          fail-on-scopes: runtime

Notes on the choices:

  • fail-on-severity: high blocks high and critical advisories. Starting at critical only is defensible for a noisy monorepo; going down to moderate is usually premature until the team trusts the gate.
  • comment-summary-in-pr: always posts the findings as a PR comment instead of burying them in the Actions log. This one option roughly doubles how often developers act on the result, in my experience rolling this out across a 200-repo org.
  • fail-on-scopes: runtime skips development-only dependencies. A vulnerable devDependency in a test helper is real but it is not "block the release" real.
  • License names must be valid SPDX identifiers, and you get either allow-licenses or deny-licenses, not both.

Then make it mandatory: Settings → Branches (or a repository ruleset) → require the dependency-review check before merging. Without required-status enforcement you have built a suggestion, not a gate.

Gate licenses like you mean it

For OSPO purposes the license gate is arguably the bigger win, because license problems are far more expensive to remove after they ship. A deny-list of AGPL-3.0 and SSPL-1.0 for anything distributed is a common floor. If you maintain a formal policy, express it as allow-licenses instead — a short allowlist (MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC) fails closed on the weird stuff, including packages whose license GitHub cannot determine, which you want a human to look at anyway.

allow-dependencies-licenses exists for the inevitable exception: a specific purl you have taken legal advice on and accepted.

What dependency review misses

Three gaps to know about before you rely on it:

  1. It only triggers on manifest changes. An advisory published after your dependency merged will never fail this check — that is Dependabot's job, and the two are complements, not substitutes. (See our notes on Dependabot's update behavior for how that half works.)
  2. It only sees what the dependency graph sees. Dependencies resolved at build time — Dockerfiles, Bazel, vendored tarballs — are invisible unless you submit them yourself via the dependency submission API.
  3. No reachability, no exploit context. The action knows an advisory exists; it does not know whether the vulnerable function is called or whether an exploit is circulating. Teams that outgrow severity-only gating typically layer a reachability-aware SCA on the same PR event — Safeguard runs this as a second check that can downgrade unreachable findings instead of blocking on them, and the Snyk comparison covers how the major tools differ here.

Frequently asked questions

Does dependency review work on private repositories without paying?

No. Private repos need the GitHub Advanced Security Code Security license. Public repositories get the action free, which is why open source projects should turn it on today.

Why did my PR pass even though the repo has known vulnerabilities?

By design, the action evaluates only the dependency diff in the PR. Existing findings on the base branch belong to Dependabot alerts and your backlog process, not to the PR gate.

Can I make it warn without blocking while the team adjusts?

Yes — set warn-only: true in the action config, keep comment-summary-in-pr: always, and flip to enforcement after a sprint or two of clean signal. Just set a date, or warn-only becomes permanent.

Which ecosystems are covered?

Anything the dependency graph parses: npm, PyPI, Maven, NuGet, Go, RubyGems, Cargo, Composer, and GitHub Actions workflows themselves, among others. If your ecosystem is not parsed, use the dependency submission API to feed the graph from your build.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.