npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@stratusagent/egress

v0.6.0

Published

The Stratus Agent egress policy: which addresses a tool may reach, enforced on the connection rather than on the name it was asked for

Readme

@stratusagent/egress

Which addresses a tool may reach, enforced on the connection rather than on the name it was asked for.

Used by @stratusagent/tool-web and @stratusagent/tool-browser. It is one module because two copies of this rule would not drift into a style difference — the stale one would be an SSRF hole — and both packs are tested against HOSTILE_URLS, the table exported from here, which is what fails if it is ever forked.

The rule

Every globally routable address, and nothing else, in both families. A blacklist that stops at RFC 1918 still leaves:

  • 169.254.169.254 — cloud instance metadata, and the credentials it serves
  • 127.0.0.1 and ::1 — the daemon's own control API, among other things
  • fc00::/7 and fe80::/10 — the same internal services over IPv6
  • ::ffff:169.254.169.254, 64:ff9b::a9fe:a9fe, 2002:a9fe:a9fe:: — the same IPv4 addresses again, written the ways an IPv4 check does not see. The well-known NAT64 prefix is judged on the IPv4 it carries, so an IPv6-only network still reaches the public internet through it; RFC 8215's local-use prefix 64:ff9b:1::/48 is refused whole, because the translator chooses the embedding length and there is no offset to read the address from

Schemes are http: and https:. file:, data:, and javascript: are refused before anything is fetched: the process doing the fetching runs as the daemon user, and address validation cannot protect a filesystem.

Validation binds to the connection

Resolving a name to check it and then letting something else resolve it again to connect is DNS rebinding with extra steps — the attacker's server answers 93.184.216.34 for the check and 169.254.169.254 for the connection.

import { createPinnedLookup, requestThroughPolicy, createEgressProxy } from '@stratusagent/egress';
  • createPinnedLookup(policy) is a lookup for Node's HTTP stack, so the addresses the socket uses are the addresses this checked. There is no second resolution to lose to.

  • requestThroughPolicy(url, …) is one exchange over that lookup, with a byte cap. It deliberately does not follow redirects: each hop is a new request to a new host, so the caller loops and each hop faces the policy again. Both of those pass agent: false alongside the lookup. Node's global agent pools sockets by host and port and knows nothing about lookup, so a connection opened under a permissive policy is one a stricter policy can be handed — and a reused socket resolves nothing, so the pinned lookup that would have refused it is never called.

  • createEgressProxy(policy) is a loopback proxy for a browser, which resolves names for itself whatever an interception handler decides. It resolves, checks, and dials the checked address. chromiumProxyOptions / chromiumProxyArgs include <-loopback> in the bypass list, without which Chromium bypasses the proxy for exactly the addresses it exists to refuse.

Widening it

| Setting | What it does | | --- | --- | | allowedHosts | Exempts specific hosts, by name or literal address. The narrow override: one internal service an agent is meant to reach. | | allowPrivateAddresses | Reaches any non-global address. The trusted-workstation posture — it turns the protection off rather than adjusting it. | | allowedSchemes | Replaces the scheme allowlist. There is no good reason to add file:. |

Neither is a substitute for network-level egress rules in a VM or hosted profile (08); this is the in-process half.