Skip to main content

PII Checker User Guide

中文版

PII Checker detects personal data and credentials in Agent inputs and outputs. It returns a structured verdict, produces safe evidence and optional redacted text, and records sanitized Security Events for audit and Observability correlation.

Scan text

Provide exactly one input source: inline text, standard input, or a UTF-8 file.

# Inline text
agent-sec-cli scan-pii --text "contact alice@example.com"

# Standard input
printf '%s' 'token=secret-value-1234567890' \
| agent-sec-cli scan-pii --stdin --redact-output

# UTF-8 file
agent-sec-cli scan-pii --input ./agent-output.txt --format text

Useful options:

OptionPurpose
--format json|textSelect structured JSON or human-readable output; default is json
--redact-outputInclude redacted_text; the input file is never modified
--include-low-confidenceInclude findings below the default confidence threshold
--raw-evidenceInclude raw evidence in local CLI output only
--max-bytes NScan at most N UTF-8 bytes and mark the result as truncated
--source SOURCELabel the audit context, such as user_input or tool_output

Supported source labels are user_input, tool_input, tool_output, model_output, observability, manual, and unknown.

Built-in detection

The built-in detector combines regex matching, format validation, and context-based confidence adjustment.

CategoryTypesDefault severity
Personal dataemail, phone_cn, credit_card, cn_idwarn
Credentialsprivate_key, bearer_token, api_key, jwtdeny
Alibaba Cloud credentialsaliyun_access_key_id, aliyun_access_key_secretdeny
Secret fieldsgeneric_secret_fielddeny

Credit card, Chinese ID, and JWT candidates are validated before becoming findings. Surrounding security keywords can increase confidence, while fixture markers such as example, dummy, test, and sample can lower it. Findings below the default 0.5 threshold are omitted unless --include-low-confidence is set.

Verdicts and redaction

The scanner aggregates findings into one verdict:

VerdictMeaning
passNo finding remains after confidence filtering
warnFindings exist, but none has deny severity
denyAt least one finding has deny severity

Each finding includes its type, category, severity, confidence, span, detector metadata, and redacted evidence. --redact-output also returns a redacted copy of the scanned text. Overlapping findings are preserved, while their overlapping spans are merged and replaced once. If different spans overlap, the complete merged range is fully redacted so a shorter match cannot leave a sensitive suffix visible.

--raw-evidence is intended only for local troubleshooting. Raw evidence is never written to Security Events. Host integrations consume the same verdict and finding schema; whether a host only observes a finding or blocks an operation depends on that host's configured PII policy.

Host hook policy

Set PII_CHECKER_HOOK_ENABLED=false to skip host PII hooks entirely. When enabled, PII_CHECKER_MODE accepts observe, warn, ask, or block and defaults to observe. ask or block falls back to warn when the host or hook event cannot enforce that action; post-execution hooks never claim to undo an external side effect. The environment policy overrides Hermes/OpenClaw capability configuration. debug maps to observe, and deny maps to block. Qwen Code additionally accepts the legacy PII_CHECKER_ENABLED switch when PII_CHECKER_HOOK_ENABLED is absent.

The host Agent reads these variables when it loads the plugin. Restart the Agent process that hosts the hook after changing them; the hook and agent-sec-core are not separate policy services.

Scanner verdict deny describes finding severity. Hook policy block controls whether the current adapter attempts enforcement.

Custom regex rules

PII Checker optionally loads custom business-specific types from one fixed user-level file:

~/.config/agent-sec/pii-checker/rules.yaml

The YAML top level is a list. Each rule contains a unique custom type, one regex, and an optional severity.

- type: dogfood_order_no
regex: '(?i)(?<=order_no[=:])DFT-[A-Z0-9]{8}'
severity: warn

- type: dogfood_customer_token
regex: 'DFT-[A-Z0-9]{16}'
severity: deny
FieldRequiredDescription
typeYesLowercase snake_case custom type, unique within the file
regexYesOne regex expression; use inline flags such as (?i)
severityNowarn or deny; defaults to deny

The complete regex match is the finding and redaction span. Capture groups and named capture groups do not change that span. If a regex matches both a field name and its value, both are redacted. Use lookaround when the full match must cover only the value. Multiple formats for one type must be combined with regex alternation (\|); the same type cannot appear in multiple rules.

Custom findings use category custom, confidence 1.0, detector custom_rule, and engine regex. They are fully redacted with a stable type marker such as [DOGFOOD_ORDER_NO_REDACTED] and flow through the same verdict, policy, Security Event, and Observability paths as built-in findings.

No CLI option, environment variable, XDG override, system-level file, or multi-file merge is supported for the custom rules path.

Custom rule validation and runtime limits

The complete custom ruleset is accepted or rejected as one unit.

Limit or ruleValue
Maximum file size256 KiB
Maximum number of rules100
Maximum regex length2,048 characters
Maximum regex group nesting depth64
Type format^[a-z][a-z0-9_]{0,63}$
Allowed severitywarn or deny
Per-rule matching timeout20 ms
Total custom matching budget per scan200 ms
Maximum custom findings per scan100

Unknown YAML fields, duplicate types, built-in type names, invalid regexes, and regexes that match an empty string make the complete custom ruleset invalid. Other zero-length matches encountered at runtime are ignored.

Rules with deny severity run before warn rules. File order is preserved within each severity. The 100-finding limit caps emitted custom findings but does not stop evaluation of later rules; truncated becomes true only when an additional valid match is omitted. Per-rule or total time limits may still stop the remaining custom rules and are reported separately.

When the file content changes, the next scan validates and compiles the new content automatically. If the new version is invalid, the previous valid version is not reused. Built-in detection remains active and scan-pii still completes successfully.

Custom rule status

Every default scan includes sanitized custom rule state in summary.custom_rules:

{
"custom_rules": {
"status": "loaded",
"rule_count": 2,
"runtime_error_count": 0,
"budget_exhausted": false,
"truncated": false
}
}

status is absent when the file does not exist, loaded when validation succeeds (including an empty list), and invalid when reading, YAML parsing, schema validation, or regex compilation fails. An invalid status includes a sanitized error_code; loaded or invalid content may include its SHA-256 digest. Runtime counters do not contain input text or regex content. A direct scan-pii invocation also prints a sanitized invalid-configuration warning to stderr while still exiting successfully.

The current error_code values are:

Error codeMeaning
read_errorThe rules file could not be read
file_too_largeThe rules file exceeds 256 KiB
invalid_utf8The rules file is not valid UTF-8
invalid_yamlThe YAML content cannot be parsed safely
top_level_not_listThe YAML top level is not a list
too_many_rulesThe file contains more than 100 rules
invalid_rule_schemaA rule has missing, unknown, incorrectly typed, or unsupported fields
invalid_rule_typeA rule type does not match the required naming format
duplicate_rule_typeThe same custom type appears more than once
reserved_rule_typeA custom type conflicts with a built-in PII type
invalid_regexA regex cannot be compiled, exceeds 64 nested groups, or its load-time validation times out
regex_matches_empty_textA regex can produce a zero-length match on an empty string
load_errorAn unexpected loader error was handled in fail-open mode

Security Events and Observability

Every scan follows the existing pii_scan Security Event path. Events contain the source, verdict, summary, finding type, severity, category, span, and redacted evidence. They do not contain the custom rules path, regex expressions, or raw sensitive matches.

Host hooks remain fail-open when custom rules are invalid and do not add a separate host warning. The sanitized summary.custom_rules state in the Security Event is the structured audit source for hook invocations.

Observability uses the existing trace context and input hash to correlate telemetry with the Security Event instead of storing another copy of finding details.