Varnish Artifact Firewall

Introduction

The Varnish Artifact Firewall is a vendor-neutral firewall for software package registries that enforces policies at request time.

It sits between package clients, such as npm and pip, and package registries. It evaluates each version in a package manifest against your rules, rewrites the manifest before it reaches the client, and refuses downloads of denied versions. Malware, versions with known vulnerabilities, and freshly published packages are stopped before they reach a developer machine or a CI/CD pipeline.

Reference architecture: CI workers and developers reach public registries through the Artifact Firewall, which checks every download, either directly or with a repository manager such as JFrog Artifactory or Sonatype Nexus in between

Main features:

  • Nine package types. The firewall serves npm, PyPI, Maven, NuGet, Hex, Go, Conda, RPM and VS Code extensions. Enforcement by package type describes what a rule does in each.
  • Rules by package and version range. A rule names packages by Package URL or name pattern, and versions by range. deny refuses them with a 403, hide keeps them out of “latest” while a client that pins one still gets it, and allow lets them through.
  • OSV rulesets. Varnish publishes rulesets for six ecosystems, generated every hour from the OSV vulnerability database. The firewall turns the severity score on each rule into an action.
  • Quarantine. Versions published in the last few days are kept out of “latest”, so that a malicious release has time to be reported before a client installs it.
  • Rulesets from a directory, Git or HTTP. Remote sources are fetched again every hour by default, and a changed ruleset is loaded without a restart.
  • Report mode. In report mode the firewall records each decision without enforcing it, to measure a ruleset’s impact before turning it on.
  • Audit log and telemetry. Each decision is written to an audit log, metrics and traces are exported over OpenTelemetry, and an admin API evaluates a package or disables a single rule at runtime.
  • Standalone or integrated with the Virtual Registry. The firewall runs from a Docker image or a Helm chart, either in front of package registries or integrated with the Varnish Virtual Registry. The Virtual Registry then routes and caches package requests, and asks the firewall about each artifact before serving it, from its cache or not.

Getting started

This section runs the firewall on your own machine, in front of the public npm registry, with a ruleset of your own. You need Docker, the npm client, and an Artifact Firewall license. Request a trial license if you do not have one.

Write a ruleset

Create a project folder with two folders inside it, config/ and rulesets/. Add a ruleset file called rulesets/team-policy.yaml:

id: team-policy
rules:
- id: no-request
  match:
  - purl: pkg:npm/request
  action: deny
  reason: request is deprecated, use fetch
- id: hold-uuid-12
  match:
  - purl: pkg:npm/uuid
    version: vers:npm/>=12.0.0
  action: hide
  reason: uuid 12 and later are ESM only

The first rule refuses every version of request. The second keeps uuid 12 and later out of “latest”, so that npm install uuid gets the newest 11.x release. Artifact Firewall Ruleset describes each field.

Configure the firewall

Put your license in config/license.lic, and add a configuration file called config/default.yaml:

firewall:
  registries:
  - name: npmjs
    remote_url: https://registry.npmjs.org
    routes:
    - host: localhost
  rulesets:
  - path: /rulesets

license:
  file: /etc/varnish-artifact-firewall/license.lic

The registries entry sends each request for the host localhost on to the public npm registry. The rulesets entry reads the ruleset files in /rulesets, where the next step mounts your rulesets/ folder.

Run the container

From your project folder, run:

docker run --rm -p 6089:6089 --name firewall \
  -v ./config:/etc/varnish-artifact-firewall:ro \
  -v ./rulesets:/rulesets:ro \
  varnish/artifact-firewall

The firewall reads its configuration from /etc/varnish-artifact-firewall/default.yaml and listens on port 6089. It loads your two rules and starts serving:

time=... level=INFO msg="loaded rulesets" default_action=allow rulesets=1 rules=2 exact_selectors=2 pattern_selectors=0
time=... level=INFO msg="serving proxy" address=[::]:6089 deployment=standalone

Try it

In a second terminal, point npm at the firewall:

export NPM_CONFIG_REGISTRY=http://localhost:6089/

request is refused, and the error names the rule and the ruleset that refused it:

npm view request
npm error code E403
npm error 403 403 Forbidden - GET http://localhost:6089/request - package blocked by firewall (rule "no-request", ruleset "team-policy")
...

