Getting Started with Artifact Firewall

Block known-vulnerable and freshly-published npm packages before they ever reach your builds using Varnish’s auto-generated OSV ruleset and a single Docker command.

This tutorial walks you through 3 steps:

  1. Create a configuration file.
  2. Run the container.
  3. Test it with real npm commands.

Prerequisites

  • Docker is installed on your machine.
  • The npm client is installed on your machine.

Step 1: Create your configuration file

Create a project folder and add a file called example-config.yaml:

varnish:
  http:
    - port: 80

virtual_registry:
  registries:
    - name: npmjs
      default: true
      enable_firewall: true
      remotes:
        - url: https://registry.npmjs.org

firewall:
  address: localhost
  default_action: allow
  default_quarantine_days: 7
  rulesets:
    - git:
        name: osv-npm
        url: https://github.com/varnish/osv-rules.git
        sub_path: rulesets/npm/all.yaml

license:
  file: /app/license.lic

Need a license? Request an Orca Premium trial license.

Two things power the firewall here:

  • rulesets.git pulls the auto-generated OSV ruleset from Varnish’s public repo, refreshed every hour. Every npm vulnerability in the OSV database becomes a firewall rule, with no manual maintenance.
  • default_quarantine_days: 7 hides any package version published in the last 7 days from latest resolution, giving you a buffer against newly-published malicious packages before they get a chance to spread.

Tip: Prefer to generate the ruleset yourself instead of pulling from Varnish’s public repo? You can run the osv-rulegen Docker image to produce an equivalent OSV ruleset locally, then point a rulesets.path entry at the output. This is useful if you want to vet or pin the ruleset rather than fetching it over the network.

Step 2: Run the container

From the folder containing example-config.yaml, run:

docker run --rm -p 80:80 -p 6090:6090 --name orca \
  -v $(pwd)/example-config.yaml:/app/config.yaml:ro \
  -v $(pwd)/license.lic:/app/license.lic:ro \
  varnish/orca --config /app/config.yaml
FlagPurpose
-p 80:80 -p 6090:6090Exposes virtual registry on port 80 and artifact firewall on port 6090 (default)
-v $(pwd)/example-config.yaml:/app/config.yaml:roMounts your config file into the container (read-only)
-v $(pwd)/license.lic:/app/license.lic:roMounts your license file to use with Orca Firewall
--config /app/config.yamlTells Orca which config file to use

You should see startup logs confirming the firewall is enabled, then the OSV ruleset loading a few seconds later. The key lines to look for:

time=... level=INFO msg="License: Firewall enabled"
time=... level=INFO msg="Loading VCL Group into Varnish" name=npmjs
time=... level=INFO msg="Varnish is ready to receive traffic"
time=... level=INFO msg="Loaded Firewall ruleset" id=osv-npm rules=218717
time=... level=INFO msg="Rulesets loaded" default_action=allow rulesets=1 rules=218717
time=... level=INFO msg="Starting Firewall" address=localhost:6090

The rules=218717 figure is the full set of npm vulnerability rules from the OSV database, every npm advisory becomes a firewall rule. Your number may differ slightly since the ruleset is regenerated hourly.

Step 3: Test it

In a new terminal, point npm at the firewall by setting it as the default registry:

export NPM_CONFIG_REGISTRY=http://localhost

This way you don’t need to append --registry=... to every npm command. The --dry-run flag means nothing actually downloads; it just resolves the request through the firewall. The --prefer-online forces npm to actually hit the registry path more reliably.

Allowed package

A package with no known vulnerabilities resolves normally:

npm --verbose pack minimist --dry-run --prefer-online
npm http fetch GET 200 http://localhost/minimist 104ms (cache updated)
npm http fetch GET 200 http://localhost/minimist/-/minimist-1.2.8.tgz 18ms (cache revalidated)
npm notice 📦  minimist@1.2.8
...

OSV rules in action: vulnerable versions silently skipped

lodash has several known CVEs in older versions. When you ask for lodash without specifying a version, the firewall transparently steers you to the latest safe version:

npm --verbose pack lodash --dry-run --prefer-online
# Audit-Logs: {"purl":"pkg:npm/lodash@4.18.1","rule_id":"default","ruleset_id":"default","action":"allow","effective_action":"allow"}

The exact version may differ depending on what’s currently latest on npmjs.com/package/lodash; the firewall steers your unpinned install to the highest version not flagged by OSV. As long as the action is allow and the rule_id is default, the OSV ruleset is working as intended.

If you explicitly pin to a vulnerable version, the audit log shows it was matched by an OSV rule:

npm --verbose pack lodash@4.17.20 --dry-run --prefer-online
# Audit-Logs: {"purl":"pkg:npm/lodash@4.17.20","rule_id":"GHSA-29mw-wpgm-hmr9","ruleset_id":"osv-npm","action":"hide","effective_action":"hide"}

The rule_id is a real GHSA identifier, look up the CVE details on osv.dev. Every rule in the osv-npm ruleset links back to its origin advisory this way.

By default, OSV severity scores below the deny threshold map to hide: the version stays installable if pinned, but is excluded from latest. To turn hide into a hard 403 block, lower the deny threshold (see the Firewall Configuration Reference) or add a custom action: deny rule, as described in Writing Custom Firewall Rules.

Quarantined: recently-published versions

With default_quarantine_days: 7, any version published in the last 7 days is hidden from latest resolution. Developers running npm install <pkg> get the latest non-quarantined version automatically, protecting against typo-squatting and newly-published malicious packages that haven’t been flagged yet by OSV.

In the audit log, quarantined versions appear with effective_action: hide even when no explicit rule matches.

Next steps