Portal Community

Built-In Sanitization Patterns

Pattern NameMatchesReplacement
passwordAny key named "password", "passwd", "pwd" (case-insensitive)[REDACTED]
api_keyKeys named "apiKey", "api_key", "x-api-key", "Authorization"[REDACTED]
tokenKeys named "token", "accessToken", "refreshToken", "bearerToken"[REDACTED]
credit_card16-digit sequences matching Luhn algorithm (Visa, MC, Amex patterns)[CC-REDACTED]
ssnUS SSN format: ddd-dd-dddd[SSN-REDACTED]
emailStandard email format (configurable — disabled by default)[EMAIL-REDACTED]
connection_stringStrings containing "Server=", "Password=", "mongodb://", etc.[CONNSTR-REDACTED]

How INodeLogger Uses LogSanitizer

// ProcessEngine/Observability/LogSanitizer.cs (simplified)
public static class LogSanitizer
{
    private static readonly List<SanitizationRule> Rules = new()
    {
        new SanitizationRule(
            name: "password",
            pattern: @"(?i)(""?password""?\s*[:=]\s*""?)([^""&\s,}]+)",
            replacement: "$1[REDACTED]"
        ),
        new SanitizationRule(
            name: "credit_card",
            pattern: @"\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13})\b",
            replacement: "[CC-REDACTED]"
        ),
        // ... more rules
    };

    public static string Sanitize(string message)
    {
        foreach (var rule in Rules)
            message = Regex.Replace(message, rule.Pattern, rule.Replacement);
        return message;
    }
}

// ProcessEngine/Observability/NodeLogger.cs
public class NodeLogger : INodeLogger
{
    public void LogInformation(string message, object? data = null)
    {
        var sanitizedMessage = LogSanitizer.Sanitize(message);
        var sanitizedData = data != null ? SanitizeObject(data) : null;
        _logger.LogInformation(sanitizedMessage, sanitizedData);
    }
}

Adding Custom Sanitization Rules

// appsettings.json — extend built-in patterns with custom rules
{
  "Observability": {
    "LogSanitization": {
      "CustomRules": [
        {
          "Name": "employee_id",
          "Pattern": "EMP-[0-9]{6}",
          "Replacement": "[EMP-ID-REDACTED]"
        },
        {
          "Name": "iban",
          "Pattern": "[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}",
          "Replacement": "[IBAN-REDACTED]"
        }
      ]
    }
  }
}

Verifying Sanitization Is Working

# After enabling sanitization, run a test workflow with known-sensitive input:
# Test input: { "password": "secret123", "cardNumber": "4111111111111111" }

# Query Loki for the execution log:
{job="processengine"} |= "test-sanitization-execution"

# Expected log output (sensitive values should be masked):
# {"executionId":"exec-test-123","level":"info","message":"Processing form input",
#  "formData":{"password":"[REDACTED]","cardNumber":"[CC-REDACTED]"}}

# If you see raw values instead of [REDACTED]:
# 1. Verify LogSanitizer is registered in DI: services.AddLogSanitizer()
# 2. Verify the field name matches a sanitization rule
# 3. Check for regex pattern escaping issues
Sanitization Applies to Message Content, Not Labels

LogSanitizer processes log message content and structured property values. Loki labels (job, tenant_id, environment) are set at the OTel Collector level and do not pass through the sanitizer. For label hygiene (ensuring labels never contain PII), see the Label Hygiene page.