> This page is for Gateway.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.merge.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.merge.dev/_mcp/server.

# Prompt injection protection

> Gateway screens prompts for direct and indirect injection, alerts or blocks on detection, and redacts leaked credentials from responses. Covers modes, thresholds, allowlists, errors, and overrides.

Prompt injection protection alerts on or blocks requests that try to override your system prompt or hijack the model. Use it wherever untrusted users or retrieved content reach the model. Two independent axes each have their own mode:

| Axis         | What it looks for                                                                          | Setting            |
| ------------ | ------------------------------------------------------------------------------------------ | ------------------ |
| **Direct**   | Injection in the prompt a user sends, such as jailbreaks or "ignore previous instructions" | `pi_mode`          |
| **Indirect** | Injected instructions inside retrieved content, tool results, or documents                 | `pi_indirect_mode` |

## Modes

Set each axis under **Security → Prompt injection** in the [dashboard](https://gateway.merge.dev/security/prompt-injection), which needs Manage security rules.

| Mode    | Dashboard label | Behavior                                                              |
| ------- | --------------- | --------------------------------------------------------------------- |
| `off`   | Off             | No screening                                                          |
| `alert` | Alert           | Screens and records detections on **Security → Alerts**, never blocks |
| `block` | Block + alert   | Blocks detections and records them                                    |

> **Tip**
>
> Start each axis in `alert`, review alerts on real traffic, allowlist false positives, then switch to `block`.

## How detection decides

Each axis's **Sensitivity** (Low, Balanced, or High) sets its thresholds, and **Advanced** exposes the raw values. Balanced uses these defaults:

| Threshold                   | Axis     | Default | Effect                                                           |
| --------------------------- | -------- | ------- | ---------------------------------------------------------------- |
| `pi_block_threshold`        | Direct   | `0.57`  | A segment blocks when its pattern-match score reaches this value |
| `pi_tier2a_block_threshold` | Indirect | `0.60`  | Score at which the heuristic signal fires                        |
| `pi_tier2b_block_threshold` | Indirect | `0.45`  | Score at which the similarity-to-known-attacks signal fires      |

Direct blocks only on the pattern-match score; a model-based classifier score appears in alerts and metadata but never blocks. Indirect blocks when both signals fire, or when one fires and the model's tool calls violate the expected structure.

`pi_pass_threshold` must be at or below `pi_block_threshold` but has no effect on screening.

## Output credential check

While direct isn't `off`, Gateway replaces leaked credentials such as API keys in non-streaming responses with a placeholder. A project's `pi_output_action: observe` records findings without redacting; other accepted values behave like `observe`.

## Allowlist patterns

The allowlist (same dashboard page) skips prompt segments matching any of its regex patterns, for workloads that look like injection, such as security research or summarizing spam.

* Up to 50 patterns per organization and 20 per project, each up to 200 characters
* Patterns must compile as Python regex, or they're rejected on save
* Project patterns add to the organization's, not replace them

Anchor patterns to your traffic. A pattern matching ordinary text, such as `s` or `.*`, is ignored so it can't switch protection off. Skipped segments appear in `allowlist_skipped_segment_ids` in the guardrails metadata.

## Test settings

**Test protection** (direct) and **Test detection** (indirect) run sample text against the current settings without sending a request.

## Blocked requests

A blocked request returns HTTP 422, even when streaming, because the block happens before the first token:

```json
{
  "error": {
    "message": "Request blocked by prompt injection detection.",
    "type": "blocked_by_pi_protection",
    "code": "pi_block_threshold"
  }
}
```

Match on `type: "blocked_by_pi_protection"`. `code` says why:

| Code                                | Meaning                                                             |
| ----------------------------------- | ------------------------------------------------------------------- |
| `pi_block_threshold`                | Direct axis score reached the block threshold                       |
| `pi_indirect_two_signals`           | Both indirect signals fired                                         |
| `pi_indirect_signal_and_structural` | One indirect signal fired alongside a tool-call structure violation |
| `sidecar_error`                     | Screening was unavailable and fail-closed is on                     |

## See scores on a response

Set `include_guardrails_metadata: true` in the body, or the `include-guardrails-metadata: true` header, to get `guardrails.prompt_injection` on the response, including blocked 422s. In `alert` mode it shows what `block` would do.

```json
"guardrails": {
  "prompt_injection": {
    "mode": "alert",
    "action": "observe",
    "score": 0.81,
    "block_threshold": 0.57,
    "triggering_segment": { "id": "msg_1", "kind": "user_message", "score": 0.81 },
    "indirect": { "mode": "off", "tainted": false, "would_block": false },
    "output": { "credential_findings": 0, "redacted": false }
  }
}
```

If screening couldn't complete, `skipped_reason` says why.

## Failure behavior

If screening is unavailable, the request proceeds unscreened, unless the project sets `pi_fail_closed: true` to reject it with `code: "sidecar_error"`.

## Override per project or customer

A project can override the modes, thresholds, output action, fail-closed behavior, and allowlist on its **Configuration** tab or with [project guardrails](/merge-gateway/automation/projects-api/guardrails); unset fields inherit the organization. [Customers](/merge-gateway/embedded-routing-stack/guardrails) can override PI settings too.

A project pinned to the API key applies its override in full. One named on the request (`X-Project-Id` header or body `project_id`) can only tighten the organization's settings, so callers can't switch protection off.

## Next steps

#### [Data loss prevention](/merge-gateway/security/data-loss-prevention)

Redact or block PII and secrets in prompts

#### [Project guardrails](/merge-gateway/automation/projects-api/guardrails)

Override PI and DLP per project

#### [Audit trail](/merge-gateway/security/audit-trail)

Review guardrail changes