Zero-dependency prompt-injection, invisible Unicode steganography, spoofed <system-reminder> delimiter, and repo-open execution trap scanner for Claude Code, Codex CLI, skills, and GitHub issues.
In today's r/ClaudeAI thread (1xozfcv, "Why are more than 98% of 16,060 open GitHub issues on anthropics/claude-code unassigned?") and r/ExperiencedDevs thread (1xnl43h, "The Agentic Code Review Dilemma"), maintainers pointed out the core blocker to letting coding agents triage issues, review PRs, or inspect cloned repos: untrusted input poisoning and repo-open execution traps.
When you point Claude Code or Codex CLI at an external GitHub issue (gh issue view), a cloned PR branch, or a third-party SKILL.md file, four classes of traps can hijack the agent:
- Workspace config auto-execution:
.claude/settings.json(hooks,apiKeyHelper,statusLine),.mcp.json, or.vscode/tasks.json("runOn": "folderOpen") inside a cloned repo that execute arbitrary commands when the agent starts. - Invisible Unicode steganography: Unicode Tag characters (
U+E0000toU+E007F), bidirectional overrides (U+202AtoU+202E), and standalone zero-width spaces (U+200B) hiding instructions that humans cannot see in the browser. - Spoofed
<system-reminder>and</tool_result>delimiters: Untrusted issue bodies or web pages attempting to close the tool output block and inject fake system reminders. - Hidden HTML comment instructions & remote shell pipes:
<!-- ignore previous instructions -->inside Markdown issues orcurl ... | bashinside installedSKILL.mdfiles.
Audit your installed skills, workspace repos, and historical .jsonl transcripts:
npx repotrapPre-scan an untrusted GitHub Issue or PR before handing it to a coding agent:
npx repotrap --gh-issue owner/repo#123Generate a deterministic Claude Code PostToolUse sanitizer hook:
npx repotrap --emit-hookRunning npx repotrap across 525 local skill markdown files (~/.gemini/config/skills and ~/.agents/skills), 16 workspace repos, and 153 local Claude Code and Codex CLI transcripts surfaced three false-positive traps that naive scanners hit, plus real findings:
- Claude Code native
type: "attachment"<system-reminder>inflation (1,526native rows vs0spoofedtool_resultdelimiters): Scanning raw.jsonllines for<system-reminder>matched1,526rows across125sessions because Claude Code serializes its own internal reminders astype: "attachment"andtype: "api-request-*"records.repotrapparses the JSONL structure (RTR012) and only flags<system-reminder>or</tool_result>when it appears inside an untrustedtool_resultorfunction_call_outputpayload (RTR008). - Codex
custom_tool_call_outputobject serialization (142zero-width chars across15tool outputs in5sessions): Unlikefunction_call_output(wherepayload.outputis a string), Codex CLI'scustom_tool_call_outputstorespayload.outputas a nested JSON object. NaiveString(payload.output)coercion turns the entire payload into"[object Object]"and misses138of the142ingestedU+200B/U+200Echaracters (RTR011). - Composite Emoji
U+200DZWJ vs standaloneU+200B(RTR014) and local build scripts (RTR013):repotrapseparates composite emoji zero-width joiners (1innotebook-guidance/SKILL.md) and benign localpackage.jsonbuild scripts (7across16repos) from1livecurl -fsSL https://composio.dev/install | bashremote shell pipe incomposio-cli/SKILL.md(RTR005) and2standaloneU+200Bcharacters insigns-of-ai-writing.md(RTR007).
| Rule | Plane | Severity | What it detects |
|---|---|---|---|
RTR001 |
Repo | CRITICAL |
Workspace .claude/settings.json defining hooks, apiKeyHelper, otelHeadersHelper, or statusLine |
RTR002 |
Repo | CRITICAL |
Workspace .mcp.json or .vscode/tasks.json ("runOn": "folderOpen") spawning commands on open |
RTR003 |
Repo | CRITICAL |
Unicode Tag characters (U+E0000–U+E007F) or Bidirectional Overrides (U+202A–U+202E) |
RTR004 |
Repo | HIGH |
HTML comments (<!-- ... -->) in Markdown/skills containing imperative prompt-injection verbs |
RTR005 |
Repo | HIGH |
Skill or instruction file piping a remote URL directly into sh / bash (curl ... | bash) |
RTR006 |
Repo | MEDIUM |
package.json preinstall/postinstall hook running network or shell payloads |
RTR007 |
Repo | LOW |
Standalone zero-width space (U+200B / U+FEFF) inside skill or documentation files |
RTR008 |
Transcript | CRITICAL |
Spoofed <system-reminder>, </tool_result>, or <function_calls> inside untrusted tool output |
RTR009 |
Transcript | CRITICAL |
Explicit prompt-override phrase (ignore previous instructions) inside untrusted tool output |
RTR010 |
Transcript | HIGH |
Hidden HTML comment inside tool_result containing imperative agent/shell instructions |
RTR011 |
Transcript | MEDIUM |
Standalone zero-width or directionality characters (U+200B, U+200E) ingested via tool output |
RTR012 |
Transcript | INFO |
Claude Code native type: "attachment" <system-reminder> rows filtered out (False-Positive Guard) |
RTR013 |
Repo | INFO |
Benign local package.json build/prepare scripts separated (False-Positive Guard) |
RTR014 |
Repo | INFO |
Composite Emoji U+200D ZWJ sequences separated from Unicode steganography (False-Positive Guard) |
- Syntactic & structural detection:
repotrapdeterministically catches invisible Unicode (U+E0000tags, Bidi overrides, standaloneU+200B), spoofed XML/harness delimiters (<system-reminder>,</tool_result>), HTML comment instructions,curl | shskill pipes, and.claude/.mcp.json/.vscoderepo-open hooks. It cannot prove whether natural-language prose without structural markers or imperative override phrases will sway a model's reasoning. --gh-issuerequires GitHub CLI (gh): Pre-scanning live GitHub issues (npx repotrap --gh-issue owner/repo#123) invokes your authenticatedgh issue viewCLI.
MIT

