Hide adversarial fixtures from coding agents#5
Merged
Conversation
Wrap every prompt-injection-shaped string in the repo in a small encode/decode helper so coding agents reading the source aren't tripped up by adversarial phrasing. There's no security property here — the decoded values land in the DOM (demo site) or in test HTML (rule tests) exactly as they did before — purely a readability shield. - extension/src/lib/encoded-fixture.ts: shared atob() wrapper with intent doc - extension/src/rules/prompt-injection-hide.ts: regex pattern sources are base64; decoded once at module load into the same RegExp[] as before - extension/src/rules/__tests__/injection-fixtures.ts: shared decoded fixture table consumed by the three rule tests that asserted on literal injection strings - demo-site/src/data/injection-fixtures.ts: same pattern for the demo's review bodies, hidden-text spans, ChatML fragments, and the AGENT- INSTRUCTION HTML comment - reviews.ts / ProductDetail.tsx: replace literal injection strings with references into the encoded module PII fixtures (phone, email, etc.) are intentionally left readable — they're not what trip up coding agents. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Chrome Web Store review treats `atob`-decoded strings in shipped JS as obfuscated code, which would put the prior commit at risk. Move the encoding boundary from runtime to build time so the bundle ships plaintext regexes: - extension/data/injection-patterns.yaml: source of truth — the 11 pattern sources stay base64-encoded here (the YAML never ships) with terse non-adversarial identifiers as `name` - extension/scripts/build-injection-patterns.ts: zod-validated codegen, decodes each `source_b64`, sanity-compiles it, emits `src/rules/injection-patterns.generated.ts` with `new RegExp(...)` literals. Mirrors the build-site-data.ts precedent - extension/build.ts + package.json: wire the codegen into `bun run build` and add `bun run build-injection-patterns` - extension/src/rules/prompt-injection-hide.ts: import INJECTION_PATTERNS from the generated file; drop the inlined encoded array and the runtime atob decode - CLAUDE.md: document the convention parallel to the site-data section Test fixtures in `__tests__/injection-fixtures.ts` still decode via atob, but they aren't reachable from any bundle entrypoint so Bun tree-shakes them out — verified `grep atob dist/*.js` is 0 across all four bundles, and the plaintext patterns are present. 385/385 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This was referenced Jun 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two-part change so coding agents reading this repo aren't tripped up by literal prompt-injection phrasing, without shipping
atob-decoded strings in the extension bundle (which Chrome Web Store review treats as obfuscated code).Part 1 — Encode the in-repo fixtures
Wrap every prompt-injection-shaped string in the repo in a small
decode(atob(...))helper. Purely a readability shield for coding agents; no security claim.extension/src/lib/encoded-fixture.ts— shareddecode()helper with intent docextension/src/rules/__tests__/injection-fixtures.ts— shared decoded-fixture table consumed by:prompt-injection-hide.test.ts(13 fixtures)hidden-text-strip.test.ts(4 fixtures)html-comment-strip.test.ts(2 fixtures)demo-site/src/data/injection-fixtures.ts— same pattern for the RiverMart fixturesreviews.ts+ProductDetail.tsx— review bodies, hidden nudges, ChatML block, and the AGENT-INSTRUCTION HTML comment all reference encoded constantsPart 2 — Decode rule patterns at build time, not runtime
CWS reviewers flag runtime base64 decoding as obfuscated code. Move the encoding boundary to build time so the shipped bundle contains plaintext regexes.
extension/data/injection-patterns.yaml— source of truth: the 11 pattern sources stay base64-encoded here (YAML never ships), each tagged with a terse non-adversarialnameextension/scripts/build-injection-patterns.ts— zod-validated codegen, decodes eachsource_b64, sanity-compiles it, emitssrc/rules/injection-patterns.generated.tswithnew RegExp(...)literals. Mirrors thebuild-site-data.tsprecedentextension/build.ts+package.json—bun run buildinvokes the codegen; manual run viabun run build-injection-patternsextension/src/rules/prompt-injection-hide.ts— importsINJECTION_PATTERNSfrom the generated file; runtimeatobdecode of patterns is goneCLAUDE.md— documents the convention parallel to the site-data sectionThe test fixtures in
__tests__/injection-fixtures.tsstill decode viaatob, but they aren't reachable from any bundle entrypoint, so Bun tree-shakes them out —grep atob dist/*.jsreturns 0 across all four bundles.Out of scope (intentional)
Verification
grep atob extension/dist/*.js— 0 hits acrosscontent.js,background.js,popup.js,options.jsignore.*previous.*instructions)bun run test— 385/385 passbun run check— clean (only the pre-existing unrelatedOptions.tsxunused-var warning remains, untouched)bun run build(extension) — clean, codegen runs as part of the pipelinebun run build(demo site) — vite builds, all JSX type-checks🤖 Generated with Claude Code