To put policy in front of dependency installs, route every npm and pip fetch through one proxy that evaluates each package and version before it reaches a laptop or a build, run it in audit mode first so you can see what it would stop, then turn on warn and block for the rules you trust, with a written exception path for the cases that need one. Rules about licences, known vulnerabilities and package age need data the package manager does not carry, so pair the install-time proxy with policy gates on the bill of materials your builds produce. This post walks through that design for any team, then shows how Safeguard's Package Firewall and policy gates do each part.
Key takeaways
- An install-time control only works if it sits on the fetch path. If developers or CI can reach the public registry directly, the policy is advice, not enforcement.
- Because a proxy sees every download, it sees transitive dependencies too. You do not need to keep a separate lockfile parser in sync with what actually got installed.
- Write the policy as a table first: the rule, the data it needs, where it is enforced and what happens on a match. Many rules belong at the gate on your SBOM, not at the install.
- Start in audit mode. Measure what would have been blocked for a few weeks before anything fails an install.
- Exceptions are part of the design, not an afterthought. A named approver, a reason, an expiry date and a record keep people from routing around the control.
- Safeguard's Package Firewall (GA) runs as an install-time proxy for npm and pip, with allow, warn and block outcomes, plus audit and quarantine modes, and records every decision to the audit trail.
- Policies and gates (GA) evaluate licence, vulnerability severity, CVSS, EPSS, component age and maintenance conditions on your SBOMs. Each policy's action is Block, Warn or Notify, and approval runs through exceptions.
- License compliance (GA), SBOM generation and analysis (GA) and software composition analysis with vulnerability management (GA) supply the data those gates read.
- The Safeguard CLI (GA) starts the local or CI proxy with
safeguard pkgfw startand runs a one-shot check of a single package version withsafeguard pkgfw check.
The situation
You are the platform engineer, or the AppSec lead who shares the job with one. The ask arrives in a short message: "Can we stop bad dependencies at install time instead of finding them in the weekly scan?" Maybe it follows an audit question about how third-party components are approved. Maybe a release slipped because a dependency with a known critical vulnerability was found two days before ship. Maybe legal found a copyleft licence in a product that cannot carry one, and asked how it got in.
Today the honest picture is usually this. Developers run npm install and pip install against the public registries. CI does the same, sometimes through a caching repository manager that stores whatever it is asked for. A scanner runs after the build, or nightly, and produces findings. By then the package is in the lockfile, in the build cache, in a container layer and possibly in production. The fix is a pull request someone has to prioritise.
The request sounds simple. The hard parts are not technical. They are deciding which rules are worth failing an install for, keeping developers productive while the control beds in, handling the package that genuinely has to come in this week, and making sure nobody quietly points their machine back at the public registry because the proxy said no once.
A bad week looks like this: the proxy goes to block mode on a Monday with a rule set nobody measured, half the CI fleet fails on a transitive dependency nobody chose, the on-call engineer adds a bypass to unblock a release, and the bypass is still there in March.
The rules behind it
None of the main frameworks say "run a package proxy". They do ask you to control which third-party components come in, to know what you are using, and to be able to show both. A short tour, with the clause numbers taken from the primary texts. This is not legal, regulatory or audit advice; read the source for your own obligations.
NIST SP 800-218, the Secure Software Development Framework
The SSDF's practice PW.4 asks producers to reuse existing, well-secured software where feasible. Task PW.4.1 covers acquiring and maintaining well-secured components from commercial, open source and other third-party developers, and PW.4.4 covers verifying that acquired components comply with the organisation's requirements throughout their life cycles. Practice PO.1 asks you to define security requirements for software development; task PO.1.1 asks you to identify and document the security requirements for your development infrastructures and processes, which is where a written dependency policy lives. An install-time control is one way to make PW.4.4 something that happens on every fetch instead of something that happens at review time.
NIST SP 800-53 Rev. 5
Two controls map closely. CM-7(5), authorised software, allow by exception, asks you to identify the software allowed to execute and to deny everything else, with periodic review. CM-11, user-installed software, asks for policies governing what users can install and for enforcement and monitoring of those policies. A package proxy with a default policy, an exception list and an audit trail is a direct way to produce evidence for both in a development environment. The supply chain risk management family, SR, frames the wider programme, and NIST SP 800-161 Rev. 1 describes how organisations manage cyber supply chain risk across acquisition.
OpenSSF's Secure Supply Chain Consumption Framework
The OpenSSF S2C2F is the most practical of the set for this topic, because it is written for consumers of open source. Its Ingest requirements include ING-1 (use package managers trusted by your organisation), ING-2 (use an OSS binary repository manager) and ING-3 (have a deny list capability). Its Scan requirements include SCA-1 (scan for known vulnerabilities), SCA-2 (scan for licences) and SCA-3 (determine whether a component is end of life). Its Enforce requirements include ENF-1, securely configure package source files such as .npmrc and pip.conf, and ENF-2, enforce use of a curated feed. The framework works as a maturity ladder: an install-time proxy with pinned client configuration covers several Ingest and Enforce requirements at once, and gates on the SBOM cover the Scan ones.
OWASP Top 10
The OWASP Top 10 carried a category for vulnerable and outdated components for years, and the 2025 edition broadens it into A03:2025 Software Supply Chain Failures. Its prevention advice includes tracking transitive dependencies as well as direct ones, removing unused dependencies, continuously inventorying component versions, and obtaining components only from official, trusted sources over secure links. It also names unmaintained components that receive no security patches as a risk. Those map well onto a policy you can enforce on every install and at the gate.
What those sources ask of an install-time control
| Source | What it asks | What an install-time policy gives you |
|---|---|---|
| NIST SP 800-218 PW.4.1, PW.4.4 | Acquire well-secured components; verify they meet your requirements across their life cycle | A check on every fetch, with the requirement written down as policy |
| NIST SP 800-218 PO.1 | Define security requirements for development | A dependency policy table you can version and review |
| NIST SP 800-53 CM-7(5) | Allow approved software by exception, deny the rest | A default action plus a recorded exception list |
| NIST SP 800-53 CM-11 | Govern and monitor user-installed software | Every install decision recorded with who, what and when |
| OpenSSF S2C2F ING-1 to ING-3, ENF-1, ENF-2 | Trusted package sources, a repository manager, a deny list, secured package source files, a curated feed | One proxy on the fetch path, with clients pinned to it |
| OpenSSF S2C2F SCA-1 to SCA-3 | Scan for known vulnerabilities, licences and end of life | Gates on the SBOM for vulnerability, licence, age and maintenance rules |
| OWASP Top 10 A03:2025 | Official sources over secure links, inventory, attention to unmaintained components | Rules on approved sources, known vulnerabilities, licences and maintenance status |
What an install-time control can see, and what it cannot
Before writing rules, be clear about what information is available at the moment of install.
What the install path knows
When a package manager asks a registry for a package, the request carries the ecosystem, the package name and, once resolution is done, the exact version being downloaded. A proxy on that path sees every one of those requests, including the ones made for transitive dependencies your direct dependencies pulled in. That is the strongest property of the design: coverage follows the downloads, not a manifest someone forgot to update.
What it has to look up
The request does not say whether the version has a known vulnerability, what licence it carries, when it was published or whether anyone still maintains it. Those come from vulnerability databases, the package's metadata and an analysis of the package itself. Anything you evaluate at install time needs that data available quickly, because a developer is waiting.
What it cannot know
The install path does not know whether your code calls the vulnerable function, whether the package will end up in a shipped artifact or only in a test tool, or whether the team already has a mitigation. Those questions are better answered later, on the SBOM of the thing you build, where reachability, product context and exceptions can be applied. That is why a sensible design splits the rules: a small set that is safe to enforce at install time, and the rest enforced at a gate on the build.
Where you can enforce
There are four common points, and most teams use two of them.
| Enforcement point | Strength | Weakness |
|---|---|---|
| Developer laptop proxy | Feedback in seconds, before code is written against the package | Easy to bypass unless the network or config is managed |
| CI proxy | Every build goes through it; hard to skip | Feedback arrives after the developer has already chosen the package |
| Proxy in front of your repository manager | One control for every client that already uses the manager | Clients that bypass the manager are not covered |
| Gate on the build's SBOM | Full context: product, reachability, exceptions | Runs after install; it fails the build, not the fetch |
Step by step: putting policy in front of installs, with or without Safeguard
These steps work with any proxy, repository manager or scanner. The Safeguard specifics come later.
1. Find every install path
List each place packages enter: developer laptops, CI runners, container builds, notebook environments, and any scripts that run pip install or npx at runtime. For each one, write down which registry it uses today and how that is configured. In npm that is the registry setting in .npmrc at the project, user or global level, or an environment variable. In pip it is index-url and extra-index-url in pip.conf or pip.ini, or the PIP_INDEX_URL environment variable. Container builds often set these inside the Dockerfile, which is easy to miss.
Pay special attention to extra-index-url in pip. When more than one index is configured, pip considers candidates from all of them, so adding your proxy as an extra index does not stop the public index from being used. Replace the index; do not add to it.
2. Choose your enforcement points
For most teams the answer is a CI proxy plus a gate on the SBOM, with a laptop proxy as an option for developers who want fast feedback. If you already run a repository manager that every client uses, fronting it gives you one place to enforce. Write down which points you are using, because the exception process and the audit evidence depend on it.
3. Write the policy as a table
Do this before touching any tool. For each rule, record the rule in plain words, the data it needs, the enforcement point, the action and who owns exceptions. A starting template:
| Rule | Data needed | Where | Action at start | Exception owner |
|---|---|---|---|---|
| No version with a known critical vulnerability that has a fixed release | Vulnerability database, fixed versions | SBOM gate, then install | Warn | AppSec lead |
| No licence outside the approved list for shipped products | Licence metadata | SBOM gate | Block for shipped products, Notify for internal tools | Legal or open source office |
| No package versions published in the last few days for production builds | Publish date | Client setting or install | Warn | Platform lead |
| No package whose last release is very old or that is marked unmaintained | Release history | SBOM gate | Notify | Owning team |
| Only packages from approved registries | Request host | Install | Block | Platform lead |
| Explicit deny list of named packages or versions | Your own list | Install | Block | AppSec lead |
Keep the first version short. Five rules you enforce are worth more than thirty you audit forever.
4. Run in audit mode first
Turn the control on so it evaluates and records, but does not block. Leave it there long enough to see a normal release cycle, typically two to four weeks. Then read the records: which rules fired, how often, on direct or transitive dependencies, and in which repositories. You are looking for rules that fire constantly on packages nobody chose (they need tuning or belong at the gate instead) and rules that never fire (they may be fine, or the data behind them may be missing).
5. Build the exception path before you block
Write the request form now. A workable template:
| Field | What to capture |
|---|---|
| Package and version | Exact ecosystem, name and version, not a range |
| Rule that fired | The rule name from your policy table |
| Business reason | Why this version is needed now |
| Compensating control | What reduces the risk while the exception is open |
| Scope | Which repositories or products the exception covers |
| Expiry | A date, after which the rule applies again |
| Approver | A named role, not a team inbox |
Two rules make this work. Exceptions expire by default. And the person who asked is told the outcome quickly, in the place they work. If an exception takes a week, people will find another path.
6. Route every client through the control
Change the registry settings found in step 1 so that clients use the proxy and only the proxy. Commit project-level .npmrc files where your repositories already use them. Set PIP_INDEX_URL or pip.conf in CI images and developer setup scripts. For container builds, pass the settings in at build time rather than baking credentials into layers.
7. Close the bypasses
A proxy that can be skipped is a suggestion. In CI, restrict outbound network access so build runners can reach the proxy but not the public registries. On laptops, managed configuration helps, but expect some developers to have reasons to reach the public registry, and give them a supported path rather than a hidden one. Check for --registry and --index-url flags in scripts, which override configuration.
8. Handle package age with the tools you already have
Two age questions come up, and they point in opposite directions.
New releases: many teams want a short delay before a freshly published version is installed in production builds, so that problems reported in the first days are caught before the version reaches them. Package managers now offer this natively:
- npm's
beforesetting, passed tonpm install, rebuilds the tree so that only versions available on or before a given date are installed, and errors if no version qualifies. - pnpm's
minimumReleaseAgesetting, added in v10.16.0, sets the minimum number of minutes that must pass after a version is published before pnpm installs it, and applies to transitive dependencies too. pnpm's docs give the default as 1440 minutes since v11, with a non-strict fallback unless you set the value yourself. - uv's
exclude-newersetting limits candidates to distributions uploaded before a timestamp, and also accepts a duration such as "1 week". It compares the upload time of each file, not the release date of the version.
Use these in CI for production builds, record the setting in your policy table, and remember that a fixed date in before or exclude-newer needs moving forward, while a duration moves on its own.
Old or abandoned packages: the opposite concern is a dependency that has not had a release in years or is marked unmaintained. That is a judgement about the project, not a single version, and it fits better at the SBOM gate, usually as Notify rather than Block, because removing an abandoned dependency is a planned piece of work.
9. Move from audit to warn, then block, one rule at a time
When audit data shows a rule fires only where it should, switch that rule to warn. Warn lets the install proceed but records and surfaces the decision, so developers start seeing it. When warn has run cleanly for a cycle and the exception path has been used a few times without friction, switch that rule to block. Never move the whole policy at once.
10. Review on a schedule
Once a quarter, look at the decisions and exceptions together. Exceptions that keep being renewed point to a rule that needs changing or a dependency that needs replacing. Rules that never fire may be dead weight. Keep the review record; it is the evidence an auditor asks for under CM-11 and CM-7(5).
Rollout checklist
- Every install path listed, with its current registry setting.
- Enforcement points chosen and written down.
- Policy table approved by AppSec, platform and, for licences, legal.
- Audit mode running for at least one release cycle.
- Exception form, approver and expiry rule live before any block.
- Client configuration changed in repositories, CI images and setup scripts.
- CI egress restricted to the proxy.
- Age settings applied to production builds.
- First rule moved to warn, then to block, with a date for each.
- Quarterly review on the calendar.
Should rules run at install time or at a gate in CI?
Both, with different jobs. Install time is the right place for rules that depend only on what the request carries and a fast lookup: approved registries, an explicit deny list, and, once you trust the data, known vulnerabilities in the exact version. A gate on the SBOM is the right place for rules that need context: whether a licence matters depends on whether the product ships, whether a vulnerability matters depends on reachability and exposure, and whether an abandoned package is acceptable depends on the plan to replace it. Running the same rule in both places is fine as long as the action is consistent; a warn at install and a block at the gate is a common and sensible pairing.
How do we handle transitive dependencies?
A proxy handles them by construction, because it sees every download, not only the packages named in your manifest. The harder question is ownership. When a transitive dependency trips a rule, the team that hit it usually did not choose it. Your exception form should let them record the direct dependency that pulled it in, and your remediation path should be upgrading that direct dependency, not pinning the transitive one by hand forever. Overrides in npm and constraints files in pip are legitimate tools for a short period, with an expiry.
How do we keep developers from bypassing the proxy?
Make the supported path faster than the workaround. That means a laptop setup script that configures the proxy for them, clear messages when something is blocked that name the rule and link the exception form, and exception decisions in hours, not days. Then make the unsupported path harder: CI egress rules, a check in code review for new --registry or --index-url flags, and a periodic look at which machines still talk to the public registries directly. The related post on what should happen when a registry proxy blocks a package covers the message and exception design in more detail.
What happens when the proxy is down?
Decide this before it happens. A control that fails open keeps builds running and lets everything through during an outage. A control that fails closed stops builds. Most teams fail closed in CI for production builds, with a short documented break-glass procedure, and fail open on laptops. Whatever you choose, write it in the policy and make sure the break-glass path is itself recorded.
How Safeguard does this
Safeguard splits the job the same way: the Package Firewall (GA) sits on the install path for npm and pip, and policies and gates (GA) enforce the rules that need SBOM context. Everything below comes from Safeguard's documentation; where the docs do not show a screen or a setting, the outcome is described instead.
1. Turn the Package Firewall on for your tenant
The Package Firewall is admin-toggleable through a feature flag and enforced server-side. An administrator turns it on for the organisation; developers do not opt in individually. The docs recommend starting in audit mode to set a baseline, then moving to warn or block as confidence grows, which is the same sequence as steps 4 and 9 above.
2. Pick where it enforces
Safeguard's docs describe three enforcement points that share the same decision core:
- a local or CI proxy, started from the Safeguard CLI (GA);
- a registry-fronting proxy that sits in front of your existing repository manager;
- the server-side runner.
The docs state plainly that there is no CLI command for fronting an existing repository manager yet, so plan the CI proxy first and ask Safeguard about the repository manager option for your setup.
3. Start the local or CI proxy
The docs show the command for a local or CI proxy covering npm and pip:
# Local / CI proxy for npm and pip (modes: audit, quarantine)
safeguard pkgfw start --mode quarantine --port 8899
The mode and port are the documented flags. In CI, start the proxy as an early step in the job, before any install runs, and keep it running for the life of the job. The docs do not print the exact npm and pip client settings for pointing at the proxy, so take the client configuration from Safeguard's docs or support for your version rather than guessing a URL form. These snippets were not run for this post.
4. Check a single package version on demand
For a quick answer about one package version, or a scripted check in a pull request workflow, the docs show a one-shot check:
# One-shot check, printed as JSON (exit 1 on block)
safeguard pkgfw check --ecosystem npm --name left-pad --version 1.3.0
It prints the decision as JSON and exits with status 1 when the decision is block, so it can fail a script or a CI step directly. This is useful in a review bot that checks a newly added dependency before anyone installs it.
5. Choose the outcome for each decision
The Package Firewall runs inline with three outcomes:
| Outcome | What happens to the install |
|---|---|
| Allow | The package passes and installs normally |
| Warn | The install proceeds; the decision is recorded and surfaced |
| Block | The install is refused |
Two modes sit alongside those outcomes:
- Audit mode evaluates and records every decision without blocking, so you can measure impact before enforcing. This is step 4 of the general plan.
- Quarantine mode holds a flagged package aside pending review instead of installing it or hard-blocking it.
Quarantine is not meant to be a permanent holding pen. The docs describe an auto-release loop: the firewall re-evaluates held packages and releases one once its verdict clears. Packages that never clear are aged out after a configurable window, 14 days by default, so quarantine does not fill up with stale entries.
6. Read the decisions as findings and audit records
Every decision is written to the audit trail with the package, the rule that fired, the mode and the outcome, scoped to your tenant and organisation. Every decision other than allow also becomes a dependency finding in Safeguard's unified findings model, which you browse from the project's Findings tab with the Package Firewall scanner filter. Each finding carries the ecosystem, the package name and version, the category that fired and the mode. In audit mode it also records the verdict that would have been enforced, which is exactly the data you need to decide whether a rule is ready for warn or block. Fetches made for transitive dependencies are marked as transitive, so you can tell a package your team chose from one that came along with it.
That gives you the evidence trail for CM-11 and CM-7(5) without a separate log pipeline: what was requested, what the policy decided, and when.
7. Put licence, vulnerability and age rules in policies and gates
Rules that need SBOM context go into Safeguard's policies and gates, which evaluate the SBOMs Safeguard builds from your connected repositories. You create a policy under Settings, then Policies, with Create Policy, define its conditions in the visual builder or in YAML, set its severity and action, then save and enable it. The documented conditions include:
| Condition | Example from the docs |
|---|---|
| Vulnerability severity | No critical CVEs |
| CVSS score | No vulnerabilities above 7.0 |
| EPSS score | No actively exploited CVEs |
| Licence | No GPL licences |
| Component age | No components older than two years |
| Maintenance | No abandoned packages |
Pre-built templates cover common cases, including No Critical Vulnerabilities, License Compliance and No Abandoned Packages. License compliance (GA) supplies the licence data and software composition analysis with vulnerability management (GA), using EPSS and CISA KEV context, supplies the vulnerability data.
8. Set each policy's action: Block, Warn or Notify
Each policy has one action, which decides what a failed policy does to the gate:
| Action | When the policy fails |
|---|---|
| Block | The gate fails |
| Warn | The gate passes, with a warning that names the policy |
| Notify | The gate passes, and Safeguard sends a notification to the workspace's configured channels: the in-app bell, connected chat integrations, and email according to each person's preferences |
Notify does not repeat itself on every evaluation. You hear about a policy when it goes from passing to failing, and again when a failing policy finds new matching issues. The gate's own outcome follows a documented order: any failed Block policy fails the gate; otherwise an evaluation error gives Error; otherwise anything not yet evaluated gives Not evaluated; otherwise a failed Warn policy gives Warning; otherwise the gate passes. An Error is never counted as a pass, and a gate that has never been evaluated shows Not evaluated, never Passed.
Policy outcomes are turned on per workspace by Safeguard. If you do not see an Outcome column on the Gates and Policies tables, ask your Safeguard contact to turn it on.
9. Fail CI on the gate
With policy outcomes on, the CLI can wait for the scan and the gate evaluation and fail the job when the gate fails:
safeguard ci scan --wait --fail-on-gate <gate>
The docs describe the exit codes: zero when the gate is Passed or Warning, with warnings and notified policies printed; non-zero when the gate is Failed, with the failing Block policies printed; and non-zero when the gate is Error or Not evaluated, or its policies were not evaluated before the timeout. That last behaviour matters: a gate that could not be evaluated does not silently pass your build.
10. Approve exceptions through the exception workflow
Approval is not a gate action. It runs through exceptions. A developer selects Request Exception, picks the policy and the finding, gives a business justification and sets an expiration date, then submits it. Approvers are notified, review and decide, and the outcome is recorded in the audit trail. That matches the exception form in step 5, including the expiry date. Compliance reporting then shows status by policy, exception history and violation trends, which is the quarterly review material from step 10.
How the pieces line up
| Your rule | Where Safeguard enforces it | What happens on a match |
|---|---|---|
| Only approved sources, explicit deny list, per-version decisions at fetch time | Package Firewall proxy | Allow, Warn or Block; or record only in audit mode; or hold in quarantine |
| Known vulnerabilities by severity, CVSS or EPSS | Policies and gates on the SBOM | Block, Warn or Notify on the gate |
| Licences outside your approved list | Policies and gates, with license compliance data | Block, Warn or Notify |
| Components that are too old or unmaintained | Policies and gates (component age, maintenance) | Usually Notify, sometimes Warn |
| Very new releases | Your package manager's own age setting in CI | The version is not resolved |
| A justified exception | Exception workflow with an expiry | Recorded approval, reported in compliance reports |
Where this sits in the rest of Safeguard
The same findings and gates feed the rest of the platform. Autonomous remediation (GA) can open pull requests that move a dependency to a fixed version, and it ships switched off with every category set to Manual. Reachability analysis (GA) helps rank which vulnerable dependencies to deal with first. The Safeguard MCP server (GA) exposes read-only tools for gate outcomes, policy outcomes and evaluation history when policy outcomes are on and your MCP access settings allow them, so an assistant can answer "why did this gate fail" without someone opening the console.
What Safeguard does not do
- The Package Firewall covers npm and pip. Safeguard's docs describe it as a proxy fronting those two ecosystems. Other package managers go through policies and gates on the SBOM, not through the install-time proxy.
- The docs do not publish client configuration. They show the CLI commands to start the proxy and check a package, but not the exact npm or pip settings to point clients at it. Confirm those with Safeguard for your version before rolling out.
- There is no CLI command for fronting an existing repository manager yet. The docs list a registry-fronting proxy as an enforcement point, and say this command does not exist today. Plan around the CI proxy until you have confirmed the setup for your manager.
- Licence, vulnerability severity, age and maintenance rules are documented for policies and gates. This post does not claim the install-time proxy evaluates each of those conditions on its own; the documented place for them is the gate on your SBOM.
- Safeguard does not close your network bypasses. Egress rules on CI runners, managed developer configuration and checks for override flags are your job. A proxy that can be skipped will be skipped.
- It does not set your new-release delay. Cooldown windows for freshly published versions come from your package manager's own settings, which you configure in CI.
- It does not decide exceptions. Safeguard routes, records and reports them. A named person in your organisation approves or denies each one.
- This post is about policy control, not threat detection. It describes how you decide, enforce and record what may be installed. Threat detection is outside its scope, and nothing here should be read as a statement about it.
Common mistakes
- Adding the proxy as an extra index in pip. With
extra-index-url, pip still consults the public index. Replaceindex-urlinstead. - Going straight to block. A rule set nobody measured will fail builds on transitive dependencies nobody chose, and the first bypass will be permanent.
- Exceptions without expiry. An exception that never ends is an undocumented policy change. Every exception gets a date.
- Putting every rule at install time. Licence and reachability decisions need product context. Enforce them at the gate on the SBOM.
- Forgetting container builds and notebooks. Dockerfiles and notebook environments often carry their own registry settings and skip the developer configuration entirely.
- Leaving CI egress open. If runners can reach the public registry, one
--registryflag undoes the policy. - Pinning transitive dependencies forever. Overrides and constraints are short-term tools. The fix is usually upgrading the direct dependency that pulled the transitive one in.
- Treating an evaluation error as a pass. A gate that could not run has not passed. Make sure your pipeline fails on Error and Not evaluated, as Safeguard's
--fail-on-gatedoes. - No owner for the deny list. Lists without an owner grow forever and nobody can say why an entry is there. Record the reason and the owner with every entry.
FAQ
What is a package firewall?
A package firewall is a proxy that sits between package managers and the registries they download from. It evaluates each package and version as it is fetched and allows it, warns on it or blocks it according to your policy. Because it is on the download path, it also sees transitive dependencies.
Does Safeguard have a package firewall for npm and pip?
Yes. Safeguard's Package Firewall (GA) runs as an install-time proxy fronting npm and pip. It supports allow, warn and block outcomes, an audit mode that records without blocking, and a quarantine mode that holds a flagged package for review.
How do I start the Safeguard Package Firewall locally or in CI?
Run safeguard pkgfw start --mode quarantine --port 8899 from the Safeguard CLI, as shown in the docs, then point npm and pip at the proxy using the client settings Safeguard documents for your version. Start it before any install step in the job.
Can I check one package version without installing it?
Yes. safeguard pkgfw check --ecosystem npm --name left-pad --version 1.3.0 returns the decision as JSON and exits with status 1 on block, so it can fail a script or a CI step.
Can Safeguard block packages by licence or known vulnerabilities?
Safeguard's policies and gates (GA) evaluate licence, vulnerability severity, CVSS, EPSS, component age and maintenance conditions on your SBOMs, and each policy's action is Block, Warn or Notify. With policy outcomes on, safeguard ci scan --wait --fail-on-gate fails the CI job when a Block policy fails.
What is the difference between Warn and Notify?
On a gate, Warn lets the gate pass with a warning that names the policy. Notify lets the gate pass and sends a notification to your configured channels: the in-app bell, chat integrations and email. Notify only fires when a policy starts failing or finds new matches, not on every evaluation.
How do exceptions work?
A developer requests an exception against a specific policy and finding, with a business justification and an expiry date. Approvers are notified and decide, and the decision is recorded in the audit trail. Approval runs through this workflow, not through a gate action.
Does a package firewall slow down installs?
Every fetch goes through one more hop and a policy lookup, so there is some cost. In most proxy designs much of it is paid once per package version, because decisions and package files can be cached, but do not assume it: measure it in audit mode on your own builds before enforcing, and run the proxy close to your CI runners.
Should I block new package versions for a few days after release?
Many teams delay very new releases in production builds. Use your package manager's own setting for it: before in npm, minimumReleaseAge in pnpm or exclude-newer in uv. Record the window in your policy table so reviewers can see it.
Where do I see what the firewall decided?
In the audit trail, which records the package, the rule, the mode and the outcome for every decision, and in Safeguard's findings, where every decision other than allow becomes a dependency finding. In audit mode each finding also shows what would have been enforced.
Related reading
- What should happen when a registry proxy blocks a package?
- Approved package allowlist or scan on install: a decision guide
- Make developers use the internal registry: enforcement steps
- Internal registry vs mirror vs proxy: what is the difference
- npm before flag: install versions published by a date
The install-time control above decides what comes in; the next question is what to do about a vulnerable version that is already in your tree, or one with no fixed release yet. The block below is Safeguard's standard answer to that, and it applies to every dependency your gates flag.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.
3. Gold Registry: start from components that are already fixed
Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | Safeguard policies and gates in CI |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
The Safeguard CLI demo is a real terminal session: the CLI is asked to fix a lodash CVE in a repository, reads the finding and the advisory, edits package.json, runs the install and tests with approval, and pushes nothing. Since CLI v11.10.0 it asks before any command that changes something, not before every command. The same CLI is the one that starts the Package Firewall proxy and runs the gate check in CI, so this is a fair picture of where those commands live.
Click through it at your own pace, or open it full screen.
The local runner demo shows setting up the runner on your own machine, approving it with its device code, and then scanning from the terminal. It does not show the Package Firewall itself, but it shows Safeguard work running on a machine you control, which is where a local or CI proxy runs too.
Click through it at your own pace, or open it full screen.
The Claude demo shows connecting Claude to the Safeguard MCP server with OAuth and choosing which tools Claude can use. Once policy outcomes are on for your workspace, questions such as which policy failed a gate and when can be asked from there in plain language.
Click through it at your own pace, or open it full screen.
Quick check
Why should you replace pip's index-url with your proxy instead of adding the proxy as an extra-index-url?
When more than one index is configured, pip considers candidates from all of them, so the public index is still used. Replacing index-url makes the proxy the only source, which is what makes the policy enforceable.
In Safeguard, what happens to a CI job using --fail-on-gate when the gate's policies could not be evaluated?
The job exits non-zero. Safeguard's docs say the command fails when the gate is Error or Not evaluated, or when its policies were not evaluated before the timeout, so an evaluation problem never counts as a pass.
Sources
- Safeguard docs: Package Firewall
- Safeguard docs: Policies and gates
- Safeguard docs: Policy outcomes and actions
- Safeguard docs: Unified findings and feature flags
- Safeguard docs: License compliance
- Safeguard docs: CI/CD integration
- Safeguard docs: CLI
- Safeguard docs: Integrations
- NIST SP 800-218, Secure Software Development Framework
- NIST SP 800-218 (PDF)
- NIST SP 800-53 Rev. 5 control catalog (OSCAL)
- NIST SP 800-161 Rev. 1, Cybersecurity Supply Chain Risk Management Practices
- OpenSSF Secure Supply Chain Consumption Framework (S2C2F)
- OWASP Top 10:2025, A03 Software Supply Chain Failures
- npm docs: config
- npm docs: npmrc
- pip docs: pip install
- pip docs: configuration
- pnpm docs: dependency resolution settings
- uv docs: settings reference
Get started: download Safeguard at safeguard.sh/download and read the setup guides at docs.safeguard.sh/docs.
Last reviewed: 25 October 2026. Product capabilities change; check docs.safeguard.sh for the current state.