Compliance Controls Mapping
Article-by-article mapping of OGuardAI controls to GDPR, HIPAA, SOC 2, and PCI DSS requirements
GDPR Alignment
| GDPR Article | Requirement | OGuardAI Control | How to Verify |
|---|---|---|---|
| Art. 5(1)(c) | Data minimization | Tokenization removes PII from LLM context | Transform API returns safe_text with detected, non-whitelisted PII tokenized or removed |
| Art. 5(1)(e) | Storage limitation | Sealed sessions auto-expire, no server-side retention | Check session TTL configuration |
| Art. 25 | Data protection by design | Trust boundary model, sealed sessions | Security whitepaper Section 1 |
| Art. 28 | Processor obligations | Self-hosted, no subprocessors in sealed mode | Deployment guide |
| Art. 30 | Records of processing | Structured audit events per operation | Audit module, diagnostics endpoint |
| Art. 32 | Security of processing | AES-256-GCM encryption, key rotation | Security whitepaper Section 2 |
| Art. 17 | Right to erasure | Sessions auto-expire, no server-side retention | Data retention doc |
| Art. 20 | Data portability | Sealed sessions are portable (client-held) | Session model |
| Art. 35 | Data protection impact assessment | Audit trail, policy validation, shadow (dry-run) mode for staging evaluation | Admin endpoints |
Note on shadow mode: shadow (dry-run) mode returns a redacted comparison (a fingerprint hash plus aggregate deltas), not raw PII, and is a dev-only diagnostic rejected as a fatal production-validation error. It is a staging-only evaluation aid for previewing detection and tokenization behavior, not a production compliance control.
HIPAA Alignment
| HIPAA Section | Requirement | OGuardAI Control | Implementation Detail |
|---|---|---|---|
| SS 164.312(a)(1) | Access control | JWT/API key auth + scope model | Auth middleware with per-endpoint scopes (Transform, Rehydrate, Detect, Policy, Batch, Rag, Revoke, Global Revoke, Session, Detect Values, Admin) |
| SS 164.312(a)(2)(iv) | Encryption/decryption | AES-256-GCM sealed sessions | Session crate with AEAD encryption |
| SS 164.312(b) | Audit controls | Structured audit events | Audit module emits events via tracing |
| SS 164.312(c)(1) | Integrity controls | AEAD authentication tag on session blobs | Tamper detection built into AES-GCM |
| SS 164.312(e)(1) | Transmission security | TLS support, encrypted session state | Deployment guide covers TLS setup |
| SS 164.502(b) | Minimum necessary | Tokenization + policy-based restore modes | 6 restore modes: full, partial, masked, formatted, abstract, none |
| SS 164.308(a)(5)(ii) | Security awareness | Policy validation and dry-run endpoints | Admin can preview impact before changes |
SOC 2 Type II Alignment
| Control | Description | OGuardAI Feature | Evidence |
|---|---|---|---|
| CC6.1 | Logical access | Auth middleware with scopes | API key/JWT validation on every request |
| CC6.3 | Role-based access | Per-endpoint scopes (Transform, Rehydrate, Detect, Policy, Batch, Rag, Revoke, Global Revoke, Session, Detect Values, Admin) | Scope-based authorization checks |
| CC6.6 | System boundary protection | Trust boundary model | Detected, non-whitelisted PII tokenized before leaving the runtime boundary |
| CC6.7 | Restrict data mobility | Policy engine controls entity exposure | Per-entity-type action rules |
| CC7.1 | Detect security events | Prompt security engine, output guard | Input/output scanning for injection and PII leaks |
| CC7.2 | System monitoring | Structured audit events, diagnostics endpoint | Audit trail, health checks |
| CC8.1 | Change management | Policy diffing, validation endpoint | Preview impact of policy changes before deployment |
| CC9.1 | Risk mitigation | Multi-layer detection (regex + NLP) | Builtin + advanced detector modes |
PCI DSS Alignment (Where Applicable)
| PCI DSS Requirement | OGuardAI Control |
|---|---|
| 3.4 -- Render PAN unreadable | Credit card tokenization with Luhn validation |
| 3.5 -- Protect cryptographic keys | Session key derived from configured secret, key rotation supported |
| 10.1 -- Audit trails | Structured audit events per operation |
| 10.3 -- Record audit trail entries | Timestamp, tenant, entity types, policy, duration in every event |
Audit Event Schema
Every OGuardAI operation emits a structured audit event: text, JSON, and chat transform; rehydrate;
the RAG ingest/query/context/answer/delete pipeline; detection (/v1/detect, /v1/batch/detect);
revocation (/v1/revoke, /v1/revoke/bulk); and image redaction (/v1/redact/image). Each event
carries only PII-free type and count metadata. A structured event looks like:
{
"timestamp_unix": 1700000000,
"event_type": "transform",
"tenant_id": "tenant_acme",
"session_id": "550e8400-...",
"policy_applied": "gdpr-strict",
"entity_types": ["email", "phone"],
"entity_count": 3,
"entities_blocked": 1,
"entities_tokenized": 2,
"duration_ms": 12.5,
"detector_mode": "builtin_regex",
"output_guard_triggered": false,
"prompt_security_triggered": false
}Key property: No raw PII values appear in audit events.
The event schema also reserves three optional GDPR Art. 30 record-of-processing fields: purpose
(a processing-purpose label), legal_basis (an Art. 6(1) lawful basis from a closed set: consent,
contract, legal_obligation, vital_interests, public_task, legitimate_interests), and
data_category (a category-of-data label). They are PII-free controlled labels, never sourced from
request content, and each is omitted from the event when unset. The runtime does not currently
populate them (there is no policy/config wiring yet), so today they are absent from every event; if a
future release wires them, they would be controller-supplied labels only, never derived from data. The
full Records of Processing (retention, data-subject categories) remains organizational and lives in
your RoPA.
Audit Export
Audit events are emitted as structured tracing events on the guardai::audit target.
They can be collected by any log aggregation system:
- ELK Stack: Filebeat -> Logstash -> Elasticsearch -> Kibana
- Datadog: Datadog Agent with JSON log parsing
- Splunk: Universal Forwarder with JSON sourcetype
- AWS CloudWatch: CloudWatch Logs agent
- Google Cloud Logging: Fluentd/Fluent Bit
Configure your tracing subscriber to output JSON format for easy parsing:
RUST_LOG=guardai::audit=info oguardai-serverPolicy Governance Events
In addition to operational audit events, OGuardAI emits policy governance events:
| Event Type | When Emitted | What It Records |
|---|---|---|
policy_loaded | Server startup | Each policy loaded from the policies directory |
policy_validated | Admin validation endpoint | Proposed policy validation result |
These events are emitted as structured log records (no raw PII) and create a record of policy state changes over time. With the default log backend, durability and tamper-resistance depend on the operator's log sink. The optional file audit backend adds a local append-only, HMAC-chained store with one tamper-evident hash chain per tenant, so each tenant's records verify independently; route it to durable, access-controlled storage for retention.
To enable durable, fail-closed audit in one step, start the server with --compliance (or set GUARDAI_COMPLIANCE=1 for an env/Helm deployment that cannot pass a flag; it accepts 1, true, yes, or on). The preset only tightens: it forces the file audit backend and strict (fail-closed) audit on the data path, so a transform, rehydrate, detect, RAG, session, or revoke operation whose audit event cannot be recorded is rejected (HTTP 503) rather than acknowledged unaudited. For a revocation, which persists before it is audited, a failed audit rolls the erasure back so no unaudited state change survives. The file sink is enqueue-based: record hands the event to a bounded in-process queue that a background task writes to disk, so strict mode rejects when the event cannot be enqueued (the queue is full or its writer has stopped), which is the fail-closed signal on the write path. Fail-closed does not extend to every event. Failure audits (a request that is already erroring), admin diagnostics, and startup events are recorded fail-open (a sink error is logged, not propagated), and the transparent proxy records its PII-safe failure audits to the log sink only. Those paths never carry raw PII, so a dropped record loses a log line, not customer data. The audit file path stays operator-configured (audit.file.path); startup fails closed if it is unset, so a compliance deployment must point the durable log at a real, access-controlled path. The gate runs regardless of auth.mode, so it holds even in dev mode where the general config validation is skipped.
# Durable, fail-closed audit; audit.file.path must be set in the config.
oguardai-server --compliance --config oguardai.yaml
# Same preset via env (Helm/container deployments).
GUARDAI_COMPLIANCE=1 oguardai-server --config oguardai.yamlVerifying audit-log integrity
The file backend is tamper-evident; the audit verify command makes it operator-provable. It re-derives the chain key from the configured session secret (never from the file), re-walks every per-tenant sub-chain, and reports whether the log is intact.
# Verify the audit file named in the config (uses the config session secret).
oguardai-server audit verify --config oguardai.yaml
# Verify an archived or relocated copy on a forensic host.
oguardai-server audit verify --config oguardai.yaml --path /backups/audit-2026-06.jsonl
# Machine-readable result for monitoring; --tenant scopes the per-chain breakdown.
oguardai-server audit verify --config oguardai.yaml --json --tenant acmeExit codes are distinct so monitoring can act on them: 0 intact, 2 broken (a definitive tamper or corruption verdict; any break in any tenant fails the whole file), 1 cannot verify (a missing or unreadable file, or audit.backend is not file). A 1 is a misconfiguration; a 2 is an integrity incident.
The output is PII-free (chain keys, counts, sequence ranges, head hashes, timestamps, and a closed set of break reasons; never event content). The audit HMAC key is never printed, only a domain-separated 8-character fingerprint so two runs can be confirmed to use the same key.
Verifying policy integrity
The policy directory itself can be signed and verified fail-closed at startup, so a modified, added, removed, or swapped policy file refuses to start the server. A policy can never be silently weakened on disk. Sign the directory with a dedicated key, then enable verification in the config.
# Sign the policy directory (writes <dir>/.signatures.json).
oguardai-server policy sign-dir --dir policies --secret "$GUARDAI_POLICY_SIGNING_KEY" --kid v1policy:
directory: policies
integrity:
manifest: policies/.signatures.json
secret: "${GUARDAI_POLICY_SIGNING_KEY}"
kid: v1The signing key is HMAC-derived and independent of the session secret, so policy governance can hold a different key than the runtime. Verification covers exactly what the server loads (each <subdir>/policy.yaml and each root-level *.yaml), rejects symlinks, and reports the first failing file as modified, unexpected, or missing. Both manifest and secret must be set; setting exactly one is a startup error, and both absent disables it (the default). Re-sign after any intentional policy change.
Notes:
- The audit key derives from the base
session.secret, independent of the session sealing keyring, so rotating sealing keys does not affect verification. Rotatingsession.secretitself invalidates prior records, so start a fresh audit file when you rotate it. - Tail truncation (deleting the most recent records) leaves a valid prefix; publish each chain
head_hashbetween audits as an external anchor to detect it. - For a portable evidence copy,
audit exportproduces an integrity-attested, PII-free NDJSON bundle (or a--tenant/--since/--untilslice) to hand a DPA or auditor:
# The whole log, attested. Refuses (exit 2) if the chain is broken.
oguardai-server audit export --config oguardai.yaml --out evidence.ndjson
# A tenant + time slice; the header still carries every chain's head hash so a
# slice cannot be passed off as the whole log.
oguardai-server audit export --config oguardai.yaml --tenant acme --since 1717200000The export verifies the whole file first and fails closed (a broken chain emits nothing, exit 2). The first line is an attestation (whole-file head hashes, totals, key fingerprint, the applied filter); the body is the PII-free events; the last line is a trailer with the exported count and a completion marker. --out writes a 0600 file and never overwrites. The exported events would carry the per-event Art. 30 label fields (purpose, legal_basis, data_category) if the runtime populated them; today those fields are unset. The complete Records of Processing (data-subject categories, retention schedules) is organizational and lives in your RoPA template, not in this runtime export.
Verification Checklist
Use this checklist to verify OGuardAI compliance controls in your deployment:
- Sealed session mode enabled (default)
- Session TTL configured appropriately
- TLS enabled for all endpoints
- Auth mode set to
ApiKey,Jwt, orOidc(notDev) - Audit events routed to SIEM/log aggregator
- Log rotation and retention configured
- Policy directory version-controlled (git)
- Policy validation run before deployments
- Encryption key rotation schedule established
- Output guard enabled for sensitive workflows
- Prompt security enabled (default)