Anypoint Mulesoft Masking Sensitive Data With DataWeave Custom Function in Logging
Secure MuleSoft logs by masking sensitive data with DataWeave, regex, and custom functions to ensure compliance and data protection.
Join the DZone community and get the full member experience.
Join For FreeWhen working with Mulesoft integration applications, especially when exchanging data between services, APIs, or third-party applications. It's important to mask sensitive data while logging.
Masking specific fields in payloads refers to the process of obfuscating sensitive information (like personal identifiers, financial data, or authentication tokens) before it's logged.
Logging Payloads: Masking Strategies
Simple Masking (Replace With Regex)
Used to hide or replace sensitive data using regular expressions.
Input payload:
{
"username": "john_doe",
"password": "mySecret123",
"ssn": "123-45-6789"
"pnone": "2131415161",
"salary": 2000000
}
DW script:
%dw 2.0
output application/json
---
payload update {
case .username -> $ replace /[a-z]/ with "*"
case .password -> $ replace /[a-z]/ with "*"
case .ssn -> $ replace /[0-9]/ with "*"
case .pnone -> $ replace /[0-9]/ with "*"
case .salary -> $ replace /[0-9]/ with "*"
}
Output payload:
{
"username": "****_***",
"password": "**S*****123",
"ssn": "***-**-****",
"pnone": "**********",
"salary": "*******"
}
Pros
- Fully customizable regex patterns
- Supports masking of multiple fields
- No extra dependencies – pure DataWeave
- Works with nested JSON using additional logic
Cons
- Regex in DataWeave can be hard to maintain
- Doesn't mask complex nested or encrypted fields by default
- Performance can be a concern for large payloads
Simple Masking (With Dataweave mask() Function)
The mask() function in DataWeave function replaces all simple elements that match the specified criteria. It's a convenient way to mask sensitive fields in a payload.
Input payload:
[{
"username": "john_doe",
"password": "mySecret123",
"ssn": "123-45-6789",
"pnone": "2131415161",
"salary": 2000000
},
{
"username": " jane_doe",
"password": "Secret@123",
"ssn": "123-55-6789",
"pnone": "1213141516",
"salary": 5000000
}]
DW script:
%dw 2.0
output application/json
import * from dw::util::Values
---
(((((payload mask "username" with "***")
mask "password" with "********")
mask "ssn" with "***")
mask "pnone" with "***-**")
mask "salary" with "***" )
Output payload:
[
{
"username": "***",
"password": "********",
"ssn": "***",
"pnone": "***-**",
"salary": "***"
},
{
"username": "***",
"password": "********",
"ssn": "***",
"pnone": "***-**",
"salary": "***"
}
]
Pros
- Built-in, no need for regex or complex logic
- Lightweight and faster than regex for simple cases
- Directly usable on any string field
- Very useful inside logger components for safe audit logs
Cons
- Works only on strings
- Doesn’t work automatically for nested objects or maps — must manually call per field
- You have to specify each field to mask; no wildcard masking
- You must define the start index and length; it doesn’t dynamically adapt to the length of sensitive values
Partial Masking
Partial masking means only part of a sensitive value is hidden. It's often used in MuleSoft logging to balance between security and traceability.
Input payload:
{
"username": "john_doe",
"password": "mySecret123",
"ssn": "123-45-6789",
"pnone": "2131415161",
"salary": 2000000
}
DW script:
%dw 2.0
fun maskAllChar(m)=(
m replace /./ with "*"
)
fun maskOnlyNumber(m)=(
m replace /[0-9]/ with "*"
)
fun maskExceptLast4Char(m)=(
if ( sizeOf(m) != null and sizeOf(m)>4 )
(m[0 to sizeOf(m)-5] replace /./ with "*") ++ m[-4 to -1]
else
m replace /./ with "*"
)
fun maskExceptFirst4Char(m)=(
if ( sizeOf(m) != null and sizeOf(m)>4 )
m[0 to 3] ++ (m[4 to sizeOf(m)-1] replace /./ with "*")
else
m replace /./ with "*"
)
output application/json
---
payload update {
case .username -> maskExceptFirst4Char($)
case .password -> maskAllChar($)
case .ssn -> maskOnlyNumber($)
case .pnone -> maskExceptLast4Char($)
case .salary -> maskExceptFirst4Char($)
}
Output payload:
{
"username": "john****",
"password": "***********",
"ssn": "***-**-****",
"pnone": "******5161",
"salary": "2000***"
}
Pros
- Fully customizable regex patterns
- Supports masking of multiple fields
- No extra dependencies — pure DataWeave
- Works with nested JSON using additional logic
Cons
- Regex in DataWeave can be hard to maintain
- Doesn't mask complex nested or encrypted fields by default
- Performance can be a concern for large payloads
Redaction (Remove Sensitive Data)
Instead of masking (e.g., *****), this approach removes sensitive fields entirely from the payload before logging.
For example:
{
"username": "",
"password": "",
"ssn": "",
"pnone": "",
"salary": 0
}
Pros
- Prevents accidental exposure of sensitive information in logs
- Reduces the risk of security breaches if logs are accessed by unauthorized users
- Easily added using DataWeave transformation, custom functions, or API policies
- Logs are consistent and readable since masked data is always replaced with a known value, like empty or zero.
Cons
- If a new sensitive field is added and not in the masking list, it won't be masked or replaced
- Once replaced with a placeholder, the original data is gone; can’t trace/debug issues where actual data was needed
- Regular expressions can miss complex or nested structures
Tokenization
Tokenization replaces sensitive fields in payloads (like credit cards, passwords, tokens) with unique tokens (e.g., TOKEN_abc123) before logging. The original value is stored securely in a token vault or database, allowing optional future lookup.
Encryption
Encrypting sensitive data in MuleSoft before logging ensures that the actual value is stored in an unreadable format, only accessible to those with decryption keys. This is one of the strongest approaches to securing data in logs.
Custom DW Function for Masking Payload Fields
A custom DataWeave (DW) function in MuleSoft to mask specific fields in the logging payload offers a smart and reusable solution.
Pros
- Easy to maintain list of sensitive fields.
- One centralized function used across flows (less duplication)
- Easy to update mask logic in one place.
- Ensures sensitive fields are always protected in logs
- Mask nested fields, supports multiple fields in a complex payload.
- If value is
nullor invalid payload will replace with empty.
Cons
- Doesn't detect patterns to identify sensitive fields
- Doesn't work with array inside array, e.g., "secret": [["s123"]]
- Performance can be a concern for large payloads
Sensitive Fields
Add comma-separated fields in the properties file. For example, maskFields = "username,password,ssn,salary,phoneNumber,dateOfBirth".
DW function:
%dw 2.0
import try, orElse from dw::Runtime
var mFields=try(() -> (p('maskFields'))) orElse ''
fun maskPayload(data, fields) =
data match {
case is Array -> data map ((item, index) -> maskPayload(item, fields))
case is Object -> data mapObject ((value, key) -> {
(key): value match {
case is Array -> if (fields contains (key as String))
value map ((item, index) -> item match {
case is String -> item replace /./ with "*"
case is Number -> item replace /./ with "*"
case is Object -> maskPayload(item, fields)
case is Array -> maskPayload(item, fields)
else -> item
})
else
value map ((item, index) -> maskPayload(item, fields))
case is Object -> maskPayload(value, fields)
case is String -> if (fields contains (key as String))
value replace /./ with "*"
else
value
case is Number -> if (fields contains (key as String))
value replace /./ with "*"
else
value
else -> value
}
})
else -> $
}
---
try(() -> (maskPayload(payload, mFields))) orElse ''
Input payload:
{
"firstName": "John",
"lastName": "Doe",
"mySystem": {
"username": "john_doe",
"password": "mySecret123"
},
"phoneNumber": [
"212 555-1234",
"646 555-4567"
],
"dateOfBirth": "1970-04-01",
"ssn": "123-45-6789",
"salary": 2000000,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021"
}
}
Output payload:
{
firstName: "John",
lastName: "Doe",
mySystem: {
username: "********",
password: "***********"
},
phoneNumber: [
"************",
"************"
],
dateOfBirth: "**********",
ssn: "***********",
salary: "*******",
address: {
streetAddress: "21 2nd Street",
city: "New York",
state: "NY",
postalCode: "10021"
}
}
Best Practices for Payload Field Masking in Logging
- Mask only what’s necessary: Don't over-mask or redact data that could still be useful for debugging or monitoring.
- Centralized logging: Ensure all your integrations are logging to a centralized logging system where you can consistently apply masking rules.
- Use contextual logging: Only log sensitive information when absolutely necessary. For example, log IDs or status messages instead of full payloads.
- Audit your logs regularly: Regularly check logs to ensure no sensitive information
Conclusion
Masking sensitive data in MuleSoft logs is crucial for safeguarding personal and confidential details, including credit card numbers, passwords, and API keys.
Using custom DataWeave functions, developers can create flexible, maintainable, and reusable logic to mask sensitive fields across different applications consistently. This approach ensures that sensitive information is never displayed in plain text, supporting compliance with security and regulatory standards such as GDPR and HIPAA.
Opinions expressed by DZone contributors are their own.
Comments