# How to Implement Data Masking or Desensitization for Sensitive Fields via INFINI Gateway

> Implement data masking and desensitization for sensitive fields using INFINI Gateway. Learn how to mask, delete, or replace sensitive data with filter-based transformations and Elasticsearch integrations.

- Repository: [INFINI Labs/gateway](https://github.com/infinilabs/gateway)
- Tags: how-to-guide
- Published: 2026-03-04

---

**INFINI Gateway provides filter-based transformations and Elasticsearch field-level security integrations to mask, delete, or replace sensitive data in request and response payloads.**

INFINI Gateway serves as a high-performance data gateway between clients and Elasticsearch clusters, offering built-in mechanisms to handle data masking or desensitization for sensitive fields via INFINI Gateway configurations. Whether you need to redact credit card numbers from JSON payloads or enforce role-based field masking at the backend, the gateway provides flexible pipeline filters and security mappings to protect sensitive information as it flows through the proxy.

## Filter-Based Masking Methods

INFINI Gateway implements data transformation through a series of filters located in the `proxy/filters/transform/` package. These filters intercept requests and responses to modify content before it reaches its destination.

### JSON Field Replacement with `request_body_json_set`

The **`request_body_json_set`** filter overwrites specific JSON fields with mask values using the `jsonparser.Set` function. In [`proxy/filters/transform/request_body_json_set.go`](https://github.com/infinilabs/gateway/blob/main/proxy/filters/transform/request_body_json_set.go) (lines 60-73), the filter loads a map of path-to-value pairs from the configuration and applies them to the request body.

```yaml
pipeline:
  - name: request_body_json_set
    config:
      ignore_missing: true
      path:
        - "user.password->***"
        - "credit_card.number->****-****-****-1234"

```

This configuration replaces `user.password` with `***` and masks the credit card number while preserving the last four digits.

### JSON Field Deletion with `request_body_json_del`

To completely remove sensitive fields rather than masking them, use the **`request_body_json_del`** filter. Located in [`proxy/filters/transform/request_body_json_del.go`](https://github.com/infinilabs/gateway/blob/main/proxy/filters/transform/request_body_json_del.go) (lines 55-68), this filter calls `jsonparser.Delete` for each configured path, eliminating the field entirely from the payload.

```yaml
pipeline:
  - name: request_body_json_del
    config:
      ignore_missing: true
      path:
        - "ssn"
        - "api_key"

```

After processing, the `ssn` and `api_key` fields no longer exist in the forwarded request.

### Regex-Based Request Masking with `request_body_regex_replace`

For pattern-based masking that doesn't rely on JSON structure, the **`request_body_regex_replace`** filter applies regular expression substitutions. As implemented in [`proxy/filters/transform/request_body_regex_replace.go`](https://github.com/infinilabs/gateway/blob/main/proxy/filters/transform/request_body_regex_replace.go) (lines 38-45), the filter compiles the pattern and executes `filter.p.ReplaceAll` on the raw body bytes.

```yaml
pipeline:
  - name: request_body_regex_replace
    config:
      pattern: "\"(\\d{16})\""
      to: "\"************\""

```

This example masks any 16-digit number (such as a full credit card number) within the request body.

### Regex-Based Response Masking with `response_body_regex_replace`

The gateway can also mask sensitive data in responses before they reach the client. The **`response_body_regex_replace`** filter operates identically to its request-side counterpart but processes `ctx.Response.GetRawBody()` instead. You can find the implementation in [`proxy/filters/transform/response_body_regex_replace.go`](https://github.com/infinilabs/gateway/blob/main/proxy/filters/transform/response_body_regex_replace.go) (lines 38-45).

```yaml
pipeline:
  - name: response_body_regex_replace
    config:
      pattern: "\"email\":\"[^\"]+\""
      to: "\"email\":\"***@***.com\""

```

This configuration obscures email addresses in the response payload by replacing them with a generic mask.

### Header and Context Manipulation

Additional transform filters such as **`set_header`**, **`response_header_format`**, and **`set_context`** provide capabilities to blank out or replace sensitive information in HTTP headers and internal context values. These filters manipulate metadata without altering the message body, useful for removing authentication tokens or correlation IDs from logs.

## Role-Mapping-Based Field Level Security

Beyond request/response transformation, INFINI Gateway supports delegating masking responsibilities to Elasticsearch through field-level security mappings.

### FieldPermission with Type Mask

The `FieldPermission` struct defined in [`common/role_mapping.go`](https://github.com/infinilabs/gateway/blob/main/common/role_mapping.go) (lines 58-61) includes a **`Type`** field that accepts the value `"mask"`. When configured, the gateway forwards these permissions to Elasticsearch, instructing the backend to return masked values (such as `"******"`) for specified fields rather than the raw data.

This integration leverages Elasticsearch's native field-level security, ensuring that sensitive fields remain masked even when accessed directly through the backend.

### Configuring Role Mappings

You define masked fields within the [`gateway.yml`](https://github.com/infinilabs/gateway/blob/main/gateway.yml) configuration by specifying role mappings that include the mask type:

```yaml
roles:
  - name: analyst
    indices:
      - names: ["sales"]
        privileges: ["read"]
        field_security:
          grant: ["order_id", "date"]
          mask: ["customer_name", "customer_email"]

```

When a user with the *analyst* role queries the `sales` index, the gateway passes this role mapping through request headers (such as `X-Forwarded-User-Role`), causing Elasticsearch to return `customer_name` and `customer_email` as masked values while preserving other fields.

## Combining Methods for End-to-End Protection

You can chain multiple filters and role mappings to create comprehensive data masking or desensitization for sensitive fields via INFINI Gateway pipelines. For example, delete highly sensitive fields from incoming requests using `request_body_json_del`, mask partially sensitive response fields with `response_body_regex_replace`, and enforce backend field-level security through role mappings.

The pipeline execution order follows your configuration sequence, allowing precise control over when each masking operation occurs during the request lifecycle.

## Summary

- **JSON manipulation**: Use `request_body_json_set` to overwrite fields with mask values or `request_body_json_del` to remove them entirely, leveraging `jsonparser.Set` and `jsonparser.Delete` in `proxy/filters/transform/`.
- **Pattern matching**: Apply `request_body_regex_replace` and `response_body_regex_replace` for regex-based masking on raw body content using `filter.p.ReplaceAll`.
- **Header security**: Utilize `set_header` and related filters to strip sensitive metadata from HTTP headers before logging or forwarding.
- **Backend integration**: Configure `FieldPermission` with `Type: "mask"` in [`common/role_mapping.go`](https://github.com/infinilabs/gateway/blob/main/common/role_mapping.go) to leverage Elasticsearch field-level security.
- **Pipeline flexibility**: Chain multiple filters in [`gateway.yml`](https://github.com/infinilabs/gateway/blob/main/gateway.yml) to implement defense-in-depth for sensitive data protection.

## Frequently Asked Questions

### How does INFINI Gateway handle JSON field masking without breaking the document structure?

INFINI Gateway uses the `jsonparser` library to surgically modify JSON documents. The `request_body_json_set` filter calls `jsonparser.Set` to replace values while preserving the surrounding JSON structure, and `request_body_json_del` uses `jsonparser.Delete` to remove keys without leaving syntax errors. Both filters operate on the parsed JSON tree rather than simple string replacement, ensuring valid JSON output even with nested objects.

### Can I mask sensitive data in responses only, leaving the request intact?

Yes. Configure the **`response_body_regex_replace`** filter in your pipeline to target outbound traffic specifically. This filter operates on `ctx.Response.GetRawBody()` after receiving the backend response but before sending it to the client, allowing you to mask sensitive fields in the response while preserving the original data in the request and backend storage.

### What is the difference between filter-based masking and role-mapping-based masking?

Filter-based masking occurs at the gateway layer, physically altering or removing data before it reaches Elasticsearch or the client. Role-mapping-based masking delegates the operation to Elasticsearch's field-level security, where the backend returns masked values based on user permissions defined in the `FieldPermission` struct with `Type: "mask"`. Filter-based approaches offer more flexibility for custom patterns, while role-mapping ensures consistent access control across direct backend queries.

### How do I mask only specific portions of a field value, such as the middle digits of a credit card number?

Use the **`request_body_regex_replace`** or **`response_body_regex_replace`** filters with capture groups. For example, the pattern `(\d{4})\d{8}(\d{4})` captures the first and last four digits of a 16-digit number, allowing the replacement string `$1********$2` to preserve the identifiable prefix and suffix while masking the middle digits. This regex-based approach in [`proxy/filters/transform/request_body_regex_replace.go`](https://github.com/infinilabs/gateway/blob/main/proxy/filters/transform/request_body_regex_replace.go) provides granular control over partial field masking.