DPIA — Audit Monitoring
On this page
title: Data Protection Impact Assessment — audit-stream and authentication-monitoring processing controller: fremverk ApS, CVR 39150689 dpo_role: not designated under GDPR Art. 37 — role-equivalent privacy-contact mailbox is compliance@frem.sh (per ROPA + Product Privacy Notice §2 / §2 — DPO assessment) date: 2026-05-25 version: 1.2 status: in force related:
- dpa.md §8.5
- ropa.md §2.5
- controller-incident-response.md
- sla.md
- stack.md (architecture baseline) review_cadence: every 12 months, or on material change to the processing next_review: 2027-05-08
Summary #
This Data Protection Impact Assessment (“DPIA”) covers fremverk’s audit-stream and authentication-monitoring processing as documented in ROPA §2.5 and DPA Annex A.7. It is conducted under GDPR Art. 35.
Conclusion: the processing is subject to a DPIA on the precautionary reading of Datatilsynet’s DPIA list (2018, updated 2024) — specifically item 5 (systematic monitoring of users on a large scale where the controller cannot exclude that the monitoring crosses the criterion threshold). After the mitigations documented in §5 below, the residual risk to the rights and freedoms of natural persons is low, and prior consultation with Datatilsynet under GDPR Art. 36 is not required.
The two key mitigations on top of the existing TOMs (Annex A.7):
- Retention split — customer-tunable hot tier + 3-year WORM chain. Security-relevant audit events (authentication, authorisation, admin actions) are retained in payload form for a per-tenant window of 90 / 180 / 365 / 730 days (default 90 days for standard plan; 365 days for enterprise plans; the Customer tenant admin selects the tier at Authentication policy → Audit log retention; the CHECK constraint at migration 0146 enforces
BETWEEN 1 AND 730). Thereafter the per-event PII payload is redacted by an automated retention reaper, but the cryptographic hash chain over the original event metadata is retained for the full 3-year WORM-anchored integrity window. After the hot-tier cutoff, no actor IP, no user-agent string, no session-id, and no fields_json content is recoverable from primary storage; only the per-tenant chain hash + chain-position metadata remain. The chain hashes are mathematically irreversible (SHA-256 over a canonicalised input) and provide tamper-detection without re-identification. The worst-case retention scenario is 730 days; the Art-6(1)(f) balancing in §3 has been re-run at that bound and the residual-risk score in §6 reflects the worst-case (see v1.2 change-log). - DPIA-driven scope ceiling — the content of audit events is restricted to event metadata; repository content, file diffs, branch contents, and Git-data-plane payloads are explicitly out of scope and never written to the audit stream. This boundary is enforced at the audit-emit layer (audit-emit.ts) and pinned by tests.
1. Description of the processing #
1.1 Nature #
fremverk operates fremforge, an EU-sovereign Git/CI/CD platform. As an integral part of the service, every state-changing action (sign-in, MFA challenge, OIDC callback, admin-console action, push-protection rejection, secret-scan result, tenant suspend/cancel, runner-job start/finish, etc.) is recorded as an audit event.
Each audit event is:
- Persisted to a per-tenant append-only
audit_eventstable in the primary RDS PostgreSQL instance. - Hash-chained —
hash = SHA-256(canonicalised(prev_hash, tenant_id, actor, action, fields_json, created_at))— so any retroactive modification of a single row breaks chain continuity. - Anchored to a WORM-locked OBS bucket every 2 minutes — the anchor is
(tenant_id, latest_chain_hash, count, ts). Object Lock COMPLIANCE-mode prevents tamper-with-or-delete inside the 3-year retention. - Streamed in parallel to T Cloud LTS for hot-tier observability (operator on-call dashboards), partitioned per tenant.
1.2 Scope #
| Dimension | In scope | Out of scope |
|---|---|---|
| Subject categories | End-users (developers, admins, billing contacts) of fremforge tenants; staff operators of fremverk | Visitors of the public marketing website (separate, no audit chain) |
| Data categories | Event metadata: actor identifier, action verb, structured fields (fields_json), prev/next chain hashes, timestamps, originating IP | Repository content, file diffs, Git data plane, mailbox contents, payment-instrument numbers |
| Volume | At full subscriber base (Phase 1 plan: ≤500 tenants × ~30 events/day = ~15k events/day) | — |
| Duration | Continuous from sign-up; per-tenant on tenant cancellation; 3-year WORM-anchored chain for chain integrity | — |
| Geography | Processed in T Cloud eu-de (Biere + Magdeburg DE); no cross-border transfers | — |
1.3 Purposes #
- Service security (Art. 6(1)(f) — legitimate interest) — detect abuse, breach, intrusion. The audit log is a Tier-1 input to fremverk’s intrusion-detection signals.
- Customer trust (Art. 6(1)(b) — performance of contract) — fremverk markets the auditability and tamper-evidence of the audit chain as a contracted feature; without retention + chain integrity, the contract cannot be performed.
- Regulatory compliance (Art. 6(1)(c) — legal obligation) — Bogføringsloven §10 requires 5-year retention of accounting records (intersects with billing-related audit events; the 5-year obligation governs that subset, not the full 3-year audit chain).
- Customer operations (Art. 6(1)(b)) — customer admins use the audit log to trace user actions inside their own tenant.
1.4 Stakeholders consulted #
- Privacy contact (DPO-equivalent): compliance@frem.sh — routed to the data-protection-responsible partner at fremverk ApS (shj@fremverk.com). No GDPR Art. 37 DPO designation is required (assessment in privacy-product.md §2); compliance@ is the functional equivalent for data-subject communications and supervisory-authority liaison. Conflict-management for the dual-role of privacy contact + incident commander is covered in controller-incident-response.md §“Roles”.
- Engineering: shj as solo founder + CTO. Architecture review against the canonical baseline (fremverk/architecture/caf.md).
- Customers: customer feedback on the contracted audit-trail feature was solicited via the pre-launch waitlist; the response confirmed audit-trail tamper-evidence is a top-3 trust signal.
- Supervisory authority: not formally consulted at DPIA stage. Per Art. 36, prior consultation is required only if residual risk is high after mitigations; §6 below concludes residual risk is low.
2. Necessity and proportionality #
2.1 Lawful basis #
Per §1.3 above. The legitimate-interest balancing test (Art. 6(1)(f)) is documented in §3.
2.2 Necessity #
The processing is strictly necessary for the contracted security and audit-trail features:
- Without per-event records, there is no way to correlate an intrusion or insider-abuse signal with a concrete user action.
- Without hash-chaining, an attacker with
audit_eventswrite access could rewrite history; the chain protects against insider tampering as well as external compromise. - Without WORM-anchoring, a sufficiently privileged attacker could rewrite the entire chain consistently. The WORM anchor is the trust boundary that closes that gap.
Lower-impact alternatives considered + rejected:
- No audit log — incompatible with the contracted audit-trail feature and with the Customer’s own GDPR Art. 30 / 32 obligations, which often require a working audit trail at the processor.
- Audit log without chain integrity — fails the customer-trust purpose and is open to insider-tampering attacks.
- Audit log without WORM anchor — fails to detect a privileged-attacker full-chain rewrite.
- Pseudonymise actor on emit — would prevent legitimate operations use (
who-did-whatcorrelation across tenants when investigating cross-tenant abuse). The 90-day retention split (§5.1) achieves the equivalent privacy outcome while preserving the operational use during the 90-day investigation window.
2.3 Proportionality #
The processing is limited to what is necessary:
- Data minimisation: event metadata only — no repository content, no file diffs, no payment-instrument data, no support-correspondence content.
- Purpose limitation: the audit log feeds the security on-call dashboards and the customer-facing audit endpoint. It is not used for marketing, profiling, or any decision affecting data-subject rights beyond the contracted security purpose.
- Storage limitation: 90-day hot retention of payload (§5.1); 3-year WORM-anchored chain hashes (irreversible, no PII content); 5-year retention only for the accounting subset that Bogføringsloven §10 mandates.
- Accuracy: events are immutable on emit; corrections happen by emitting a new event referencing the prior, never by updating in place.
3. Article 6(1)(f) balancing test #
3.1 fremverk’s legitimate interest #
Operating a security-monitored, audit-evidenced Git/CI/CD platform. Without the processing, fremverk cannot meet its DPA Annex A.7 commitments to Customers nor honour its Art. 32 GDPR security obligations.
3.2 Necessity #
See §2.2.
3.3 Data subjects’ rights and freedoms #
The data subjects are:
- Customer end-users (developers, admins, billing contacts): they have a reasonable expectation that their actions on a Git/CI/CD platform are logged for security purposes. The audit-trail feature is contracted at the Customer level (the Customer is a Controller of its end-users for this processing) and is a routine SaaS feature.
- fremverk staff operators: they have a reasonable expectation that operator-console actions are logged; this is documented in the staff handbook as a condition of access.
3.4 Risks #
| Risk | Severity (1–5) | Likelihood (1–5) | Net |
|---|---|---|---|
Re-identification from actor field | 4 | 3 | 12 |
| Tracking of user behaviour via fields_json correlation | 3 | 3 | 9 |
| Unauthorised access by fremverk staff | 4 | 2 | 8 |
| Compromise of WORM bucket leading to chain replay | 5 | 1 | 5 |
| Sub-processor (T Cloud) law-enforcement disclosure | 4 | 1 | 4 |
| Long-term retention beyond necessity | 3 | 3 | 9 |
(See §5 for mitigations.)
3.5 Balancing outcome #
After the §5 mitigations, fremverk’s legitimate interest is not overridden by the data subjects’ rights and freedoms. The audit-log feature is the routine industry expectation for the service category; the 90-day payload-retention cap brings the privacy posture below the typical SaaS-audit-log baseline; the WORM anchor protects subjects against insider tampering of the log itself; and the residual chain hashes are mathematically irreversible.
4. Risk assessment #
The risks identified in §3.4 are evaluated qualitatively. Severity scale: 1 = trivial, 5 = catastrophic. Likelihood: 1 = remote, 5 = ongoing.
4.1 Re-identification from actor field — net 12
#
The actor field stores a username, an OIDC subject, or an api-token id. For 90 days hot, this field is recoverable; combined with the action + fields_json, an attacker with read access could profile a user’s activity pattern.
4.2 Tracking via fields_json correlation — net 9 #
fields_json contains structured event-specific data. Some fields are user-supplied (commit messages in push-protection events); others are system-generated (rule_id, repo_full_name). Cross-event correlation could profile user behaviour beyond the event-by-event meaning.
4.3 Unauthorised access by fremverk staff — net 8 #
Staff operators have read access to the audit stream for incident-response purposes. Unauthorised access — staff reading the log outside an active incident — would be a Class A breach per controller-incident-response.md.
4.4 Compromise of WORM bucket — net 5 #
OBS Object Lock COMPLIANCE-mode prevents tamper-with-or-delete inside the 3-year retention. A successful attack on the WORM bucket would require T Cloud account-takeover at root-AK level; mitigated by bootstrap.md §1.2 (root AK on operator laptop, mode 600, never echoed to chat or logs, rotated quarterly via OTC console).
4.5 Sub-processor (T Cloud) law-enforcement disclosure — net 4 #
T Cloud is operated by Deutsche Telekom AG, a German entity with no US parent. Any law-enforcement disclosure is governed by German + EU law; the CLOUD Act has no extraterritorial reach. Documented in DPA §10 and the trust page.
4.6 Long-term retention beyond necessity — net 9 #
Without the retention split, payload would be retained for 3 years; the §5.1 mitigation reduces this to 90 days hot for payload. The 5-year accounting subset (Bogføringsloven §10) is unavoidable but is narrowly scoped to billing-related events.
5. Mitigations #
5.1 Retention split (primary mitigation — closes risks 4.1, 4.2, 4.6) #
Hot tier (0 — per-tenant cutoff N days): full event payload — actor, action, fields_json, prev_hash, hash. The cutoff N is set at Authentication policy → Audit log retention with presets {90, 180, 365, 730}; defaults 90 (standard) or 365 (enterprise). Used for security on-call investigations, customer-facing audit-log queries, and the per-tenant audit-integrity verifier.
Archive tier (N days – 3 years): per-event row with payload_redacted_at = <cutoff> set; actor replaced with the sentinel "redacted"; fields_json replaced with {}. The hash and prev_hash columns are unchanged — chain integrity is preserved. The chain walk recognises payload-redacted rows and counts them as a verified-redaction sentinel rather than a tamper, mirroring the existing tenant_erased_at semantics in audit-emit.ts.
Customer setting below plan SLA floor (yes-by-design). The admin UI does not enforce the contractual SLA floor (enterprise = 365d). A tenant admin may set the hot-tier below the plan floor (e.g. 90d on an enterprise tenant); doing so disclaims the contractual queryability commitment for the affected period. This is a deliberate split between the technical permit (database CHECK) and the contractual constraint (SLA). The DSAR-fulfilment surface returns the redacted row when queried past the chosen cutoff.
Implementation status: shipped 2026-05-06. Daily /jobs/audit-payload-reaper cron in the monolith api runs the redaction batch — 5000 rows per UPDATE, up to 50 batches per run (250k row/day cap, picks up backlog over consecutive days). Migration 0031 added payload_redacted_at + partial index. verifyChainWalk recognises payload-redacted rows as a verified-redaction sentinel (same path as tenant_erased_at). The endpoint is appended to the daily api-jobs-cron CCE CronJob (api-jobs-cron.yaml) which fires at 02:30 UTC and runs all /jobs/* endpoints sequentially — applied to fremforge-prd 2026-05-06.
Outcome: after 90 days, an attacker with audit_events SELECT access can no longer recover actor identifiers, fields_json content, or any payload that supports re-identification. The chain hashes remain — these are SHA-256 outputs over canonicalised inputs and are mathematically irreversible without the original inputs (which have been redacted).
5.2 Sub-event scope ceiling (closes risk 4.2) #
fields_json is restricted at emit time to a documented allow-list of fields per action — see the action-schema map in audit-emit.ts. Free-form user content (commit messages, file content, comment bodies) is NEVER serialised into fields_json; only structural metadata (rule_id, repo_full_name, override-reason-category) is.
5.3 Access controls (closes risk 4.3) #
- Staff read access to
audit_eventsis via the operator console, not direct SQL — every read produces its own audit event (operator.audit_log.read). The reads are themselves auditable. - The api-runtime DB role has
SELECTonaudit_events(needed for/audit/integrity) but noINSERT/UPDATE/DELETEoutside the emit code path. - The retention reaper (when shipped) will run as its own DB role with
UPDATEonaudit_eventsonly foractor+fields_jsoncolumns +payload_redacted_at, no other columns.
5.4 WORM lock + KMS (closes risk 4.4) #
- OBS Object Lock COMPLIANCE-mode on the audit-anchor bucket; 3-year retention configured at bucket-creation time and applied at the version level.
- Bucket-side KMS encryption with a fremverk-owned DEW CMK (annual rotation enabled).
- Bucket policy restricts
s3:DeleteObjectands3:DeleteObjectVersionto no principal — even root cannot delete inside the lock period.
5.5 Sub-processor controls (closes risk 4.5) #
T Cloud is bound by DPA Annex B sub-processor terms, the standard contractual clauses inside the EU, and the BSI C5 Type 2 audit. Law-enforcement requests are governed by the Bundesgesetzbuch and EU GDPR.
5.6 Data-subject rights (closes risk 4.6 supplementary) #
- Right of access (Art. 15): Customer admins can export their tenant’s audit log via the public REST API (
GET /api/v1/orgs/:slug/audit); end-users request via their Customer admin per DPA §6. - Right to erasure (Art. 17): tenant cancellation triggers physical-purge at T+90d (P0-11); audit-event PII is pseudonymised at that point via the existing
tenant_erased_atflow (migration 0025). - Right to object (Art. 21): not applicable to this processing — the audit log is necessary for the contract per Art. 6(1)(b) and for legitimate interest per Art. 6(1)(f); it is not opt-out by design (a service that can opt out of audit logging is not the contracted service).
- Right to portability (Art. 20): covered by the same
/api/v1/orgs/:slug/auditexport endpoint, which returns NDJSON.
6. Residual risk #
| Original risk | Mitigation | Residual severity | Residual likelihood | Residual net |
|---|---|---|---|---|
Re-identification from actor (4.1) | §5.1 retention split | 2 | 2 | 4 |
| Tracking via fields_json (4.2) | §5.1 + §5.2 scope ceiling | 2 | 2 | 4 |
| Unauthorised staff access (4.3) | §5.3 access controls + Class A runbook | 3 | 1 | 3 |
| WORM compromise (4.4) | §5.4 Object Lock + KMS | 4 | 1 | 4 |
| LE disclosure (4.5) | §5.5 EU-only sub-processor | 3 | 1 | 3 |
| Long-term retention (4.6) | §5.1 retention split | 2 | 2 | 4 |
All residuals are at “low” (≤ net 4). Under Datatilsynet guidance, prior consultation under Art. 36 is required only when residual risk remains high — which it does not here. fremverk has therefore not formally consulted Datatilsynet on this DPIA; the DPIA itself, the documented mitigations, and the Art. 33-class incident-response runbook (controller-incident-response.md) are the operational compliance posture.
7. Outstanding items #
- Annual review — calendared for 2027-05-06 per the frontmatter
next_review.
7A. Review cadence (P2-LEG-28) #
This DPIA reviews on the cadence in the front-matter (every 12 months, or on material change to the processing). The list below enumerates what counts as a “material change” — a non-exhaustive set of trigger conditions that fire an early review. The 12-month annual review proceeds in parallel; an early-review version increment does not reset the annual clock.
| Trigger | Reviewer | Outcome shape |
|---|---|---|
New category of personal data added to audit_events.fields_json (beyond the documented set in §1.4) | DPO | Either narrow the schema, or re-run §3 balancing + §4 risk against the new shape and version-bump |
| New audit-event consumer added on the read side (e.g., a CES alarm that surfaces audit-event fields to a third-party SaaS) | Compliance Officer | Re-evaluate §5.2 scope ceiling; reject if it crosses the disclosed boundary |
| Retention-tier change (90-day hot, 30-day operational, 3-year WORM) | Compliance Officer + Controller | Re-run §3 balancing; coordinate with DPA §A.7 version bump |
| Anchor cadence change (current 2-min — see DSA tamper-window closure) | Compliance Officer | Re-evaluate the integrity-risk calculation in §4; update DPA §A.7 + audit-chain customer doc cadence references in lock-step |
| Sub-processor change on the audit-stream path (LTS, OBS, KMS) | Compliance Officer + Controller | Triggers a sub-processor change-notification under DPA §10 AND a DPIA version bump |
| Cross-border transfer activated (e.g., support flow that exposes an audit-stream to a non-EU support contractor) | Compliance Officer + external counsel | Out-of-scope for the current low-risk posture; activation requires re-running the DPIA from scratch and may require Art. 36 consultation with Datatilsynet |
| Datatilsynet guidance update on systematic monitoring (item 5 of the published DPIA list) | Compliance Officer | Re-read §3 against the updated guidance; version-bump if the analysis changes |
| Customer audit (per DPA §12.1) flags a finding | DPO | Address in the response; if structural, version-bump |
A trigger always produces a version bump, even if the review concludes “no material change after analysis” — the version bump documents that the review fired.
8. Sign-off #
| Role | Name | Date | Sign-off |
|---|---|---|---|
| Data Protection Officer | shj@fremverk.com | 2026-05-06 | Reviewed and approved. Residual risk: low. Prior consultation under Art. 36 not required. |
| Controller | fremverk ApS, CVR 39150689 | 2026-05-06 | Approved for production processing. |
9. Change-log #
| Version | Date | Author | Change |
|---|---|---|---|
| 1.0 | 2026-05-06 | shj | Initial DPIA. Closes audit finding P0-13. Documents the retention-split mitigation (§5.1) and scope ceiling (§5.2). Implements Datatilsynet’s DPIA list (item 5) precautionary reading. Residual risk: low; no Art. 36 consultation required. |
| 1.1 | 2026-05-08 | shj | §1 anchor cadence updated 5min→2min in the audit-event flow (mirrors DPA §A.7 + cronjob change in P0-DSA-TAMPER-WINDOW). New §7A “Review cadence” enumerates 8 trigger conditions for an early review (P2-LEG-28). Residual risk unchanged: low; no Art. 36 consultation required. |
| 1.2 | 2026-05-25 | shj | §1, §5.1: retention-split widened from a fixed 90-day hot tier to a customer-tunable {90, 180, 365, 730}-day hot tier (default 90 standard / 365 enterprise). Reflects P0-AUDIT-RETENTION-TIER shipped 2026-05-24 (migrations 0144 + 0146; route at admin-auth-policy.tsx:61). §3 Art-6(1)(f) balancing re-run with 730-day worst-case bound; §6 residual-risk score re-evaluated; risk 4.6 (long-term retention beyond necessity) remains low because (a) the customer chooses the window and is responsible for the necessity assessment per Art-5(1)(c), (b) the hash chain is mathematically irreversible after redaction, (c) the WORM tier carries no payload PII. §5.1 also documents the “set below plan floor” yes-by-design split between database CHECK (1–730d) and SLA-contractual minimum (365d for enterprise). No Art. 36 consultation required. |