Injection Detection
Injection detection finds prompt injection in your agents' actions in real time, and acts on it before the compromised instruction reaches its target.
Prompt injection is one of the most critical security threats to AI agents. An attacker crafts input that overrides the agent's instructions and makes it perform unintended actions: exfiltrate data, bypass access controls or execute malicious operations.
Overview
MITRITY inspects agent actions for prompt injection indicators, using three detection layers. When it detects a potential injection, the system:
- assigns an injection probability score (0.0 to 1.0);
- identifies matched patterns that describe the injection technique;
- creates an injection event in the audit log;
- takes the action for the detection method that fired: block, alert or log, as the policy's injection mode sets it.
Injection detection runs on every scanned agent action that the gateway intercepts, before policy rules are evaluated. A blocked injection therefore stops the action without any policy matching it.
Detection Methods
MITRITY scans with three layers: pattern matching, statistical analysis and an ML classifier. Each layer produces its own score, and the combined score is the injection probability.
Pattern Matching
Rule-based detection, using MITRITY's built-in library of known injection patterns. The edge lowercases the input and matches these categories. A pattern hit scores 0.9.
| Pattern Category | Description | Examples |
|---|---|---|
instruction_override | Attempts to override the agent's instructions | "Ignore previous instructions", "New instructions:", "You are now" |
system_prompt | System-prompt markers inside the input | <|im_start|>system, <system>, [INST], <<SYS>>, "### System", "System:" |
role_hijacking | Attempts to change the agent's role | "Act as a …", "Pretend to be …", "Your new role", "From now on you …" |
exfiltration | Instructions to send data out | "Send all data to …", "exfiltrate", "export all" |
separator_attack | Delimiters that open a new instruction block | A code fence labelled system or instructions, <instruction> or <prompt> tags, a "system" or "role" key in JSON |
encoding | Instructions hidden by encoding | Base64 blocks that decode to a known injection phrase, zero-width characters |
An event's matched_patterns names each hit as <category>:<name>, for example instruction_override:ignore-previous, encoding:base64-ignore-previous or encoding:zero-width-characters.
Statistical Analysis
This layer looks at statistical properties of the input, to catch injection that does not match a known pattern. Inputs shorter than 50 characters are not analyzed.
Signals analyzed:
- Entropy shift: a large difference in character entropy between the first and the second half of the input
- Instruction-like text: a high share of imperative, command-like verbs
- High entropy: very high character entropy overall, as encoded or obfuscated content has
ML Classifier
The third layer reuses the edge's local ML model, DriftGuard, rather than a dedicated injection classifier. It runs only when both of these are true:
- the edge runs with
ml.enabled(off by default) and a model loaded; - the injection settings the control plane sends turn
ml_classifieron.
The control plane sends ml_classifier: false in every mission profile (see Configuring detection), so this layer does not run in current profiles. Detections come from pattern matching and statistical analysis. When the edge runs with ml.enabled, model updates arrive with the heartbeat.
Combined Scoring
The edge combines the three scores into the injection probability, in this order:
- If a pattern matched, the probability is the highest of the three scores.
- Otherwise, if the statistical score is 0.6 or more, it is the higher of the statistical and ML scores.
- Otherwise, an ML score above 0 is used on its own.
- Otherwise, a statistical score of 0.3 or more is used on its own.
A probability below 0.3 is not a detection.
Injection Probability Scores
The injection probability is a number from 0 to 1. In current profiles, these are the scores an action can get, and what each one does:
| Score | What it means | Action |
|---|---|---|
| Below 0.3 | Not a detection. No injection event is created | None |
| 0.3 to 0.9, without a pattern hit | A statistical detection. The score depends on which statistical signals fired | pattern_action |
| 0.9 | A pattern hit | pattern_action |
The score does not choose the action. Every detection in current profiles takes pattern_action, which the policy's injection mode sets, as the next section describes. The ML layer, and with it ml_action, does not run in current profiles (see ML Classifier).
Configuring detection
Injection detection is a policy feature. You set it per policy, on the policy form or through the policy API (POST /api/v1/policies to create a policy, PUT /api/v1/policies/{policy_id} to update one):
| Field | Form label | Values | Default on a new policy | What it decides |
|---|---|---|---|---|
injection_mode | Prompt Injection Detection | off, log, enforce | enforce | The scan on every tool-call surface. off turns the scan off everywhere, LLM prompts included |
llm_injection_mode | LLM prompt injection | off, alert, enforce | alert | How the scan treats a prompt sent through the LLM Gateway |
A policy in the Debug override mode (override_mode: log_only) never blocks: an injection block becomes log, and enforce on LLM prompts is sent as alert.
From these fields, the control plane builds the injection settings that it sends to the edge in the agent's mission profile, as injection_config. Nothing else in them is configurable:
{
"injection_config": {
"enabled": true,
"pattern_matching": true,
"statistical_analysis": true,
"ml_classifier": false,
"pattern_action": "block",
"ml_action": "alert",
"ml_threshold": 0.7,
"scan_targets": ["llm:*", "mcp:*", "egress:*", "delegate:*", "http:request", "builtin:*", "shell:*"],
"llm_mode": "alert"
}
}
| Field | Type | Value the control plane sends | Description |
|---|---|---|---|
enabled | boolean | true | Sent only when injection_mode is not off |
pattern_matching | boolean | true | Run the pattern matcher |
statistical_analysis | boolean | true | Run the statistical analyzer |
ml_classifier | boolean | false | Run the ML classifier |
pattern_action | enum | block; log when injection_mode is log or the policy is in Debug | What a pattern or statistical detection does |
ml_action | enum | alert | What an ML detection does |
ml_threshold | float | 0.7 | The ML probability strictly above which an ML detection counts |
scan_targets | array | the list above | Action-type globs to scan. An action type outside this list is never scanned |
llm_mode | enum | the policy's llm_injection_mode | The mode for LLM prompts (llm:* action types) |
Two things are worth knowing about this model:
- There is no hold. An injection verdict is
block,alertorlog. There is noalert_threshold/hold_threshold/deny_thresholdtriple, and no human-approval queue for injections: a blocked action is denied outright. Holds come from approval workflows on policy rules. ml_thresholdis the only threshold an action setting has. A pattern hit always firespattern_action. A statistical detection needs a probability of at least 0.3, and then firespattern_actiontoo.
The policy's injection mode sits above all of this:
- In
logmode, a would-be block is recorded aslogged, and the action proceeds. - In
offmode, the scan does not run at all.
Prompts sent through the LLM Gateway follow llm_injection_mode (enforce · alert · off, default alert). A hit in a prompt is recorded and the call proceeds, unless the policy says enforce. The tool call that the prompt induces keeps injection_mode. off on injection_mode turns the scan off for prompts too.
Injection Events
When MITRITY detects an injection, it creates an injection event in the audit log.
Event Structure
{
"id": "inj_evt_8k2m",
"tenant_id": "tnt_4f9a",
"agent_id": "agt_support-bot",
"agent_name": "support-bot",
"event_id": "evt_71c2",
"action_type": "mcp:web__fetch_url",
"detection_method": "pattern",
"injection_probability": 0.9,
"matched_patterns": ["instruction_override:ignore-previous", "exfiltration:send-to"],
"flagged_content_hash": "9f2b1c…",
"action_taken": "blocked",
"false_positive": false,
"occurred_at": "2026-03-01T14:30:00Z",
"created_at": "2026-03-01T14:30:01Z"
}
detection_method is a single value (pattern, statistical, ml_classifier or combined), not a per-method breakdown. The flagged content itself is never stored. flagged_content_hash is a SHA-256 digest, so an event can be correlated without the payload leaving the edge.
Viewing Injection Events
Go to Monitoring > Injection Events in the dashboard. The injection events view shows:
- all detected injection attempts;
- the injection probability, and which detection method fired;
- the matched pattern names;
- the agent and action context;
- the false positive status.
API Reference
List Injection Events
curl "https://api.mitrity.com/api/v1/injection-events?agent_id=agt_support-bot&limit=25" \
-H "Authorization: Bearer mk_your-api-key"
Query parameters:
| Parameter | Type | Description |
|---|---|---|
agent_id | string | Filter by agent |
limit | integer | Results per page |
offset | integer | Offset for pagination |
This endpoint does not support score, outcome, false-positive or date filters, so filter client-side. Injection events are not forwarded to SIEM destinations. A SIEM destination receives the agent's action and its decision, for example blocked, not the injection event's score or matched patterns.
Response:
{
"data": [
{
"id": "inj_evt_8k2m",
"agent_id": "agt_support-bot",
"agent_name": "support-bot",
"action_type": "mcp:web__fetch_url",
"detection_method": "pattern",
"injection_probability": 0.9,
"action_taken": "blocked",
"matched_patterns": ["instruction_override:ignore-previous", "exfiltration:send-to"],
"false_positive": false,
"occurred_at": "2026-03-01T14:30:00Z"
}
],
"meta": {
"request_id": "req_inj001",
"timestamp": "2026-03-01T15:00:00Z",
"next_cursor": null,
"total": 1
}
}
Get a Single Injection Event
curl https://api.mitrity.com/api/v1/injection-events/inj_evt_8k2m \
-H "Authorization: Bearer mk_your-api-key"
Returns the same event shape as the list endpoint.
Mark as False Positive
If an injection event is a false positive, mark it. The mark, your reason, who marked it and when are recorded on the event:
curl -X POST https://api.mitrity.com/api/v1/injection-events/inj_evt_8k2m/false-positive \
-H "Authorization: Bearer mk_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"false_positive": true,
"reason": "Legitimate instruction from support workflow automation"
}'
Response:
{
"data": {
"id": "inj_evt_8k2m",
"false_positive": true,
"false_positive_reason": "Legitimate instruction from support workflow automation",
"false_positive_marked_by": "user_jsmith",
"false_positive_marked_at": "2026-03-01T16:00:00Z"
},
"meta": {
"request_id": "req_inj002",
"timestamp": "2026-03-01T16:00:00Z"
}
}
Marking an event does not change how later actions are scanned.
Get Injection Summary
curl "https://api.mitrity.com/api/v1/injection-events/summary" \
-H "Authorization: Bearer mk_your-api-key"
Response:
{
"data": {
"total_events": 127,
"blocked": 13,
"alerted": 89,
"by_method": {
"pattern": 71,
"statistical": 22,
"ml_classifier": 18,
"combined": 16
},
"by_agent": [
{ "agent_id": "agt_support-bot", "agent_name": "support-bot", "count": 78 },
{ "agent_id": "agt_chat-bot", "agent_name": "chat-bot", "count": 34 }
]
},
"meta": {
"request_id": "req_inj003",
"timestamp": "2026-03-01T17:00:00Z"
}
}
False Positive Management
Common False Positive Scenarios
| Scenario | Cause | Resolution |
|---|---|---|
| Support workflows | Agents forwarding user-written instructions containing command-like language | Mark as FP; use Log for the agent's policy while you review |
| Code generation | Agents generating code that includes prompt-like strings | Mark as FP; use Log for the agent's policy while you review |
| Documentation retrieval | Agents reading documentation containing injection examples | Mark as FP |
| Multi-agent delegation | Agent A instructing Agent B using natural language | Mark as FP; see delegation chains |
Reducing False Positives
- Mark false positives promptly, so that the events show which detections were wrong.
- Put the agent's policy on Log for Prompt Injection Detection while you measure, then switch to Enforce. Customer-facing agents see more injection-like input than backend agents.
- Keep LLM prompt injection on Alert for agents that read logs, web pages or tickets, which legitimately contain injection-shaped text.
- Monitor the false positive rate. Target a false positive rate below 5%. If it is above 10%, your settings may be too aggressive.
Integration with Policies
Injection detection is its own stage of the governance pipeline, not a policy rule. The outcome comes from the policy's injection mode, sent to the edge as pattern_action and ml_action, and it applies regardless of action type. scan_targets decides which action types are scanned at all.
There is no injection-score constraint on a policy rule. Rule constraints match the arguments of an action, and numeric constraints are integer upper bounds: see Writing Policies. A key such as
injection_score_minis accepted by the API and then evaluated against nothing, so the rule matches as if it were not there.
Order matters here. The injection scan runs before policy rules are evaluated, so a detection set to block denies the action on its own, without any policy matching it. Policies decide what happens to the actions that the scan lets through.
Best Practices
Enable Detection on All Agents
Injection attacks can target any agent, not just customer-facing ones. Keep Prompt Injection Detection on in every policy, and choose between Log and Enforce by each agent's risk profile.
Separate the two detection paths
The two detection paths already act differently. With the policy on Enforce, a pattern or statistical detection blocks, because a pattern hit is a known technique, not a guess. An ML detection only alerts (ml_action: alert), and the ML layer does not run in current profiles.
Measure what gets through, not only what gets caught
Injection events tell you what detection caught. They cannot tell you what it missed. Red Teaming runs the other half of the measurement. It sends adversarial attempts at your own routes on a schedule, and records the ones that reached their goal. A detection gap then shows up as a finding with a remediation, rather than as silence in the event stream.
Review Injection Events Daily
Review injection events daily, especially statistical detections (detection_method: statistical). No known pattern matched them, so they are the most valuable for understanding your false positive rate, and for deciding between Log and Enforce.
Correlate with DLP Events
Injection attacks often come before data exfiltration. When you see an injection event, check for matching DLP events from the same agent.
Keep the ML Model Updated
When the edge runs with ml.enabled, it receives ML model updates through the heartbeat. Make sure your gateway or sidecar keeps its connection to the control plane, so that updates arrive on time.
Related Documentation
- Red Teaming: governed adversarial tests that measure what detection misses
- Delegation Chains: govern agent-to-agent delegation
- Credential Broker: secure credential management for agents
- Threat Intelligence: a shared threat feed for cross-tenant protection
- Destination Allowlists: DLP controls for data exfiltration prevention
- Approval Workflows: human-in-the-loop holds, which policy rules provide and injection verdicts do not