Threat Model
The scope and limitations of Shield’s local SDK checks and hosted injection detector.
This page describes the local SDK checks: injection detection from @zeroleaks/shield/local, output sanitization, and tool policies. These run in your process; optional model or LLM detectors have their own artifact and network requirements. The root detect export calls the hosted Shield API, which classifies submitted text and does not enforce tool policies or sanitize output.
Local checks catch known attack styles and much of their obfuscation. They know your agent's tools only as far as you describe them in a tool policy, and they do not replace testing the agent itself.
What Shield catches
| Threat | Mechanism |
|---|---|
| Direct prompt injection | detect(): a classifier trained on public injection and jailbreak datasets, plus patterns for well-known phrasings |
| Indirect injection in tool results and documents | The provider wrappers scan tool results by default; call detect() on retrieved documents, web pages, and emails you add yourself. spotlight() and harden() also tell the model to treat that content as data. |
| Tool poisoning | scanTools() checks MCP and other tool definitions for instructions in descriptions and schemas, shadowed names, and hidden characters |
| Instructions split across turns | detectConversation() also scans the latest user messages joined together |
| Obfuscation | Normalization folds look-alike letters, strips invisible characters, joins spaced-out letters, and decodes leetspeak; payloads in base64, hex, binary, URL encoding, HTML entities, escapes, ROT13, Morse, Braille, reversed or upside-down text, Unicode tags, and variation selectors are decoded and scanned |
| Non-English attacks | The classifier was trained on data in over a dozen languages, including Russian, Spanish, Turkish, Chinese, German, French, Portuguese, and Japanese |
| System prompt leaks | sanitize() finds prompt text in output, including when it is obfuscated, reversed, or encoded, and redacts it; a canary planted with harden() catches paraphrased or translated leaks |
| Credential and personal data leaks | detectSecrets() and detectPII() in output, redacted by the wrappers by default (PII is opt-in) |
| Data exfiltration through rendering | detectExfiltration() flags markdown images, HTML resources, and links that would send data to a host you didn't allow |
| Data exfiltration through tool calls | A tool policy refuses undeclared tools, arguments that don't match the tool's schema, and tools you labeled as sending data out once the session has read untrusted content, whether or not detection found the injection |
What Shield does not catch
| Gap | Why |
|---|---|
| Misuse of legitimate permissions | Shield knows only the tools and rules you give a tool policy, and a call the policy allows goes through. A polite request that gets the agent to refund the wrong account or email the wrong person may contain nothing that looks like an injection. |
| Novel or subtle attacks | The classifier generalizes beyond fixed phrasings, but carefully written instructions that read like ordinary content still get through. The archived local evaluation documents earlier results; it does not measure current hosted tiers. |
| Gradual multi-turn manipulation | detectConversation() catches instructions split across turns, not slow persuasion over many turns |
| Content Shield doesn't see | Images, PDFs, and audio are not scanned, and neither is text you send to the model without passing it through a wrapper or detect() |
| Heavily reworded or translated leaks | sanitize() matches the prompt's words; a canary catches leaks that drop them only if the canary itself is repeated |
| Secrets in formats it doesn't know | detectSecrets() covers over 100 credential formats plus high-entropy assignments; internal tokens with no recognizable shape can pass |
False positives
The classifier flags some benign text, most often short imperative requests to the model ("from now on, answer in French") and text about security or passwords. The wrappers block by default, so first run your real traffic with onDetection: "warn" and review the findings. Then raise classifier.threshold, use allowPhrases, or add a secondaryDetector.
How to use Shield
- As one layer. Shield blocks or redacts attacks before they reach the model or the user. Pair it with least-privilege tool permissions, human approval for destructive actions, and egress controls, which limit what a successful injection can do.
- With testing. Run ZeroLeaks scans against your real agent in development and CI to find what an attacker can actually make it do. Every finding comes with a policy or configuration change, and the next scan runs the same attacks again to confirm the fix still holds.
- Watch the callbacks.
onInjectionDetected,onLeakDetected, andonOutputFindingsreport what was found, where, and at what risk. Log them and review the findings as you tune detection.