Skip to main content

Module dlp

Module dlp 

Source
Expand description

Edge DLP — PII / secret detection and redaction (gateway L3).

Extends the WAF-lite idea (crate::waf) from “is this request an attack” to “does this payload contain data that must not leave (or arrive)”. Three detector families, fastest-first:

  • signature detectors — linear-time regex patterns for well-shaped secrets and PII (provider keys, AWS keys, private-key blocks, emails, card-like numbers, SSNs, phones, IBANs). A signature may carry a post-match validator (e.g. the Luhn check for card numbers) so a digit run that doesn’t checksum is not flagged.
  • a gazetteer detector — an aho_corasick automaton over an operator-supplied term list (known customer names, project codenames, internal identifiers). Linear-time, many-term, the dictionary half Presidio leans on a deny-list for.
  • an entropy detector — flags long, high-Shannon-entropy tokens that look like credentials but match no signature (a catch-all; off by default since it can false-positive).

When the optional ner cargo feature is built, a fourth family — a small ONNX NER model (GLiNER / DeBERTa class, via the pure-Rust [edgeguard_ner] crate) — runs over the buffered text to catch the entities regex can’t: person, address, org. The NER family is the slow part and is never run on the streaming path; the always-present signature/gazetteer/entropy fast path is what actually enforces on a stream. With the ner feature off, the engine is byte-for-byte the deterministic-only engine and pulls no ML dependency (the single-static-binary promise).

Four modes, a report-first rollout ladder:

  • off — disabled.
  • report — detect, count, log; pass the payload through unchanged.
  • block — a request with a finding is rejected 403; a response is withheld.
  • redact — each finding’s span is rewritten per the configured RedactStyle; the payload flows on. The default style is [REDACTED:<category>]; mask keeps the last four characters, hash emits a stable opaque token so the same value redacts identically everywhere.

The engine here is pure (no I/O on the deterministic path): scan returns the findings and redact rewrites them. The proxy applies it to the inbound request body and the (buffered) response body; streaming responses are scanned frame-by-frame with a carry buffer so a secret split across two SSE frames is still caught.

All regexes are the linear-time regex crate (no backtracking), so a crafted payload can’t cause catastrophic blowup — the same ReDoS-safety the WAF relies on.

Structs§

DlpEngine
The compiled DLP engine. Built once per config (re)load and carried on the proxy Runtime.
Finding
One detected span: [start, end) byte offsets into the scanned text, its category, and a detector confidence in [0.0, 1.0]. Deterministic detectors (signature / gazetteer / entropy) always report 1.0; the NER family reports the model’s per-entity probability so it can be thresholded and audited.
MaskMap
A reversible mask map: the placeholder↔original mapping built while redacting an inbound request, used to unmask the response (buffered and streamed) back to the caller’s own values. The provider only ever sees placeholders; the client gets its data restored — the round-trip an irreversible [REDACTED] tag (and any unmask that can restore another caller’s value) cannot do.

Enums§

DlpMode
What to do when a payload has a finding.
RedactStyle
How a redacted span is rewritten in redact mode.

Constants§

CATEGORIES
Stable category labels (also the metric label and the [REDACTED:<category>] tag). A fixed set, so the metric cardinality is bounded. Keep in sync with DLP_CATEGORIES in crate::metrics.