Repository navigation
strangerDanger v0.2.0
Secret and PII redaction guard for AI coding agents — now enforcing at the
OpenCode V2 request boundaries.
strangerDanger does not guarantee prevention of every secret leak. It
protects the specific surfaces listed below and fails closed everywhere else.
Read the limitations before relying on it.
Features
- Boundary redaction, not just auditing. Registers all four V2 model-request
hooks —session.prompt,session.context,session.generate,
session.title— plussession.compactionandtool.execute.after, so
prompts, tool results, transient generations, titles, and compaction
transcripts are scanned immediately before transmission. Redaction is
ordering-independent: whatever path a request takes, its assembled
system/messagesare re-scanned before dispatch. - 236 detection rules — 221 vendored from gitleaks (MIT), 12 clean-room
additions for AI/ML providers, and 3 entropy detectors. - Standalone CLI (
sd):scan,redact,audit,rules,allowlist,
version. - Five plugin tools:
sd_status,sd_audit,sd_allowlist_add,
sd_allowlist_show,sd_scan. - Allowlist by fingerprint, rule ID, path, or regex
(.strangerdanger-allowlist.toml). - Independent: requires no companion plugin; the only interop surface is the
optional, read-only, semver-versioned@gitdamnit/stranger-danger/engineexport.
Security improvements
- File reads never modify files. The pre-read hook is strictly read-only; a
detected secret no longer rewrites the file on disk. - Effective outbound protection. 0.1.0's V1
eventhandler only audited
after the fact. 0.2.0 redacts before transmission. - Fail-closed by construction. Bounded, windowed scanning: content over the
size ceiling, a window timeout/error, a cyclic structure, or nesting beyond 32
levels is replaced with an explicit marker instead of being passed through. - Cycle-safe structured redaction — fixes a fail-open where a self-referential
tool output left the entire result, including plain string secrets, unredacted. Tool.Error.metadatais redacted (it is surfaced to the model).- No raw secrets in output. CLI, tools, and the audit log report safe metadata
only (rule, description, source, line/column, 8-hex fingerprint, redaction
token). The audit log never stores the matched value. - Safe
sd redact— atomic write (temp + fsync + rename); no plaintext backup
in the working tree unless opted in, and then a0600backup outside the tree. - Critical regex fix — RE2/Pcre constructs that crashed
new RegExpat import
time are translated to valid JavaScript. sd_scaninput bounded to 8 MiB so a model-invoked scan cannot exhaust
memory or hang the server.- Directory installs load — the package ships a root
index.js, so
{ "package": "/path/to/stranger-danger" }no longer silently fails with
"Plugin entrypoint not found".
Compatibility
- OpenCode V2 runtime,
@opencode/plugin >= 2.0.0
(validated against@opencode/plugin@2.0.29on OpenCode2.0.21). - Node
>= 20(CI and runtime validation on Node 22).
Installation
OpenCode V2 plugin
npm publication is pending (see Distribution). Until then,
install from the repository, or pointpluginsat a local checkout directory.
Standalone CLI
npm install -g @gitdamnit/stranger-danger # once published to npmUpgrade notes
- Breaking: 0.1.0 → 0.2.0 migrates to the OpenCode V2 plugin API.
Configure the plugin underplugins(not the V1pluginkey) and run an
OpenCode V2 host. - Rule count is now 236 (was ~172).
- The pre-read hook no longer rewrites files. If you relied on that behavior,
usesd redact(or your own tooling) to remediate files on disk. - The audit log moved to a project-scoped path:
<project>/.opencode/state/strangerdanger-audit.jsonl(git-ignored,0600).
Known limitations
- Provider-native WebSocket traffic is not inspected. The experimental
experimental.ws.*hooks are deliberately not registered. Plain-HTTP providers
and the HTTP fallback of a WebSocket route are covered. - Raw
http.requestbodies are not scanned. The plugin edits assembled
system/messages, not HTTP bodies. Content a provider layer adds outside
those is not covered.event.subscribeis observation-only (post-admission). - Structured values: only string leaves of plain objects/arrays are redacted.
Exotic objects (Map,Set,Date, typed arrays) are passed through unchanged. - Encoded secrets: detection is pattern/entropy based; secrets obfuscated so
they match no rule are not caught. - No universal guarantee: a secret that no rule matches, or that travels
through one of the surfaces above, is not stopped. Use it alongside
.gitignore, secret managers, and provider-side controls.
See SECURITY.md
for the full policy.
Testing summary
- Local: typecheck, lint, and build pass;
npm test322 pass / 0 fail;
package validation (pack→ isolated install → exercise artifact) passes. - Docker Plugin Test Lab: OpenCode
2.0.21, Node22.23.3, image
opencode-plugin-lab:local
(sha256:76ebd805cd548a638b9b1508e5f16e680cd5b082cd3f3561d28f2f2301336ff1):
145 passed / 0 failed / 0 skipped, covering runtime loading, tool
registration, synthetic secret detection, context and tool-output redaction,
large-output windowed scanning, fail-closed oversize handling, allowlist
behavior, secret-free audit logging, per-session isolation, the offline
model-request path, all six plugin load orders, and failure isolation. - The released source tree is byte-identical to the verified development
commit9cfd8135429bffb2e5e32e97f23bec3f5b6277bd; this release adds
documentation and package metadata only.
Distribution
This is the GitHub release. The package is not yet on npm: the
@gitdamnit scope has no published package and the repository has no NPM_TOKEN
configured. The publish.yml workflow runs on v*.*.* tags and will publish to
npm once registry credentials are set up.
Licence
MIT — see LICENSE.
Attribution
- gitleaks/gitleaks (MIT) — vendored detection rules.
- Yelp/detect-secrets (Apache-2.0) — entropy detection approach (clean-room
TypeScript implementation). - boxpositron/envsitter-guard (MIT) — complementary plugin.
{ "$schema": "https://opencode.ai/config.json", "plugins": ["@gitdamnit/stranger-danger"] }