When a developer opens a pull request against a repository wired into Snyk, a vulnerability scan can run before a single human reviewer looks at the diff. That automation is built on GitHub Actions — Snyk publishes a set of official, language-specific actions (in the snyk/actions repository) that plug into a repo's existing CI workflow files and run snyk test, snyk code test, snyk container test, or snyk iac test against the code in the PR. The mechanism is not magic: it's a Docker-based GitHub Action, a stored SNYK_TOKEN secret, a pull_request trigger, and an exit code that GitHub interprets as pass or fail. Because so many teams now gate merges on automated security checks, understanding exactly how that pipeline works — what gets scanned, when, and what makes a check go red — matters for anyone maintaining a supply chain security program. Here's the mechanical breakdown.
What is Snyk's GitHub Actions integration, exactly?
It's a published catalog of GitHub Actions that wrap the Snyk CLI, listed publicly in the snyk/actions GitHub repository and on the GitHub Marketplace. Rather than shipping one generic action, Snyk maintains separate entry points for different ecosystems — snyk/actions/node, snyk/actions/python, snyk/actions/golang, snyk/actions/maven, snyk/actions/gradle, snyk/actions/docker, snyk/actions/terraform, and roughly a dozen others — each one a thin wrapper that pulls a Docker image containing the Snyk CLI preconfigured for that language's dependency resolution logic. This is distinct from Snyk's native GitHub App integration (configured under Snyk's "Integrations" settings), which connects directly to a repo via OAuth and posts its own PR checks outside of any workflow YAML. The Actions-based path is the one teams use when they want scanning to live inside their own CI definitions, version-controlled alongside the rest of the pipeline, rather than delegated entirely to a third-party app's background service.
How does a pull request trigger a Snyk scan?
It triggers the same way any GitHub Actions job triggers: through an on: clause in a workflow YAML file that listens for the pull_request event. A typical setup looks like:
on: pull_request
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
When a contributor opens or updates a PR, GitHub's runner provisions a fresh Ubuntu VM, checks out the PR's head commit, and executes the job's steps in order. The SNYK_TOKEN — an API token generated from a Snyk account and stored as an encrypted GitHub Actions secret — authenticates the CLI inside the container so it can pull vulnerability data from Snyk's backend and, for paid tiers, report results back to the Snyk web dashboard. Nothing about this is bespoke to Snyk; it's the standard GitHub Actions secrets-and-trigger model applied to a security tool instead of a build tool.
What happens inside the Snyk Action when it runs?
The container resolves the project's dependency tree and diffs it against Snyk's vulnerability database. For a Node.js project, that means parsing package.json and the lockfile to build a full dependency graph, then checking every resolved package version — direct and transitive — against known CVEs and Snyk-curated advisories. For snyk/actions/docker, it pulls and inspects the built image layers; for snyk/actions/terraform, it statically parses .tf files for misconfigurations rather than resolving packages at all. This step is where most of the scan's wall-clock time is spent: on a typical mid-sized Node or Python project, dependency resolution and lookup usually finishes in well under a minute, though monorepos with thousands of transitive dependencies or large container images can push that past several minutes. The CLI outputs results as JSON or, if configured, in SARIF format via the --sarif-file-output flag — this is the detail that connects the scan to the rest of GitHub's tooling.
How do scan results reach the pull request and the Security tab?
They reach it through a second, separate action: github/codeql-action/upload-sarif. Snyk's own action does not push findings directly into GitHub's UI — the documented pattern chains a Snyk step that emits a SARIF file with a follow-up step that uploads it:
- uses: snyk/actions/node@master
continue-on-error: true
with:
args: --sarif-file-output=snyk.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: snyk.sarif
Once uploaded, findings appear under the repository's Security tab as code scanning alerts, and — for alerts introduced by the PR's diff — as inline annotations on the changed lines within the pull request's "Files changed" view. This is why continue-on-error: true shows up in nearly every published example: without it, a failing Snyk step would stop the job before the SARIF upload step ever runs, and the PR would show a red check with no annotations explaining why.
What severity thresholds and exit codes control whether a PR is blocked?
Whether a PR gets blocked comes down to a single CLI flag and an exit code, not a Snyk-specific gating system layered on top of GitHub. The --severity-threshold argument accepts low, medium, high, or critical, and the Snyk CLI exits with a non-zero status if it finds any issue at or above that threshold. GitHub Actions treats a non-zero exit code from any step as a job failure by default, which surfaces as a red "X" status check on the pull request. If that check is configured as a required status check in the repo's branch protection rules, the merge button is disabled until the issue is fixed or the check is bypassed by someone with override permissions. Set the threshold to critical and only CVSS-critical issues block the merge; set it to low and nearly any known issue does. There is no scanning logic beyond this — teams tune blocking behavior entirely through that one argument plus GitHub's own branch protection settings.
What are the limits of scanning inside GitHub Actions?
The scan only ever sees what's checked out in that specific PR run, at that specific commit, in that specific job's filesystem. It doesn't have visibility into what happens after merge — a dependency that resolves cleanly today can have a new CVE disclosed against it next week, and nothing in the PR-time workflow re-runs the check retroactively unless a separate scheduled workflow (commonly triggered on: schedule with a cron expression, run nightly or weekly) or Snyk's continuous monitoring via snyk monitor picks it up later. The check is also fundamentally CLI-scoped: it evaluates the manifest and lockfile in the repo, not the actual artifact that eventually gets built, signed, and deployed, so a build step that fetches a different dependency version than what was scanned — due to a floating version range, a private registry override, or a build-time script — can silently drift from what the PR check approved. And because the action runs as one job among potentially many in a workflow, a misconfigured continue-on-error, a missing required-check designation in branch protection, or a token with insufficient scope can all cause the scan to run without ever actually being able to block a merge.
How Safeguard Helps
Dependency scanning inside a PR check is one control among many that a software supply chain needs, and it works best when it's backed by verification of what actually happens between that check passing and code reaching production. Safeguard focuses on that gap: verifying build provenance and artifact integrity, generating and tracking SBOMs tied to what was actually built rather than what a manifest claimed at scan time, and giving security teams policy controls that span the full pipeline — not just the moment a PR is opened, but the build, packaging, and deployment steps that follow. Where a GitHub Actions-based scanner answers "did this pull request introduce a known vulnerable package," Safeguard is built to answer the adjacent questions teams often can't: was this artifact built from the code that was actually reviewed, has anything been substituted or tampered with in the pipeline since, and does the deployed system match its attested provenance. Used together, dependency-level PR scanning and pipeline-level provenance verification close different parts of the same supply chain, which is why we built Safeguard to complement — not replace — the scanning tools teams already run.