Skip to main content

PII Filter (Rust)

High-performance PII detection and masking library for ContextForge.

Features

  • Detects 12+ PII types (SSN, email, credit cards, phone numbers, and more)
  • Built-in detectors follow default_mask_strategy and default to redact
  • Multiple masking strategies (redact, partial, hash, tokenize, remove)
  • Parallel regex matching with RegexSet (5-10x faster than Python)
  • Zero-copy operations for nested JSON/dict traversal
  • Whitelist support for false positive filtering
  • Deterministic overlap resolution: earliest match wins, then the longest match wins
  • Structural validation for SSNs and common card issuer ranges to reduce false positives
  • Explicit guardrails for oversized inputs and pathological custom patterns

Build

make install

Runtime Requirements

This plugin depends on cpex>=0.1.0,<0.2 and imports hook models from cpex.framework. The compiled Rust extension is mandatory; there is no Python fallback implementation.

Usage

The Python plugin requires the compiled Rust extension and uses it for all detection and masking operations.

Hook Signatures

All plugin hooks now accept an optional extensions parameter that carries OpenTelemetry trace context:

def prompt_pre_fetch(
    self,
    payload: typing.Any,
    context: typing.Any,
    extensions: typing.Any = None
) -> typing.Any: ...

def prompt_post_fetch(
    self,
    payload: typing.Any,
    context: typing.Any,
    extensions: typing.Any = None
) -> typing.Any: ...

def tool_pre_invoke(
    self,
    payload: typing.Any,
    context: typing.Any,
    extensions: typing.Any = None
) -> typing.Any: ...

def tool_post_invoke(
    self,
    payload: typing.Any,
    context: typing.Any,
    extensions: typing.Any = None
) -> typing.Any: ...

The extensions parameter is optional and defaults to None. When present, it carries OpenTelemetry trace context (e.g., trace_id), allowing plugins to emit metrics or observability data tied to the current trace.

Metrics and Observability

When a trace context is present (via extensions.request.trace_id), the plugin emits operational metrics on result.metadata["pii_filter"] with the following schema:

result.metadata["pii_filter"] = {
    "total_detections": 2,       # int — total number of PII detections in this call
    "total_masked": 2,           # int — total number masked/redacted
    "detection_types": ["email", "ssn"],  # list[str] — distinct type names, sorted, deduped
    "stage": "tool_post_invoke", # str — which hook stage emitted this
}

Gating: Metrics are only emitted when a valid trace_id is present in the trace context. The trace_id itself is an input (read from extensions.request.trace_id) and is never included in the output metrics.

Security Note (S1): The plugin never includes raw sensitive content in any output, logs, or metrics. All PII detection and masking operations are performed with the guarantee that sensitive values are redacted before any externalization.

Migration Note

Version 0.2.0 intentionally changes the built-in default masking policy from partial masking to redact. Set default_mask_strategy: "partial" explicitly if you need the previous behavior.

Version 0.2.1 changes custom-pattern inheritance: when custom_patterns[].mask_strategy is omitted or set to null/None, the pattern inherits default_mask_strategy instead of forcing redact.

Version 0.2.0 also tightens the default privacy posture for observability: detection logging is disabled unless you opt in with log_detections: true.

Version 0.2.1 validates default_mask_strategy and custom_patterns[].mask_strategy strictly. Invalid values that older builds silently treated as redact now fail fast during plugin initialization.

Version 0.3.6 is a breaking change for any existing consumer reading detection metadata:

  • The old context.metadata["pii_filter_stats"] and context.metadata["pii_detections"] channels have been removed entirely. There is no compatibility shim; code reading those keys will silently stop receiving data.
  • Detection/masking metrics are now emitted on result.metadata["pii_filter"] instead, with keys total_detections, total_masked, detection_types, and stage (see Metrics and Observability above for the full schema).
  • All plugin hooks (prompt_pre_fetch, prompt_post_fetch, tool_pre_invoke, tool_post_invoke) now accept a new optional extensions parameter carrying OpenTelemetry trace context. Emission to result.metadata["pii_filter"] is gated solely on extensions.request.trace_id being present and valid — if no trace context is supplied, no metrics are written at all, regardless of any config flag.
  • Consumers that previously read context.metadata["pii_filter_stats"] / context.metadata["pii_detections"] unconditionally must migrate to reading result.metadata["pii_filter"] and must pass a trace_id via extensions to receive metrics.

Detection Coverage

This section describes the current Rust detector behavior so users know what is intentionally matched and what is intentionally left alone. The detector is optimized to reduce noisy false positives, which means some generic identifiers are only matched when they appear with clear context labels.

Social Security Numbers (SSN)

Covers

  • Dashed US SSNs such as 123-45-6789
  • Compact 9-digit SSNs only when they appear with SSN-specific context such as SSN, Social Security, or Social Security Number
  • Structural validation that rejects impossible values such as 000-12-3456, 666-12-3456, 123-00-4567, and 123-45-0000

Does not cover

  • Bare 9-digit values without SSN context
  • Real-world identity verification or SSA-backed validation
  • Country-specific national identifiers outside the US SSN patterns

