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

@red_official/pentry

v1.1.0

Published

Security tests for your web app, in your test suite. Like Jest, but it pen-tests. Zero dependencies.

Downloads

446

Readme

Pentry

Security tests for your web app, right in your test suite.

Like Jest, but it pen-tests. Point it at your running app and it probes for the OWASP Top 10 — broken access control, XSS, CORS holes, missing security headers, and more — then reports each finding with reproducible evidence and a fix.

CI npm license zero dependencies


Why Pentry

Security scanning today is either a heavyweight external tool owned by a separate team (ZAP, Burp) or a SaaS you wire into CI. Neither lives where developers work: the test suite. Pentry does.

  • 🧪 Runs in your tests and CI — assert that your app has no security regressions the same way you assert it returns 200.
  • 🎯 Precision over noise — every finding ships with the exact request/response that proves it. A scanner you can't trust gets deleted from CI in a week; Pentry is built to cry wolf as little as possible.
  • 🔒 Safe by default — only scans localhost/private addresses unless you explicitly authorize an external target. You test what you own.
  • 📦 Zero runtime dependencies — a security tool shouldn't drag in a supply chain. Pentry has none.
  • 🧩 Extensible — built-in checks are just objects; write your own in a few lines.
  • 📤 Reports anywhere — pretty console, JSON, SARIF (GitHub code scanning), JUnit (CI test UIs), Markdown (PR comments), and HTML.

How it compares

| | ZAP / Burp | StackHawk | Pentry | | ------------- | --------------- | -------------- | ------------------------ | | Where it runs | External tool | SaaS + CI | Your test suite & CI | | Cost | Free / paid | Paid | Free & open source | | Setup | Heavy, separate | Account + YAML | npm i + 3 lines | | Runtime deps | — | — | Zero | | Owned by | Security team | Security team | Developers |

Pentry isn't trying to replace a full DAST suite or a human pentest — it catches the common, automatable issues early, where developers already work.

Install

npm install --save-dev @red_official/pentry

Requires Node.js 18+.

Quick start

In a test

import { test } from 'vitest'; // or jest, node:test, etc.
import { scan } from '@red_official/pentry';

test('app has no security regressions', async () => {
  const report = await scan({ target: 'http://localhost:3000' });
  report.assert(); // throws (failing the test) if anything ≥ "medium" is found
});

From the CLI

npx @red_official/pentry scan http://localhost:3000
Pentry security report — http://localhost:3000
────────────────────────────────────────────────────────────
MED   Missing Content-Security-Policy header
      security-headers · http://localhost:3000/
      No Content-Security-Policy was set. A CSP is the most effective
      defense-in-depth control against cross-site scripting…
      Fix: Set a Content-Security-Policy header. Start strict…
      GET http://localhost:3000/ → 200

HIGH  Protected route reachable without authentication: /api/admin
      access-control · http://localhost:3000/api/admin
      …
────────────────────────────────────────────────────────────
1 high · 1 medium
✗ 2 finding(s) at or above "medium" — failing.

The CLI exits non-zero when findings meet the --fail-on threshold, so it gates a pipeline out of the box.

Testing protected routes

Tell Pentry which routes should require auth and how to authenticate, and it will verify both that anonymous users are blocked and that your headers don't leak:

const report = await scan({
  target: 'http://localhost:3000',
  routes: [
    '/',
    { path: '/api/admin', protected: true },
    { path: '/api/me', method: 'GET', protected: true },
  ],
  auth: { headers: { Authorization: 'Bearer <test-token>' } },
  failOn: 'high',
});

Route discovery

Don't hand-list routes — derive them from your app or an OpenAPI spec:

import { scan, discoverExpressRoutes, discoverOpenApiRoutes } from '@red_official/pentry';

// From an Express app instance
await scan({ target: `http://localhost:${port}`, routes: discoverExpressRoutes(app) });

// …or from any OpenAPI / Swagger document (framework-agnostic)
import spec from './openapi.json' with { type: 'json' };
await scan({ target: 'http://localhost:3000', routes: discoverOpenApiRoutes(spec) });

discoverRoutes(input) auto-detects which adapter to use. More adapters (Fastify, Next.js) are on the roadmap.

What it checks

| Check | ID | What it catches | | ---------------------- | ----------------------- | ------------------------------------------------------------------------- | | Security headers | security-headers | Missing/invalid CSP, HSTS, X-CTO, clickjacking, Referrer/Permissions/COOP | | Cookie flags | cookies | Missing HttpOnly/Secure/SameSite; __Host-/__Secure- prefixes | | Sensitive caching | cache-control | JSON / cookie-setting responses that are cacheable | | Information disclosure | info-disclosure | Server/X-Powered-By version banners | | Subresource Integrity | subresource-integrity | Cross-origin scripts/styles without an integrity hash | | CORS misconfiguration | cors | Arbitrary-origin reflection, credentialed wildcard | | Transport security | transport-security | Mixed content; missing HTTP→HTTPS redirect | | Dangerous HTTP methods | http-methods | TRACE/TRACK enabled (Cross-Site Tracing) | | Broken access control | access-control | protected routes reachable without auth | | Reflected input (XSS) | reflected-input | User input reflected unencoded into HTML | | Verbose errors | error-disclosure | Stack traces / framework internals in error responses | | Exposed resources | exposed-resources | Directory listing; .env / .git/config served directly | | GraphQL introspection | graphql-introspection | GraphQL endpoints exposing their schema |

See docs/checks.md for the full reference, including severity and remediation for each.

CI integration

Upload SARIF to get findings in GitHub's Security tab and on PRs:

- run: npx @red_official/pentry scan http://localhost:3000 --format sarif --output pentry.sarif
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: pentry.sarif

Full guide: docs/ci-integration.md.

Documentation

Contributors: see docs/internal for architecture and design notes.

Responsible use

Pentry actively sends crafted (non-destructive) requests to a target. Only run it against systems you own or are explicitly authorized to test. By default it refuses any target that isn't loopback/private; the allowExternal opt-in exists for your own staging/production hosts, not other people's. See SECURITY.md.

Contributing

Issues and PRs welcome — see CONTRIBUTING.md. New checks are the highest-impact contribution; the check-authoring guide walks through it.

License

MIT