Usage Guide
Complete guide to CloakLLM — installation, configuration, middleware integration, audit logs, and more.
PII protection middleware for LLMs — detect, tokenize, and audit before prompts leave your infrastructure.
Table of Contents
- Installation
- Quick Start
- How It Works
- Configuration Reference
- Multi-Turn Conversations
- Batch Processing
- Performance Metrics
- Redaction Mode
- Custom Patterns
- LLM-Powered Detection (Ollama)
- Custom LLM Categories
- Multi-Language Detection
- Entity Hashing
- Incremental Streaming
- Cryptographic Attestation
- Entity Detection Reference
- CLI
- Audit Logs
- Security
- Context Risk Analysis
- Token Specification
- Pluggable Detection Backends
- Article 12 Compliance Mode
- Enterprise Key Management
- Disabling / Re-enabling
Installation
Python
For LiteLLM middleware integration:
Requires Python 3.10+.
JavaScript
Zero runtime dependencies. Requires Node.js 18+.
MCP Server
Depends on cloakllm (the Python SDK).
Quick Start
Python — OpenAI SDK
One line to wrap your OpenAI client:
Python — LiteLLM
One line to protect all your LLM calls:
Python — Standalone Shield
Use the Shield directly without any LLM framework:
JavaScript — OpenAI SDK
One line to wrap your OpenAI client:
JavaScript — Vercel AI SDK
Use as language model middleware:
JavaScript — Standalone Shield
Use the Shield directly without any LLM framework:
MCP — Claude Desktop
Important: MCP tools are called by the LLM, not before it. Your prompt is sent to the LLM provider first, then the LLM decides to call CloakLLM's tools. This means the MCP server cannot prevent PII in your prompt from reaching the provider. It is useful for sanitizing data the LLM works with during a conversation (documents, files, tool outputs). To protect prompts before they leave your infrastructure, use the SDK middleware instead (
enable_openai/cloakllm.enable()).
Add CloakLLM to your claude_desktop_config.json:
Or using uvx:
The MCP server exposes 6 tools:
sanitize — Detect and cloak PII, returns sanitized text + token map ID.
sanitize_batch — Sanitize multiple texts with a shared token map.
desanitize — Restore original values using a token map ID.
desanitize_batch — Restore original values in multiple texts using a shared token map.
analyze — Detect PII without cloaking.
analyze_batch — Analyze multiple texts for PII without cloaking.
How It Works
CloakLLM uses a multi-pass detection pipeline to find PII before it reaches an LLM provider. The pipeline is built from pluggable backends — you can replace or extend any stage (see Pluggable Detection Backends).
Default 3-Pass Detection
-
Regex (both SDKs) — High-precision pattern matching for structured data: emails, SSNs, credit cards, phone numbers, IP addresses, API keys, AWS keys, JWTs, IBANs.
-
spaCy NER (Python only) — Named entity recognition for names, organizations, and locations (PERSON, ORG, GPE). The JS SDK does not include spaCy; instead, these categories are handled by the optional Ollama LLM pass.
-
Ollama LLM (opt-in, both SDKs) — Local LLM-based semantic detection for contextual PII: addresses, dates of birth, medical terms, financial data, and more. Data never leaves your machine.
Tokenization
Detected entities are replaced with deterministic tokens in [CATEGORY_N] format:
john@acme.com→[EMAIL_0]Sarah Johnson→[PERSON_0]123-45-6789→[SSN_0]
Tokens are deterministic — the same input produces the same token within a session. A TokenMap stores the bidirectional mapping and can be reused across multi-turn conversations.
Token injection is prevented by escaping fullwidth brackets in user input.
The TokenMap also exposes entity_details (Python) / entityDetails (JS) — per-entity metadata (category, offsets, confidence, source, token) without original text. Use to_report() / toReport() for a full summary suitable for compliance dashboards.
Audit Logs
Every sanitize/desanitize operation is logged to hash-chained JSONL files:
- No PII stored — only hashes and token counts
- Tamper-evident — each entry's
prev_hashlinks to the previous entry'sentry_hash(SHA-256) - Genesis hash — first entry links to
"0" * 64 - Designed for EU AI Act Article 12 compliance
Configuration Reference
Python ShieldConfig
| Option | Type | Default | Env Var | Description |
|---|---|---|---|---|
spacy_model | str | "en_core_web_sm" | CLOAKLLM_SPACY_MODEL | spaCy model for NER |
ner_entity_types | set[str] | {"PERSON", "ORG", "GPE", "LOC", "FAC", "NORP", "EMAIL", "PHONE"} | — | Entity types for spaCy NER |
detect_emails | bool | True | — | Detect email addresses |
detect_phones | bool | True | — | Detect phone numbers |
detect_ssns | bool | True | — | Detect Social Security Numbers |
detect_credit_cards | bool | True | — | Detect credit card numbers |
detect_api_keys | bool | True | — | Detect API keys |
detect_ip_addresses | bool | True | — | Detect IP addresses |
detect_iban | bool | True | — | Detect IBAN numbers |
custom_patterns | list[tuple[str, str]] | [] | — | Custom (name, regex) patterns |
llm_detection | bool | False | CLOAKLLM_LLM_DETECTION | Enable Ollama LLM detection |
llm_model | str | "llama3.2" | CLOAKLLM_LLM_MODEL | Ollama model name |
llm_ollama_url | str | "http://localhost:11434" | CLOAKLLM_OLLAMA_URL | Ollama server URL |
llm_timeout | float | 10.0 | — | LLM request timeout (seconds) |
llm_confidence | float | 0.85 | — | Confidence threshold for LLM detections |
custom_llm_categories | list[tuple[str, str]] | [] | — | Custom (name, description) categories for LLM detection |
llm_allow_remote | bool | False | CLOAKLLM_LLM_ALLOW_REMOTE | Allow non-localhost Ollama URLs (SSRF prevention) |
locale | str | "" | — | Locale for country-specific PII patterns (e.g., "de", "fr") |
entity_hashing | bool | False | CLOAKLLM_ENTITY_HASHING | Enable per-entity HMAC-SHA256 hashing |
entity_hash_key | str | None | CLOAKLLM_ENTITY_HASH_KEY | HMAC key (auto-generated if omitted) |
context_analysis | bool | False | CLOAKLLM_CONTEXT_ANALYSIS | Enable automatic context risk analysis |
context_risk_threshold | float | 0.7 | — | Risk score threshold for warnings |
descriptive_tokens | bool | True | — | [PERSON_0] vs [TKN_A3F2] |
audit_enabled | bool | True | — | Enable audit logging |
log_dir | Path | ./cloakllm_audit | CLOAKLLM_LOG_DIR | Audit log directory |
otel_enabled | bool | False | CLOAKLLM_OTEL_ENABLED | Enable OpenTelemetry |
otel_service_name | str | "cloakllm" | OTEL_SERVICE_NAME | OTel service name |
auto_mode | bool | True | — | Auto-sanitize in middleware |
mode | str | "tokenize" | — | "tokenize" (reversible) or "redact" (irreversible) |
skip_models | list[str] | [] | — | Model prefixes to skip |
JavaScript ShieldConfig
| Option | Type | Default | Env Var | Description |
|---|---|---|---|---|
detectEmails | boolean | true | — | Detect email addresses |
detectPhones | boolean | true | — | Detect phone numbers |
detectSsns | boolean | true | — | Detect Social Security Numbers |
detectCreditCards | boolean | true | — | Detect credit card numbers |
detectApiKeys | boolean | true | — | Detect API keys |
detectIpAddresses | boolean | true | — | Detect IP addresses |
detectIban | boolean | true | — | Detect IBAN numbers |
customPatterns | Array<{name, pattern}> | [] | — | Custom regex patterns |
llmDetection | boolean | false | CLOAKLLM_LLM_DETECTION | Enable Ollama LLM detection |
llmModel | string | "llama3.2" | CLOAKLLM_LLM_MODEL | Ollama model name |
llmOllamaUrl | string | "http://localhost:11434" | CLOAKLLM_OLLAMA_URL | Ollama server URL |
llmTimeout | number | 10000 | — | LLM request timeout (ms) |
llmConfidence | number | 0.85 | — | Confidence threshold for LLM detections |
customLlmCategories | Array<{name, description?}> | [] | — | Custom categories for LLM detection |
llmAllowRemote | boolean | false | CLOAKLLM_LLM_ALLOW_REMOTE | Allow non-localhost Ollama URLs (SSRF prevention) |
locale | string | "" | — | Locale for country-specific PII patterns (e.g., "de", "fr") |
entityHashing | boolean | false | CLOAKLLM_ENTITY_HASHING | Enable per-entity HMAC-SHA256 hashing |
entityHashKey | string | undefined | CLOAKLLM_ENTITY_HASH_KEY | HMAC key (auto-generated if omitted) |
contextAnalysis | boolean | false | CLOAKLLM_CONTEXT_ANALYSIS | Enable automatic context risk analysis |
contextRiskThreshold | number | 0.7 | — | Risk score threshold for warnings |
descriptiveTokens | boolean | true | — | [PERSON_0] vs opaque tokens |
auditEnabled | boolean | true | — | Enable audit logging |
logDir | string | "./cloakllm_audit" | CLOAKLLM_LOG_DIR | Audit log directory |
autoMode | boolean | true | — | Auto-sanitize in middleware |
mode | string | "tokenize" | — | "tokenize" (reversible) or "redact" (irreversible) |
skipModels | string[] | [] | — | Model prefixes to skip |
Environment Variables
These work across all three SDKs:
| Variable | Default | Description |
|---|---|---|
CLOAKLLM_LOG_DIR | ./cloakllm_audit | Audit log directory |
CLOAKLLM_LLM_DETECTION | false | Enable LLM-based detection |
CLOAKLLM_LLM_MODEL | llama3.2 | Ollama model for LLM detection |
CLOAKLLM_OLLAMA_URL | http://localhost:11434 | Ollama server URL |
CLOAKLLM_LLM_ALLOW_REMOTE | false | Allow non-localhost Ollama URLs |
CLOAKLLM_SPACY_MODEL | en_core_web_sm | spaCy model (Python only) |
CLOAKLLM_ENTITY_HASHING | false | Enable per-entity HMAC-SHA256 hashing |
CLOAKLLM_ENTITY_HASH_KEY | (auto-generated) | HMAC key for entity hashing |
CLOAKLLM_CONTEXT_ANALYSIS | false | Enable automatic context risk analysis |
CLOAKLLM_AUDIT_ENABLED | true | Enable/disable audit logging (MCP) |
CLOAKLLM_OTEL_ENABLED | false | Enable OpenTelemetry (Python only) |
OTEL_SERVICE_NAME | cloakllm | OpenTelemetry service name (Python only) |
Multi-Turn Conversations
Reuse the token map across turns so the same entities always map to the same tokens.
Python
JavaScript
Batch Processing
Sanitize multiple texts at once with a shared token map and a single audit entry. Same entities across texts get the same token.
Python
JavaScript
MCP
Use the sanitize_batch tool:
Key Behaviors
- Shared token map: Same entity in different texts gets the same token
- Single audit entry: One
sanitize_batchevent instead of N separatesanitizeevents - Per-text entity tracking: Each entity detail includes a
text_indexfield indicating which text it came from - Reusable token map: Pass
token_map/tokenMapfrom a previous call for multi-turn batch conversations
Performance Metrics
Track detection performance with per-pass timing breakdowns in audit logs and accumulated metrics via the metrics() API.
Per-Pass Timing in Audit Logs
Every audit entry includes a timing object with per-pass breakdowns:
Accumulated Metrics API
Use metrics() to get accumulated performance stats across all calls, and reset_metrics() / resetMetrics() to clear them.
Python
JavaScript
Redaction Mode
Redaction mode provides irreversible PII removal — entities are replaced with [CATEGORY_REDACTED] placeholders instead of numbered tokens. No token map is stored, so the original values cannot be recovered. This is designed for GDPR right-to-erasure and scenarios where you must guarantee PII is permanently destroyed.
Python
JavaScript
MCP
Pass mode: "redact" to the sanitize tool. No token_map_id is returned in redact mode.
Key Behaviors
- Token format:
[CATEGORY_REDACTED](e.g.,[EMAIL_REDACTED],[PERSON_REDACTED]) - Token map is empty — no bidirectional mappings stored
desanitize()returns the input unchanged (no-op)- Audit log entries include
"mode": "redact"for traceability
Custom Patterns
Add your own regex patterns to detect domain-specific PII.
Python
JavaScript
LLM-Powered Detection (Ollama)
Both SDKs support an optional local LLM pass via Ollama for detecting PII that requires contextual understanding.
Enabling
Or via environment variable:
What It Catches
| Category | Examples |
|---|---|
ADDRESS | 742 Evergreen Terrace, Springfield |
DATE_OF_BIRTH | born January 15, 1990 |
MEDICAL | diabetes mellitus, blood type A+ |
FINANCIAL | account 4521-XXX, routing 021000021 |
NATIONAL_ID | TZ 12345678 |
BIOMETRIC | fingerprint hash F3A2... |
USERNAME | @johndoe42 |
PASSWORD | P@ssw0rd123 |
VEHICLE | plate ABC-1234 |
In the JS SDK, the LLM pass also detects PERSON, ORG, and GPE (since JS has no spaCy NER).
Configuration
| Option | Python | JavaScript | Default |
|---|---|---|---|
| Model | llm_model | llmModel | "llama3.2" |
| Server URL | llm_ollama_url | llmOllamaUrl | "http://localhost:11434" |
| Timeout | llm_timeout | llmTimeout | 10.0s / 10000ms |
| Confidence | llm_confidence | llmConfidence | 0.85 |
If Ollama is not running, the LLM pass is silently skipped.
Custom LLM Categories
Define domain-specific PII types that the Ollama LLM pass should detect. This extends the built-in LLM categories (ADDRESS, MEDICAL, etc.) with your own semantic types.
Python
JavaScript
MCP
Pass custom_llm_categories as a JSON string of [name, description] pairs:
Key Behaviors
| Behavior | Details |
|---|---|
| Name validation | Must match ^[A-Z][A-Z0-9_]*$ (Python enforces at config time) |
| Excluded categories | Categories handled by regex/NER (EMAIL, PHONE, SSN, etc.) are skipped with a warning |
| Description hints | Descriptions are injected into the Ollama system prompt to guide detection |
| Requires LLM detection | llm_detection / llmDetection must be enabled for custom categories to take effect |
Multi-Language Detection
CloakLLM supports locale-specific PII detection for 13 non-US locales. Setting a locale activates country-specific regex patterns for SSNs, phone numbers, IBANs, tax IDs, and national IDs. In Python, it also auto-selects the appropriate spaCy NER model for that language.
Supported Locales
| Locale | Country | Example Patterns |
|---|---|---|
de | Germany | Steuer-IdNr, Personalausweis, DE phone, DE IBAN |
fr | France | NIR (INSEE), carte d'identite, FR phone, FR IBAN |
es | Spain | DNI/NIE, ES phone, ES IBAN |
it | Italy | Codice Fiscale, IT phone, IT IBAN |
pt | Portugal | NIF, PT phone, PT IBAN |
nl | Netherlands | BSN, NL phone, NL IBAN |
pl | Poland | PESEL, NIP, PL phone, PL IBAN |
se | Sweden | Personnummer, SE phone, SE IBAN |
no | Norway | Fodselsnummer, NO phone, NO IBAN |
dk | Denmark | CPR-nummer, DK phone, DK IBAN |
fi | Finland | Henkilotunnus, FI phone, FI IBAN |
gb | United Kingdom | NINO, GB phone, GB IBAN |
au | Australia | TFN, AU phone |
Python
JavaScript
Key Behaviors
- spaCy model auto-selection (Python only): Each locale maps to the appropriate spaCy language model (e.g.,
deusesde_core_news_sm,frusesfr_core_news_sm). Install the model withpython -m spacy download <model_name>. - Pattern replacement: Locale-specific patterns replace the default US-centric patterns for SSN, phone, and similar categories.
- Composable: Locale patterns work alongside custom patterns, LLM detection, and entity hashing.
- Default: When no locale is set (empty string), US patterns are used.
Entity Hashing
Per-entity HMAC-SHA256 hashing enables cross-request entity correlation without storing PII. Each detected entity gets a deterministic, keyed hash — the same entity always produces the same hash, allowing you to track "the same person appeared in 47 requests" without knowing who.
Python
JavaScript
MCP
Pass entity_hashing and optionally entity_hash_key to the sanitize tool:
How It Works
- HMAC-SHA256:
HMAC(key, "CATEGORY:normalized_text")— keyed hash prevents rainbow table attacks - Category prefix:
EMAIL:john@acme.comandPERSON:john@acme.comproduce different hashes, preventing cross-type collisions - Normalization: Input is lowercased and stripped of whitespace for consistency (
John Smithandjohn smithproduce the same hash) - Auto-key: If
entity_hashing=Truebut no key is provided, a random 32-byte hex key is generated per Shield instance - Deterministic: Same entity + same key = same hash, across requests and SDK languages
- Works everywhere: Compatible with
tokenizemode,redactmode,sanitize_batch, and multi-turn conversations
Security Notes
- The HMAC key is a deployment secret — never share it or log it
- Entity hashes are one-way — you cannot recover the original PII from a hash
- Use a consistent key across requests to enable correlation; rotate the key to break correlation
Incremental Streaming
When using streaming LLM responses, CloakLLM desanitizes tokens incrementally as chunks arrive — no buffering of the full response. The StreamDesanitizer state machine replaces [CATEGORY_N] tokens as soon as the closing ] arrives, passing plain text through immediately.
All middleware integrations (OpenAI SDK, LiteLLM, Vercel AI SDK) use StreamDesanitizer automatically. You only need the standalone API if you're building a custom streaming pipeline.
Python
JavaScript
How It Works
- Plain text passes through
feed()immediately — no latency added [bracket triggers internal buffering of a potential token]bracket resolves the buffer against the token map (case-insensitive) and emits the original value, or the literal text if not a known token- Buffer overflow — if the buffer exceeds 40 characters without a
], it flushes incrementally to prevent unbounded memory use flush()— call at end-of-stream to emit any remaining buffered text
Middleware Integration
All middleware paths use StreamDesanitizer internally:
| Middleware | Streaming Support |
|---|---|
Python OpenAI SDK (enable_openai) | Incremental desanitization |
Python LiteLLM (cloakllm.enable) | Incremental desanitization |
JS OpenAI SDK (enable) | Incremental desanitization |
JS Vercel AI SDK (createCloakLLMMiddleware) | Incremental desanitization |
No configuration needed — streaming desanitization is automatic when stream: true / stream=True is used.
Cryptographic Attestation
Ed25519 digital signatures prove that sanitization occurred. Each sanitize() call produces a signed certificate containing input/output hashes, entity count, categories, and detection passes. Batch operations use Merkle trees for efficient multi-text proofs.
Setup
Or load from file / environment variable:
Using Certificates
Batch Attestation with Merkle Trees
Cross-Language Compatibility
Certificates are fully cross-language compatible. A certificate signed in Python verifies in JavaScript and vice versa, using identical canonical JSON serialization and Ed25519 signatures.
Configuration
| Option | Python | JavaScript | Default |
|---|---|---|---|
| Signing keypair | attestation_key | attestationKey | None |
| Key file path | attestation_key_path | attestationKeyPath | None |
| Environment variable | CLOAKLLM_SIGNING_KEY_PATH | CLOAKLLM_SIGNING_KEY_PATH | — |
Python Optional Dependencies
JavaScript uses Node.js built-in crypto module — no extra dependencies.
Entity Detection Reference
| Category | Examples | Detection Method |
|---|---|---|
EMAIL | john@acme.com | Regex |
PHONE | +1-555-0142, 050-123-4567 | Regex |
SSN | 123-45-6789 | Regex |
CREDIT_CARD | 4111111111111111 | Regex |
IP_ADDRESS | 192.168.1.100 | Regex |
API_KEY | sk-abc123..., AKIA... | Regex |
AWS_KEY | AKIA1234567890ABCDEF | Regex |
JWT | eyJhbGciOi... | Regex |
IBAN | DE89370400440532013000 | Regex |
| Custom | (your patterns) | Regex |
PERSON | John Smith, Sarah Johnson | spaCy NER (Python) / Ollama LLM (JS) |
ORG | Acme Corp, Google | spaCy NER (Python) / Ollama LLM (JS) |
GPE | New York, Israel | spaCy NER (Python) / Ollama LLM (JS) |
ADDRESS | 742 Evergreen Terrace | Ollama LLM |
DATE_OF_BIRTH | 1990-01-15 | Ollama LLM |
MEDICAL | diabetes mellitus | Ollama LLM |
FINANCIAL | account 4521-XXX | Ollama LLM |
NATIONAL_ID | TZ 12345678 | Ollama LLM |
BIOMETRIC | fingerprint hash | Ollama LLM |
USERNAME | @johndoe42 | Ollama LLM |
PASSWORD | P@ssw0rd123 | Ollama LLM |
VEHICLE | plate ABC-1234 | Ollama LLM |
| Custom LLM | (your categories) | Ollama LLM (via custom_llm_categories) |
CLI
Both SDKs include a CLI for scanning text, verifying audit logs, and viewing statistics.
Python
JavaScript
Example Output
scan:
verify:
stats:
Audit Logs
File Format
Audit logs are stored as JSONL files in the configured log directory:
Entry Structure
Each line is a JSON object with these key fields:
| Field | Description |
|---|---|
event_id | Unique event ID (UUID4) |
seq | Sequence number within the file |
timestamp | ISO 8601 timestamp |
event_type | "sanitize", "desanitize", "sanitize_batch", "desanitize_batch", "shield_enabled", or "shield_disabled" |
entity_count | Number of entities detected |
categories | Map of category → count |
prompt_hash | SHA-256 hash of the original text |
sanitized_hash | SHA-256 hash of the sanitized text |
model | LLM model name (if provided) |
provider | LLM provider name (if provided) |
tokens_used | List of tokens used (no original values) |
latency_ms | Processing time in milliseconds |
metadata | Additional context (e.g., user_id, session_id) |
mode | "tokenize" or "redact" |
entity_details | Per-entity metadata array (PII-safe: category, offsets, confidence, source, token, and entity_hash when hashing is enabled) |
timing | Per-pass breakdown: total_ms, detection_ms, regex_ms, ner_ms, llm_ms, tokenization_ms |
prev_hash | SHA-256 hash of the previous entry |
entry_hash | SHA-256 hash of this entry |
No original PII is stored in audit logs — only hashes, token counts, and categories.
Verification
Python:
JavaScript:
CLI:
Tamper Detection
The hash chain makes tampering evident. Each entry's entry_hash is computed from its contents including prev_hash. If any entry is modified, deleted, or reordered, the chain breaks and verify_audit() / verifyAudit() reports the specific entries that fail validation. The returned final_seq / finalSeq value indicates the last sequence number seen, which can be compared against expected counts to detect log truncation.
Security
Ollama SSRF Prevention
By default, the Ollama LLM detection pass only connects to localhost URLs. This prevents server-side request forgery (SSRF) if an attacker controls the llm_ollama_url / llmOllamaUrl configuration. To allow connections to remote Ollama servers, explicitly opt in:
Or via environment variable:
CLI PII Redaction
The CLI scan command redacts detected PII values by default. To display original values in the output, use the --show-pii flag:
Thread Safety
CloakLLM is designed for concurrent use:
- TokenMap: Thread-safe. Multiple threads can read/write tokens concurrently.
- AuditLogger: Thread-safe. Concurrent sanitize calls produce correctly ordered, hash-chained audit entries.
- LLM cache: Thread-safe. The Ollama detection cache handles concurrent access without corruption.
Redacted Analysis
The analyze() method supports redacting PII values in its output:
Context Risk Analysis
Even after tokenization, surrounding context can reveal identity. CloakLLM's ContextAnalyzer scores this re-identification risk.
Standalone Analysis
Python:
JavaScript:
Automatic Analysis
Enable context_analysis to automatically analyze every sanitize() call:
Python:
JavaScript:
Three Signals
| Signal | Description | Weight |
|---|---|---|
| Token density | Ratio of tokens to total words | x1.5 |
| Identifying descriptors | Words like "CEO", "founder", "only" near tokens | x0.15 each |
| Relationship edges | Phrases like "works at", "lives in" connecting two tokens | x0.20 each |
Risk levels: low (0–0.3), medium (0.3–0.7), high (above 0.7). Score capped at 1.0.
CLI
Token Specification
CloakLLM v0.5.1 introduces a formal token standard. The full spec is in TOKEN_SPEC.md.
Token Format
All tokens follow the grammar [CATEGORY_N] in tokenize mode or [CATEGORY_REDACTED] in redact mode:
- Category: uppercase letters, digits, and underscores (e.g.,
EMAIL,CREDIT_CARD,DATE_OF_BIRTH) - Suffix: zero-based counter (e.g.,
0,1,42) orREDACTED - Maximum token length: 40 characters (including brackets)
Validation Utilities
Both SDKs export functions to validate and parse tokens:
Python:
JavaScript:
Custom Category Names
Custom categories (via custom_patterns or custom_llm_categories) must:
- Match the pattern
^[A-Z][A-Z0-9_]*$ - Not collide with any of the 62 built-in category names
Both SDKs enforce these rules at config creation time.
Pluggable Detection Backends
v0.5.2 introduces a DetectorBackend base class that lets you replace or extend the default detection pipeline. The built-in pipeline runs regex → NER → LLM (opt-in). With pluggable backends, you can swap any stage, add custom detectors, or build an entirely custom pipeline.
Writing a Custom Backend
Python:
JavaScript:
Using Custom Backends
Pass a backends array to Shield to replace the default pipeline:
Python:
JavaScript:
Built-In Backends
Both SDKs export three built-in backend classes:
| Backend | Name | Description |
|---|---|---|
RegexBackend | "regex" | Pattern matching for structured PII (emails, SSNs, etc.) |
NerBackend | "ner" | Named entity recognition (spaCy in Python, compromise in JS) |
LlmBackend | "llm" | Ollama-based semantic detection for contextual PII |
When no backends parameter is provided, Shield builds the default pipeline automatically (regex → NER → LLM if enabled).
Dynamic Metrics
When custom backends are used, timing keys in shield.metrics() and audit log entries are derived from each backend's name property (e.g., profanity_ms), instead of the hardcoded regex_ms/ner_ms/llm_ms.
Article 12 Compliance Mode
CloakLLM v0.6.0 introduces a formal EU AI Act Article 12 compliance profile. Activating it adds tamper-detectable compliance metadata to every audit entry, enables a runtime guard against PII leakage in logs, and unlocks structured compliance reporting for auditors.
For the regulatory rationale, see The Article 12 Paradox whitepaper.
Activation
Python:
JavaScript:
When activated, every audit entry gains four fields, all included in the SHA-256 hash chain:
| Field | Value | Purpose |
|---|---|---|
compliance_version | "eu_ai_act_article12_v1" | Schema version for regulator-facing tooling |
article_ref | ["EU_AI_Act_Art_12", "EU_AI_Act_Art_19"] | Articles satisfied by this entry |
retention_hint_days | 180 (default) | Recommended retention for downstream log-rotation systems |
pii_in_log | false | Asserted at runtime — never true |
compliance_summary()
Returns a structured map of EU AI Act and GDPR articles addressed by the current configuration.
Python: shield.compliance_summary()
JavaScript: shield.complianceSummary()
export_compliance_config()
Writes the compliance summary to a JSON file. This is the artifact you hand to an auditor.
Python:
JavaScript:
verify_audit() compliance report
Returns a structured compliance report with a verdict of "COMPLIANT" or "NON_COMPLIANT".
Python:
JavaScript:
CLI
Emits the report as JSON to stdout. Exit code 0 for COMPLIANT, 1 for NON_COMPLIANT.
The PII guard
In compliance mode, every audit entry passes through a runtime guard before being hashed. Any field of entity_details containing forbidden keys (original_value, original_text, raw_text, plain_text, value) causes the write to be rejected. This is the structural enforcement of CloakLLM's core invariant: audit logs contain zero original PII.
Enterprise Key Management
⚠ EXPERIMENTAL — disabled in v0.6.1. The KMS providers shipped in v0.6.0 had bugs that produced unverifiable signatures. They now raise
NotImplementedError. UseLocalKeyProvider(the default) for production attestation. Full rebuild planned for v0.7.0.
The scaffolding for HSM-backed signing keys is in place but not production-usable in v0.6.1.
Supported providers
| Provider | Config value |
|---|---|
| AWS KMS | attestation_key_provider="aws_kms" |
| GCP KMS | attestation_key_provider="gcp_kms" |
| Azure Key Vault | attestation_key_provider="azure_keyvault" |
| HashiCorp Vault | attestation_key_provider="hashicorp_vault" |
Usage
When key_rotation_enabled=True, a key_rotation_event audit entry is logged at session init recording key_id, key_provider, and key_version. No PII is included.