# Exfiltration scanning

> How Botyard scans outbound bot requests for Runtime Vault secrets: what is scanned, redact, strict and log-only modes, where to set the mode, and rotation.

Canonical URL: https://docs.botyard.io/docs/exfiltration-scanning

Exfiltration scanning is Botyard's safety check for outbound bot requests. It is designed to
catch cases where a bot attempts to send a sensitive Runtime Vault value to an LLM, search
provider, or other proxied upstream.

## What is scanned

Provider proxy scans the outbound data that could reach an upstream provider:

* request body
* path
* query string
* forwarded custom headers

Internal transport headers, Botyard routing headers, and bot authentication headers are excluded
because they are not forwarded upstream and create unnecessary false positives.

## What values are scanned for

The scanner compares outbound payloads against Runtime Vault variables saved with **Sensitive
value** turned on. Variables saved with it turned off are shown as **Plain** in the Runtime
Vault list and are not scanned for. Values shorter than 8 characters are also not scanned for,
because short strings match ordinary text too often.

The scanner can detect the raw value and common encodings such as base64, base64url, and URL
encoding. Audit records store the matched key path and encoding, not the secret value or raw
payload.

## Where scanning happens

Scanning is centralized in the secrets service:

1. Provider proxy builds a scannable payload from the outgoing request.
2. Provider proxy sends that payload plus org, bot, call type, and endpoint metadata to the
   secrets service.
3. The secrets service loads the organization's sensitive values from encrypted storage,
   using a short-lived per-org scanner cache.
4. The scanner returns whether it matched a value. For a match in the request body it also
   returns the body with the match removed.
5. Provider proxy forwards the request, forwards the redacted body, or refuses the request,
   depending on where the match was and the organization's scanner mode.

Plaintext sensitive values stay inside the secrets service scanner cache. They are not copied
into provider proxy for scanning.

## What happens on a match

What the proxy does depends on where the secret was found:

* **Request body.** The matched value is cut out in flight and replaced with
  `[redacted:<key_path>]`, and the redacted request is forwarded. The secret never reaches the
  provider, and the conversation keeps working. Botyard records a `secrets.exfiltration.redacted`
  audit event.
* **Path, query string, or forwarded headers.** The request is refused with `403 Forbidden` and
  nothing is sent upstream. A secret in these places points to deliberate exfiltration rather
  than an accidental paste, so there is no redact-and-continue path. Botyard records a
  `secrets.exfiltration.blocked` audit event with critical severity.

In `log_only` mode neither happens: the match is recorded as a `secrets.exfiltration.detected`
audit event and the request is forwarded unchanged.

## Scanner modes

Each row describes an organization whose mode the proxy has resolved:

| Mode               | Match in the body             | Match in path, query, or headers | If the scanner cannot run                  |
| ------------------ | ----------------------------- | -------------------------------- | ------------------------------------------ |
| `redact` (default) | Redact and forward.           | Refuse with `403`.               | Forward the request unscanned (fail open). |
| `strict`           | Redact and forward.           | Refuse with `403`.               | Refuse with `503` (fail closed).           |
| `log_only`         | Record and forward unchanged. | Record and forward unchanged.    | Forward the request unscanned.             |

When the scanner cannot run, the proxy looks up the organization's mode separately. The mode
is unknown if that lookup fails, or if the organization has not chosen a mode and the proxy has
not recently learned the platform default. An unknown mode is treated as fail open by default,
so the request is forwarded unscanned, even for a `strict` organization. The exception is an
organization the proxy recently saw in `strict`: that cached `strict` is used instead. It also
means an organization that leaves `strict` can keep getting `503` responses for up to 60
seconds (the default cache lifetime) while the scanner is unavailable.

`redact` is the default for every organization that has not chosen a mode. `strict` gives the
same protection on a match, and is for organizations where letting an unscanned request through
is worse than a bot request failing while the scanner is unavailable. `log_only` lets the secret
reach the provider; use it only to investigate false positives or during a rollout.

## Set the scanner mode

The mode is set per organization:

1. Open **User menu** › **Settings** › **General** › **Security**.
2. On the **Exfiltration Scanner** card, choose **Redact**, **Strict**, or **Log only** under
   **Enforcement**.

Changing the mode needs permission to update organization settings. By default that is the
organization owner role. The API equivalent is `PUT /v1/orgs/{org_id}/settings/scanner`. A
change normally applies to the next scan. If Botyard cannot clear the scanner's cached settings
when you save, the old mode can stay in effect until that cache expires, by default after 60
seconds. While the scanner is unavailable, the outage rules under
[Scanner modes](#scanner-modes) apply instead.

## Rotation and cache invalidation

Runtime Vault writes invalidate the scanner cache after the database transaction commits. This
avoids a race where a scan could refill the cache from old values while a rotation is still
committing. If invalidation fails, the cache TTL still bounds how long stale scanner data can
live.

## Safety pattern

This is a **data loss prevention** control placed at the egress point. It is strongest when
combined with Runtime Vault policy:

* Runtime Vault controls which bot can request a secret.
* Leases make plaintext access short-lived.
* Exfiltration scanning checks whether sensitive values are leaving through provider calls.
* Audit logs record lease and scanner events without storing raw payloads.

The scanner is not a substitute for least privilege or review. It is a tripwire at the point
where model calls and search requests leave the platform.
