Skip to content

Latest commit

 

History

56 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

leafblind

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.

中文文档

Screenshots

Without leafblind — the LLM sees and repeats raw credentials:

without leafblind

With leafblind — values are redacted to SECRET_VALUE_REDACTED_FOR_SAFETY, variable names preserved:

with leafblind


Installation

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).

Mechanism

  • Hooks the context event (model-agnostic, fires before every LLM call, prior to convertToLlm).
  • Hooks the before_provider_request event to catch tool results in streaming providers.
  • redact() is a deterministic pure function: same input → same output, fixed placeholder SECRET_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/bare VAR=) 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 like PASS_ZTE=... that a keyword list would miss.
  • Variable name preserved: export VAR=sk-xxxexport 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 on pass / pwd / psk / user_name / user_id / secret / token / api_key / access_key. This catches basic_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 /aim headings (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.

Coverage

Environment Variable Declaration Syntaxes (value redacted, name kept)

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"

Token Formats (whole match replaced)

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.

Performance

1 MB text filtering ≤ 50 ms (measured: 8 ms with 50 secrets / 4 ms without secrets).

Testing

node --experimental-strip-types --test leafblind.test.mjs
node --experimental-strip-types --test leafblind.integration.test.mjs

108 test cases (98 unit + 10 integration), all using purely fictional placeholder values (marked fake/test). No real secrets.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages