> ## Documentation Index
> Fetch the complete documentation index at: https://gateway.forceaisecurity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Attachment policy

> Govern the files and images attached to chat requests and /v1/files uploads: which types and sizes are allowed, and whether each attachment is scanned before the request proceeds.

The Attachment Policy guardrail is a security layer over the **files and images attached to a request**. On every chat completion it extracts the attachments from the messages, checks them against your rules, and refuses the request on the first violation. The same policy also governs raw `/v1/files` uploads when it is enabled as a deployment-wide default.

> [!NOTE]
>
> This governs attachments, not prompt text. For scanning the text of a prompt or completion use the content-filter / PineSmith guardrails; this one decides which files and images are allowed through.

## The one gotcha: extensions vs MIME types

This is the most common surprise, so read it first.

> [!WARNING]
>
> **An inline image from the Playground or a vision API call has a MIME type but no filename.** It arrives as a data URL — `data:image/png;base64,...` — which carries `image/png` but nothing for an extension rule to read. So a `png` entry in **`blocked_extensions`** will **not** block Playground or API images. Block those with **`blocked_mime_types`** instead.

Use the right field for what you want to block:

| You want to block | Field to use | Example value |
| - | - | - |
| Inline images (Playground, vision API) | `blocked_mime_types` | `image/png` or `image/*` |
| Uploaded files with a name (`report.png`, `setup.exe`) | `blocked_extensions` | `png, exe` |
| Both, to be safe | both fields | `blocked_mime_types: image/png` + `blocked_extensions: png` |

Extension rules match a filename; MIME rules match the declared content type. Inline images only have the latter. Uploaded files (`/v1/files`, or a `file` message part with a `filename`) have both.

## Enable it

The guardrail does nothing until it is active in the gateway config. Enable it on the `pre_call` hook so it blocks before the request reaches the model:

```yaml theme={null}
guardrails:
  - guardrail_name: attachment_policy
    litellm_params:
      guardrail: attachment_policy
      mode: pre_call
      default_on: true
      # policy fields go here, e.g.:
      blocked_mime_types: "image/png"
```

Recreate the gateway after changing the config so it loads the guardrail. `default_on: true` also makes the policy apply to `/v1/files` uploads; without it, the policy only runs on requests that select the guardrail. All fields below can be set here or in the **Security -> Guardrails** UI (they are the same `litellm_params`).

## Policy fields

### Type rules

**blocked\_mime\_types** `string`

Comma-separated MIME block-list. Takes precedence over the allow-list. Supports a `type/*` wildcard. This is the field that blocks inline Playground/API images.

**Example:** `image/png` blocks inline PNGs. `image/*` blocks every inline image. `application/pdf, image/png` blocks PDFs and PNGs.

**allowed\_mime\_types** `string`

Comma-separated MIME allow-list. When set, any attachment whose MIME type is not on the list is blocked. Blank allows any type not named in the block-list.

**Example:** `image/jpeg, application/pdf` allows only JPEGs and PDFs; a `data:image/png` request is blocked because PNG is not on the list. `image/*` allows any image but no documents.

**blocked\_extensions** `string`

Comma-separated filename-extension block-list (no dot). Takes precedence over the allow-list. Matches **uploaded/named files only**, not inline images.

**Example:** `exe, sh, js, png` blocks a `setup.exe` upload and a `photo.png` upload, but does **not** block a Playground image (use `blocked_mime_types` for that).

**allowed\_extensions** `string`

Comma-separated filename-extension allow-list. When set, any named file whose extension is not on the list is blocked. Blank allows any extension not blocked.

**Example:** `pdf, csv` allows only `.pdf` and `.csv` uploads and blocks a `data.xlsx` upload.

### Size and count

**max\_size\_mb** `number`

Maximum size per attachment, in megabytes. Blank means no size limit. Applies to any attachment whose size is known (inline base64 content and sized uploads).

**Example:** `5` blocks a single attachment larger than 5 MB.

**max\_attachments** `integer`

Maximum number of attachments allowed on a single request. Blank means no count limit.

**Example:** `3` blocks a message that carries four or more images/files.

### Content scanning

**scan\_content** `boolean` (default: false)

