BytesafeDependency Firewall

Prevent dependency confusion

Stop public registries from serving packages that share names with your internal packages.

Dependency confusion is an attack on private package names: an attacker publishes a package on the public registry under the same name as one of your internal packages, often with a high version number, and waits for a build to resolve the public copy instead of yours. The firewall closes this with its internal upstream model, plus an optional rule as a second layer.

How the firewall resolves internal names

When any upstream marked internal knows a package, the firewall serves versions only from internal upstreams. Public copies of that name are not merged in, no matter their version numbers.

Firewall resolution
Client requests an internal package
Firewall queries all upstreams
Internal registryhas version 1.4.0
Public registrysame name, version 99.9.9
Any internal upstream knows this package?
Serve internal only: 1.4.099.9.9 never seen
Merge external versionsno internal copy

Step 1: mark your private registry as internal

In the dashboard, open the firewall, go to Upstreams, edit your private registry, and enable Internal registry. As JSON:

{
  "id": "e2de947a",
  "endpoint": "https://npm.acme.internal",
  "internal": true,
  "cached": false
}

See Configure upstreams for the full upstream setup.

Step 2 (optional): reserve your package names

Step 1 protects the names your internal registry serves today. Names it does not serve are still resolved from the public registry: a package you deleted internally, or a prefix you have reserved but not published under yet.

A rule closes that gap. It matches the naming convention your internal packages use and blocks it from external upstreams:

  • Execution phase: filter versions (called versions in config, API, and CLI)
  • Selector: package name @acme/* (your internal prefix), internal: External
  • Effect: block and log

As JSON:

{
  "id": "acme-scope-internal-only",
  "executionPhase": "versions",
  "selector": { "packageName": "@acme/*", "internal": "external" },
  "ruleEffect": { "block": true, "log": true },
  "description": "Never serve @acme/* from external registries"
}

A name under your prefix can now only come from an internal upstream, whether or not your internal registry currently lists it. Use whatever marks your internal packages: an npm scope, a Maven group prefix (com.acme.*), a Go module path prefix.

Verify

Request an internal package and confirm the log entry contains your internal upstream ID, not the public upstream ID:

bsfw logs --firewall <firewall-id>

If you added the step 2 rule, also try a name under your prefix that only exists publicly; the request should be blocked and logged with the rule ID.

On this page