Portal Community

The Problem

An email node processes a customer service notification. The email template is assembled from workflow data and may contain:

The email node returns an execution result that includes message metadata. This result flows into the next node and is written to the execution log. Without redaction, PII from the email body appears in both places.

The Solution: Post-Phase Redaction

PiiRedactionGuard runs in the Post phase, after the email is sent. It scans the node's output (the delivery receipt/metadata returned by the email executor), finds PII, and replaces it before the result propagates.

{
  "guardRails": {
    "individual": [
      {
        "name": "PiiRedactionGuard",
        "enabled": true,
        "config": {
          "redaction_method": "partial",  // keep first+last char: j**n@***.c*m
          "fields": []                    // empty = scan entire output
        }
      }
    ]
  }
}

What the Redaction Does

Before redaction (raw output from email node):

{
  "messageId": "msg-abc-123",
  "to": "john.smith@company.com",
  "subject": "Your order is confirmed",
  "status": "delivered",
  "deliveryReceipt": "Delivered to john.smith@company.com at 14:32:01"
}

After PiiRedactionGuard (mask method):

{
  "messageId": "msg-abc-123",
  "to": "**********************",
  "subject": "Your order is confirmed",
  "status": "delivered",
  "deliveryReceipt": "Delivered to ********************** at 14:32:01"
}

After PiiRedactionGuard (partial method):

{
  "messageId": "msg-abc-123",
  "to": "j**************m",
  "subject": "Your order is confirmed",
  "status": "delivered",
  "deliveryReceipt": "Delivered to j**************m at 14:32:01"
}

Why Post-Phase Only?

The email node must receive the recipient's email address to send the email — blocking it in Pre would prevent delivery. The correct pattern for email is:

{
  "guardRails": {
    "individual": [
      // Pre: allow input with email address (needed for delivery)
      // but log that it contains PII
      {
        "name": "PiiDetectionGuard",
        "enabled": true,
        "order": 1,
        "enableDelayedEnforcement": true,  // log violation but do not block
        "config": { "sensitivityLevel": "medium" }
      },

      // Post: redact PII from the email node's output/receipt
      {
        "name": "PiiRedactionGuard",
        "enabled": true,
        "config": {
          "redaction_method": "partial"
        }
      }
    ]
  }
}

Result Propagation

After PiiRedactionGuard runs, OutputModified=true is set. BaseNodeExecutor detects this and updates the node execution result:

// In BaseNodeExecutor.OnPostGuardRails():
var postResult = await _guardExecutor.ExecutePostAsync(guardContext, nodeResult.OutputData);
if (postResult.OutputModified)
{
    // The redacted output replaces the original
    nodeResult.OutputData = guardContext.Output;
}

The downstream node and execution log receive the redacted version. The raw email address never appears outside the email delivery layer.

Redaction happens in reverse positional order PiiRedactionGuard applies redactions from end to start of the string (reverse position order). This preserves string offsets — earlier redactions don't shift the positions used by later ones.