OGuardAI
Use Cases

HR & Employee Data

Protect employee PII when using AI for HR workflows, recruiting, and internal documentation while respecting works-council and GDPR obligations

Protect employee personal data (names, salary, national IDs, dates of birth, contact details) when using AI to draft HR documents, summarize personnel files, and answer employee questions.


The Problem

HR teams handle some of the most sensitive personal data in the company: national identifiers, dates of birth, salary and compensation, bank details, health-related absences, and performance notes. AI can speed up drafting reference letters, summarizing personnel files, screening applications, and answering routine policy questions. But every one of those tasks pulls employee PII into the prompt.

In the EU, employee data sits under both GDPR and, in codetermined companies, works-council (Betriebsrat) agreements that constrain how personnel data may be processed and who may see it. Sending raw salary figures or a national ID to a third-party LLM provider is a data-minimization and access-control problem, not just a privacy nicety. Naive redaction breaks the workflow: strip every name from a team roster and the AI can no longer draft per-person feedback; strip the salary and it cannot summarize a compensation review.


How OGuardAI Solves It

OGuardAI sits between your HR application and the AI model. Employee identifiers and compensation are tokenized with safe metadata, so the model can draft and summarize while the real values stay inside the runtime. Restore is role-gated: ordinary HR staff get masked salary and masked contact details back, while the hr_manager role restores them in full.

HRIS / ATS / Personnel File
    |
    v
OGuardAI Runtime (employee PII exists only here, transiently)
    |
    +---> Tokenized text (identifiers + salary tokenized) ---> LLM Provider
    +---> Encrypted session blob ---------------------------> Your Application
    |
    v
Restored output (role-gated)
    +---> hr_manager: full restore (salary, contact, employee id)
    +---> HR staff: masked salary and contact
    +---> Redacted: SSN, date of birth, passport, health id (never recoverable)

Detected Entity Types

These are the entity types the shipped hr policy governs.

Entity TypeExamplesDefault Action
person **Employee and applicant namesTokenize, full only for hr_manager
salary *Annual pay, compensation figuresTokenize, masked; full only for hr_manager
employee_id *Personnel numbersTokenize, full only for hr_manager
emailWork and personal emailTokenize, full only for hr_manager
phoneContact numbersTokenize, full only for hr_manager
addressHome and office addressesTokenize
companyEmployer, former employersTokenize
ibanPayroll bank accountsTokenize, restore masked
credit_cardCompany card numbersTokenize, restore masked
ssnNational insurance / social securityRedact (never reaches the model)
date_of_birthDOB fieldsRedact (never reaches the model)
passportPassport numbersRedact (never reaches the model)
health_idHealth-related identifiersRedact (never reaches the model)

Entity types marked with * are custom types defined via custom_patterns in the policy, not built-in. See the Extending Entities guide for how to add custom types.

Entity types marked with ** are detected by the NER detector sidecar, which requires detector.mode set to both or advanced. The built-in detector alone covers structured PII (email, phone, IBAN, card, identifiers, address, date of birth) but does not detect person, company, or location names. In builtin-only mode employee names are not tokenized and would reach the model, so set detection.required_for: [person] if you need the request to fail closed rather than pass names through. Treat name protection as a data-minimization control, not an absolute guarantee.


Example Policy

The hr policy ships in policies/hr/policy.yaml. It redacts the high-sensitivity identifiers, tokenizes names and contact details, and gates full restore of salary, names, contact, and personnel numbers behind the hr_manager caller role.

name: "hr"
version: "1.0.0"
description: "Human resources policy: SSN, date of birth, passport, and health id redacted; salary masked for HR staff and full only for the hr_manager role; employee names and contact tokenized, full only for hr_manager."

rules:
  - entity_type: "ssn"
    protection_level: 1
    action: "redact"
    conditions: []
  - entity_type: "date_of_birth"
    protection_level: 1
    action: "redact"
    conditions: []
  - entity_type: "passport"
    protection_level: 1
    action: "redact"
    conditions: []
  - entity_type: "health_id"
    protection_level: 1
    action: "redact"
    conditions: []
  - entity_type: "iban"
    protection_level: 1
    action: "tokenize"
    restore_mode: "masked"
    conditions: []
  - entity_type: "credit_card"
    protection_level: 1
    action: "tokenize"
    restore_mode: "masked"
    conditions: []
  - entity_type: "salary"
    protection_level: 2
    action: "tokenize"
    restore_mode: "masked"
    conditions:
      - field: "caller_role"
        operator: "eq"
        value: "hr_manager"
        override_restore_mode: "full"
  - entity_type: "person"
    protection_level: 2
    action: "tokenize"
    conditions:
      - field: "caller_role"
        operator: "eq"
        value: "hr_manager"
        override_restore_mode: "full"
  - entity_type: "email"
    protection_level: 2
    action: "tokenize"
    conditions:
      - field: "caller_role"
        operator: "eq"
        value: "hr_manager"
        override_restore_mode: "full"
  - entity_type: "phone"
    protection_level: 2
    action: "tokenize"
    conditions:
      - field: "caller_role"
        operator: "eq"
        value: "hr_manager"
        override_restore_mode: "full"
  - entity_type: "address"
    protection_level: 2
    action: "tokenize"
    conditions: []
  - entity_type: "location"
    protection_level: 2
    action: "tokenize"
    conditions: []
  - entity_type: "company"
    protection_level: 2
    action: "tokenize"
    conditions: []
  # HR-defined entity (detected by custom_patterns below); full only for hr_manager.
  - entity_type: "employee_id"
    protection_level: 2
    action: "tokenize"
    conditions:
      - field: "caller_role"
        operator: "eq"
        value: "hr_manager"
        override_restore_mode: "full"

