Response Transforms

Overview

Response Transforms are per-backend rules that rewrite, inject, or mask response body content via a Rust Lua filter. Response body manipulation is not possible with HAProxy’s native http-response rules (which only handle headers), so this feature uses the HAProxy filter API.

Transform Types

Replace

Regex find/replace with $1 backreferences. Scoped per backend and filtered by content type.

Find: <title>(.*?)</title>
Replace: <title>Acme - $1</title>

Inject

Insert a string before, after, or in place of a regex anchor. Common use case: inject a script or analytics tag before </body>.

Anchor: </body>
Position: before
Inject: <script src="/analytics.js"></script>

Mask

Detect sensitive data in the response body and replace it with a token. Two masking modes:

  • tokenize: Store token-to-original mapping in Valkey with a TTL. Supports bidirectional unmask (for backend services that need the original value).
  • encrypt: AES-256-GCM encryption with a key from an environment variable. No external storage needed.

Built-in PII Detectors

DetectorDetects
emailEmail addresses
phonePhone numbers
ssnSocial Security Numbers
credit_cardCredit card numbers
ipIP addresses

You can also use custom regex patterns for domain-specific sensitive data.

Configuration

PropertyDescription
nameDisplay name
backend_id / backend_idsPer-backend scoping
priorityOrdered (drag-and-drop)
enabledToggle without deleting
transform_typereplace, inject, or mask
content_typesComma-separated MIME prefixes to process
max_body_sizeSkip if body is larger (default 1MB)
find_regexRegex for replace/mask
replace_stringReplacement for replace
inject_stringString to inject
inject_positionbefore, after, or replace
mask_moderegex or detector
detectoremail, phone, ssn, credit_card, ip
token_modetokenize or encrypt
token_prefixPrefix for tokens (e.g. MASK_)
token_ttlTTL for tokenize mode (seconds)
encrypt_key_envEnvironment variable name for encrypt key

Feature Gating

Feature flag required

Response Transforms are gated behind the resp_transform_enabled feature flag. Enable it in Settings > Global Options before configuring transforms.

Filter Ordering

The filter pipeline order is:

cache -> resp_transform -> compression

Transforms run before compression so that compression compresses the transformed output. Transforms run after cache so that the cache stores the raw body (and the transform is applied on each cache hit).

HA Recommendation

Use encrypt mode for HA

For high-availability deployments, encrypt mode is recommended because it is stateless — no external Valkey dependency. Use tokenize mode when you need TTL-based expiry or per-token revocation.

Fail-to-Encrypt Fallback

When using tokenize mode and Valkey is unreachable during masking, the transform automatically falls back to AES-256-GCM encryption. This ensures PII is still masked even if the token store is temporarily unavailable.

FCGI Limitation

The response transform filter is skipped for FastCGI backends due to an HAProxy 3.4 bug.

Step-by-Step: Replace Text in Responses

  1. Navigate to Settings > Global Options and enable resp_transform_enabled
  2. Navigate to Performance > Response Transforms
  3. Click Add Transform
  4. Name: replace-title
  5. Backend: select your backend
  6. Type: replace
  7. Content types: text/html
  8. Find regex: <title>(.*?)</title>
  9. Replace: <title>My Site - $1</title>
  10. Save and Apply

Step-by-Step: Inject a Script

  1. Navigate to Performance > Response Transforms
  2. Click Add Transform
  3. Name: inject-analytics
  4. Backend: select your backend
  5. Type: inject
  6. Content types: text/html
  7. Anchor regex: </body>
  8. Position: before
  9. Inject string: <script src="/analytics.js" defer></script>
  10. Save and Apply

Step-by-Step: Mask PII (Encrypt Mode)

  1. Navigate to Settings > Global Options and enable resp_transform_enabled
  2. Set an encryption key in your environment: RESP_TRANSFORM_KEY=<32-byte-hex-key>
  3. Navigate to Performance > Response Transforms
  4. Click Add Transform
  5. Name: mask-emails
  6. Backend: select your backend
  7. Type: mask
  8. Mask mode: detector
  9. Detector: email
  10. Token mode: encrypt
  11. Token prefix: MASKED_
  12. Encrypt key env: RESP_TRANSFORM_KEY
  13. Save and Apply
Encrypt key requirements

The encryption key must be a 32-byte (256-bit) value. Generate one with openssl rand -hex 32 and set it as an environment variable. The same key must be used across all coreX Manager instances for consistent masking.

Verification

  1. Test replace:

    curl -k https://localhost/ | grep '<title>'

    Expect the replaced title.

  2. Test inject:

    curl -k https://localhost/ | grep 'analytics.js'

    Expect the injected script before </body>.

  3. Test mask:

    curl -k https://localhost/api/users

    Email addresses should be replaced with MASKED_ prefixed tokens.

  4. Test unmask (tokenize mode):

    • Use the unmask API endpoint with the token to retrieve the original value
    • Verify the original value matches

Next Steps