Skip to main content

DLP scanner — data classes & strict mode

The outbound message scanner runs on every channel (SMS, MMS, WhatsApp, email, RCS, and IM routes) and flags regulated identifiers in a message body before it dispatches. This page covers the data classes it detects, why its false-positive rate is deliberately low, how a finding becomes a send gate, and how it differs from the transcript scrubber that strips personal data out of stored agent conversations.
The scanner is a tenant-owned control. Its categories and response mode are scoped to your organization, and on a send the policy enforcement mode you picked (warn, strict, or off) decides what a finding does. HIPAA and PCI-DSS define the obligation; this control is one way to enforce part of it on the message lane.

What the scanner detects

Four categories ship, each built to avoid false positives: The default set is credit_card, ssn, and iban — the payment and identity data most likely to put a message outside PCI, HIPAA, or GDPR policy. passport is added on request. You keep the default unless you opt into passport or narrow the set for a conversation you have already vetted.

Why checksum validation matters for a strict-mode organization

strict mode turns every scanner block verdict into a refused send. A loose detector would take legitimate messages down with it. Every category above validates a candidate twice — shape, then checksum or the registry ranges — before it counts, so grouped digits, order ids, and tracking codes don’t trip the gate. The one class that shape alone can’t pin (a bare alphanumeric token) is kept out of the default set entirely rather than risked on vague matching. This is why strict is safe to leave on for the whole workspace: the scanner refuses actual card/identity data, not numerals or account-shaped strings.

How a finding becomes the verdict

The DLP rule rolls its hits up through the policy scanner, the pre-send gate that also checks TCPA quiet hours, SHAFT content, spam keywords, opt-out phrasing, and country sender rules. All channels run it, because a card number is sensitive on SMS, WhatsApp, email, and RCS alike. The scanner emits a dlp violation on a hit, and in its default block mode the violation raises the verdict to block. What happens next depends on two settings:
  • Your organization’s policy enforcement mode (the warn / strict / off switch covered in the policy scanner page): in warn (default) the send proceeds and the finding is recorded; in strict it is refused with POLICY_VIOLATION.
  • The DLP category mode (block / redact / warn / off): block (default) raises the block verdict; warn flags without raising the verdict; redact strips the sensitive value before dispatch as a flagged send; off turns the DLP check out for your organization.
The DLP scanner ships as the dlp-scanner module in the @devotel/compliance package; the send-path verdict comes from the sibling policy scanner that folds every rule into one outcome.

Tuning the scanner for your organization

The DLP rule is a tenant-owned control, and its knobs live in your organization’s scanner settings:
  • mode — one of block (default), redact, warn, or off. It decides what a finding does on the verdict chain in the next section.
  • categories — the scanned set. The platform floor is credit_card, ssn, iban; list passport explicitly (or set the dedicated passport opt-in flag alongside) to add the context-gated passport detector, and drop a category to narrow the set for a lane you have already vetted.
  • Precedence — a setting you omit falls back to the floor: no mode entry means block, and an empty or absent categories list means the three default categories. You never turn the floor down by omission; off is the only way to take the rule out entirely.
The write surface for these settings is read-only on the public API today: the policy scan mode endpoint is the only self-serve compliance toggle, and a DLP change goes through support. Ask support to set the mode and category floor above; the change applies on the very next scan and is recorded on your audit feed so the change is visible next to the mode switch’s own settings.policy_scan_mode_updated entry.

Choosing a polarity, and what comes back

Positives are already rare — every category validates twice before it counts — so the mode is a statement about what your posture does with a hit, not about tolerances.
One draft body, four different response shapes depending on the mode: A HIPAA-coverage tenant that collects identity documents adds passport and keeps block. A PCI-coverage tenant that has already vetted a lane narrows to the categories its posture actually lists, or drops to warn while it watches the hit count. Pick redact when the stream of accidental pastes is high enough that hard-blocked retries cost you more than the residual ambiguity of a redacted body.

Audit and false-positive remediation

Every block-verdict refusal writes one audit event, policy.message_blocked, carrying the channel, the verdict, and the violated rule names — no matched text, ever (the Privacy posture section). It sits on the same tamper-evident audit chain as the settings changes above, so an operator reading a content complaint has the mode flip and the refusal in one feed. On a block, work it as a review queue, not a retry loop:
  1. Read the finding — the violations list on the send error (or in your audit feed) names the rule dlp_sensitive_data and its category; the X-Policy-Violations header on a flagged send carries the category and its character offsets only.
  2. Confirm it is a real hit, not an order id or tracking code — the checksum and registry checks in What the scanner detects already reject numerals that fail validation; a candidate that still fired passed both halves, so treat it as a true positive unless you can identify the exact source value.
  3. Fix the message, not the gate — rewrite the body to move the regulated value to a secure channel (a hosted payment page or form), and the send that would have been refused goes out clean.
  4. If the value really must travel — that is the signal the lane is mis-routed, not the detector. Move the flow to an API surface you own end-to-end; never position a waiver as the fix.
Manual override of a block verdict is not a public control: there is no “send anyway” flag, no per-message waiver parameter, and no operator UI that lets a refusal through on a strict-mode send. The tenant-level changes above (tuning categories or stepping block → redact/warn) are the only supported remediations, and off is the only removal — use it knowing it leaves the universal PCI/HIPAA/GDPR floor unenforced on the lane.

Privacy posture

A finding tells you where and what, not the matched value. Each hit carries a character span (start and end offsets) and a category label only — the scanner never returns the offending text. The same is true when you run redact: matched spans are substituted with typed sentinel tokens ([REDACTED_CARD], [REDACTED_SSN], [REDACTED_IBAN], [REDACTED_PASSPORT]). The detector therefore can’t leak a card or identity number into logs, response headers, or the audit trail, and it stays safe to run on every send and on every keystroke of the compose-time linter.

Putting it to work

Enable a category. By default the floor is credit_card, ssn, iban. A HIPAA tenant that collects identity documents can opt into passport; a PCI tenant who has already vetted a lane can reduce the categories to exactly the cards and accounts its policies allow. The scanner accepts only the four shipped categories. Compose a clean message. A marketing body must not carry a PAN. When a customer’s payment or identity data is pasted in, the pre-send POST /api/v1/messages/lint call flags it as block before anything dispatches, so the author rewrites the body. In strict mode the same refusal comes back on the send call itself, so the message never got sent. Live linting and agent drafts. The agent or dashboard compose UI calls /messages/lint debounced as text is typed, and gets the same verdict and violations back without sending anything. An AI agent draft goes through the same call, so a generated card or identity number is caught before it ever reaches a customer.

DLP vs. the transcript scrubber

The DLP scanner is a send gate: it refuses or flags regulated data at send time. The transcript scrubber (@devotel/shared/utils/pii, the redactPii family) is a storage gate: it strips personal data from agent conversation transcripts as they are inserted so the stored record never holds the original text. The tradeoffs differ with the job:
  • The transcript scrubber is destructive — the original text is gone from the stored row — so it tolerates some false positives rather than hold up a conversation write.
  • The DLP send gate must stay precise and auditable, so it validates twice and keeps the scan synchronous and offset-only; an AI agent or customer gets a block/warn verdict it can act on, not a silent rewrite.
Use both: the transcript scrubber keeps stored agent conversations clean, and the DLP rule stops regulated data from leaving in the first place. The two scopes meet only inside the scanner’s send-path verdict.