Metadata filtering

Remove blocked versions from registry listings, so package managers quietly pick a safe version instead of failing at download.

Without metadata filtering, a package manager can choose a blocked version and only find out when the download returns 403. With it, the firewall checks the versions listed in each package's metadata and removes the blocked ones before the client sees them. A range like ^3.0.0 then resolves to the newest allowed version, and the install succeeds.

Without filteringWith filtering
npm install pkg@^3 when 3.0.1 is blockedPicks 3.0.1, fails with E403Picks 3.0.0, succeeds
npm install [email protected]E403notarget: the version doesn't exist as far as npm can tell
npm install pkg when latest is blockedE403latest is rewritten to the newest allowed version, so it succeeds
npm ci from a lockfile with 3.0.1E403E403 (lockfiles skip metadata)

Downloads are still checked either way. Filtering only changes what the listing shows.

Before you start:

  • A running firewall (Block installs with Firewall)
  • Redis cache set up. Filtering works without it, but Redis is recommended: it keeps filtering verdicts across restarts and shares them between instances.

1. Turn it on

Append to .env:

METADATA_FILTERING_ENABLED=true

The defaults are right for most deployments: blocked versions are removed, warned versions stay visible, and the newest 100 versions of each package are checked. To change them, see Settings worth knowing.

docker compose up -d --force-recreate

To set it in socket.yml instead, add a top-level block (a sibling of socket:, not inside it):

metadata_filtering:
  enabled: true

2. Create something to filter

You need a package with one blocked version. Add a deny rule for is-odd version 3.0.1 to your Default policy, as shown in Policy config: Block or allow one package.

Verify

Compare the version list from the public registry with the list through the firewall:

diff <(curl -s  https://registry.npmjs.org/is-odd       | jq -r '.versions | keys[]') \
     <(curl -sk https://sfw.example.com/npm/is-odd     | jq -r '.versions | keys[]')

Expected: the blocked version is the only difference.

7d6
< 3.0.1

The firewall logs the same result:

docker compose logs socket-firewall | grep "metadata filtering complete"
# npm metadata filtering complete: 6 allowed, 1 filtered out of 7

Then see what npm does with it, from a fresh directory:

cd "$(mktemp -d)" && npm cache clean --force
npm install is-odd@^3.0.0      # succeeds, installs 3.0.0
npm ls is-odd
npm install [email protected]       # npm error notarget No matching version found for [email protected]
  • The diff shows only 3.0.1, and the log shows 1 filtered
  • npm install is-odd@^3.0.0 succeeds and installs 3.0.0
  • npm install [email protected] fails with notarget, not E403
  • Removing the deny rule (and waiting out the cache, below) brings 3.0.1 back

If the diff is empty, check that the firewall was recreated after the .env edit and that the deny rule is in the Default policy. If anything requested is-odd metadata before you added the rule (for example, a baseline diff), its allowed verdicts are cached: flush Redis (rc FLUSHDB, see Redis cache) and run the diff again.

How each ecosystem is filtered

GranularityEcosystemsWhat's removed
Per versionnpm, Go, RubyGems, Cargo, Conda, OpenVSX, NuGet (registration and flat-container)The whole version
Per filePyPIIndividual files (one wheel or the sdist). A version-level block removes all of its files
Per version in listings, per file at downloadMavenBlocked versions are removed from maven-metadata.xml. Downloads are checked per file (a blocked version's .jar returns 403 even if its .pom is allowed)

Settings worth knowing

Set these in socket.yml, under a top-level metadata_filtering: block, then recreate the container.

metadata_filtering:
  enabled: true
  filter_warn: false
  max_versions: 100
  include_unchecked_versions: true
  cache_ttl: 3600
SettingDefaultWhen to change it
filter_warnfalsetrue also hides versions with a Warn action. See the caution below
max_versions100Newest N versions checked per package. Raise it if teams install old versions of very active packages
include_unchecked_versionstrueLeave it on. See the warning below
cache_ttl3600How long per-version filtering verdicts are cached, in seconds
🚧

Use socket.yml for these, not .env

On firewall 2.16.0, only METADATA_FILTERING_ENABLED is read from the environment. METADATA_FILTER_WARN, METADATA_MAX_VERSIONS, METADATA_INCLUDE_UNCHECKED_VERSIONS and METADATA_CACHE_TTL are listed in the Configuration Reference but ignored.

🚧

filter_warn: true can empty a listing

It hides every version with any warn alert. Common warn alerts such as Unmaintained, Deprecated and Unpopular can apply to every version of a package, which then disappears entirely and every install of it fails. Check your Warn rules before turning this on.

❗️

include_unchecked_versions: false does not mean "hide unscanned versions"

It hides every version outside the max_versions window. On packages with frequent prereleases, the newest 100 versions can all be prereleases, so false can remove every stable version from the listing. To block versions Socket hasn't scanned yet, set socket.fail_open_unscanned: false (or SOCKET_FAIL_OPEN_UNSCANNED=false), which hides them from listings and blocks their download.

Why filtering seems not to work

SituationWhat happens
Lockfile or pinned version (npm ci, pip install -r with == pins, fixed Maven versions)The client goes straight to the download. It's still blocked, but no fallback version can be chosen
Client metadata cacheThe client reuses old metadata. Clear it once: npm cache clean --force, pip cache purge, delete ~/.m2/repository/<group>
Policy just changedFiltering verdicts are cached for up to cache_ttl (1 hour). Flush Redis to apply now (see Redis cache)
Blocked version is older than the newest max_versionsIt isn't checked, so it stays listed. Its download is still blocked
No allowed version matches the rangeThe install fails with notarget instead of E403

Event volume

Filtering checks each listed version with Socket, and each check is logged as a decision event with event_category: "proactive". One listing can produce up to max_versions events (about 100 for a busy package like rollup). A version removed from a listing is logged with decision: "blocked" and response_code: 403, even though the client received a normal 200 listing.

Expect event volume in logs and your SIEM to rise as soon as filtering is on. To count real install blocks, exclude event_category: "proactive". See Data.

Works with cooldown

With a cooldown set to Block, versions younger than the window are removed from listings too, and latest moves to the newest version past the window. Range installs and bare npm install pkg then succeed with no error. A developer who pins a brand-new version gets notarget.

Performance

The first metadata request for a package checks up to max_versions versions with Socket, so it's slower than an unfiltered request. Later requests are served from the Redis cache. Very large metadata (Conda repodata.json, the most popular npm packages) is buffered in memory, up to max_body_size (500 MB by default).

Reference


Did this page help you?