Send each attachment to the configured HTTP scanner and block on a flagged verdict. Requires `scanner_api_base`.

**Example:** `true` to route every allowed attachment to your scanner for a malware/DLP check before the request proceeds.

**scanner\_api\_base** `string`

Base URL of the attachment scanner. The guardrail POSTs to `<base>/scan` with the attachment (`filename`, `mime_type`, `size_bytes`, and base64 content when available) and expects a JSON verdict `{"blocked": bool, "reason": str}`. Required when `scan_content` is on.

**Example:** `http://attachment-scanner.forceai.svc.cluster.local:8080`

**scanner\_api\_key** `string`

Bearer token sent to the scanner as the `Authorization` header. Optional.

**Example:** `sk-scanner-...` (sent as `Authorization: Bearer sk-scanner-...`).

**scanner\_timeout\_seconds** `number` (default: 10.0)

How long to wait for the scanner before treating the scan as failed.

**Example:** `5` fails the scan if the scanner does not answer within five seconds (see `block_on_error` for what happens then).

**block\_on\_error** `boolean` (default: true)

Fail closed: if the scanner is unreachable or errors, block the request instead of letting the attachment through unscanned. Turn off to fail open (availability over security).

**Example:** `false` lets requests through when the scanner is down, trading safety for availability.

### Enforcement behavior

**on\_flagged\_action** `string` (default: block)

What the caller gets on a violation.

* `block` — HTTP 400 with a neutral error (default)
* `passthrough` — a neutral refusal returned as an ordinary 200 completion
* `monitor` — the violation is logged but the request is allowed through (observation only)

**Example:** `monitor` while you tune the rules, then switch to `block` to enforce.

**refusal\_message** `string`

Message the caller sees when the policy blocks. Defaults to a neutral `This request was blocked by the attachment policy.` and deliberately omits which rule fired; the full reason stays on the log record.

**Example:** `Images are not permitted on this workspace.`

## Recipes

```yaml Block all PNGs (inline + uploads) theme={null}
guardrails:
  - guardrail_name: attachment_policy
    litellm_params:
      guardrail: attachment_policy
      mode: pre_call
      default_on: true
      blocked_mime_types: "image/png"   # catches Playground / API images
      blocked_extensions: "png"          # catches uploaded .png files
```

```yaml Allow only PDFs theme={null}
guardrails:
  - guardrail_name: attachment_policy
    litellm_params:
      guardrail: attachment_policy
      mode: pre_call
      default_on: true
      allowed_mime_types: "application/pdf"
```

```yaml Block executables, cap size and count theme={null}
guardrails:
  - guardrail_name: attachment_policy
    litellm_params:
      guardrail: attachment_policy
      mode: pre_call
      default_on: true
      blocked_extensions: "exe, sh, bat, js"
      max_size_mb: 10
      max_attachments: 5
```

```yaml Scan every attachment, fail closed theme={null}
guardrails:
  - guardrail_name: attachment_policy
    litellm_params:
      guardrail: attachment_policy
      mode: pre_call
      default_on: true
      scan_content: true
      scanner_api_base: "http://attachment-scanner:8080"
      block_on_error: true
```

## Test it

With `blocked_mime_types: image/png` active, an inline PNG is refused with HTTP 400:

```bash theme={null}
curl -s -o /dev/null -w "%{http_code}\n" -X POST http://localhost:4000/v1/chat/completions \
  -H "Authorization: Bearer $FORCEAI_KEY" -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [{
      "role": "user",
      "content": [
        {"type": "text", "text": "what is this?"},
        {"type": "image_url", "image_url": {"url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="}}
      ]
    }]
  }'
```

Expect `400`. Swap the rule to `blocked_extensions: png` only and the same request returns `200` — the extension rule cannot see the inline image, which is exactly the gotcha above.

## How enforcement resolves

> [!NOTE]
>
> Block beats allow, and the first violation wins. For each attachment the static checks run in order — blocked extension, extension allow-list, blocked MIME, MIME allow-list, size — and the first one that fails returns the refusal. Only if an attachment passes every static check (and `scan_content` is on) is it sent to the scanner. `max_attachments` is checked once for the whole request before the per-attachment checks.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.