heygrc
Guide

GDPR code review checks: which duties show up in a pull request

Most "GDPR code review" search results are cookie scanners or generic secure-coding essays. This is the PR-level map: Art. 5(1)(c) and (e), Art. 17, Art. 25, Art. 32, and Art. 44 as they appear in a diff, with a worked example that is not a retention bug.

Tristan RothFounder of heygrc and ISMS Copilot

  • Founder of Better ISMS
  • Built ISMS Copilot, the GRC assistant for ISO 27001 and neighboring frameworks
  • Maps framework controls to pull-request diffs in heygrc

Engineers searching for GDPR code review checks usually want one thing: a short list of legal duties that can actually break in a normal pull request, not a full privacy-programme handbook. The Regulation is mostly process, records, and organisational measures. A consistent minority of duties still land in code: what you store, how long you keep it, whether a delete path reaches every copy, what the defaults expose, how processing is secured, and where data is hosted.

This guide is that map. It is deliberately not the walkthrough of a single storage-limitation bug (that lives at /guides/catching-a-gdpr-retention-bug-in-code-review) and not a control deep dive (those live under /frameworks/gdpr). It is the code-review checklist: which articles to name, what the change shape looks like, and what a reviewer can ask without becoming counsel.

The articles that tend to move in a diff

Art. 5(1)(c) data minimisation: a change starts collecting or logging more personal data than the purpose needs (full request bodies, full identity records copied into a side store). Art. 5(1)(e) storage limitation: a new personal-data store or cache ships with no retention bound, or a purge window is widened without purpose. Art. 17 right to erasure: a delete path stops short of a cache, search index, analytics export, or processor copy. Art. 25 data protection by design and by default: a personal field becomes visible or shared with every user by default, or a protective default is flipped off. Art. 32 security of processing: encryption, access control, or integrity measures on personal data are weakened (TLS floor dropped, plaintext token store, admin path opened). Art. 44 chapter on transfers: personal data is moved to a new region or third-country processor without the transfer story your programme expects.

Those glosses are plain-English for engineers, not the Regulation's text. When a finding cites a clause, it is a signal to the author and privacy contact, not a determination that processing is unlawful.

Worked example: privacy-by-default flipped for "support convenience"

A support team wants faster ticket triage. An engineer opens a pull request that changes the customer profile API so every authenticated staff role receives full_name, email, phone, and last_four payment digits in the default list endpoint, not only on an explicit "expand=pii" request. The change is small: one serializer flag flipped from false to true. Tests update to expect the richer payload. Code review talks about response size and cache headers. Nothing looks like a security bug; authentication still works.

What moved is Art. 25 data protection by design and by default: personal data is now exposed by default to a wider set of internal consumers than the previous least-privilege shape. The safer shape keeps the narrow default and requires an explicit, audited expand for support tooling. That is a different failure mode from the retention bug (Art. 5(1)(e) on a new store with no purge) and from a pure minimisation logging example (Art. 5(1)(c) on request bodies). A compliance-aware review cites Art. 25 (and often Art. 5(1)(c) as a supporting principle) on the PR while the flag is still easy to reverse.

What to ask in review without becoming a DPO

For any change that touches personal data: what fields are new, who can see them by default, how long they live, and whether a delete or export path still reaches them. For region or vendor changes: where does the data go, and does privacy already track that processor or transfer. For "cleanup" PRs: did we remove encryption, access checks, or audit lines that protected personal data (Art. 32 adjacent).

You do not need to quote the Regulation. You need to refuse to merge when the answer is "unknown" until someone owns the privacy step, or restore the safer default.

Where heygrc fits, and the honesty boundary

heygrc is built to read each pull request against the frameworks you selected, including the GDPR when enabled, and to name the article a change appears to touch (for example Art. 25 on a widened default payload). It does not decide lawful basis, run DPIAs, maintain RoPA, approve transfers, or replace your DPO. A green review is not a supervisory sign-off.

Bug and quality reviewers stay on the same PR. They ask whether the code is correct. GDPR questions ask whether personal-data duties still hold. Run both.