Skip to main content

Input Controls

HIPAA PHI Detector

hipaa-phi-detector replaces or blocks text that looks like protected health information before the model receives it: the base PII identifiers, plus names, medical record numbers, health plan IDs, and other HIPAA identifiers.

It is a text detector, not a guarantee of complete de-identification. The gateway also applies the HIPAA rules to streamed and buffered answers.

Configuration​

Save this as policy-config.yaml. Start with synthetic data on a test agent, with the config-first workflow.

policy-config.yaml
pack:
  name: hipaa-phi-detector
  version: "1.0.0"
  enabled: true

policies:
  chain:
    - hipaa-phi-detector

policy:
  hipaa-phi-detector:
    action: redact

Fields​

FieldTypeDefaultDescription
actionredact or blockredactWhat happens to a match in the request. redact replaces it and continues. block stops the request. For the response behavior of each value, see Output behavior.

action is the only field. Lint rejects the removed fields mode and safe_harbor_method.

What the detector finds​

Both sets are heuristic and text-only.

Base PII engine​

  • Email addresses
  • Social Security numbers
  • Phone numbers
  • Public IP addresses
  • URLs with paths or query strings
  • Dates
  • Account numbers
  • ZIP codes
  • License plates
  • MAC addresses, IMEI numbers, and vehicle identification numbers

HIPAA-oriented extensions​

  • Person names
  • Street addresses and city terms
  • Fax numbers
  • Medical record numbers
  • Health plan or policy identifiers
  • Certificate and driver's license numbers
  • Device identifiers and serial numbers
  • Biometric identifier terms in text
  • Photo or facial image terms in text

How it works​

  1. The gateway joins the request messages into one string.
  2. It runs the base PII detector and the HIPAA rules on it.
  3. No match: allow with hipaa_phi.clean.
  4. A match: the verdict that action selects, with the reason code of the first match.
  5. With redact, each match is replaced with a marker before dispatch.
  6. For a response, the gateway applies the output behavior of action. See Output behavior.
  7. The event records the first match type, its reason code and confidence, the detection count, and the confidence counts.

Output behavior​

With gateway 0.1.26 or later, the gateway applies these rules to the model response:

ConfigurationResponse
action: redactThe shared redaction pipeline runs with the HIPAA rules on. This applies to streamed and buffered Chat Completions, Responses, and Messages responses. A changed response has a nested hipaa_phi.detected result and the top-level reason redact.applied.
action: blockPHI in a streamed or buffered Chat Completions, Responses, or Messages response blocks the response. The reason code is the code of the first match, as on a request. A streamed response sends no text before the block.

A buffered response block returns HTTP 400 with the error code content_policy_violation. A buffered Messages block uses the Anthropic error shape. A streamed response block ends the stream with the error event of its API, with the code content_policy_violation. The request records the usage that the provider reports.

The nested redaction result names hipaa-phi-detector only when the chain has no pii-detector. See Output redaction reason codes.

Phase and verdicts​

ItemValue
Input phaseThe joined request messages
Output phaseResponse text, through the shared redaction pipeline or the block check
Verdictsallow, redact, block
Reason code without a matchhipaa_phi.clean
Reason codes for a matchThe code of the first match, such as phi.name_detected, phi.mrn_detected, or pii.ssn_detected
Reason code for output redactionhipaa_phi.detected

Examples​

Redact matching PHI-like content​

Test the configuration above offline:

Add to policy-config.yaml
testing:
  suites:
    - name: hipaa-phi-detector
      cases:
        - name: redacts-ssn
          input: {messages: [{role: user, content: "My SSN is 123-45-6789."}]}
          expected: {verdict: redact, reason_code: redact.applied}
        - name: redacts-mrn
          input: {messages: [{role: user, content: "Patient MRN: 12345678 needs a follow-up."}]}
          expected: {verdict: redact, reason_code: redact.applied}
        - name: allows-greeting
          input: {messages: [{role: user, content: "Hello"}]}
          expected: {verdict: allow, reason_code: ok}

All three pass. The nested results name the matches: pii.ssn_detected and phi.mrn_detected. A redact verdict does not show the forwarded text, so also send a synthetic identifier through a test gateway with a test upstream, and check that a marker replaced it.

Block PHI-like input before the model receives it​

Inside policy-config.yaml
policy:
  hipaa-phi-detector:
    action: block

Send the synthetic identifier again. The request stops before the provider call, and the runtime event names the match, such as pii.ssn_detected.

Limits and failure behavior​

  • This is a heuristic text detector. It does not prove HIPAA Safe Harbor de-identification.
  • Images, audio, and other non-text data are not examined.
  • It does not control access. Use RBAC for minimum-necessary rules.
  • In the response pass, the gateway turns the HIPAA rules on and the PCI rules off. This applies to streamed and buffered responses.
  • For streamed responses, the gateway buffers the whole answer before it sends it. With action: redact, the gateway redacts the answer. With action: block and gateway 0.1.26 or later, PHI in the answer blocks the stream.
  • With action: block, the gateway examines a streamed Chat Completions or Responses answer when the provider marks the end of the output. If the provider closes the stream without that marker, the gateway redacts the answer and does not block it. A Messages stream is always examined at the end.
  • When the chain also has pii-detector, the response redaction event names pii-detector as the policy type, with pii.detected.

Next steps​