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

ssrf-fetch

v0.1.0

Published

A drop-in fetch() that blocks SSRF: refuses loopback/private/link-local/CGNAT targets and pins the connection to the validated IP to defeat DNS rebinding (TOCTOU).

Readme

ssrf-fetch

A drop-in fetch() that stops SSRF. It refuses to connect to internal network targets and pins the connection to the IP it just validated, so a hostile DNS server can't rebind the hostname to an internal address after the check (TOCTOU).

Zero config. One dependency (undici). Works with Node's native fetch.

import { safeFetch } from 'ssrf-fetch';

// Same signature as fetch(). Throws instead of connecting to an internal host.
const res = await safeFetch(userProvidedUrl);
const body = await res.text();

Why

Any time your server fetches a URL it didn't author — a webhook target, an avatar URL from a user profile, a link-preview/OpenGraph crawl, an "import from URL" feature — an attacker can point that URL inward:

  • http://169.254.169.254/latest/meta-data/ — cloud instance metadata (IAM creds)
  • http://localhost:6379/ — Redis, Postgres, or any local service
  • http://10.0.0.5/admin — a private service with no auth because it's "internal"

Plain fetch() will happily make those requests from inside your network. That's SSRF, and it's #10 on the OWASP Top 10.

What it does

safeFetch():

  1. Requires http(s) — no file:, gopher:, ftp:, etc.

  2. Resolves the hostname and blocks internal addresses — if any resolved address is loopback, link-local, private, unique-local, or CGNAT, the request is refused:

    | Range | Example | |---|---| | 0.0.0.0/8 | 0.0.0.0 | | 10.0.0.0/8 | private | | 127.0.0.0/8 | loopback | | 169.254.0.0/16 | link-local incl. 169.254.169.254 metadata | | 172.16.0.0/12 | private | | 192.168.0.0/16 | private | | 100.64.0.0/10 | CGNAT | | ::1, :: | IPv6 loopback / unspecified | | fe80::/10 | IPv6 link-local | | fc00::/7 | IPv6 unique-local | | ::ffff:a.b.c.d | IPv4-mapped (the embedded v4 is re-checked) |

  3. Disables redirects — a public URL must not 30x-bounce into an internal one.

  4. Closes the DNS-rebinding hole (TOCTOU) — this is the part most guards miss. Checking the DNS record and then calling fetch() re-resolves the name, so a hostile DNS server can return a public IP on the check and an internal IP on the connect. ssrf-fetch pins the request to the exact addresses it just validated via a custom undici Agent lookup, so the connection can only go where the check passed. The Host header and TLS SNI stay the original hostname, so certificate validation is unaffected.

Install

npm install ssrf-fetch

Requires Node.js 20+ (uses global fetch and undici v7).

API

safeFetch(url, init?): Promise<Response>

A drop-in replacement for fetch(). Same arguments, returns a standard Response.

  • redirect is always forced to 'error'.
  • A 5-second timeout is applied unless you pass your own signal.
  • Throws if the protocol isn't http(s) or the host resolves to any internal address. Wrap in try/catch and fall back as needed:
import { safeFetch } from 'ssrf-fetch';

try {
  const res = await safeFetch(url);
  // ...use res
} catch (err) {
  // blocked protocol, blocked host, redirect, or timeout
}

addressIsBlocked(ip): boolean

Classifies a resolved IP string as internal (true) or public (false). Useful if you resolve DNS yourself or want to validate an address without making a request.

import { addressIsBlocked } from 'ssrf-fetch';

addressIsBlocked('169.254.169.254'); // true
addressIsBlocked('1.1.1.1');         // false

Limitations & scope

  • This is an egress guard, not an allowlist. It blocks known-internal ranges. For the strongest posture, combine it with an explicit allowlist of hostnames you intend to reach.
  • It does not proxy or sandbox the request body; it controls where the connection is allowed to go.
  • It intentionally blocks all redirects. If you need to follow redirects to public hosts, resolve and re-validate each hop yourself.
  • DNS resolution uses the system resolver (node:dns). Pinning defeats rebinding between the check and the connect; it does not defend against a fully compromised resolver returning a public IP for a genuinely internal name you meant to reach.

License

MIT © Ian Duncan