BSN (Dutch Citizen Service Number)

Covers

  • 9-digit BSNs when they appear with explicit Dutch/BSN-style context such as BSN, Citizen ID, Citizen Service Number, or Burgerservicenummer
  • Phrases such as My BSN is 123456789

Does not cover

  • Generic unlabeled 9-digit numbers
  • Generic business identifiers such as order numbers, invoice numbers, or tracking numbers unless they also use BSN-specific wording
  • Validation against authoritative Dutch registries

Credit Card Numbers

Covers

  • Common 13-19 digit card numbers with spaces or dashes
  • Luhn-valid numbers from the major issuer families currently recognized by the detector, including Visa, Mastercard, American Express, Discover, Diners Club, JCB, UnionPay, and Maestro

Does not cover

  • Numbers that fail Luhn validation
  • Arbitrary long digit strings that do not match a recognized card-prefix family
  • Full issuer-specific business rules beyond prefix and Luhn checks

Email Addresses

Covers

  • Standard email addresses such as alice@example.com
  • Full redaction by default, or partial masking when explicitly configured

Does not cover

  • Full RFC-complete email parsing
  • Mailbox ownership verification or domain reachability checks
  • Obfuscated emails such as alice at example dot com

Phone Numbers

Covers

  • Common US phone number formats such as 555-123-4567, (555) 123-4567, and 1 555 123 4567
  • International numbers with an explicit leading + and enough digits to look like an E.164-style value

Does not cover

  • Short local extensions or ambiguous local-only numbers
  • International numbers without a leading +
  • Country-by-country numbering-plan validation

IP Addresses

Covers

  • Standard IPv4 dotted-quad addresses
  • Fully expanded IPv6 addresses in the eight-group hexadecimal form

Does not cover

  • Shorthand IPv6 forms such as 2001:db8::1
  • Hostnames, URLs, or CIDR ranges
  • Private/public classification or network reachability checks

Dates of Birth

Covers

  • Explicitly labeled date-of-birth phrases such as DOB: 01/15/1990
  • Unlabeled dates in MM/DD/YYYY or MM-DD-YYYY form within the configured year range

Does not cover

  • Locale-specific date parsing beyond the built-in patterns
  • Natural-language dates such as 15 January 1990
  • Any proof that a matched date is actually a birth date when no DOB-style label is present

Passport Numbers

Covers

  • Passport identifiers only when they appear with explicit passport context such as Passport, Passport No, or Passport Number
  • Label-plus-value matches such as Passport Number: AB123456

Does not cover

  • Standalone alphanumeric IDs without passport wording
  • Country-specific passport validation rules
  • Broader travel-document types that do not use passport labels

Driver's License Numbers

Covers

  • Driver's license values with explicit labels such as DL, License, or Driver's License

Does not cover

  • Unlabeled alphanumeric identifiers
  • State-by-state or country-by-country license validation rules
  • Vehicle registration numbers or other transport-related IDs

Bank Account Numbers

Covers

  • Account numbers when they appear with explicit account-style context such as Account, Acct, Bank Account, or Account Number
  • IBAN-like values that match the built-in pattern

Does not cover

  • Bare 8-17 digit values without account context
  • Full IBAN country validation or checksum verification
  • Routing-number-only detection

Medical Record Numbers

Covers

  • Explicitly labeled medical record identifiers such as MRN or Medical Record

Does not cover

  • Unlabeled healthcare identifiers
  • Insurance member IDs, prescription IDs, or other healthcare-adjacent identifiers unless added through custom patterns
  • Validation against provider or hospital systems

Custom Patterns

Covers

  • User-defined regex patterns for organization-specific identifiers
  • Explicit per-pattern masking strategies
  • Guardrails that reject patterns that are too long or too complex for maintainable admin-authored configuration

Does not cover

  • Unlimited regex expressiveness
  • Automatic tuning of custom patterns for precision or recall
  • Protection against poor pattern choices that are syntactically valid but semantically too broad

Custom patterns are intended for trusted operators editing plugin configuration, not untrusted end-user input. The Rust implementation relies on the regex crate, which avoids catastrophic backtracking during matching, and then applies additional length and complexity limits to keep custom expressions readable and cheap to compile.

Security Notes

  • Detection logging is disabled by default. Enable it only if your logging pipeline is allowed to receive derived PII metadata.
  • OTel detection-detail metrics (result.metadata["pii_filter"]) are only emitted when a valid trace_id is present in the extensions hook parameter (extensions.request.trace_id); no trace context means no metrics are written. The include_detection_details config field does not gate this and is currently a reserved no-op.
  • Whitelist patterns are compiled case-insensitively.
  • Custom patterns must stay within basic length and complexity limits and are meant for trusted admin-authored configuration.
  • Very large strings and oversized nested collections are rejected instead of being scanned indefinitely.

Masking Notes

  • HASH masking emits the first 16 hexadecimal characters of a salted SHA-256 digest, for example [HASH:8f434346648f6b96].
  • Earlier releases emitted 8 hexadecimal characters. Update downstream parsers if they assumed the shorter fixed-width placeholder.

Testing

# Rust unit tests
make test

# Python tests
make test-python

# Benchmarks
make bench

Performance

Expected 5-10x speedup over Python implementation for typical payloads.

Metadata

Release files for cpex-pii-filter 0.3.10

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cpex-pii-filter 0.3.10
File Size Uploaded Provenance Actions
cpex_pii_filter-0.3.10.tar.gz 67.9 kB With provenance Details for cpex_pii_filter-0.3.10.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for cpex-pii-filter 0.3.10
File Actions
cpex_pii_filter-0.3.10-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details for cpex_pii_filter-0.3.10-cp311-abi3-win_amd64.whl
cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_x86_64.whl CPython 3.11 abi3 Linux glibc 2.34+ x86-64 Details for cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_x86_64.whl
cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_s390x.whl CPython 3.11 abi3 Linux glibc 2.34+ IBM System/390x Details for cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_s390x.whl
cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_ppc64le.whl CPython 3.11 abi3 Linux glibc 2.34+ PowerPC 64-le Details for cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_ppc64le.whl
cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_aarch64.whl CPython 3.11 abi3 Linux glibc 2.34+ ARM64 Details for cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_aarch64.whl
cpex_pii_filter-0.3.10-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details for cpex_pii_filter-0.3.10-cp311-abi3-macosx_11_0_arm64.whl

Total release size: 5.3 MB

Release files / cpex_pii_filter-0.3.10.tar.gz

Download URL cpex_pii_filter-0.3.10.tar.gz
Size 67.9 kB
Tags Source
SHA-256 checksum
How to use checksums
5760006a59762e158fdbd2a0c6a08229d33c8de1450f5250645e95284f560d5f
BLAKE2b-256 checksum
How to use checksums
204ef7f6479901b88f37aef743481ed1bea4e425b3d89b55eb2580c1fb95388e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

Release files / cpex_pii_filter-0.3.10-cp311-abi3-win_amd64.whl

Download URL cpex_pii_filter-0.3.10-cp311-abi3-win_amd64.whl
Size 828.8 kB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
b9efb045238db19ea3564ffdfad909a8da566873925ae6cc102cf205376b3143
BLAKE2b-256 checksum
How to use checksums
4b71ee97062f0971e99e50e0fb780c9bf8bb5be15cf036f5e96a698e301cb3f4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

Release files / cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_x86_64.whl

Download URL cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_x86_64.whl
Size 902.8 kB
Tags CPython 3.11 Linux glibc 2.34+ x86-64 abi3
SHA-256 checksum
How to use checksums
45e6e2d77e6e6b534b720e54beb50b4bada2f2c937a521b2664d4ea9533d0b4e
BLAKE2b-256 checksum
How to use checksums
66181ff1744ad88a420fe57facf4a90101ec306bf7a7abed10f207a7c562eef9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

Release files / cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_s390x.whl

Download URL cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_s390x.whl
Size 951.4 kB
Tags CPython 3.11 Linux glibc 2.34+ IBM System/390x abi3
SHA-256 checksum
How to use checksums
4005356a1146c6b17488f30f28fc838ebebb5694c252b16e1bedc0ac44991fca
BLAKE2b-256 checksum
How to use checksums
bbabfbfa35a8fa47013abdef435f89b11972f1cdd28c8770ed698640056480a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

Release files / cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_ppc64le.whl

Download URL cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_ppc64le.whl
Size 932.1 kB
Tags CPython 3.11 Linux glibc 2.34+ PowerPC 64-le abi3
SHA-256 checksum
How to use checksums
8be21d2708f09c12bcd5213b16267b729b93c95bf5aa91f55462d0d8e8c941c8
BLAKE2b-256 checksum
How to use checksums
bdb8a868febc1a5e768d16d9f87ddcef1e6a68ed7829e51683099ed7137b1531
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

Release files / cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_aarch64.whl

Download URL cpex_pii_filter-0.3.10-cp311-abi3-manylinux_2_34_aarch64.whl
Size 847.7 kB
Tags CPython 3.11 Linux glibc 2.34+ ARM64 abi3
SHA-256 checksum
How to use checksums
a5226f524a2ec90ce1ef38157d6295bfa6ed18a2720ffbaa361a75aa9c9beb4f
BLAKE2b-256 checksum
How to use checksums
2b92863d8f38304c3c549dc235582d393a10faa5751a933be79b019bcdfc2840
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

Release files / cpex_pii_filter-0.3.10-cp311-abi3-macosx_11_0_arm64.whl

Download URL cpex_pii_filter-0.3.10-cp311-abi3-macosx_11_0_arm64.whl
Size 786.8 kB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
5546d61b1d61d6f76d02bf413c779b7663fcedb27d0c66e06255145842a90b97
BLAKE2b-256 checksum
How to use checksums
5d4af9ff3e74b4a42f40dca70a05aec46b0ba5305c7565aa33136594850288a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

Security for cpex-pii-filter 0.3.10

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 7 files in this release have been uploaded with provenance metadata.

Select from 7 files

Attestation for cpex_pii_filter-0.3.10.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page