custom_patterns:
  - entity_type: "employee_id"
    pattern: '\bEMP[-:\s]?\d{4,8}\b'
    confidence: 0.9
    context_words: ["employee", "emp", "staff", "personnel"]
  - entity_type: "salary"
    pattern: '\b\d{1,3}(?:[.,]\d{3})+(?:[.,]\d{2})?\b'
    confidence: 0.85
    context_words: ["salary", "gehalt", "compensation", "annual", "pay", "vergütung"]

defaults:
  protection_level: 2
  action: "tokenize"
  restore_mode: "partial"
  on_redact: "continue"

metadata_policy:
  expose_gender: true
  expose_formality: true
  expose_language: true
  expose_role: true

The caller_role condition is the access control: a request that passes context.caller_role: "hr_manager" restores salary, names, contact, and personnel numbers in full; any other caller gets the masked default. Pass the role on the transform request via context.caller_role.


Example API Call

Transform a personnel note

curl -X POST http://localhost:3000/v1/transform \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key-here" \
  -d '{
    "input": "Employee Jonas Weber (EMP-40218), SSN 078-05-1120, DOB 1990-03-12, annual salary 82.000,00 EUR. Contact: jonas.weber@company.de, +49 89 1234567. Payroll IBAN DE89 3704 0044 0532 0130 00.",
    "policy": "hr",
    "context": { "caller_role": "hr_staff" }
  }'

Response (tokenized)

{
  "safe_text": "Employee {{person:p_001:ad4f97591c16}} ({{custom:employee_id:x_001:e9c35b18ad9b}}), SSN [REDACTED:ssn], DOB [REDACTED:date_of_birth], annual salary {{custom:salary:x_002:251177a0ba1f}}. Contact: {{email:e_001:1bcaef1a4aff}}, {{phone:ph_001:71453119be53}}. Payroll IBAN {{iban:ib_001:a7a60e9fe667}}.",
  "session_id": "01916d5b-8e2f-7000-8000-000000000004",
  "session_state": "eyJ2IjoxLCJzaWQiOi...",
  "entity_context": [
    { "token": "{{person:p_001:ad4f97591c16}}", "type": "person", "gender": "male", "language": "de" }
  ],
  "stats": { "entities_detected": 8, "entities_transformed": 6, "entities_blocked": 2 }
}

The SSN and date of birth are redacted (purged from the session, never recoverable). Name, personnel number, salary, contact details, and IBAN are tokenized. The model can draft the letter or summary from tokens without seeing the real values.

Rehydrate for an HR manager

curl -X POST http://localhost:3000/v1/rehydrate \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key-here" \
  -d '{
    "output": "<LLM-generated summary with tokens>",
    "session_state": "eyJ2IjoxLCJzaWQiOi..."
  }'

The caller role is bound from the authenticated principal (its API-key scope or JWT claim), not the request body. When the principal carries caller_role: hr_manager, salary, name, contact, and personnel number restore in full. The same session state rehydrated for an hr_staff caller returns masked salary and masked contact, and the redacted SSN, date of birth, passport, and health id stay purged for everyone.


Data Protection Notes

RequirementHow OGuardAI Addresses It
GDPR Art. 5(1)(c) data minimizationOnly detected entity types are tokenized or redacted before the prompt leaves the runtime; the high-sensitivity identifiers are redacted outright
GDPR Art. 9 special categoriesHealth identifiers are redacted and never transmitted to the provider
Access control (need-to-know)The caller_role condition restores salary and contact in full only for hr_manager; ordinary HR staff get masked values
Works-council (Betriebsrat) agreementsRole-gated restore and PII-free audit events support internal agreements on who may view personnel data through AI-assisted tooling
AuditEvery transform and rehydrate emits structured events with entity types and counts, never raw employee data

OGuardAI is one technical control in a broader HR data-governance program. It reduces the employee PII that reaches an LLM provider for detected entities; it does not, by itself, make an HR AI deployment GDPR-compliant. Confirm your processing basis and any works-council agreement with your data protection officer.