GDPR posture

What gets collected, how it's stored, what happens on an Article 17 request - engineering reality, not marketing.

5 min read · verified against [email protected]

Collection - what gets collected per event

Every detection, ban, and rate-limit hit produces an event. The event carries a fixed set of fields. What's NOT collected matters as much as what is.

Collected:

  • Identity (encrypted + hashed): IP address, User-Agent string
  • Geo enrichment (derived from IP): country, region, city, ASN, ASN org (nullable)
  • Request metadata: endpoint, method, status_code, reason

Explicitly NOT collected:

  • Request body fragments, response body fragments
  • Untyped headers (any header not explicitly enriched)
  • Authorization tokens, cookies, custom auth
  • No names, emails, account IDs unless they pass through endpoint or reason fields

Storage - IP and User-Agent get the dual treatment

The two highest-sensitivity fields are stored two ways: encrypted at rest (recoverable for dashboard display) AND hashed (irreversible, for correlation). The hash enables "the same IP triggered three different rules" without keeping anything plaintext-equivalent on the indexable surface.

FieldEncrypted at restHashed (BLAKE2b)
IP addresssealed under the project key (see Encryption key rotation) - decryptable for dashboard displayip_hash - irreversible, used for correlation and indexing
User-Agentsame envelope as IP, decryptable for display, truncated before encryption to bounded lengthuser_agent_hash - BLAKE2b over the truncated value, stable across requests from the same client

This exceeds typical pseudonymization expectations. The encrypted form is recoverable; the hash is not, but neither is on the public surface.

Retention - by plan tier

Retention is applied at the org level. A scheduled purge deletes events where timestamp < cutoff. Sized to match common compliance expectations per customer segment.

For current per-tier retention windows, check Settings → Billing in the dashboard. The values vary by plan and change.

Article 17 - anonymization, not deletion

When a user invokes their right to erasure, Guard Core anonymizes the events that identify them. The event rows survive in the database; the identifiable fields are nulled or replaced with sentinel values. This is a deliberate engineering choice - defensible under GDPR's exceptions for security records.

What happens: deletion-request flow runs the anonymization path. Identifying fields replaced with sentinels or NULL. Row stays in the table. Aggregate counts unchanged. Correlation chains broken: behavior key cleared.

Why this design: aggregate threat intel survives. Attack patterns inform other customers' defenses. An attacker's request to be "forgotten" shouldn't erase evidence others use. GDPR Art. 17(3)(e) explicitly preserves "compelling legitimate grounds" for security records.

Document this in your DPA so users know what they're agreeing to.

Field-by-field - before vs after anonymization

FieldBeforeAfter anonymization
ip_address1.2.3.4 (encrypted)ANONYMIZED_IP (0.0.0.0)
user_agentMozilla/5.0 ... (encrypted)NULL
threat_score0.87NULL
rule_id, rule_versionrule_8f3a, v=12NULL
asn, asn_orgAS15169, Google LLCNULL
behavior_keysha256(IP|svc|bucket)NULL

The one path to hard delete: when the last member of an org is deleted, that org's security events are physically removed from the database - orphan cleanup. This is the only code path that actually drops the rows.

Audit log - every admin data operation is recorded

A dedicated GDPR audit table captures the full lifecycle of admin actions on user data. The audit log itself is the audit log. There is no separate "who did the deletion" hidden somewhere else.

Operations recorded: Deletion (Art. 17), Export (Art. 15), Rectification (Art. 16), Restriction (Art. 18), Objection (Art. 21).

Retention buckets:

  • 10 years - GDPR mandate. The audit log itself is required record-keeping. Long horizon for regulator inquiries and DPA disputes.
  • 1 year - operational. Lower-stakes events that don't carry the same mandate. Routine actions, internal admin queries.

Posture summary - what to put in your DPA

GDPR ArticlePositionImplementation
Art. 6(1)(f)Lawful basis - legitimate interest (security monitoring)Processing is necessary to protect customer infrastructure from automated attacks. Balance test favors the controller given the limited categories of data collected.
Art. 5(1)(c)Pseudonymization - exceeds typical expectationsIPs and UAs are both encrypted at rest AND hashed for correlation. Neither raw form is on the indexable surface.
Art. 15Right of access - export-request flowSibling to the deletion path. Returns the user's identifiable records in a portable format.
Art. 17Right to erasure - anonymization under Art. 17(3)(e)Identifiable fields nulled; aggregate security records retained. Document this in your DPA explicitly.

Troubleshooting

SymptomLikely causeFix
User requested deletion, but IP still appears in the dashboardIP column shows 0.0.0.0 (sentinel). That's the anonymized state, not the original. Threat score, rule_id, ASN, behavior key on those rows are also cleared.Working as designed. Row retained for aggregate analytics; user is no longer identifiable. Confirm by inspecting the row. Every identifying field should be nulled or sentinel.
Events older than retention period are still visiblePurge job not scheduled, not running, or in a different environment. Org's tier was bumped recently; old retention applied while job was queued.Check scheduler. Verify org's current plan tier matches expected retention. Manually trigger purge with a tight cutoff date as a test.
An admin action isn't in the audit logAction bypassed the centralized GDPR path - a direct DB write that skipped the audit hook. Common with ad-hoc scripts or migrations.Find the bypass and route it through the GDPR audit-aware code path. Treat as P1. Gaps in the audit log are a compliance liability AND make incident forensics harder.