Skip to content

Triage stage has no deterministic detection for hidden/invisible Unicode obfuscation (Tag Block ASCII smuggling, bidi override) #42

Description

@Rahul-s-007

ADR's triage stage (TriageLLM) relies entirely on LLM judgment to catch malicious conversation content — nothing in the pipeline inspects the literal characters for known prompt-injection-obfuscation techniques. Two such techniques are already part of ADR's own threat model:

  • Unicode Tag Block "ASCII smuggling" (U+E0000–U+E007F): each ASCII character maps to an invisible codepoint; there's no legitimate use of this range in real text. This is a well-known, already-public technique (documented at embracethered.com, cited in the public AITech-9.2/AISubtech-9.2.1 AI-security taxonomy). I have a merged reference implementation for detecting it in Cisco's skill-scanner project: github.com/cisco-ai-defense/skill-scanner#94.
  • Bidi override/isolate characters (U+202A–U+202E, U+2066–U+2069), used to visually hide or reorder text. ADR's own benchmark already plants this exact payload in context_providers/source_codes/mcp_servers_1/mcp_connector/mcp_connector.py:37, wired into two real tasks (110, 301, both ground_truth: "malicious") — but nothing catches it deterministically.

Confirmed by reading the code directly: TriageLLM._format_conversation() passes message content through completely unmodified, neither triage prompt mentions Unicode obfuscation as an escalation trigger, and the 17-entry threat taxonomy (threat_repository.yaml) doesn't name it under any technique. The comparison LlamaFirewall baseline in this same benchmark has no equivalent check either.

I already have a fix scoped: a deterministic pre-filter in TriageLLM.analyze() that short-circuits before any LLM call when it fires (zero cost, zero reliance on the LLM noticing hidden characters), 2 new detection_guidance entries under the existing ADR.T0002 technique (not a new top-level ID — keeps the paper-aligned 17-technique count intact), a new benchmark fixture demonstrating Tag Block smuggling end-to-end (the existing fixture only covers the bidi variant), and tests proving both the new fixture and the existing mcp_connector.py fixture are now deterministically caught. Opening this first for visibility — PR to follow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions