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

@arvoretech/pi-secret-firewall

v0.3.0

Published

Redacts secrets (env vars, .env files, token patterns) from the model context and tool outputs, exposing them only as $SECRET_* shell env vars the model can reference but never read

Readme

@arvoretech/pi-secret-firewall

A secret firewall for the Pi/Kiro agent. It keeps secret values out of the model context entirely, exposing them only as shell environment variables that the model can reference by name but never read. Where a secret value would appear, the model instead sees a self-describing placeholder that names the exact shell variable to use, e.g. «SECRET DATABASE_URL redacted — ... read it in bash as "$DATABASE_URL"».

How it works

On session start (and on demand) it discovers secrets from two sources:

  1. Real environment variables whose name looks sensitive (*_TOKEN, *_SECRET, *_API_KEY, *_PASSWORD, DATABASE_URL, ...) — exact value match, zero false positives.
  2. .env / .env.local / .env.development* files in the cwd.

Each secret value gets a stable, self-describing placeholder that tells the model exactly how to use it. For env/dotenv secrets the shell variable is the secret's original name: MY_API_KEY=xptolksjf«SECRET MY_API_KEY redacted — the real value is live in your shell env; read it in bash as "$MY_API_KEY"».

Redaction happens on three channels:

  • input hook — the user's own message is redacted at the moment it is submitted, before it is stored in the session or shown in the transcript. So a pasted secret never persists in the user's session and the user sees the placeholder too, making it clear the value was redacted.
  • context hook — every message sent to the model (user text, assistant text, thinking, and tool-call arguments) has secret values swapped for their placeholder.
  • tool_result hook — output from bash, read, grep, etc. is redacted, so cat .env returns placeholders, not values.

A pattern fallback also catches well-known token shapes (AWS keys, JWTs, sk-..., GitHub/Slack tokens, PEM private keys) that leak into output even when they were never in an env var. When such a token is caught, it is captured and auto-exported to the shell under a generated name (SECRET_JWT, SECRET_JWT_2, ...), written to process.env, and replaced in the context with the same self-describing placeholder. So if you paste a JWT into the chat, the model sees ... read it in bash as "$SECRET_JWT" and can use it via curl -H "Authorization: Bearer $SECRET_JWT" without ever seeing the value. Captured names show up under /secret-firewall status.

Standing guidance in the system prompt

A before_agent_start hook appends a short section to the system prompt every turn explaining the contract: placeholders are not the value and not an unset variable; the real value is live in the shell; reference it by name in a bash command; never echo/print/cat it. It also lists the currently available secret env var names. This is what stops the model from concluding "the env var isn't set" or treating the placeholder text as the literal value.

Security model — the model never sees the value

This extension uses the shell-env-only strategy:

  • The real value lives in process.env (which the bash tool inherits).
  • The model references it as a shell variable: curl -H "Authorization: Bearer $MY_API_KEY".
  • The shell resolves $MY_API_KEY at execution time.
  • The value never returns to the context — any echo of it in tool output is redacted again.

The extension never re-hydrates placeholders itself. If the model writes the literal value instead of the shell reference, that value is redacted on the way back, but the model must use the $NAME reference for a command to actually use the secret.

Pasted/leaked tokens are captured and exported

When a value is caught by a pattern rule (JWT, AWS key, sk-..., etc.) it is not only masked — its real value is captured and exported as a $SECRET_* shell variable on the fly. This means a token pasted into the chat becomes usable in bash ($SECRET_JWT) without the model ever seeing the value, and without needing it in .env beforehand. Distinct values caught by the same pattern get suffixed names ($SECRET_JWT_2).

Limits / non-goals

  • A determined model could still exfiltrate a secret by transforming it before printing (e.g. base64). This raises the bar; it is not a sandbox.
  • Values shorter than 8 chars or matching trivial values (true, 3000, ...) are not protected — they are not secrets and redacting them breaks the agent.
  • Infra/session vars (PATH, HOME, SSH_AUTH_SOCK, *_SESSION, ...) are explicitly never treated as secrets.

Commands

  • /secret-firewall — show status (protected secrets, redaction count, the shell env var names the model may reference).
  • /secret-firewall-toggle — enable/disable redaction.
  • /secret-firewall-rescan — re-scan env + .env files.

Develop

pnpm build   # tsc -> dist/
pnpm test    # node --test against dist/
pnpm lint    # tsc --noEmit