Skip to content

Filter Strategies

A filter strategy controls what happens to a detected PII token. Each identifier type supports a Strategies list; the first strategy whose condition evaluates to true is applied. If the list is empty, the default REDACT strategy is used.

Available Strategies

Strategy Constant Description
REDACT AbstractFilterStrategy.Redact Replace the token with a formatted redaction label
RANDOM_REPLACE AbstractFilterStrategy.RandomReplace Replace with a random GUID (consistent within a context)
STATIC_REPLACE AbstractFilterStrategy.StaticReplace Replace with a fixed string
CRYPTO_REPLACE AbstractFilterStrategy.CryptoReplace Replace with AES-encrypted ciphertext
FPE_ENCRYPT_REPLACE AbstractFilterStrategy.FpeEncryptReplace Format-preserving encryption
HASH_SHA256_REPLACE AbstractFilterStrategy.HashSha256Replace Replace with the SHA-256 hex digest
LAST_4 AbstractFilterStrategy.Last4 Keep only the last 4 characters
MASK AbstractFilterStrategy.Mask Overwrite characters with a mask character
SAME AbstractFilterStrategy.Same Leave the token unchanged (mark as detected but not replaced)
TRUNCATE AbstractFilterStrategy.Truncate Keep only the first character
SHIFT_DATE AbstractFilterStrategy.ShiftDate Shift a detected date by a configurable offset (date filters only)

Strategy Details

REDACT

Replaces the token with a formatted label. The redactionFormat string may contain:

  • %t — replaced with the filter type name (e.g. ssn, email-address)
  • %l — replaced with the token's classification label (if any)

Default format: {{{REDACTED-%t}}}

new SsnFilterStrategy
{
    Strategy = "REDACT",
    RedactionFormat = "[REMOVED-%t]"
}
{ "strategy": "REDACT", "redactionFormat": "[REMOVED-%t]" }

RANDOM_REPLACE

Replaces the token with a randomly generated GUID. When a Context Service is configured, the same token always receives the same GUID within a named context, preserving referential integrity.

new SsnFilterStrategy
{
    Strategy = "RANDOM_REPLACE"
}

See Context Service for details on maintaining consistency across documents.


STATIC_REPLACE

Replaces the token with a fixed string supplied in staticReplacement. Falls back to REDACT format if staticReplacement is empty.

new EmailAddressFilterStrategy
{
    Strategy = "STATIC_REPLACE",
    StaticReplacement = "user@redacted.invalid"
}
{ "strategy": "STATIC_REPLACE", "staticReplacement": "user@redacted.invalid" }

CRYPTO_REPLACE

Encrypts the token using AES and replaces it with the Base64-encoded ciphertext. Requires a Crypto block on the Policy with a valid key and iv. Falls back to REDACT if the policy has no Crypto configuration or decryption fails.

var policy = new Policy
{
    Name = "encrypted",
    Crypto = new Crypto
    {
        Key = Convert.ToBase64String(aesKey),   // 16, 24, or 32 bytes
        Iv  = Convert.ToBase64String(aesIv)     // 16 bytes
    },
    Identifiers = new Identifiers
    {
        Ssn = new Ssn
        {
            Strategies = new List<SsnFilterStrategy>
            {
                new SsnFilterStrategy { Strategy = "CRYPTO_REPLACE" }
            }
        }
    }
};

FPE_ENCRYPT_REPLACE

Format-preserving encryption. Requires an Fpe block on the Policy with key and tweak.

var policy = new Policy
{
    Name = "fpe-policy",
    Fpe = new Fpe { Key = "...", Tweak = "..." },
    Identifiers = new Identifiers
    {
        CreditCard = new CreditCard
        {
            Strategies = new List<CreditCardFilterStrategy>
            {
                new CreditCardFilterStrategy { Strategy = "FPE_ENCRYPT_REPLACE" }
            }
        }
    }
};

HASH_SHA256_REPLACE

Replaces the token with its lower-case SHA-256 hex digest. Optionally appends a random salt before hashing when salt: true is set.

new EmailAddressFilterStrategy
{
    Strategy = "HASH_SHA256_REPLACE",
    Salt = true     // prepend random salt before hashing
}
{ "strategy": "HASH_SHA256_REPLACE", "salt": true }

LAST_4

Keeps the last four characters of the token and discards the rest. If the token is shorter than four characters, the full token is returned.

new CreditCardFilterStrategy { Strategy = "LAST_4" }

