How it works

Nine stages, four principles, one invariant.

The architecture is informed by the production Data Sanitization Proxy that has shipped inside the BlackUnicorn Command Centre. The standalone library keeps the load-bearing primitives and strips out everything platform-specific.

Six stones, one path

Every step is a failure point that defaults to blocked.

Each phase emits a uniform result. Any error in any stage halts the request. There is no cleartext fallback — not because we hide it behind a flag, but because no such code path exists.

  1. 01
    Identity

    Verify the caller from a signed session. No self-reported headers.

  2. 02
    Classify

    Nine-stage pipeline. NFKC → blocklist → regex → struct → NER → operator-lists → coreference → escalation.

  3. 03
    Pseudonymize

    Type-preserving placeholders. Session-scoped. AES-256-GCM map.

  4. 04
    Route

    HIGH → L1 local. MEDIUM → L2 contracted. LOW → any. No override.

  5. 05
    Rehydrate

    Reverse only the runes the outbound map created. Unknown ones stay masked.

  6. 06
    Audit

    HMAC-SHA-256, never raw text. Tamper-evident store. Audit-on-audit.

The four design principles

Non-negotiable. Skip any one and Runelm is decorative.

Fail-closed, always

If the classifier errors, the pseudonymizer crashes, the integrity check fails — the request is blocked. There is no best-effort path past a failure. The whole point of the system is that no external call goes out unless every safety step succeeded.

Single chokepoint

Every code path that calls an LLM must go through Runelm. One shared client module. Direct httpx, fetch, or SDK calls to provider URLs are prohibited by code review. If a single path bypasses Runelm, the system provides no guarantee.

Map-bounded rehydration

Only reverse placeholders that the outbound substitution map created for this session. If the LLM response contains a placeholder-shaped token not in your map, leave it alone. Otherwise prompt injection can trick the model into outputting fake placeholders to extract real values.

Verified caller identity

Any sensitivity boost based on caller role (finance, security-ops) must come from authenticated session identity — signed JWT, mTLS subject, session-cookie principal. Never from a self-reported HTTP header. A self-reported caller can claim any identity.

The classification pipeline, stage by stage

Layered. Order matters. Later stages can only escalate the level, never lower it.

  1. 01 Unicode normalization (NFKC)
    Close homoglyph, zero-width, compatibility-decomposition bypasses.
  2. 02 Keyword blocklist
    Sub-1ms. Obfuscation-aware: raw + Base64 + leetspeak + homoglyph views.
  3. 03 Custom regex patterns
    Operator-defined. Invalid regexes logged at load, skipped at runtime.
  4. 04 Built-in regex patterns
    IPv4/6, CIDR, email, IBAN, AWS/GCP/GitHub keys, JWT, PEM, AD SID, LDAP DN, paths.
  5. 05 Structured-data pre-processing
    Parse JSON / XML / CSV / Nmap / Burp before NER — sensitive data hides in structure.
  6. 06 NER via Presidio
    Default analyzer plus custom recognizers detect names, orgs, and contact data.
  7. 06.5 Operator-list cross-reference
    Detected names matched against operator-maintained client / employee / engagement lists. Detection stays separate from inflation.
  8. 07 Coreference detection
    Phrases like "the client" or "the target" force a MEDIUM floor — a level signal, not a substituted entity.
  9. 07.5 Identity boost
    A verified caller identity escalates the level one step — from a signed session, never a self-reported header.
  10. 08 Per-caller override
    Operator-pinned forced minimums with audit and expiry.
  11. 09 Conversation-level escalation
    Session level only escalates. Once HIGH, every subsequent message stays HIGH.

The routing matrix

The classification level forces the routing decision. There is no --allow-l3-for-high flag. The system enforces the policy, it does not ask.

LevelAllowed tierExamples
BLOCKEDnoneAPI keys, credentials, private keys, MFA codes
HIGHL1 local onlyRevenue, forecasts, active engagement names, pre-disclosure vulnerability findings
MEDIUML1 + L2 contractedAggregated metrics, anonymized cohorts, employee names in non-sensitive context
LOWany providerPublic docs, generic coding help, market news