Mask Sensitive Trace Data
Protect your sensitive information from traces using the masking feature
Included on the Enterprise plan. Book a demo, opens in a new tab. Included on the Team plan. Included on the Starter plan. Not included on the Free plan.
Overview
Masking allows you to automatically redact or transform sensitive data in your traces before they're sent to the observatory. Masking is essential for several reasons:
- Security: Prevent exposure of credentials or sensitive business data
- Regulatory Compliance: Meet requirements like GDPR, HIPAA, or CCPA
Configure Masking
To implement masking, you need to define a masking function and configure the trace manager to use it.
import re
from deepeval.tracing import observe, trace_manager
def masking_function(data):
if isinstance(data, str):
data = re.sub(r'\b(?:\d{4}[- ]?){3}\d{4}\b', '[REDACTED CARD]', data)
return data
return data
trace_manager.configure(mask=masking_function)
@observe()
def llm_app(query: str):
return "4242-4242-4242-4242"
llm_app("Test Masking")import { observe, traceManager } from 'deepeval/tracing';
const maskingFunction = (data: any): any => {
if (typeof data === 'string')
return data.replace(/\b(?:\d{4}[- ]?){3}\d{4}\b/g, '[REDACTED CARD]');
return data;
};
traceManager.configure({ mask: maskingFunction });
const agent = (query: string): string => {
return "4242-4242-4242-4242";
};
const observedAgent = observe({ type: "agent", fn: agent });
observedAgent("Test Masking");The masking function is automatically applied to:
- Span attributes: Any attributes passed to span decorators or wrappers
- Observed function I/O: all input parameters and return values of observed functions.
Example Masking functions
Credit card number
import re
from typing import Any
def mask_credit_card(data: Any) -> Any:
if isinstance(data, str):
return re.sub(r'\b(?:\d{4}[- ]?){3}\d{4}\b', '[REDACTED CARD]', data)
elif isinstance(data, list):
return [mask_credit_card(item) for item in data]
elif isinstance(data, dict):
return {k: mask_credit_card(v) for k, v in data.items()}
else:
return data
print(mask_credit_card("My card number is 4111 1111 1111 1234."))
# Output: My card number is [REDACTED CARD].function maskCreditCard(data: any): any {
if (typeof data === 'string') {
return data.replace(/\b(?:\d{4}[- ]?){3}\d{4}\b/g, '[REDACTED CARD]');
} else if (Array.isArray(data)) {
return data.map(item => maskCreditCard(item));
} else if (data !== null && typeof data === 'object') {
return Object.fromEntries(
Object.entries(data).map(([k, v]) => [k, maskCreditCard(v)])
);
} else {
return data;
}
}
console.log(maskCreditCard("My card number is 4111 1111 1111 1234."));
// Output: My card number is [REDACTED CARD].Email address
import re
from typing import Any
def mask_email(data: Any) -> Any:
if isinstance(data, str):
return re.sub(r'\b([\w.%+-])[^\s@]*(@[\w.-]+\.\w+)', r'\1*****\2', data)
elif isinstance(data, list):
return [mask_email(item) for item in data]
elif isinstance(data, dict):
return {k: mask_email(v) for k, v in data.items()}
else:
return data
print(mask_email("Contact me at johndoe@example.com."))
# Output: Contact me at j*****@example.com.function maskEmail(data: any): any {
if (typeof data === 'string') {
return data.replace(/\b([\w.%+-])[^\s@]*(@[\w.-]+\.\w+)/g, '$1*****$2');
} else if (Array.isArray(data)) {
return data.map(item => maskEmail(item));
} else if (data !== null && typeof data === 'object') {
return Object.fromEntries(
Object.entries(data).map(([k, v]) => [k, maskEmail(v)])
);
} else {
return data;
}
}
console.log(maskEmail("Contact me at johndoe@example.com."));
// Output: Contact me at j*****@example.com.Bank account number
import re
from typing import Any
def mask_bank_account(data: Any) -> Any:
if isinstance(data, str):
return re.sub(
r'\b\d{6,}(?!\d)',
lambda m: '*' * (len(m.group()) - 4) + m.group()[-4:],
data
)
elif isinstance(data, list):
return [mask_bank_account(item) for item in data]
elif isinstance(data, dict):
return {k: mask_bank_account(v) for k, v in data.items()}
else:
return data
print(mask_bank_account("My account is 9876543210."))
# Output: My account is ******3210.function maskBankAccount(data: any): any {
if (typeof data === 'string') {
return data.replace(/\b\d{6,}(?!\d)/g, match => {
return '*'.repeat(match.length - 4) + match.slice(-4);
});
} else if (Array.isArray(data)) {
return data.map(item => maskBankAccount(item));
} else if (data !== null && typeof data === 'object') {
return Object.fromEntries(
Object.entries(data).map(([k, v]) => [k, maskBankAccount(v)])
);
} else {
return data;
}
}
console.log(maskBankAccount("My account is 9876543210."));
// Output: My account is ******3210.Passport number
import re
from typing import Any
def mask_passport_number(data: Any) -> Any:
if isinstance(data, str):
return re.sub(r'\b([A-Z])([A-Z0-9]{6,8})([A-Z0-9])\b', r'\1*******\3', data)
elif isinstance(data, list):
return [mask_passport_number(item) for item in data]
elif isinstance(data, dict):
return {k: mask_passport_number(v) for k, v in data.items()}
return data
print(mask_passport_number("Passport: A12345678."))
# Output: Passport: A*******8.function maskPassportNumber(data: any): any {
if (typeof data === 'string') {
return data.replace(/\b([A-Z])([A-Z0-9]{6,8})([A-Z0-9])\b/g, '$1*******$3');
} else if (Array.isArray(data)) {
return data.map(item => maskPassportNumber(item));
} else if (data !== null && typeof data === 'object') {
return Object.fromEntries(
Object.entries(data).map(([k, v]) => [k, maskPassportNumber(v)])
);
} else {
return data;
}
}
console.log(maskPassportNumber("Passport: A12345678."));
// Output: Passport: A*******8.Last updated on