Skip to main content

Detect PCI and PII in prompts

The AI Gateway uses Microsoft Presidio to scan requests and responses for personally identifiable information (PII) and payment data. Configure in-cluster scanning under spec.processor on the AIGateway resource. You can combine it with prompt injection screening.

Choose what happens on a match

aigateway.yaml
spec:
processor:
replicas: 2
requestAction: Block
responseAction: LogOnly
placeholder: '[REDACTED]'
nerProvider:
type: presidio
timeout: '5s'
failureAction: fail-closed
presidio:
scoreThreshold: 50
language: 'en'
entities:
- CREDIT_CARD
- US_SSN
- EMAIL_ADDRESS
- PHONE_NUMBER
ActionOn the requestOn the response
BlockRefused. The prompt never reaches the provider.Refused. The response is not delivered.
RedactMatches replaced with placeholder, then forwarded.Matches replaced before the client sees them.
LogOnlyRecorded, forwarded unmodified.Recorded, forwarded unmodified.

responseAction is optional and falls back to requestAction.

Choose which entities to look for

entities controls what the scanner detects. The default includes structured identifiers and model-derived entities such as PERSON and LOCATION.

EntityMatches
CREDIT_CARDCard numbers, checksum-validated
US_SSNUS Social Security numbers
ABA_ROUTING_NUMBERUS bank routing numbers, checksum-validated
IBAN_CODEInternational bank account numbers
EMAIL_ADDRESSEmail addresses
PHONE_NUMBERPhone numbers, region-aware
IP_ADDRESSIPv4 and IPv6 addresses
US_ITINUS taxpayer identification numbers
IN_AADHAARIndian Aadhaar numbers
AU_TFNAustralian tax file numbers
UK_NHSUK NHS numbers
PERSONPersonal names, from the language model
LOCATIONPlace names, from the language model
DATE_TIMEDates and times, from the language model

The full supported list is published in the Presidio documentation. Custom recognizers appear under their configured entity name and can be listed here verbatim.

Tune the confidence threshold

scoreThreshold sets the minimum detection confidence from 0 to 100 and defaults to 50. Test representative traffic in LogOnly mode, then adjust the threshold and entity list to balance false positives and false negatives. For predictable enforcement, select the structured identifiers required by your data-handling policy.

Decide how failures behave

Configure parsing, redaction, and detection backend failures independently. Use the closed settings in production and open settings only during rollout or incident response.

spec:
processor:
extractionFailureAction: Block
mutationFailureAction: Block
nerProvider:
failureAction: fail-closed
FieldClosed settingOpen setting
extractionFailureActionRefuse if the body cannot be parsedForward unmodified
mutationFailureActionRefuse if redaction failsForward unmodified
nerProvider.failureActionRefuse on backend error, timeout, or open circuitLog a warning and forward

A circuit breaker applies failureAction without calling an unhealthy detection backend:

spec:
processor:
nerProvider:
circuitBreaker:
failureThreshold: 5
resetTimeout: '30s'

The spec.resilience circuit breaker protects model providers separately.

Size the scanner

timeout limits each detection call and defaults to 5s. Test large request bodies before lowering it because timeouts count as detection backend failures.

warning

Keep spec.processor.messageTimeout strictly greater than nerProvider.timeout, or the request will be abandoned before the detection call returns.

concurrency limits parallel detection calls for one request. It defaults to 8 and accepts values from 1 to 128. Changing it rolls the processor.

Each Presidio pod processes one request at a time. Scale presidio.replicas before raising concurrency. If stacklok_ai_gateway_presidio_analyze_inflight divided by the number of ready analyzer pods exceeds 1, calls are queuing in the backend.

spec:
processor:
nerProvider:
concurrency: 16
presidio:
replicas: 2
maxReplicas: 6
targetCPUUtilization: 75
resources:
requests:
cpu: '500m'
memory: 1Gi
limits:
cpu: '2'
memory: 2Gi

The language model uses approximately 800 MiB of memory after startup. The analyzer is CPU-bound, so use replicas and autoscaling for additional capacity. At two or more replicas, the gateway creates a PodDisruptionBudget.

Cache scan results

Enable the result cache to avoid scanning repeated text. It stores detection results in the platform's Redis or Valkey instance, keyed by the text and scanning configuration.

spec:
processor:
nerProvider:
resultCache:
enabled: true
ttl: '24h'

The cache uses the platform chart's Redis configuration. If the gateway cannot resolve the backend, scanning continues without caching. Use the hit-rate metric to verify that the cache is serving results.

What read access to the cache discloses

Cache keys are an unsalted hash of the scanned text, which makes the keyspace a confirmation oracle. Anyone who can read the backing Redis can hash a candidate piece of text, probe for the key, and confirm whether that exact text was scanned by this gateway.

On a hit they learn more than the yes or no. The entry carries the entity types found, the name of the rule that matched, and the byte offsets of each detection, which discloses the position and length of every detected value. If you ship custom recognizers, the rule name tells a reader which of your own detection rules fired.

The cache limits exposure as follows:

  • Entries omit scanned text and matched substrings.
  • Each gateway uses a separate keyspace.
  • Integrity tags prevent a writer from inserting a result that suppresses detection.

Treat read access to the cache as permission to confirm whether specific text passed through the gateway. Leave caching disabled if that disclosure conflicts with your security requirements.

The integrity secret

By default, the gateway creates <GATEWAY_NAME>-ner-cache-mac in its namespace. The Secret contains the integrity key for cached results.

To supply your own instead, through External Secrets, sealed secrets, or out-of-band creation, name it on the operator chart:

values.yaml
nerResultCache:
macSecret:
name: <SECRET_NAME>
key: mac-secret

Place a supplied Secret in each gateway namespace. Its value must contain at least 32 bytes of printable text. Base64-encoded random data satisfies this requirement.

The gateway re-scans entries when it cannot verify the integrity tag. Replace the Secret value to rotate it; existing entries then miss the cache and are re-scanned.

Time to live and footprint

ttl defaults to 24 hours. Cache keys include the scanning configuration, so changes to thresholds, entities, recognizers, or the analyzer image cause cache misses. Shorten the TTL to reduce the disclosure window and memory use.

Cache metrics

MetricWhat it measures
stacklok_ai_gateway_ner_cache_lookups_totalOne per attempted read, labeled hit or miss and request or response
stacklok_ai_gateway_ner_cache_errors_totalBackend or codec faults, labeled by operation and error type
stacklok_ai_gateway_ner_cache_op_duration_secondsBackend round-trip per operation

Use the hit rate to measure avoided detection calls. Cache errors become misses and trigger a normal detection call.

Next steps