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

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 (lines 60-73), the filter loads a map of path-to-value pairs from the configuration and applies them to the request body.

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 (lines 55-68), this filter calls jsonparser.Delete for each configured path, eliminating the field entirely from the payload.

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 (lines 38-45), the filter compiles the pattern and executes filter.p.ReplaceAll on the raw body bytes.

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 (lines 38-45).

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 (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 configuration by specifying role mappings that include the mask type:

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 to leverage Elasticsearch field-level security.
  • Pipeline flexibility: Chain multiple filters in 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 provides granular control over partial field masking.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →