# Content Filter Object Structure (https://www.librechat.ai/docs/configuration/librechat_yaml/object_structure/message_filter)

## Overview

LibreChat provides two server-side filter configurations:

- `filters` applies source-aware policy to selected fields across messages, prompts, agents, files, skills, memories, tools, and other reusable content.
- `messageFilter` is the legacy message-text filter. Existing deployments can keep using it while migrating to `filters.messages`.

Both are opt-in. When both are configured, both policies apply.

<Callout type="warning" title="Base configuration only">
  `filters` is loaded only from the base `librechat.yaml`. Database, role, group, and user
  overrides cannot add, change, or remove it. In a multi-replica deployment, roll out or restart
  every replica together and verify that each loaded the same base configuration before treating
  the policy as active.
</Callout>

## Source-Aware Filters

Each source has an optional `pii` policy. Omit `filters`, a source, or its `pii` block to leave that scope disabled.

```yaml filename="librechat.yaml"
filters:
  messages:
    unattributedAssistantContent: model_output
    pii:
      action: audit
      fields: [text, summary, attachment_reference]
      starterPatterns: [sk_prefix, bearer_header, api_key_header]
      customPatterns:
        - id: organization_identifier
          label: Organization identifier
          regex: 'ORG-[A-Z0-9]{12}'
  files:
    pii:
      fields: [name, content, extracted_text, transcript]
      uninspectable: block
  skills:
    pii:
      fields: [name, description, instructions, imported_text, file_text]
```

### Pattern Configuration

For each enabled source:

- Omit `action` or set it to `block` to reject matches. Set `action: audit` for a shadow rollout that records findings without rejecting, changing, or redacting content.
- Omit `fields` to inspect every supported field for that source. An explicit list must contain between 1 and 256 supported field names.
- Omit `starterPatterns` to enable the full starter catalog. Set it to `[]` to disable starter patterns while retaining any `customPatterns`.
- Configure `customPatterns` with an `id`, user-facing `label`, and `regex`.

Audit mode evaluates all configured fragments and rules so operators can measure findings before enforcement. Each info-level audit record identifies the action, detector, rule, label, source, field, and provenance, but never includes the matched text or source content. Audit mode does not provide redaction; unsupported action values are rejected when the configuration loads.

Actions are configured independently per source, so one source can audit while another blocks. `filters.files.pii.uninspectable: block` remains an independent fail-closed rule for opaque or oversized selected file content, even when that source's pattern action is `audit`.

The built-in starter pattern IDs are:

- `sk_prefix`: `sk-`-style token prefixes.
- `bearer_header`: bearer tokens in text.
- `api_key_header`: `api-key` header-shaped text.

Custom patterns use RE2JS's bounded, linear-time regular-expression syntax. Backreferences and lookaround are unsupported, and some escapes differ from JavaScript regular expressions. LibreChat rejects invalid or unsupported patterns while loading the configuration.

### Supported Sources and Fields

| Source | Supported fields |
| --- | --- |
| `messages` | `name`, `text`, `summary`, `quote`, `answer`, `decision_response`, `decision_reason`, `content_part`, `attachment_reference`, `assembled_context` |
| `prompts` | `name`, `description`, `oneliner`, `category`, `command`, `text`, `preset_text`, `system`, `context`, `instructions`, `additional_instructions`, `greeting`, `example_input`, `example_output` |
| `agentInstructions` | `name`, `category`, `description`, `instructions`, `additional_instructions`, `edge_description`, `edge_prompt`, `edge_prompt_key`, `artifacts`, `support_contact_name`, `support_contact_email` |
| `conversationStarters` | `text` |
| `conversationTitles` | `title` |
| `feedback` | `text` |
| `skills` | `name`, `display_title`, `description`, `category`, `frontmatter`, `instructions`, `imported_text`, `file_name`, `file_text` |
| `memories` | `key`, `value`, `summary` |
| `files` | `name`, `content`, `extracted_text`, `transcript`, `uri` |
| `toolArguments` | `name`, `arguments`, `output` |
| `modelParameters` | `stop`, `request_fields`, `response_format`, `metadata` |
| `actionMetadata` | `raw_spec`, `domain`, `privacy_policy_url`, `authorization_type`, `custom_auth_header`, `authorization_content_type`, `authorization_url`, `client_url`, `scope`, `token_exchange_method`, `api_key`, `oauth_client_id`, `oauth_client_secret` |

### Message Provenance

`filters.messages.unattributedAssistantContent` controls how legacy assistant content without provenance is classified:

- `model_output` (default): preserves legacy behavior by treating unattributed assistant content as model output.
- `inspect`: treats otherwise unattributed assistant content, including selected attachment projections, as submitted content. Assistant content explicitly marked as model output remains exempt.

This classification can affect an enabled legacy `messageFilter.pii` policy even when `filters.messages.pii` is omitted. Inventory or migrate old records before relying on retroactive inspection.

### Uninspectable Files

`filters.files.pii.uninspectable` controls selected file content that LibreChat cannot inspect, including opaque or oversized content:

- `allow` (default): preserves compatibility and permits the content.
- `block`: rejects it before provider or storage side effects.

Roll out `block` deliberately. It can make older files unavailable for reuse until inspectable text is present.

### Stored and Reused Content

Enabling or changing a policy does not rewrite or delete stored records. LibreChat applies the current policy when protected content is submitted, copied, shared, reused, or becomes model-bound.

Safe metadata edits can still succeed so blocked records remain repairable. In management views, blocked prompt or preset fields can be blank with `contentFilterBlocked: true`; blocked prompt groups return an error on direct retrieval and are omitted from collection and reuse responses. A rejected background memory update can be skipped while the main chat response continues.

Blocking source-aware text matches return HTTP `400` with `content_filter_block`. Uninspectable file rejections use `content_filter_uninspectable`.

### Limits

- Up to 256 fields, starter patterns, or custom patterns per source.
- Up to 256 custom patterns across the full configuration.
- Pattern IDs up to 256 characters, labels up to 512 characters, and regexes up to 512 characters.
- Up to 8,192 total regex characters and 8,192 compiled filter instructions.

## Legacy `messageFilter`

`messageFilter.pii` rejects matching caller-supplied message text before moderation, model requests, or persistence with `message_filter_pii_block`. It remains block-only and does not accept `action`. It does not inspect file contents or the other reusable sources covered by `filters`.

```yaml filename="librechat.yaml"
messageFilter:
  pii:
    starterPatterns:
      - sk_prefix
      - bearer_header
      - api_key_header
    customPatterns:
      - id: anthropic_api_key
        label: Anthropic API key
        regex: 'sk-ant-[A-Za-z0-9_-]{20,}'
```

The legacy filter checks chat-route user text and caller-supplied text across all roles in OpenAI-compatible Chat Completions and Responses requests. It uses the same built-in IDs and linear-time custom-regex rules described above.