uuid resolves to its newest 11.x release, although the latest on the npm registry is in the 14.x line:

npm view uuid version
11.1.1

A client that pins a hidden version, as in npm install uuid@14.0.3, still gets it. Use deny to refuse those too.

The firewall writes each decision to its audit log, on the container’s standard output:

{"id":"01a1c4c5-e35b-711e-baf3-14b0cb5a978e","ts":"2026-11-10T09:24:25.563Z","kind":"listing","purl":"pkg:npm/request","rule_id":"no-request","ruleset_id":"team-policy","action":"deny","enforced_action":"deny","registry":"npmjs","mode":"normal","outcome":"blocked"}

To change the rules, edit the files in rulesets/. A SIGHUP makes the firewall read them again without a restart:

docker kill --signal=HUP firewall

Subscribe to the OSV rulesets

Varnish publishes ready-made rulesets in varnish/osv-rules, generated every hour from the OSV vulnerability database. Together they hold more than 260,000 rules. Over 230,000 of them name packages that were published as malware, from OSV’s MAL- advisories, and the rest name versions affected by a known vulnerability, from CVEs and security advisories.

Ecosystem Ruleset
npm rulesets/npm/all.yaml
PyPI rulesets/pypi/all.yaml
Maven rulesets/maven/all.yaml
NuGet rulesets/nuget/all.yaml
Go rulesets/go/all.yaml
Hex rulesets/hex/all.yaml

Add the npm ruleset to config/default.yaml as a git source. The firewall fetches it again every hour:

firewall:
  registries:
  - name: npmjs
    remote_url: https://registry.npmjs.org
    routes:
    - host: localhost
  default_quarantine_days: 7
  rulesets:
  - path: /rulesets
  - git:
      name: osv
      url: https://github.com/varnish/osv-rules.git
      sub_path: rulesets/npm/all.yaml

license:
  file: /etc/varnish-artifact-firewall/license.lic

OSV lists a malicious package once someone has reported it. default_quarantine_days keeps each version out of “latest” for its first seven days, to leave time for that.

A new Git source needs a restart. Stop the firewall with Ctrl+C and run the same docker run command again. The firewall clones the repository before it starts serving:

time=... level=INFO msg="loaded rulesets" default_action=allow rulesets=2 rules=230811 exact_selectors=226510 pattern_selectors=0

A package that was published as malware is now refused:

npm view nodemon-sudo
npm error code E403
npm error 403 403 Forbidden - GET http://localhost:6089/nodemon-sudo - package blocked by firewall (rule "MAL-2026-10014", ruleset "osv-npm")
...

A rule names the package, the affected versions, the advisory, and a severity score:

- id: MAL-2026-10014
  aliases:
  - GHSA-8228-4gjp-c339
  match:
  - purl: pkg:npm/nodemon-sudo
  severity: 10
  reason: Malicious code in nodemon-sudo (npm)
- id: GHSA-2234-fmw7-43wr
  aliases:
  - CVE-2024-48913
  match:
  - purl: pkg:npm/hono
    version: vers:npm/<4.6.5
  severity: 5.9
  reason: Hono allows bypass of CSRF Middleware by a request without Content-Type header.

The firewall turns the score into an action with its severity thresholds. On the defaults, a malicious package scores 10 and is refused outright, and the vulnerable versions of hono score 5.9 and are kept out of “latest”, so that a client which does not pin a version gets one that is not affected.

To subscribe to every ecosystem, set sub_path: rulesets, or list several rulesets under sub_paths. To generate the rulesets yourself, from a local copy of the OSV data or with a different action for the few advisories that have no score, run osv-rulegen.

Next steps

  • Deployment covers the Helm chart, and the ways to run the firewall with a Virtual Registry.
  • Enforcement by package type describes what deny, hide and quarantine do in each ecosystem.
  • The configuration pages describe each setting, and the ruleset format, including how to validate rulesets in CI.
  • The tutorials go further: the OSV rules on lodash, rule priorities, and a firewall in front of JFrog Artifactory.
  • The audit log, metrics and tracing and the admin API cover what the firewall records and how to operate it at runtime.
  • The changelog lists the feature additions, changes, fixes and removals in each Artifact Firewall release.

®Varnish Software, Wallingatan 12, 111 60 Stockholm, Organization nr. 556805-6203