Output example: 1234 (from 4111-1111-1111-1234).


MASK

Replaces characters with a mask character (default *). Use maskLength to control how many characters are written:

maskLength value Behaviour
"same" (default) Mask has the same length as the original token
Integer string, e.g. "6" Mask has exactly that many characters (capped at token length)
new SsnFilterStrategy
{
    Strategy = "MASK",
    MaskCharacter = "#",
    MaskLength = "same"
}
{ "strategy": "MASK", "maskCharacter": "#", "maskLength": "6" }

SAME

Marks the token as detected but leaves the text unchanged. Useful when you want spans and metadata without altering the output.

new PhoneNumberFilterStrategy { Strategy = "SAME" }

TRUNCATE

Keeps only the first character of the token.

new EmailAddressFilterStrategy { Strategy = "TRUNCATE" }

SHIFT_DATE

Date filters only. Applies to DateFilterStrategy; ignored by all other filter types.

Shifts a detected date forward or backward by a configurable number of days, months, and/or years while preserving the original date format. All three offsets default to 0 and can be combined freely. Negative values shift the date into the past.

Supported date formats

Example Format
1/15/1990 Numeric M/D/YYYY
January 15, 1990 Full month name
15-Jan-1990 Day-abbreviated-month-year
Jan 15, 1990 Abbreviated month name

If the detected token cannot be parsed as a date, or if the Date filter type is not active, SHIFT_DATE falls back to REDACT.

Properties

Property JSON key Type Default Description
Days days int 0 Days to add (negative to subtract)
Months months int 0 Months to add (negative to subtract)
Years years int 0 Years to add (negative to subtract)

C# example

using Phileas.Policy.Filters;
using Phileas.Policy.Filters.Strategies;

var policy = new Policy
{
    Name = "date-shift-policy",
    Identifiers = new Identifiers
    {
        Date = new Date
        {
            DateFilterStrategies = new List<DateFilterStrategy>
            {
                new DateFilterStrategy
                {
                    Strategy = AbstractFilterStrategy.ShiftDate,
                    Years  = -1,
                    Days   = 14
                }
            }
        }
    }
};

JSON policy example

{
  "name": "date-shift-policy",
  "identifiers": {
    "date": {
      "dateFilterStrategies": [{
        "strategy": "SHIFT_DATE",
        "years": -1,
        "days": 14
      }]
    }
  }
}

Example transformation

Input Output
DOB: January 15, 1990 DOB: January 29, 1989
Admitted: 3/1/2024 Admitted: 3/15/2023

Salting

Any strategy can optionally append a random 16-byte Base64 salt to the token before processing by setting salt: true. The generated salt is included in the Span.Salt field of the result so it can be recorded for auditing or reproduction.

new SsnFilterStrategy
{
    Strategy = "HASH_SHA256_REPLACE",
    Salt = true
}

Strategy Conditions

Strategies can include a condition property that controls when they are applied. When multiple strategies are defined, phileas-net evaluates their conditions in order and applies the first strategy whose condition evaluates to true.

new EmailAddressFilterStrategy
{
    Strategy = "MASK",
    Condition = "confidence > 0.8 and context == \"internal\""
}

Supported condition fields: - confidence - Detection confidence (0.0 to 1.0) - context - Context name passed to FilterService.Filter() - token - The detected text value - type - Classification type (e.g., "PER", "LOC")

Supported operators: - Comparison: ==, !=, >, <, >=, <=, is, is not - String: startswith - Logical: and

See Filter Conditions for detailed examples and usage patterns.


Configuring Strategies Per Identifier

Each identifier type has a corresponding strategy class (e.g. SsnFilterStrategy, EmailAddressFilterStrategy). Set the Strategies list on the identifier:

var policy = new Policy
{
    Name = "multi-strategy",
    Identifiers = new Identifiers
    {
        Ssn = new Ssn
        {
            Strategies = new List<SsnFilterStrategy>
            {
                new SsnFilterStrategy { Strategy = "MASK" }
            }
        },
        EmailAddress = new EmailAddress
        {
            Strategies = new List<EmailAddressFilterStrategy>
            {
                new EmailAddressFilterStrategy { Strategy = "HASH_SHA256_REPLACE" }
            }
        },
        PhoneNumber = new PhoneNumber
        {
            Strategies = new List<PhoneNumberFilterStrategy>
            {
                new PhoneNumberFilterStrategy { Strategy = "LAST_4" }
            }
        }
    }
};