Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Hide adversarial fixtures from coding agents#5

Merged
twschiller merged 3 commits into
mainfrom
encode-injection-fixtures
May 30, 2026
Merged

Hide adversarial fixtures from coding agents#5
twschiller merged 3 commits into
mainfrom
encode-injection-fixtures

Conversation

@twschiller

@twschiller twschiller commented May 30, 2026

Copy link
Copy Markdown
Contributor

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 — shared decode() helper with intent doc
  • extension/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 fixtures
  • reviews.ts + ProductDetail.tsx — review bodies, hidden nudges, ChatML block, and the AGENT-INSTRUCTION HTML comment all reference encoded constants

Part 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-adversarial 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.jsonbun run build invokes the codegen; manual run via bun run build-injection-patterns
  • extension/src/rules/prompt-injection-hide.ts — imports INJECTION_PATTERNS from the generated file; runtime atob decode of patterns is gone
  • CLAUDE.md — documents the convention parallel to the site-data section

The 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 — grep atob dist/*.js returns 0 across all four bundles.

Out of scope (intentional)

  • PII fixtures (phone, email, credit-card-shaped strings in reviews) — those don't trip up coding agents the way directive-phrased text does, so they stay readable for ergonomics
  • Innocent CSS selectors / DOM-mechanic code in the other rules — no injection text in them

Verification

  • grep atob extension/dist/*.js — 0 hits across content.js, background.js, popup.js, options.js
  • Plaintext patterns present in shipped bundle (e.g. ignore.*previous.*instructions)
  • bun run test — 385/385 pass
  • bun run check — clean (only the pre-existing unrelated Options.tsx unused-var warning remains, untouched)
  • bun run build (extension) — clean, codegen runs as part of the pipeline
  • bun run build (demo site) — vite builds, all JSX type-checks
  • Manual: load the demo site in a browser, confirm the rendered review bodies / hidden nudges / ChatML strings appear visually identical to before

🤖 Generated with Claude Code

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]>
@vercel

vercel Bot commented May 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agent-browser-shield-demo-site Ready Ready Preview, Comment May 30, 2026 12:21pm

Request Review

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]>
@twschiller twschiller changed the title Base64-encode prompt-injection fixtures Hide adversarial fixtures from coding agents May 30, 2026
@twschiller twschiller merged commit 9e2b4e0 into main May 30, 2026
6 checks passed
@twschiller twschiller deleted the encode-injection-fixtures branch May 30, 2026 12:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant