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

@devslab/ssrf-guard-js

v0.1.1

Published

SSRF protection for JavaScript and TypeScript: URL policy validation, private-network blocking, redirect checks, and LLM tool-input guards.

Readme

ssrf-guard-js

한국어 | Docs

SSRF protection for JavaScript and TypeScript.

This is the JS/TS sibling of devslab-kr/ssrf-guard. It ports the same core security model:

  • URL-time validation: scheme, host allowlist, port, userinfo, IP-literal checks
  • private-network IP classification
  • LLM/tool-call JSON scanning for hidden URLs
  • guarded fetch with URL, DNS, and redirect checks

Install

pnpm add @devslab/ssrf-guard-js

For a copy-paste tutorial, see the documentation site: https://devslab-kr.github.io/ssrf-guard-js/

URL Policy

import { validateUrl } from '@devslab/ssrf-guard-js';

validateUrl('https://api.example.com/v1', {
  exactHosts: ['api.example.com'],
  allowedSchemes: ['https'],
  allowedPorts: [-1, 443],
});

Empty exactHosts and suffixes are fail-closed: no host is allowed until you configure one.

Defaults:

  • allowedSchemes: ['http', 'https']
  • allowedPorts: [-1, 80, 443]
  • rejectIpLiteralHosts: true
  • rejectUserInfo: true
  • blockPrivateNetworks: true

LLM Tool Input Guard

import { guardToolInputJson } from '@devslab/ssrf-guard-js';

const violation = guardToolInputJson(
  JSON.stringify({ request: { target: 'http://169.254.169.254/latest/meta-data/' } }),
  { exactHosts: ['api.example.com'] },
);

if (violation) {
  return violation; // structured JSON error for the model/tool caller
}

The guard walks the entire JSON tree. A bad URL hidden inside a nested object, array, or explanation field is still blocked.

Guarded Fetch

import { safeFetch } from '@devslab/ssrf-guard-js';

const response = await safeFetch('https://api.example.com/data', {
  exactHosts: ['api.example.com'],
  allowedSchemes: ['https'],
});

safeFetch validates the URL, checks DNS results for private/local IPs, and revalidates every redirect hop.

Node's built-in fetch does not expose the same socket-level IP pinning API that the Java Apache HttpClient adapter uses. Treat safeFetch as a strong guard rail, but use strict allowlists or a dedicated egress service for high-risk arbitrary URL crawling.

Express

import express from 'express';
import { createExpressUrlGuard } from '@devslab/ssrf-guard-js';

const app = express();
app.use(express.json());

app.post(
  '/crawl',
  createExpressUrlGuard({
    exactHosts: ['example.com'],
    suffixes: ['example.com'],
    allowedSchemes: ['https'],
  }),
  async (req, res) => {
    res.json({ ok: true });
  },
);

The middleware scans req.body and req.query by default. It returns a structured 400 response when it finds a blocked URL.

Vite

Use this when your Vite dev server has SSR/proxy endpoints that receive a URL and then fetch it server-side.

// vite.config.ts
import { defineConfig } from 'vite';
import { ssrfGuardVitePlugin } from '@devslab/ssrf-guard-js/vite';

export default defineConfig({
  plugins: [
    ssrfGuardVitePlugin({
      routes: ['/api/crawl'],
      policy: {
        suffixes: ['example.com'],
        allowedSchemes: ['https'],
      },
    }),
  ],
});

The plugin scans query params named url, target, uri, and href by default. Example blocked request:

/api/crawl?url=http://169.254.169.254/latest/meta-data/

LangChain / Agent Tools

createGuardedToolHandler wraps any object-input tool function without taking a hard dependency on LangChain.

import { DynamicStructuredTool } from '@langchain/core/tools';
import { z } from 'zod';
import { createGuardedToolHandler, safeFetch } from '@devslab/ssrf-guard-js';

const policy = {
  suffixes: ['example.com'],
  allowedSchemes: ['https'],
};

export const fetchUrlTool = new DynamicStructuredTool({
  name: 'fetch_url',
  description: 'Fetch an allowed URL',
  schema: z.object({ url: z.string().url() }),
  func: createGuardedToolHandler(policy, async ({ url }) => {
    const response = await safeFetch(url, policy);
    return await response.text();
  }),
});

If the model tries to pass a private IP, metadata URL, or non-allowed host, the tool returns a structured ssrf_blocked JSON string instead of fetching it.

Block Reasons

Thrown SsrfGuardError instances expose stable reason values:

  • blocked_scheme
  • blocked_host
  • blocked_port
  • blocked_ip_literal
  • blocked_userinfo
  • blocked_private_ip
  • blocked_redirect
  • blocked_other

License

Apache-2.0

Maintainer Release

Publishing is handled by GitHub Actions.

  1. Add an npm automation token as the repository secret NPM_TOKEN.
  2. Bump version in package.json.
  3. Commit the change.
  4. Create and push a matching tag, for example:
git tag v0.1.1
git push origin main --tags

The Publish to npm workflow verifies the package, checks that the tag matches package.json, then runs:

npm publish --access public --provenance