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

script-jail

v0.2.4

Published

Backend-isolated install auditor for npm/pnpm/yarn lifecycle scripts.

Downloads

1,150

Readme

script-jail

Backend-isolated audit of npm, pnpm, and Yarn lifecycle scripts. script-jail turns dependency install behavior into a deterministic .script-jail.lock.yml so suspicious file, env, process, native-addon, and network behavior is visible in code review.

What It Does

When package-lock.json, pnpm-lock.yaml, or yarn.lock changes, the GitHub Action re-runs the install through a Linux audit backend. backend: auto tries Firecracker first, then Docker, then a bare Linux executor. Each backend runs the same guest agent with strace plus the LD_PRELOAD shim and Node preloads.

The generated .script-jail.lock.yml records lifecycle-script reads and writes outside the owning package directory, env-var reads, protected-secret accesses, execve, audit-bypass attempts, legacy dlopen quarantine events, and blocked network attempts. In check mode, any non-canonical lockfile diff fails the PR with a unified diff.

Status

Released. script-jail and its three platform packages are published to npm, and each GitHub release carries the full artifact set. The Action and CLI verify every downloaded rootfs, kernel, shim, and Docker image against the hash manifest committed in src/action/artifact-manifest.ts before use. Backends: Firecracker, Docker, and bare Linux in CI; a Virtualization.framework VM (vz) and a native no-VM bare backend on macOS.

GitHub Action

Use check mode on pull requests. Commit .script-jail.lock.yml when an intentional dependency change alters the audit.

name: script-jail

on:
  pull_request:
    paths:
      - package-lock.json
      - pnpm-lock.yaml
      - yarn.lock
      - .script-jail.yml
      - .script-jail.lock.yml

jobs:
  audit-install:
    runs-on: ubuntu-24.04
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v6
        with:
          persist-credentials: false

      - uses: Brooooooklyn/scriptjail@<pinned-tag>
        with:
          mode: check
          config: .script-jail.yml
          lock: .script-jail.lock.yml
          backend: auto
          spoof-platform: linux
          # Defaults to the runner CPU architecture when omitted.
          # spoof-arch: arm64
          cache-firecracker: "true"

backend: auto prefers Firecracker when Linux, /dev/kvm, and tap0 are available. On GitHub-hosted ubuntu-24.04-arm, KVM is unavailable, so the parity workflow normally falls through to Docker.

Configuration

.script-jail.yml defines which files and env vars should be hidden from lifecycle scripts and marked as protected in the lockfile:

protected:
  files:
    - ~/.ssh/**
    - ~/.npmrc
    - $REPO/.env
    - $REPO/.env.*
  env:
    - NPM_TOKEN
    - NODE_AUTH_TOKEN
    - GITHUB_TOKEN

spoof:
  platform: linux
  arch: arm64

The Action inputs spoof-platform and spoof-arch override the config for that run without modifying the file on disk.

Lockfile Example

The generated .script-jail.lock.yml is grouped by package identity and lifecycle stage. Empty lists are intentional: they keep the schema stable and make newly observed behavior obvious in diffs. Two extra lists, audit_bypass and env_tamper, appear only when populated — a clean run renders neither.

schema_version: 1
manager: pnpm
manager_lockfile_sha256: "..."
node_version: 24.15.0
generated_at: 2026-05-28T08:00:00.000Z
packages:
  [email protected]:
    lifecycle:
      postinstall:
        external_reads:
          - <HIDDEN> $HOME/.npmrc
          - $REPO/package.json
        escaped_writes:
          - <CROSS_PACKAGE> $NODE_MODULES/victim-package/package.json
          - $TMPDIR/<hash>/build.log
        env_read:
          - <HIDDEN> NPM_TOKEN
          - PATH
        spawn_attempts:
          - node postinstall.js
        spawn_blocked:
          - <ENOENT> gcc -c native.c
        dlopen_attempts: []
        network_attempts:
          - <BLOCKED> connect 198.51.100.7:443

macOS CLI

On macOS 14 or newer, the CLI audits installs through one of two backends:

  • vz (default on Apple Silicon) — boots the same Linux guest agent in a lightweight VM through Apple's Virtualization.framework.
  • bare — runs natively with a Mach-O DYLD_INSERT_LIBRARIES shim and bundled bash/coreutils substitutes, no VM. Network activity is recorded but not blocked on this backend; SIP-protected tools that cannot be instrumented are marked <AUDIT_BLIND>.
pnpm exec script-jail init                  # create .script-jail.lock.yml
pnpm exec script-jail update                # overwrite .script-jail.lock.yml
pnpm exec script-jail check                 # diff against the committed lockfile
pnpm exec script-jail check --backend bare  # native audit, no VM

When no subcommand is provided, the CLI defaults to init if the lockfile does not exist and check if it does. The runtime artifacts (VZ helper, VZ kernel, rootfs, and the .so/.dylib shims) ship inside @script-jail/darwin-arm64; a repo checkout resolves them from images/ instead.

Installation and packaging

The main script-jail npm package is JS-only: it ships dist/cli.cjs, the guest agent (dist/guest-agent.cjs), the Node preloads, and this README — no runtime artifacts. The platform-specific runtime payloads live in three optional dependency packages, one per supported host:

  • @script-jail/darwin-arm64 — VZ helper (script-jail-vm), VZ kernel (vmlinux-vz-arm64), libscriptjail-arm64.so, a compressed Ubuntu 24.04 arm64 rootfs, and the bare-backend binaries (libscriptjail-arm64.dylib, bash-arm64, coreutils-arm64).
  • @script-jail/linux-x64libscriptjail.so and a compressed Ubuntu 24.04 x64 rootfs.
  • @script-jail/linux-arm64libscriptjail-arm64.so and a compressed Ubuntu 24.04 arm64 rootfs.

Each optional package declares matching os/cpu, so npx script-jail (or any install) automatically pulls only the @script-jail/<os>-<arch> that matches the current host and skips the rest. Intel macOS (darwin-x64) is not supported. In a repo checkout the CLI instead resolves these artifacts from images/ as a development fallback. On first run, the CLI expands the compressed rootfs into a sparse cache under ~/Library/Caches/script-jail on macOS, or under SCRIPT_JAIL_CACHE_DIR (falling back to the system temp dir) on Linux.

How It Works

Install auditing is split into two phases. Phase A runs the package-manager fetch with network enabled and no audit output. Phase B disables network and runs lifecycle scripts under strace, the Rust LD_PRELOAD shim, and Node preloads. The guest normalizes attributed events into a byte-stable YAML lockfile. See docs/design.md for rationale and docs/architecture.md for the control flow.

Why Backend Isolation

A pure-JS install sandbox cannot close the important gaps: native addons and child_process reach the kernel, libc/libuv env reads bypass a process.env Proxy, and bun does not honor the Node preload model. Firecracker is the strongest Linux isolation boundary; Docker and bare mode keep the same syscall/preload audit available on runners without KVM.

Docs

License

MIT