Blinded by a leaf. — 一叶障目,不见泰山。
A pi-agent extension that redacts access tokens, passwords, private keys, and environment variable values from all LLM API requests using deterministic regex matching — while preserving variable names.
Designed for and tested on pi-agent ≥ 0.80.2.
Why this exists: the assumption is that an LLM agent only needs
environment variable names to reason about configuration — never their
actual values. This extension redacts all values to SECRET_VALUE_REDACTED_FOR_SAFETY before they
reach the model, while preserving variable names and declaration syntax.
Without leafblind — the LLM sees and repeats raw credentials:
With leafblind — values are redacted to SECRET_VALUE_REDACTED_FOR_SAFETY, variable names preserved:
Add extensions in pi's settings.json pointing to your clone of this
repo:
{
"extensions": ["<path-to-cloned-repo>"]
}Or symlink/copy this directory into ~/.pi/agent/extensions/leafblind/ (pi
auto-discovers extensions/*/index.ts).
- Hooks the
contextevent (model-agnostic, fires before every LLM call, prior toconvertToLlm). - Hooks the
before_provider_requestevent to catch tool results in streaming providers. redact()is a deterministic pure function: same input → same output, fixed placeholderSECRET_VALUE_REDACTED_FOR_SAFETY— does not break prompt cache prefix.- Syntax-driven, redact-all-values (for
=-style declarations): every environment-variable declaration (export/declare/set/bareVAR=) has its VALUE replaced; the variable name and declaration keyword are preserved. Sensitivity is NOT decided by the variable name -- this catches non-obvious names likePASS_ZTE=...that a keyword list would miss. - Variable name preserved:
export VAR=sk-xxx→export VAR=SECRET_VALUE_REDACTED_FOR_SAFETY. - Known token formats (AWS/OpenAI/GitHub/Slack/JWT/Bearer) and PEM private key blocks are replaced in their entirety.
- Command options (
--opt=val) and function arguments (func(arg=val)) are NOT declarations (Syntax 1-3,=-style only) and are left untouched. - Multi-line PEM private key blocks are fully replaced.
- YAML colon assignments (
key: value) and JSON key-value pairs ("key": "value") are keyword-driven, not redact-all, and share one keyword list (SENSITIVE_KEY): case-insensitive substring match onpass/pwd/psk/user_name/user_id/secret/token/api_key/access_key. This catchesbasic_auth.password/wifi_pass/PASS_ZTE:in indented scrape configs (Kuma leak, session 019f1b5d) and"user_id": "..."in JSON logs alike, while leaving structured config keys (host/port/image/replicas/title/date) and/aimheadings (Constraints:/Scope:) intact. YAML: same-line values only -- block scalars (KEY: |/KEY: >) and values on following lines are not inferred. JSON: quoted values only, 4+ characters. - URL-embedded credentials (
scheme://user:pass@host) are redacted when the password is 6+ characters; the username is left visible. - Email / phone numbers / general PII are NOT matched.
| Syntax | Example |
|---|---|
export VAR=val |
export PASS_ZTE=xxx |
Bare VAR=val (line start / after ; &) |
PASS_ZTE=xxx |
password: val (YAML / colon -- keyword-driven, indented OK) |
wifi_pass: xxx |
"key": "val" (JSON -- keyword-driven, same list as YAML) |
"user_id": "xxx" |
scheme://user:pass@host (URL credentials, password 6+ chars) |
https://admin:xxx@host |
declare -x VAR=val |
declare -x SECRET=xxx |
env VAR=val cmd |
env API_KEY=xxx cmd |
set VAR=val (Windows) |
set DB_PASS=xxx |
$env:VAR = "val" (PowerShell) |
$env:TOKEN = "xxx" |
set -x VAR val (fish) |
set -x MY_PWD xxx |
os.environ["VAR"] = "val" (Python) |
os.environ["PSK"] = "xxx" |
Known token formats — including AWS access keys, OpenAI keys, GitHub tokens,
Slack tokens, JWTs, Bearer tokens, and PEM private key blocks — are matched
via regex and replaced in their entirety with SECRET_VALUE_REDACTED_FOR_SAFETY.
1 MB text filtering ≤ 50 ms (measured: 8 ms with 50 secrets / 4 ms without secrets).
node --experimental-strip-types --test leafblind.test.mjs
node --experimental-strip-types --test leafblind.integration.test.mjs108 test cases (98 unit + 10 integration), all using purely fictional placeholder values (marked
fake/test). No real secrets.