Safeguard
Open Source Security

How the --policy-path option centralizes ignore rules acr...

A technical look at how Snyk's --policy-path flag lets teams share one .snyk ignore file across repos instead of duplicating exceptions everywhere.

Daniel Chen
Security Engineer
6 min read

Vulnerability triage rarely stops at "found it." Once a team decides a finding is a false positive, not exploitable in context, or scheduled for a later patch window, that decision has to be recorded somewhere Snyk will respect on every future scan. The default mechanism is a .snyk policy file sitting next to the manifest it applies to. That works fine for a single repository. It breaks down fast for an organization running 30, 60, or 200 services, where the same third-party CVE — say a transitive lodash or axios advisory — shows up in dozens of repos at once and someone has to decide, repo by repo, whether to duplicate the same ignore entry everywhere. Snyk's --policy-path flag exists specifically to let a CLI invocation point at a policy file that lives somewhere other than the project root, which is what makes centralizing those rules across projects possible in the first place.

What does the --policy-path flag actually do?

--policy-path tells snyk test and snyk monitor to load ignore and patch rules from a file location you specify, instead of the .snyk file Snyk would otherwise look for in the current working directory. The default behavior, documented in Snyk's CLI reference, is auto-discovery: Snyk looks for a file literally named .snyk in the directory where the scan is run. Passing snyk test --policy-path=/shared-config/.snyk overrides that lookup and reads the policy from wherever that path resolves, whether that's a sibling directory, a path checked out from a separate configuration repository, or a location mounted into a CI container. Nothing about the vulnerability scan itself changes — the flag only changes where the exception list comes from.

How is a .snyk policy file structured?

A .snyk file is YAML with a version header and one or more top-level sections, most commonly ignore and, for older patch-based workflows, patch. A typical entry under ignore is keyed by the vulnerability identifier (for example SNYK-JS-LODASH-1040724) and contains a list of match rules, each with a reason string, an expires timestamp, and an optional path that scopes the ignore to a specific dependency chain rather than blanket-suppressing the CVE everywhere it appears. The file also carries a version field (Snyk has iterated the schema through versions like v1.5.0) so the CLI knows how to parse older files generated by earlier tooling. Because it's plain YAML, it's diffable, reviewable in a pull request, and — critically for centralization — copyable as a single artifact that many projects can reference instead of owning their own copy.

How does Snyk match ignore rules to vulnerabilities across projects?

Matching happens by vulnerability ID first, then by the optional dependency path inside that ID's block. When snyk test runs against a manifest and finds a vulnerability, it checks the loaded policy file for an entry with a matching ID; if the entry has no path restriction, the ignore applies wherever that vulnerability is found in the current scan, and if a path is specified (for example * > request > qs), the ignore only suppresses that finding along that specific dependency chain. This is what makes one shared file usable across multiple codebases with different dependency trees — a rule written for SNYK-JS-QS-3153490 will match that same advisory in any project pointed at the file, without teams needing to hand-craft a separate entry per repo, as long as the path scoping (or lack of it) is intentional rather than accidental.

How do expiration dates keep centralized ignores from becoming permanent?

Every ignore entry can carry an expires field, an ISO 8601 timestamp such as 2026-08-15T00:00:00.000Z, after which Snyk stops honoring the suppression and the finding reappears in scan output and exit codes. This is generated automatically when you use the snyk ignore CLI command with an --expiry flag — for example snyk ignore --id=SNYK-JS-LODASH-1040724 --expiry=2026-08-15 --reason="Patch scheduled in Q3 release" writes both the reason and the expiry into the policy file. Because the expiry lives in the same file that's shared across projects, a security or platform team can set one deadline that governs every repo pointed at that file, rather than tracking 40 separate expiration dates scattered across 40 separate .snyk files with no shared source of truth.

How do teams actually wire a shared policy file into CI across many repos?

In practice, teams check the centralized .snyk file into a dedicated configuration repository or a shared library package, then have each project's CI job pull that file down before invoking Snyk, commonly via a git submodule, a build step that copies the file from a shared artifact, or a mounted path in a container image. The CI step then runs something like snyk test --policy-path=./shared/.snyk --severity-threshold=high so every pipeline resolves ignores against the same canonical list. Snyk's own CLI documentation frames --policy-path as compatible with both snyk test and snyk monitor, meaning the same centralized file governs both point-in-time scans and the continuously monitored snapshots Snyk keeps for a project, so ignore decisions stay consistent whether a scan is triggered by a pull request or by Snyk's scheduled re-testing of previously monitored dependencies.

What are the limits of file-based centralization?

The main limitation is that --policy-path centralizes storage, not governance — the file itself has no built-in access control, so anything with write access to the shared repo or artifact can add, edit, or quietly widen an ignore rule, and there's no CLI-enforced approval workflow before a suppression takes effect locally. It's also a pull-based model: a project only picks up the latest ignore list when its CI job re-fetches the file, so a stale checkout or a cached copy in a long-lived build image can leave a repo scanning against outdated exceptions. And because matching is scoped to vulnerability ID and dependency path, teams still need discipline in how specific they make each path entry — an overly broad, unscoped ignore written for one project's dependency tree can silently suppress a genuinely different exposure in another project that happens to pull in the same package via a different chain.

How Safeguard Helps

Snyk's --policy-path mechanism solves a real problem — nobody should hand-maintain forty copies of the same ignore rule — but it does so at the file level, which means the governance questions it leaves open (who approved this suppression, is it still current, does it apply consistently everywhere it's referenced) end up being tracked in spreadsheets, Slack threads, or tribal knowledge rather than in the security tooling itself. Safeguard approaches this from the supply-chain side: rather than centralizing exceptions in a YAML file that has to be fetched and trusted by every pipeline, Safeguard tracks dependency risk, provenance, and remediation status across an organization's full repository inventory in one place, with an audit trail attached to every exception decision — who made it, why, and when it expires — visible across every project it touches, not just the ones whose CI happened to pull the latest file. For teams already using ignore-file workflows like --policy-path, that visibility layer is complementary: it doesn't replace the scanning decision, it makes the resulting exceptions accountable at the organization level instead of the individual repository level.

Never miss an update

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