
Dpia Assessment
- 48 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
DPIA Assessment is a Claude skill for GDPR Article 35 Data Protection Impact Assessments that checks DPIA thresholds, manages a risk register, and scores residual risk.
About
DPIA Assessment is tooling for GDPR Article 35 Data Protection Impact Assessments. It evaluates whether a DPIA is required using Art. 35(3) triggers and the nine EDPB criteria, manages a risk register with mitigation tracking and residual-risk calculation, and checks the Art. 36 consultation threshold. A privacy team uses it to determine DPIA obligations and document data-protection risk. The skill is marked experimental and explicitly not legal advice.
- Checks whether a GDPR Art. 35 DPIA is required via Art. 35(3) triggers and 9 EDPB criteria
- Manages a JSON risk register with likelihood/severity scoring and residual-risk after mitigations
- Checks the Art. 36 prior-consultation threshold for high residual risk
Dpia Assessment by the numbers
- 48 all-time installs (skills.sh)
- Ranked #1,343 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
dpia-assessment capabilities & compatibility
- Capabilities
- data breach response · eu ai act specialist
- Use cases
- security audit
- Pricing
- Free
What dpia-assessment says it does
GDPR Art. 35 Data Protection Impact Assessment with threshold checking, risk registers, and EDPB criteria scoring.
Evaluates whether a DPIA is required, manages risk registers with mitigation tracking, and generates documentation meeting supervisory authority expectations.
Checks Art. 35(3) mandatory triggers and 9 EDPB criteria.
npx skills add https://github.com/borghei/claude-skills --skill dpia-assessmentAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 48 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Determine if a GDPR DPIA is required and track data-protection risks and mitigations to residual risk.
Who is it for?
Privacy and DPO teams deciding whether a processing activity needs a DPIA and documenting its data-protection risk.
Skip if: Legal advice or final legal sign-off; it is marked experimental and outputs assessments, not legal determinations.
When should I use this skill?
Assessing whether a new processing activity requires a DPIA, building a privacy risk register, or checking Art. 36 consultation.
What you get
A Required/Recommended/Not Required verdict with EDPB criteria scores and a risk register showing residual risk after mitigations.
- DPIA required/recommended/not-required verdict
- EDPB criteria scoring
- risk register with residual risk
By the numbers
- 9 EDPB criteria assessed
- 1-5 likelihood and severity scales
- 20+ common DPIA risks catalog
Files
⚠️ EXPERIMENTAL — This skill is provided for educational and informational purposes only. It does NOT constitute legal advice. All responsibility for usage rests with the user. Consult qualified legal professionals before acting on any output.
DPIA Assessment
GDPR Article 35 Data Protection Impact Assessment tooling. Evaluates whether a DPIA is required, manages risk registers with mitigation tracking, and generates documentation meeting supervisory authority expectations.
---
Table of Contents
- Tools
- DPIA Threshold Checker
- DPIA Risk Register
- Reference Guides
- Workflows
- Legal Precision Points
- Output Formats
- Troubleshooting
- Success Criteria
- Scope & Limitations
- Anti-Patterns
- Tool Reference
---
Tools
DPIA Threshold Checker
Evaluates whether a DPIA is required based on processing activity description. Checks Art. 35(3) mandatory triggers and 9 EDPB criteria.
# Check a processing activity (interactive prompts)
python scripts/dpia_threshold_checker.py --activity "AI-based credit scoring using financial and behavioral data of retail banking customers across EU"
# Check from JSON description
python scripts/dpia_threshold_checker.py --input processing.json
# JSON output
python scripts/dpia_threshold_checker.py --activity "Employee monitoring via CCTV in workplace" --json
# Generate blank input template
python scripts/dpia_threshold_checker.py --template > processing.jsonChecks performed:
- Art. 35(3)(a): Automated decision-making with legal/significant effect
- Art. 35(3)(b): Large-scale processing of special category data (Art. 9) or criminal data (Art. 10)
- Art. 35(3)(c): Systematic monitoring of publicly accessible area on large scale
- 9 EDPB criteria from WP 248 rev.01 with two-criterion presumption rule
Output:
- Verdict: Required / Recommended / Not Required
- Art. 35(3) trigger matches
- EDPB criteria scores with reasoning
- Two-criterion presumption analysis
---
DPIA Risk Register
Manages a DPIA risk register in JSON format. Add risks, apply mitigations, and calculate residual risk.
# Initialize a new risk register
python scripts/dpia_risk_register.py init --output dpia_risks.json
# Add a risk
python scripts/dpia_risk_register.py add --register dpia_risks.json \
--description "Unauthorized access to profiling data" \
--rights-category "right-to-privacy" \
--likelihood 4 --severity 3
# Add mitigation to a risk
python scripts/dpia_risk_register.py mitigate --register dpia_risks.json \
--risk-id 1 --measure "Implement role-based access control" \
--likelihood-reduction 2 --severity-reduction 1
# View risk register table
python scripts/dpia_risk_register.py view --register dpia_risks.json
# Generate residual risk summary
python scripts/dpia_risk_register.py summary --register dpia_risks.json --json
# Check Art. 36 consultation threshold
python scripts/dpia_risk_register.py art36-check --register dpia_risks.jsonRights categories: right-to-privacy, non-discrimination, freedom-of-expression, right-to-information, right-to-not-be-subject-to-automated-decisions, right-to-physical-safety
---
Reference Guides
EDPB Criteria
references/edpb_criteria.md
Complete EDPB 9-criteria assessment framework:
- Each criterion with description, indicators, and scoring guidance
- Art. 35(3) mandatory triggers
- Two-criterion presumption rule (WP 248 rev.01)
- Multi-jurisdictional DPIA analysis
- National blacklist/whitelist overview (DE, FR, IE, BE, NL, IT, PL)
Risk Scoring Methodology
references/risk_scoring_methodology.md
DPIA risk scoring from the data subject perspective:
- Likelihood and severity scales (1-5)
- Rights categories per Recital 75
- Risk level thresholds (Low/Medium/High/Very High)
- Mitigation effectiveness scoring
- Residual risk calculation
- Art. 36 consultation triggers
- Risk catalog: 20+ common DPIA risks
---
Workflows
Workflow 1: Full DPIA Assessment
Step 1: Threshold check — determine if DPIA required
→ python scripts/dpia_threshold_checker.py --activity "description"
Step 2: If Required or Recommended, describe the processing
→ Document purpose, legal basis, data categories, recipients, retention
Step 3: Assess necessity and proportionality
→ Confirm lawful basis (Art. 6, cumulative with Art. 9 if special categories)
→ Verify purpose limitation, data minimization, storage limitation
Step 4: Identify risks from data subject perspective
→ python scripts/dpia_risk_register.py init --output dpia_risks.json
→ Add risks using references/risk_scoring_methodology.md catalog
Step 5: Apply mitigations and calculate residual risk
→ python scripts/dpia_risk_register.py mitigate --register dpia_risks.json ...
Step 6: Check Art. 36 consultation requirement
→ python scripts/dpia_risk_register.py art36-check --register dpia_risks.json
Step 7: Document and review
→ python scripts/dpia_risk_register.py summary --register dpia_risks.jsonWorkflow 2: Quick Threshold Assessment
Step 1: Describe the processing activity
→ python scripts/dpia_threshold_checker.py --template > processing.json
→ Fill in processing details
Step 2: Run threshold check
→ python scripts/dpia_threshold_checker.py --input processing.json --json
Step 3: Review verdict and reasoning
→ Required: proceed to full DPIA (Workflow 1)
→ Recommended: proceed unless strong justification to skip (document)
→ Not Required: document the assessment and rationaleWorkflow 3: AI System DPIA
Step 1: Classify AI system (EU AI Act risk level if applicable)
→ Map to DPIA triggers (automated decision-making, profiling, scoring)
Step 2: Run threshold check with AI-specific indicators
→ python scripts/dpia_threshold_checker.py --activity "AI system description"
Step 3: Dual-phase risk analysis (EDPB Opinion 28/2024)
→ Phase 1: Training data risks (collection, bias, consent)
→ Phase 2: Inference risks (decisions, profiling, transparency)
Step 4: Assess from data subject perspective
→ Add risks covering both training and inference phases
→ Include algorithmic bias, lack of transparency, unfair outcomes
Step 5: Apply mitigations specific to AI
→ Explainability measures, human oversight, bias testing
→ Document FRIA distinction per EU AI Act Art. 27 if applicable---
Legal Precision Points
12 points of legal precision that distinguish expert-level DPIA work.
| # | Point | Detail |
|---|---|---|
| 1 | Art. 35(3) absolute triggers | Three mandatory triggers require DPIA regardless of other analysis: (a) automated decisions with legal effect, (b) large-scale special category/criminal data, (c) systematic public area monitoring |
| 2 | Two-criterion presumption | If 2 or more of the 9 EDPB criteria are met, DPIA is presumptively required (WP 248 rev.01). Can rebut only with documented justification |
| 3 | Art. 9 cumulative with Art. 6 | Special category data requires BOTH an Art. 6 lawful basis AND an Art. 9(2) exception. Neither alone is sufficient |
| 4 | Large scale four-factor test | Assess: (a) number of data subjects, (b) volume of data, (c) geographic extent, (d) duration/permanence. No fixed numeric threshold |
| 5 | National blacklists additive | SA-published lists of processing operations requiring DPIA add to (not replace) Art. 35(3) and EDPB criteria |
| 6 | Multi-jurisdictional checking | If processing spans multiple member states, check each SA's blacklist. Most restrictive list applies |
| 7 | Pre-processing obligation | DPIA must be completed BEFORE processing begins (Art. 35(1)). Retroactive DPIAs do not satisfy the requirement |
| 8 | AI dual-phase analysis | EDPB Opinion 28/2024: AI systems require separate risk analysis for training phase and inference/deployment phase |
| 9 | Art. 36 sequential | Prior consultation with SA (Art. 36) is triggered only AFTER DPIA is completed and residual risk remains high. Cannot skip the DPIA |
| 10 | Pseudonymization nuance | EDPB Guidelines 01/2025: pseudonymization reduces risk but does not eliminate DPIA requirement. Still personal data |
| 11 | Data subject perspective | All risks must be assessed from the data subject's perspective (Recital 75), not the controller's business perspective |
| 12 | AI Act FRIA distinction | EU AI Act Art. 27 requires Fundamental Rights Impact Assessment (FRIA) for high-risk AI. FRIA is separate from GDPR DPIA — both may be required |
---
Output Formats
Threshold Verdict
VERDICT: DPIA REQUIRED
Reason: Art. 35(3)(a) trigger matched (automated decision-making with legal effect)
+ 4 of 9 EDPB criteria met (two-criterion presumption applies)
Matched triggers: automated_decision_making, evaluation_scoring, sensitive_data, large_scaleRisk Register Table
| ID | Description | Rights Category | L | S | Score | Level | Mitigation | Residual L | Residual S | Residual Score | Residual Level |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | Unauthorized profiling | Right to privacy | 4 | 3 | 12 | High | RBAC + encryption | 2 | 2 | 4 | Low |
| 2 | Discriminatory outcomes | Non-discrimination | 3 | 4 | 12 | High | Bias testing + human review | 2 | 3 | 6 | Medium |
Residual Risk Overview
Total risks: 8
Mitigated: 6 (75%)
Residual risk distribution:
Low: 3 (37.5%)
Medium: 3 (37.5%)
High: 2 (25.0%)
Very High: 0 (0.0%)
Art. 36 consultation: NOT TRIGGERED (no Very High residual risks)---
Troubleshooting
| Problem | Possible Cause | Resolution |
|---|---|---|
| Threshold checker says "Not Required" but processing feels risky | Activity description too vague or missing key details | Provide more specific description including data types, scale, automation level, and data subject categories |
| Two-criterion presumption triggered but controller disagrees | Controller must document justification for rebutting presumption | Document specific reasons why DPIA is not needed despite criteria match; SA may challenge this |
| Risk register shows High residual risk after mitigations | Mitigations insufficient or not properly scored | Review mitigation effectiveness; consider additional controls; if residual risk remains high, Art. 36 consultation required |
| Multi-jurisdictional check produces conflicting results | Different SAs have different blacklists and thresholds | Apply the most restrictive requirement; document the analysis for each jurisdiction |
| AI system DPIA unclear on training vs. inference risks | Training and inference phases have different risk profiles | Separate the analysis per EDPB Opinion 28/2024; assess each phase independently then combine |
| Art. 36 check unclear on threshold | Residual risk near the boundary between High and Very High | Document the borderline assessment; consider voluntary consultation as good practice |
---
Success Criteria
- All high-risk processing activities assessed -- threshold check completed before processing begins, with documented verdict and reasoning
- Risk register complete with mitigations -- every identified risk has likelihood, severity, rights category, and at least one mitigation measure
- Residual risk acceptable or Art. 36 consultation initiated -- no unaddressed Very High residual risks
- Documentation meets SA expectations -- assessment follows Art. 35(7) requirements: systematic description, necessity/proportionality, risks, mitigations
- EDPB criteria properly applied -- two-criterion presumption correctly evaluated with documented reasoning
---
Scope & Limitations
In Scope:
- DPIA threshold assessment against Art. 35(3) triggers and EDPB criteria
- Risk register management with mitigation tracking and residual risk calculation
- Art. 36 prior consultation threshold assessment
- Multi-jurisdictional blacklist awareness (DE, FR, IE, BE, NL, IT, PL)
- AI system dual-phase DPIA analysis guidance
- Data subject perspective risk assessment per Recital 75
Out of Scope:
- Legal advice on lawful basis selection (Art. 6) or Art. 9(2) exception applicability
- Supervisory authority submission or interaction
- Technical implementation of mitigations (encryption, access control)
- DPO appointment or consultation logistics
- National blacklist exhaustive coverage beyond listed jurisdictions
- EU AI Act conformity assessment (see eu-ai-act-specialist)
---
Anti-Patterns
- Conducting DPIA after processing has started -- Art. 35(1) requires DPIA before processing begins; retroactive DPIAs do not satisfy the legal obligation and create enforcement exposure
- Assessing risk from the controller's perspective -- DPIA risks must be evaluated from the data subject's perspective per Recital 75; business impact is irrelevant to this analysis; a breach that is minor for the company may be catastrophic for affected individuals
- Treating pseudonymization as eliminating DPIA need -- pseudonymized data remains personal data under GDPR (Recital 26); pseudonymization is a mitigation that reduces risk scores, not a basis for skipping the DPIA entirely
- Skipping Art. 36 consultation when residual risk is high -- if residual risk remains Very High after mitigations, prior consultation with the supervisory authority is mandatory, not optional
- Conflating DPIA with FRIA -- the EU AI Act's Fundamental Rights Impact Assessment (Art. 27) is a separate obligation from GDPR DPIA; completing one does not satisfy the other; both may be required for AI systems processing personal data
---
Tool Reference
dpia_threshold_checker.py
Evaluates whether a DPIA is required based on Art. 35(3) triggers and EDPB criteria.
| Flag | Required | Description |
|---|---|---|
--activity <text> | Yes (unless --input or --template) | Processing activity description |
--input <file> | Yes (unless --activity) | Path to JSON processing description |
--template | No | Generate blank input template |
--json | No | Output in JSON format |
dpia_risk_register.py
Manages DPIA risk register with mitigation tracking and residual risk calculation.
| Subcommand | Description |
|---|---|
init | Create new empty risk register (--output required) |
add | Add risk (--register, --description, --rights-category, --likelihood, --severity required) |
mitigate | Add mitigation (--register, --risk-id, --measure, --likelihood-reduction, --severity-reduction required) |
view | Display risk register table (--register required) |
summary | Generate summary with distribution (--register required, --json optional) |
art36-check | Check Art. 36 consultation requirement (--register required) |
EDPB Criteria for DPIA Threshold Assessment
Complete reference for the 9 EDPB criteria, Art. 35(3) mandatory triggers, two-criterion presumption rule, and multi-jurisdictional analysis.
---
Table of Contents
- Art. 35(3) Mandatory Triggers
- EDPB 9 Criteria
- Two-Criterion Presumption Rule
- Criterion Detailed Analysis
- Multi-Jurisdictional DPIA Analysis
- National Blacklist Overview
- Threshold Decision Matrix
---
Art. 35(3) Mandatory Triggers
These three triggers make a DPIA mandatory regardless of any other analysis. If any one is met, the DPIA must be conducted before processing begins.
| Trigger | Article | Description | Examples |
|---|---|---|---|
| (a) Automated decisions with legal effect | Art. 35(3)(a) | Systematic and extensive evaluation of personal aspects based on automated processing, including profiling, on which decisions are based that produce legal effects concerning the natural person or similarly significantly affect them | Credit scoring, automated insurance pricing, automated recruitment screening, algorithmic content moderation affecting access to services |
| (b) Large-scale special/criminal data | Art. 35(3)(b) | Processing on a large scale of special categories of data referred to in Art. 9(1), or of personal data relating to criminal convictions and offences referred to in Art. 10 | Hospital patient record systems, national health registries, genetic testing services, large-scale biometric authentication, criminal background check databases |
| (c) Systematic public area monitoring | Art. 35(3)(c) | Systematic monitoring of a publicly accessible area on a large scale | City-wide CCTV systems, facial recognition in public spaces, Wi-Fi tracking in shopping centers, smart city sensor networks, body-worn cameras in public-facing roles |
Key interpretation notes:
- "Legal effect" includes denial of credit, employment decisions, social benefits determinations, and immigration decisions
- "Similarly significant effect" includes effects that influence circumstances, behavior, or choices and have a prolonged or permanent impact (WP 251 rev.01)
- "Large scale" has no fixed numeric threshold — assessed by number of data subjects, data volume, geographic extent, and duration (see Criterion 5 below)
- "Publicly accessible area" includes streets, shopping centers, parks, and any area generally open to the public regardless of ownership
---
EDPB 9 Criteria
Source: EDPB (formerly WP29) Guidelines on Data Protection Impact Assessment, WP 248 rev.01.
| # | Criterion | Description |
|---|---|---|
| 1 | Evaluation or scoring | Profiling and predicting, especially concerning data subjects' performance at work, economic situation, health, personal preferences, interests, reliability, behavior, location, or movements |
| 2 | Automated decision-making with legal/significant effect | Processing aimed at taking decisions on data subjects producing legal effects or similarly significantly affecting them |
| 3 | Systematic monitoring | Processing used to observe, monitor, or control data subjects, including data collected through networks or systematic monitoring of publicly accessible areas |
| 4 | Sensitive data or highly personal data | Processing of special categories (Art. 9), criminal data (Art. 10), or data considered highly personal (financial, location, communications, browsing) |
| 5 | Large scale processing | Assessed by: number of data subjects, volume of data items, geographic extent, duration or permanence of processing |
| 6 | Matching or combining datasets | Combining datasets from different processing operations or different controllers in a way that would exceed data subjects' reasonable expectations |
| 7 | Vulnerable data subjects | Data concerning persons where there is an imbalance of power: children, employees, patients, elderly, mentally ill, asylum seekers |
| 8 | Innovative technology | Use of novel technology including AI, machine learning, IoT, biometrics, blockchain, deep fakes, autonomous vehicles |
| 9 | Preventing exercise of right or service | Processing that prevents data subjects from exercising a right, using a service, or entering into a contract |
---
Two-Criterion Presumption Rule
Per WP 248 rev.01, paragraph II.C:
"In most cases, a data controller can consider that a processing meeting two criteria would require a DPIA to be carried out. In general, the WP29 considers that the more criteria are met by the processing, the more likely it is to present a high risk to the rights and freedoms of data subjects, and therefore to require a DPIA, regardless of the measures which the controller envisages to adopt."
Decision Logic
| Criteria Met | Verdict | Action Required |
|---|---|---|
| 0 | Not Required | Document threshold assessment |
| 1 | Recommended | DPIA recommended as good practice; document rationale if not conducting |
| 2 | Presumptively Required | DPIA required unless controller can document why processing does not result in high risk |
| 3+ | Required | DPIA required; multiple criteria indicate elevated risk profile |
Rebutting the Presumption
The two-criterion presumption can be rebutted, but:
- The controller must document specific reasons why the processing does not result in high risk despite meeting two or more criteria
- The documentation must be available to the supervisory authority upon request
- Supervisory authorities may challenge the rebuttal and require a DPIA anyway
- In practice, rebutting the presumption is rarely advisable — conducting the DPIA is usually less effort than documenting and defending a rebuttal
---
Criterion Detailed Analysis
Criterion 1: Evaluation or Scoring
| Indicator | Weight | Examples |
|---|---|---|
| Profiling based on behavior | High | User behavior tracking for ad targeting, content recommendation |
| Credit or financial scoring | High | Credit score calculation, fraud detection scoring |
| Performance evaluation | Medium | Employee performance algorithms, student assessment tools |
| Health risk prediction | High | Predictive health analytics, insurance risk scoring |
| Location-based profiling | Medium | Movement pattern analysis, geofencing-based profiles |
| Personality assessment | High | Psychometric testing, behavioral prediction models |
Criterion 2: Automated Decision-Making
| Indicator | Weight | Examples |
|---|---|---|
| Automated approval/denial | High | Loan applications, insurance claims, visa processing |
| Service eligibility determination | High | Benefits eligibility, service tier assignment |
| Price personalization | Medium | Dynamic pricing based on personal data, insurance premium calculation |
| Content restriction | Medium | Age verification, content moderation, account suspension |
| Employment decisions | High | Automated CV screening, algorithmic scheduling, automated termination |
Criterion 3: Systematic Monitoring
| Indicator | Weight | Examples |
|---|---|---|
| CCTV/video surveillance | High | Workplace cameras, retail analytics, public space monitoring |
| Online tracking | Medium | Cookie-based tracking, cross-site tracking, fingerprinting |
| Location tracking | High | GPS tracking of employees/vehicles, mobile app location services |
| Communication monitoring | High | Email monitoring, call recording, messaging surveillance |
| IoT sensor data collection | Medium | Smart home data, wearable devices, connected vehicle telemetry |
Criterion 4: Sensitive or Highly Personal Data
| Data Type | Article Reference | Sensitivity |
|---|---|---|
| Health data | Art. 9(1) | Special category |
| Genetic data | Art. 9(1) | Special category |
| Biometric data (for identification) | Art. 9(1) | Special category |
| Racial or ethnic origin | Art. 9(1) | Special category |
| Political opinions | Art. 9(1) | Special category |
| Religious or philosophical beliefs | Art. 9(1) | Special category |
| Trade union membership | Art. 9(1) | Special category |
| Sex life or sexual orientation | Art. 9(1) | Special category |
| Criminal convictions/offences | Art. 10 | Restricted processing |
| Financial data | WP29 guidance | Highly personal |
| Location data | WP29 guidance | Highly personal |
| Communication content | WP29 guidance | Highly personal |
Criterion 5: Large Scale — Four-Factor Test
| Factor | Assessment Questions | Examples |
|---|---|---|
| (a) Number of data subjects | How many individuals are affected? Absolute number and proportion of relevant population | >10,000 data subjects typically qualifies; city-wide or regional scope |
| (b) Volume of data | How much data per subject? How many data items total? | Multiple data categories per subject; high granularity |
| (c) Geographic extent | Regional, national, international? Multiple jurisdictions? | Nationwide service; EU-wide processing; multi-country operations |
| (d) Duration or permanence | Ongoing or one-time? How long is data retained? | Continuous processing; long retention periods; permanent records |
Note: A single GP practice processing patient data is NOT large scale (Recital 91). A hospital system serving a region IS large scale. No fixed numeric threshold exists — all four factors must be considered together.
Criterion 6: Matching or Combining
| Indicator | Weight | Examples |
|---|---|---|
| Cross-platform data combination | High | Combining social media data with purchase history |
| Third-party data enrichment | High | Augmenting customer records with data broker information |
| Multiple controller data sharing | Medium | Joint controllership combining datasets |
| Unexpected correlation | High | Combining datasets for purposes beyond original collection |
Criterion 7: Vulnerable Data Subjects
| Vulnerable Group | Power Imbalance | Considerations |
|---|---|---|
| Children | Cannot validly consent (under 16, or national threshold) | Parental consent; age-appropriate design; best interests |
| Employees | Economic dependence on employer | Cannot freely consent in employment context (WP29); EDPB Guidelines 2/2023 |
| Patients | Dependent on healthcare providers | Difficulty withholding consent for treatment-linked processing |
| Elderly | Potential cognitive/technological barriers | Accessibility of information and consent mechanisms |
| Asylum seekers | Dependent on state authorities | Power imbalance with processing entity |
| Students | Dependent on educational institution | Institutional pressure to consent |
Criterion 8: Innovative Technology
| Technology | Risk Factors | Assessment Notes |
|---|---|---|
| AI/Machine Learning | Opacity, bias, unpredictability | Both training and inference phases; EDPB Opinion 28/2024 |
| Facial recognition | Biometric data, surveillance | Art. 9 special category when used for identification |
| IoT devices | Pervasive collection, limited control | Data minimization challenges; consent difficulties |
| Blockchain | Immutability conflicts with erasure right | Art. 17 tension; pseudonymization approaches |
| Generative AI | Training data provenance, output accuracy | Purpose limitation; accuracy principle; transparency |
| Deepfake technology | Identity, consent, accuracy | Potential for fraud, defamation, manipulation |
Criterion 9: Preventing Exercise of Rights
| Scenario | Impact | Examples |
|---|---|---|
| Mandatory processing for service access | Denies choice | "Accept tracking or no access" |
| Credit scoring affecting contracts | Financial exclusion | Loan denial based on automated scoring |
| Content filtering affecting expression | Rights limitation | Algorithmic content suppression |
| Access control based on biometrics | Physical access restriction | Biometric-only building entry |
---
Multi-Jurisdictional DPIA Analysis
When processing spans multiple EU/EEA member states, the DPIA analysis must consider:
| Step | Action | Reference |
|---|---|---|
| 1 | Identify all jurisdictions where data subjects are located | Art. 35(1) |
| 2 | Check Art. 35(3) triggers (universal — apply everywhere) | Art. 35(3) |
| 3 | Apply EDPB 9-criteria assessment | WP 248 rev.01 |
| 4 | Check each jurisdiction's national blacklist | Art. 35(4) |
| 5 | Check each jurisdiction's national whitelist | Art. 35(5) |
| 6 | Apply most restrictive requirement | Principle of highest protection |
| 7 | Document multi-jurisdictional analysis | Accountability principle |
Lead supervisory authority: Under the one-stop-shop mechanism (Art. 56), the lead SA for cross-border processing is the SA of the main establishment. However, DPIA obligations apply regardless of which SA is lead.
---
National Blacklist Overview
Processing types requiring DPIA per national supervisory authority published lists (Art. 35(4)). This is non-exhaustive — always check current SA-published lists.
Germany (DSK / State DPAs)
| Processing Type | Notes |
|---|---|
| Processing of biometric data for identification in public spaces | Stricter than base GDPR |
| Profiling with risk of discrimination | Includes credit scoring |
| Processing employee data using AI | Specific to employment context |
| Large-scale processing of location data | Includes fleet tracking, app location |
| Automated analysis of audio/video recordings | CCTV analytics, call center monitoring |
France (CNIL)
| Processing Type | Notes |
|---|---|
| Health data processing for research | Even with pseudonymization |
| Biometric processing for access control | Workplace biometric systems |
| Genetic data processing | Any scale |
| Profiling with legal/significant effects | Broader than Art. 35(3)(a) |
| Processing of vulnerable persons' data at large scale | Includes social services |
Ireland (DPC)
| Processing Type | Notes |
|---|---|
| Processing involving innovative technology | Broad interpretation |
| Large-scale profiling | Lower threshold than some SAs |
| Processing preventing exercise of rights | Strict interpretation |
| Systematic monitoring of employees | Workplace surveillance |
Belgium (APD/GBA)
| Processing Type | Notes |
|---|---|
| Processing of biometric data | Any identification purpose |
| Processing of genetic data | Including research contexts |
| Processing for direct marketing based on profiling | Stricter than some SAs |
| Processing of judicial data on large scale | Broader than Art. 10 alone |
Netherlands (AP)
| Processing Type | Notes |
|---|---|
| Covert investigation or monitoring | Including fraud investigation |
| Blacklists or exclusion lists | Internal warning systems |
| Processing of financial data indicating financial status | Broader financial data scope |
| Biometric data for identification | Similar to DE |
Italy (Garante)
| Processing Type | Notes |
|---|---|
| Processing data for automated decisions including profiling | Broad scope |
| Processing genetic, biometric, health data on large scale | Lower threshold |
| Systematic monitoring of employees | Including productivity monitoring |
| Data collected via IoT applications | Smart devices, wearables |
Poland (UODO)
| Processing Type | Notes |
|---|---|
| Processing using biometric data | For identification or verification |
| Processing of genetic data | All contexts |
| Processing of location data | Including mobile tracking |
| Processing data for credit/insurance scoring | Explicit inclusion |
---
Threshold Decision Matrix
Quick reference combining all trigger sources:
| Trigger Source | Threshold | Result if Met |
|---|---|---|
| Art. 35(3)(a) — automated decisions with legal effect | Any match | DPIA mandatory |
| Art. 35(3)(b) — large-scale special/criminal data | Any match | DPIA mandatory |
| Art. 35(3)(c) — systematic public area monitoring | Any match | DPIA mandatory |
| EDPB criteria — 2 or more met | 2+ of 9 | DPIA presumptively required |
| EDPB criteria — 1 met | 1 of 9 | DPIA recommended |
| National blacklist — processing type listed | Any match | DPIA mandatory per that SA |
| National whitelist — processing type listed | Any match | DPIA not required per that SA |
| None of the above | No matches | DPIA not required (document assessment) |
Priority order: Art. 35(3) > National blacklist > EDPB criteria > National whitelist. A whitelist entry cannot override an Art. 35(3) trigger.
DPIA Risk Scoring Methodology
Risk scoring system for Data Protection Impact Assessments from the data subject perspective per GDPR Recital 75 and EDPB guidance.
---
Table of Contents
- Scoring Scales
- Rights Categories
- Risk Level Thresholds
- Mitigation Effectiveness Scoring
- Residual Risk Calculation
- Art. 36 Consultation Triggers
- Risk Catalog
---
Scoring Scales
Likelihood Scale
Likelihood assesses the probability of the risk materializing given the processing activity and its context.
| Level | Label | Probability | Description | Indicators |
|---|---|---|---|---|
| 1 | Negligible | <5% | Extremely unlikely given current controls and processing context | No known attack vector; multiple layers of protection; no precedent |
| 2 | Limited | 5-25% | Unlikely but cannot be entirely ruled out | Theoretical vulnerability exists; similar incidents rare in industry |
| 3 | Significant | 25-50% | Reasonable possibility | Known vulnerabilities in similar systems; some industry precedent; partial controls |
| 4 | Maximum | 50-75% | More likely than not to occur | Active threats targeting similar processing; control gaps identified; industry incidents common |
| 5 | Almost certain | >75% | Expected to occur | Demonstrated vulnerability; active exploitation attempts; no effective controls |
Severity Scale (Data Subject Perspective)
Severity is assessed exclusively from the data subject perspective per Recital 75. This is NOT about business impact to the controller.
| Level | Label | Description | Examples of Impact on Data Subjects |
|---|---|---|---|
| 1 | Negligible | Minor inconvenience that data subjects can easily overcome | Brief delay in service; minor administrative correction needed; temporary limited access |
| 2 | Limited | Significant inconvenience that data subjects can overcome with some effort | Need to re-register for service; minor financial cost to remediate; time spent dealing with issue |
| 3 | Significant | Consequences that data subjects may overcome with serious difficulties | Financial loss requiring recovery effort; reputational damage in limited circle; emotional distress |
| 4 | Maximum | Irreversible or very difficult to overcome consequences | Identity theft with financial impact; discriminatory treatment; job loss; health consequences |
| 5 | Critical | Consequences that cannot be overcome; existential impact | Physical harm or danger; severe financial ruin; irreversible discrimination; loss of liberty |
Recital 75 Risk Sources
Recital 75 identifies these specific risk outcomes that must be assessed:
| Risk Outcome | Typical Severity |
|---|---|
| Discrimination | 3-5 |
| Identity theft or fraud | 3-5 |
| Financial loss | 2-4 |
| Damage to reputation | 2-4 |
| Loss of confidentiality of data protected by professional secrecy | 3-5 |
| Unauthorized reversal of pseudonymisation | 2-4 |
| Significant economic or social disadvantage | 3-5 |
| Deprivation of rights and freedoms | 4-5 |
| Prevention from exercising control over personal data | 2-4 |
| Physical harm | 4-5 |
---
Rights Categories
DPIA risks must be mapped to the specific fundamental rights they affect. This ensures the assessment covers all dimensions of impact.
| Category | Relevant Rights | GDPR Articles | Charter Articles |
|---|---|---|---|
| Right to privacy | Protection of personal data; private and family life | Art. 5, 6, 25, 32 | Art. 7, 8 EU Charter |
| Non-discrimination | Equal treatment regardless of protected characteristics | Art. 5(1)(a), 22 | Art. 21 EU Charter |
| Freedom of expression | Ability to express opinions without surveillance chilling effects | Art. 85, 89 | Art. 11 EU Charter |
| Right to information | Transparency about processing; access to own data | Art. 12-15 | Art. 8(2) EU Charter |
| Right to not be subject to automated decisions | Human involvement in significant decisions; right to explanation | Art. 22 | Art. 8, 47 EU Charter |
| Right to physical safety | Protection from physical harm resulting from data processing | Art. 32 | Art. 3 EU Charter |
Mapping Guidance
When adding a risk to the register, select the primary rights category affected:
| If the risk involves... | Primary category |
|---|---|
| Unauthorized access to personal data | right-to-privacy |
| Biased algorithmic decisions | non-discrimination |
| Surveillance or monitoring chilling effects | freedom-of-expression |
| Lack of transparency about processing | right-to-information |
| Automated decisions without human review | right-to-not-be-subject-to-automated-decisions |
| Safety implications of data misuse | right-to-physical-safety |
---
Risk Level Thresholds
Risk Score = Likelihood x Severity. Thresholds follow the standard 5x5 matrix.
| Score Range | Level | Color | Action Required |
|---|---|---|---|
| 1-4 | Low | Green | Accept residual risk. Document in DPIA. No further mitigation required. |
| 5-9 | Medium | Yellow | Consider additional mitigations. Document rationale if accepting. Monitor. |
| 10-15 | High | Orange | Additional mitigations required before processing. DPO consultation mandatory. |
| 16-25 | Very High | Red | Processing cannot proceed. Art. 36 prior consultation with SA required. Fundamental redesign or additional safeguards mandatory. |
Risk Level Decision Table
| Likelihood \ Severity | 1 (Negligible) | 2 (Limited) | 3 (Significant) | 4 (Maximum) | 5 (Critical) |
|---|---|---|---|---|---|
| 5 (Almost certain) | 5 Medium | 10 High | 15 High | 20 Very High | 25 Very High |
| 4 (Maximum) | 4 Low | 8 Medium | 12 High | 16 Very High | 20 Very High |
| 3 (Significant) | 3 Low | 6 Medium | 9 Medium | 12 High | 15 High |
| 2 (Limited) | 2 Low | 4 Low | 6 Medium | 8 Medium | 10 High |
| 1 (Negligible) | 1 Low | 2 Low | 3 Low | 4 Low | 5 Medium |
---
Mitigation Effectiveness Scoring
When applying a mitigation, assess its effectiveness in reducing likelihood and severity.
Likelihood Reduction
| Reduction | Effectiveness | Examples |
|---|---|---|
| 0 | No effect on likelihood | Mitigation addresses severity only (e.g., insurance) |
| 1 | Minor reduction | Basic access controls; awareness training; policy documentation |
| 2 | Moderate reduction | Role-based access control; encryption at rest; regular audits |
| 3 | Significant reduction | Multi-factor authentication; zero-trust architecture; automated monitoring |
| 4 | Major reduction | End-to-end encryption; complete data anonymization; processing redesign |
Severity Reduction
| Reduction | Effectiveness | Examples |
|---|---|---|
| 0 | No effect on severity | Mitigation addresses likelihood only (e.g., stronger authentication) |
| 1 | Minor reduction | Incident response plan; data subject notification procedures; pseudonymization |
| 2 | Moderate reduction | Data minimization; purpose limitation enforcement; retention limits |
| 3 | Significant reduction | Pseudonymization with separated key management; human oversight for automated decisions |
| 4 | Major reduction | Full anonymization; processing scope reduction; data subject opt-out mechanisms |
Mitigation Type Reference
| Mitigation Type | Typical L Reduction | Typical S Reduction | Notes |
|---|---|---|---|
| Encryption (at rest) | 1-2 | 1 | Reduces unauthorized access likelihood; limits breach severity |
| Encryption (in transit) | 1-2 | 0-1 | Protects data in motion |
| Pseudonymization | 1 | 1-2 | Reduces re-identification risk; not anonymization |
| Access control (RBAC) | 2 | 0 | Limits who can access data |
| Data minimization | 0-1 | 2-3 | Reduces data available if breach occurs |
| Retention limits | 0 | 1-2 | Limits data available over time |
| Human oversight | 0-1 | 2-3 | For automated decisions; reduces harm from errors |
| Consent management | 1 | 1 | Ensures lawful processing; enables data subject control |
| Audit logging | 1 | 0-1 | Deters misuse; enables detection and response |
| Incident response plan | 0 | 1-2 | Reduces impact through rapid response |
| Data subject notification | 0 | 1 | Enables subjects to take protective action |
| Anonymization | 3-4 | 3-4 | Removes personal data status entirely |
| Differential privacy | 2-3 | 2-3 | Statistical privacy guarantees for aggregate queries |
| Bias testing/auditing | 0-1 | 2-3 | For AI systems; reduces discriminatory outcomes |
| Transparency measures | 0 | 1-2 | Privacy notices, algorithmic explanations |
---
Residual Risk Calculation
Residual risk is calculated after applying all mitigations to a risk.
Formula
Residual Likelihood = max(1, Original Likelihood - Sum of Likelihood Reductions)
Residual Severity = max(1, Original Severity - Sum of Severity Reductions)
Residual Score = Residual Likelihood x Residual Severity
Residual Level = Level corresponding to Residual ScoreRules
- Residual likelihood and severity cannot go below 1 (risk is never zero)
- Multiple mitigations are cumulative in their reductions
- Mitigations with overlapping mechanisms should not be double-counted
- Residual risk must be documented even if Low
- If residual risk remains Very High after all feasible mitigations, Art. 36 consultation is mandatory
Example
| Step | Likelihood | Severity | Score | Level |
|---|---|---|---|---|
| Original risk | 4 | 4 | 16 | Very High |
| After mitigation 1 (RBAC, L-2, S-0) | 2 | 4 | 8 | Medium |
| After mitigation 2 (data minimization, L-0, S-2) | 2 | 2 | 4 | Low |
---
Art. 36 Consultation Triggers
When Prior Consultation is Required
Art. 36(1): The controller shall prior to processing consult the supervisory authority where the DPIA under Art. 35 indicates that the processing would result in a high risk in the absence of measures taken by the controller to mitigate the risk.
In practice, this means:
| Residual Risk Level | Art. 36 Obligation |
|---|---|
| Low | No consultation required |
| Medium | No consultation required |
| High | Consultation not strictly required; voluntary consultation recommended |
| Very High | Prior consultation MANDATORY |
Consultation Process
| Step | Requirement | Timeline |
|---|---|---|
| 1 | Submit DPIA to supervisory authority | Before processing begins |
| 2 | Include: purposes, means, safeguards, DPO contact, DPIA results | With submission |
| 3 | SA acknowledges receipt | Varies by SA |
| 4 | SA provides written advice | Within 8 weeks (Art. 36(2)) |
| 5 | SA may extend for complex cases | Additional 6 weeks with notice |
| 6 | Controller must follow SA advice | Before processing begins |
Borderline Cases
For residual risks near the High/Very High boundary (scores 14-16):
- Score 14-15 (High): Formal Art. 36 not required, but voluntary consultation demonstrates accountability. Document the borderline assessment.
- Score 16 (Very High): Art. 36 consultation is mandatory. Even if the controller considers the risk adequately mitigated, the score threshold triggers the obligation.
---
Risk Catalog
20+ common DPIA risks organized by type with typical severity and likelihood ranges.
Unauthorized Access / Confidentiality
| Risk | Typical L | Typical S | Primary Rights Category |
|---|---|---|---|
| External attacker gains access to personal data | 2-4 | 3-5 | right-to-privacy |
| Insider threat — employee accesses data without authorization | 2-3 | 2-4 | right-to-privacy |
| Third-party processor breach | 2-3 | 3-4 | right-to-privacy |
| Cloud storage misconfiguration exposes data | 2-4 | 3-5 | right-to-privacy |
| Unencrypted data intercepted in transit | 1-3 | 2-4 | right-to-privacy |
Excessive Collection / Purpose Limitation
| Risk | Typical L | Typical S | Primary Rights Category |
|---|---|---|---|
| Data collected beyond stated purpose | 2-4 | 2-3 | right-to-privacy |
| Function creep — data used for new undisclosed purpose | 3-4 | 2-4 | right-to-information |
| Excessive data collection relative to stated purpose | 2-3 | 2-3 | right-to-privacy |
| Inadequate privacy notice — data subjects uninformed | 3-4 | 2-3 | right-to-information |
Retention / Deletion
| Risk | Typical L | Typical S | Primary Rights Category |
|---|---|---|---|
| Data retained beyond necessary period | 3-4 | 2-3 | right-to-privacy |
| Inability to delete data upon request (Art. 17) | 2-3 | 2-4 | right-to-privacy |
| Backup retention prevents complete erasure | 3-4 | 1-3 | right-to-privacy |
| Lack of automated retention enforcement | 3-4 | 2-3 | right-to-privacy |
Cross-Border Transfer
| Risk | Typical L | Typical S | Primary Rights Category |
|---|---|---|---|
| Transfer to inadequate country without safeguards | 2-3 | 3-4 | right-to-privacy |
| Standard Contractual Clauses not implemented | 2-3 | 3-4 | right-to-privacy |
| Transfer Impact Assessment not conducted | 3-4 | 2-3 | right-to-privacy |
Automated Decision-Making / Profiling
| Risk | Typical L | Typical S | Primary Rights Category |
|---|---|---|---|
| Automated decisions without human review option | 2-4 | 3-5 | right-to-not-be-subject-to-automated-decisions |
| Algorithmic bias producing discriminatory outcomes | 2-4 | 3-5 | non-discrimination |
| Lack of transparency in automated logic | 3-4 | 2-4 | right-to-information |
| Inaccurate profiling leading to unfair treatment | 2-4 | 3-5 | non-discrimination |
| No mechanism to contest automated decisions | 2-3 | 3-4 | right-to-not-be-subject-to-automated-decisions |
Surveillance / Monitoring
| Risk | Typical L | Typical S | Primary Rights Category |
|---|---|---|---|
| Chilling effect on behavior from monitoring awareness | 3-5 | 2-4 | freedom-of-expression |
| Disproportionate employee monitoring | 3-4 | 2-4 | right-to-privacy |
| Location tracking beyond necessary scope | 2-4 | 2-4 | right-to-privacy |
| Biometric data collection without adequate safeguards | 2-3 | 4-5 | right-to-privacy |
Safety
| Risk | Typical L | Typical S | Primary Rights Category |
|---|---|---|---|
| Data breach enables physical stalking or harassment | 1-2 | 4-5 | right-to-physical-safety |
| AI system makes safety-critical decision based on inaccurate data | 1-3 | 4-5 | right-to-physical-safety |
| Medical data inaccuracy leads to treatment error | 1-2 | 4-5 | right-to-physical-safety |
#!/usr/bin/env python3
"""
DPIA Risk Register
Manages a DPIA risk register in JSON format. Supports adding risks,
applying mitigations, calculating residual risk, and checking Art. 36
consultation thresholds.
Usage:
python dpia_risk_register.py init --output dpia_risks.json
python dpia_risk_register.py add --register dpia_risks.json --description "Unauthorized access" --rights-category "right-to-privacy" --likelihood 4 --severity 3
python dpia_risk_register.py mitigate --register dpia_risks.json --risk-id 1 --measure "RBAC" --likelihood-reduction 2 --severity-reduction 1
python dpia_risk_register.py view --register dpia_risks.json
python dpia_risk_register.py summary --register dpia_risks.json --json
python dpia_risk_register.py art36-check --register dpia_risks.json
"""
import argparse
import json
import sys
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional
VALID_RIGHTS_CATEGORIES: List[str] = ["right-to-privacy", "non-discrimination", "freedom-of-expression", "right-to-information", "right-to-not-be-subject-to-automated-decisions", "right-to-physical-safety"]
def get_risk_level(score: int) -> str:
"""Return risk level based on score."""
if score <= 4:
return "Low"
elif score <= 9:
return "Medium"
elif score <= 15:
return "High"
return "Very High"
def clamp(value: int, lo: int, hi: int) -> int:
"""Clamp value to range."""
return max(lo, min(hi, value))
def load_register(filepath: str) -> Dict[str, Any]:
"""Load risk register from file."""
path = Path(filepath)
if not path.exists():
print(f"Error: Register file not found: {filepath}", file=sys.stderr)
sys.exit(1)
try:
with open(path, "r") as f:
return json.load(f)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON in register: {e}", file=sys.stderr)
sys.exit(1)
def save_register(filepath: str, register: Dict[str, Any]) -> None:
"""Save risk register to file."""
register["last_modified"] = datetime.now().isoformat()
with open(filepath, "w") as f:
json.dump(register, f, indent=2)
def cmd_init(args: argparse.Namespace) -> None:
"""Initialize a new empty risk register."""
register: Dict[str, Any] = {"dpia_title": "", "processing_activity": "", "controller": "",
"created": datetime.now().isoformat(), "last_modified": datetime.now().isoformat(), "risks": [], "next_id": 1}
output = args.output or "dpia_risks.json"
save_register(output, register)
print(f"Risk register initialized: {output}")
def cmd_add(args: argparse.Namespace) -> None:
"""Add a risk to the register."""
if args.rights_category not in VALID_RIGHTS_CATEGORIES:
print(f"Error: Invalid rights category '{args.rights_category}'", file=sys.stderr)
print(f"Valid: {', '.join(VALID_RIGHTS_CATEGORIES)}", file=sys.stderr)
sys.exit(1)
likelihood = clamp(args.likelihood, 1, 5)
severity = clamp(args.severity, 1, 5)
score = likelihood * severity
register = load_register(args.register)
risk_id = register.get("next_id", len(register["risks"]) + 1)
level = get_risk_level(score)
risk: Dict[str, Any] = {"id": risk_id, "description": args.description, "rights_category": args.rights_category,
"likelihood": likelihood, "severity": severity, "score": score, "level": level, "mitigations": [],
"residual_likelihood": likelihood, "residual_severity": severity, "residual_score": score,
"residual_level": level, "added": datetime.now().isoformat()}
register["risks"].append(risk)
register["next_id"] = risk_id + 1
save_register(args.register, register)
if args.json:
print(json.dumps(risk, indent=2))
else:
print(f"Risk #{risk_id} added: {args.description}")
print(f" Score: {score} ({get_risk_level(score)})")
print(f" Rights: {args.rights_category}")
def cmd_mitigate(args: argparse.Namespace) -> None:
"""Add a mitigation to a risk."""
register = load_register(args.register)
risk = None
for r in register["risks"]:
if r["id"] == args.risk_id:
risk = r
break
if risk is None:
print(f"Error: Risk #{args.risk_id} not found", file=sys.stderr)
sys.exit(1)
mitigation: Dict[str, Any] = {
"measure": args.measure,
"likelihood_reduction": clamp(args.likelihood_reduction, 0, 4),
"severity_reduction": clamp(args.severity_reduction, 0, 4),
"added": datetime.now().isoformat(),
}
risk["mitigations"].append(mitigation)
# Recalculate residual risk
total_l_reduction = sum(m["likelihood_reduction"] for m in risk["mitigations"])
total_s_reduction = sum(m["severity_reduction"] for m in risk["mitigations"])
risk["residual_likelihood"] = clamp(risk["likelihood"] - total_l_reduction, 1, 5)
risk["residual_severity"] = clamp(risk["severity"] - total_s_reduction, 1, 5)
risk["residual_score"] = risk["residual_likelihood"] * risk["residual_severity"]
risk["residual_level"] = get_risk_level(risk["residual_score"])
save_register(args.register, register)
if args.json:
print(json.dumps(risk, indent=2))
else:
print(f"Mitigation added to Risk #{args.risk_id}")
print(f" Measure: {args.measure}")
print(f" Original: {risk['score']} ({risk['level']})")
print(f" Residual: {risk['residual_score']} ({risk['residual_level']})")
def cmd_view(args: argparse.Namespace) -> None:
"""Display risk register as table."""
register = load_register(args.register)
risks = register.get("risks", [])
if not risks:
print("Risk register is empty.")
return
if args.json:
print(json.dumps(register, indent=2))
return
print(f"DPIA Risk Register — {register.get('dpia_title', 'Untitled')}")
print(f"Total risks: {len(risks)}\n")
print(f"{'ID':>3} | {'Description':<35} | {'L':>1}x{'S':>1} | {'Score':>5} | {'Level':<9} | {'ResScore':>8} | {'ResLevel':<9}")
print("-" * 95)
for risk in sorted(risks, key=lambda r: r["residual_score"], reverse=True):
desc = risk["description"][:33] + ".." if len(risk["description"]) > 35 else risk["description"]
print(f"{risk['id']:>3} | {desc:<35} | {risk['likelihood']}x{risk['severity']} | {risk['score']:>5} | {risk['level']:<9} | {risk['residual_score']:>8} | {risk['residual_level']:<9}")
def cmd_summary(args: argparse.Namespace) -> None:
"""Generate risk register summary."""
register = load_register(args.register)
risks = register.get("risks", [])
if not risks:
print("Risk register is empty.")
return
total = len(risks)
mitigated = sum(1 for r in risks if len(r.get("mitigations", [])) > 0)
# Distribution (original)
orig_dist: Dict[str, int] = {"Low": 0, "Medium": 0, "High": 0, "Very High": 0}
for r in risks:
orig_dist[r["level"]] += 1
# Distribution (residual)
res_dist: Dict[str, int] = {"Low": 0, "Medium": 0, "High": 0, "Very High": 0}
for r in risks:
res_dist[r["residual_level"]] += 1
# Rights category breakdown
rights_breakdown: Dict[str, int] = {}
for r in risks:
cat = r.get("rights_category", "unknown")
rights_breakdown[cat] = rights_breakdown.get(cat, 0) + 1
# Art. 36 check
very_high_residual = res_dist.get("Very High", 0)
art36_triggered = very_high_residual > 0
pct = round(100 * mitigated / total, 1)
summary: Dict[str, Any] = {"total_risks": total, "mitigated_count": mitigated, "mitigated_percentage": pct,
"original_distribution": orig_dist, "residual_distribution": res_dist, "rights_category_breakdown": rights_breakdown,
"art36_consultation_triggered": art36_triggered, "very_high_residual_count": very_high_residual, "generated": datetime.now().isoformat()}
if args.json:
print(json.dumps(summary, indent=2))
return
print("=" * 55)
print("DPIA RISK REGISTER SUMMARY")
print(f"Total: {total} | Mitigated: {mitigated} ({summary['mitigated_percentage']}%)\n")
for label, dist in [("Original", orig_dist), ("Residual", res_dist)]:
print(f"{label} Distribution:")
for level in ["Very High", "High", "Medium", "Low"]:
count = dist[level]
print(f" {level:<10} {count:>3} ({round(100*count/total,1):>5.1f}%) {'#'*count}")
print()
print(f"Art. 36: {'TRIGGERED — ' + str(very_high_residual) + ' Very High residual risk(s)' if art36_triggered else 'NOT TRIGGERED'}")
print("=" * 55)
def cmd_art36_check(args: argparse.Namespace) -> None:
"""Check Art. 36 prior consultation requirement."""
register = load_register(args.register)
risks = register.get("risks", [])
very_high_risks = [r for r in risks if r.get("residual_level") == "Very High"]
high_risks = [r for r in risks if r.get("residual_level") == "High"]
if args.json:
result = {
"art36_triggered": len(very_high_risks) > 0,
"very_high_count": len(very_high_risks),
"high_count": len(high_risks),
"very_high_risks": very_high_risks,
"recommendation": "",
}
if very_high_risks:
result["recommendation"] = (
"Art. 36 prior consultation with supervisory authority is MANDATORY. "
"Controller must consult before processing begins."
)
elif high_risks:
result["recommendation"] = (
"Art. 36 not strictly required, but voluntary consultation is recommended "
"given High residual risks."
)
else:
result["recommendation"] = "Art. 36 prior consultation is not required."
print(json.dumps(result, indent=2))
return
print("ART. 36 PRIOR CONSULTATION CHECK")
if very_high_risks:
print(f"RESULT: CONSULTATION REQUIRED — {len(very_high_risks)} Very High residual risk(s)")
for r in very_high_risks:
print(f" Risk #{r['id']}: {r['description']} (score: {r['residual_score']})")
print("Action: Consult SA before processing (Art. 36(1)); SA has 8+6 weeks to respond")
elif high_risks:
print(f"RESULT: NOT STRICTLY REQUIRED — {len(high_risks)} High residual risk(s); voluntary consultation recommended")
else:
print("RESULT: NOT REQUIRED — all residual risks at Medium or Low")
def main() -> None:
parser = argparse.ArgumentParser(description="DPIA Risk Register")
sub = parser.add_subparsers(dest="command", help="Command")
p_init = sub.add_parser("init", help="Initialize new risk register")
p_init.add_argument("--output", type=str, help="Output file path")
p_add = sub.add_parser("add", help="Add a risk")
p_add.add_argument("--register", required=True); p_add.add_argument("--description", required=True)
p_add.add_argument("--rights-category", required=True); p_add.add_argument("--likelihood", type=int, required=True)
p_add.add_argument("--severity", type=int, required=True); p_add.add_argument("--json", action="store_true")
p_mit = sub.add_parser("mitigate", help="Add mitigation")
p_mit.add_argument("--register", required=True); p_mit.add_argument("--risk-id", type=int, required=True)
p_mit.add_argument("--measure", required=True); p_mit.add_argument("--likelihood-reduction", type=int, required=True)
p_mit.add_argument("--severity-reduction", type=int, required=True); p_mit.add_argument("--json", action="store_true")
for name in ["view", "summary", "art36-check"]:
p = sub.add_parser(name)
p.add_argument("--register", required=True); p.add_argument("--json", action="store_true")
args = parser.parse_args()
if not args.command:
parser.print_help()
sys.exit(1)
commands = {
"init": cmd_init,
"add": cmd_add,
"mitigate": cmd_mitigate,
"view": cmd_view,
"summary": cmd_summary,
"art36-check": cmd_art36_check,
}
cmd_func = commands.get(args.command)
if cmd_func:
try:
cmd_func(args)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
else:
parser.print_help()
sys.exit(1)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
DPIA Threshold Checker
Evaluates whether a GDPR Article 35 Data Protection Impact Assessment is
required based on processing activity description. Checks Art. 35(3) mandatory
triggers and 9 EDPB criteria with two-criterion presumption rule.
Usage:
python dpia_threshold_checker.py --activity "AI-based credit scoring of retail customers"
python dpia_threshold_checker.py --input processing.json --json
python dpia_threshold_checker.py --template > processing.json
"""
import argparse
import json
import re
import sys
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
# Art. 35(3) mandatory triggers
ART35_TRIGGERS: Dict[str, Dict[str, Any]] = {
"automated_decision_making": {"article": "Art. 35(3)(a)", "description": "Systematic and extensive evaluation based on automated processing producing legal/significant effects", "keywords": ["automated decision", "credit scor", "profiling", "algorithmic decision", "automated processing", "legal effect", "significant effect", "ai-based decision", "machine learning decision", "automated reject", "automated approv", "scoring model", "risk scoring", "eligibility determination"]},
"large_scale_special_category": {"article": "Art. 35(3)(b)", "description": "Large-scale processing of special categories (Art. 9) or criminal data (Art. 10)", "keywords": ["health data", "genetic data", "biometric", "racial", "ethnic origin", "political opinion", "religious belief", "trade union", "sexual orientation", "criminal record", "criminal conviction", "offence data", "medical record", "patient data", "health record", "special category", "sensitive data"]},
"systematic_monitoring": {"article": "Art. 35(3)(c)", "description": "Systematic monitoring of a publicly accessible area on a large scale", "keywords": ["cctv", "video surveillance", "public area monitoring", "facial recognition", "public space", "smart city", "traffic monitoring", "crowd monitoring", "body camera", "drone surveillance", "public wifi tracking", "location tracking public"]},
}
# 9 EDPB criteria (WP 248 rev.01)
EDPB_CRITERIA: Dict[str, Dict[str, Any]] = {
"evaluation_scoring": {"number": 1, "description": "Evaluation or scoring, including profiling and predicting", "keywords": ["scoring", "profiling", "rating", "ranking", "evaluation", "prediction", "behavioral analysis", "personality assessment", "credit score", "risk assessment", "performance score"]},
"automated_decision_legal_effect": {"number": 2, "description": "Automated decision-making with legal or similarly significant effect", "keywords": ["automated decision", "legal effect", "significant effect", "contract denial", "service denial", "automated reject", "credit decision", "insurance pricing", "employment decision"]},
"systematic_monitoring": {"number": 3, "description": "Systematic monitoring", "keywords": ["monitoring", "surveillance", "tracking", "observation", "cctv", "employee monitoring", "internet monitoring", "gps tracking", "email monitoring", "keystroke logging", "screen monitoring"]},
"sensitive_data": {"number": 4, "description": "Sensitive data or data of a highly personal nature", "keywords": ["health", "genetic", "biometric", "racial", "ethnic", "political", "religious", "trade union", "sexual", "criminal", "financial", "location data", "communication content", "browsing history", "children", "minor", "vulnerable"]},
"large_scale": {"number": 5, "description": "Data processed on a large scale", "keywords": ["large scale", "millions", "thousands", "nationwide", "country-wide", "regional", "all customers", "all employees", "all users", "population", "extensive", "mass processing", "bulk"]},
"matching_combining": {"number": 6, "description": "Matching or combining datasets", "keywords": ["matching", "combining", "merging", "cross-referenc", "data fusion", "data linking", "dataset combination", "enrichment", "augmenting", "multiple sources", "third-party data", "data broker"]},
"vulnerable_subjects": {"number": 7, "description": "Data concerning vulnerable data subjects", "keywords": ["children", "minor", "elderly", "patient", "mentally ill", "employee", "asylum seeker", "refugee", "student", "disabled", "vulnerable", "power imbalance", "dependent"]},
"innovative_technology": {"number": 8, "description": "Innovative use or applying new technological or organisational solutions", "keywords": ["ai", "artificial intelligence", "machine learning", "deep learning", "blockchain", "iot", "smart device", "fingerprint", "facial recognition", "voice recognition", "neural network", "generative ai", "llm", "novel", "innovative", "new technology", "emerging technology"]},
"preventing_right_or_service": {"number": 9, "description": "Processing preventing exercise of a right or use of service/contract", "keywords": ["prevent access", "deny service", "block", "restrict access", "gatekeeping", "eligibility check", "mandatory processing", "no opt-out", "compulsory", "required processing", "prerequisite"]},
}
def generate_template() -> Dict[str, Any]:
"""Generate a blank processing activity template."""
return {"activity_name": "", "description": "", "purpose": "", "legal_basis": "",
"data_categories": [], "data_subjects": [], "recipients": [],
"retention_period": "", "international_transfers": False, "transfer_destinations": [],
"automated_decision_making": False, "special_category_data": False,
"large_scale": False, "systematic_monitoring": False,
"innovative_technology": False, "vulnerable_data_subjects": False, "notes": ""}
def check_keywords(text: str, keywords: List[str]) -> Tuple[bool, List[str]]:
"""Check if any keywords match in the text. Returns (matched, matching_keywords)."""
text_lower = text.lower()
matched: List[str] = []
for kw in keywords:
if kw.lower() in text_lower:
matched.append(kw)
return len(matched) > 0, matched
def build_activity_text(data: Dict[str, Any]) -> str:
"""Build searchable text from structured input."""
parts: List[str] = []
for key in ["activity_name", "description", "purpose", "notes"]:
val = data.get(key, "")
if val:
parts.append(str(val))
for key in ["data_categories", "data_subjects", "recipients", "transfer_destinations"]:
val = data.get(key, [])
if isinstance(val, list):
parts.extend(str(v) for v in val)
# Add explicit flags as text
flag_map = {
"automated_decision_making": "automated decision making with legal effect",
"special_category_data": "special category sensitive data health biometric",
"large_scale": "large scale processing nationwide millions",
"systematic_monitoring": "systematic monitoring surveillance tracking",
"innovative_technology": "innovative technology AI machine learning",
"vulnerable_data_subjects": "vulnerable data subjects children employees patients",
}
for flag, text in flag_map.items():
if data.get(flag, False):
parts.append(text)
return " ".join(parts)
def assess_art35_triggers(text: str) -> List[Dict[str, Any]]:
"""Check Art. 35(3) mandatory triggers."""
triggered: List[Dict[str, Any]] = []
for trigger_id, trigger in ART35_TRIGGERS.items():
matched, keywords = check_keywords(text, trigger["keywords"])
if matched:
triggered.append({
"id": trigger_id,
"article": trigger["article"],
"description": trigger["description"],
"matched_keywords": keywords,
})
return triggered
def assess_edpb_criteria(text: str) -> List[Dict[str, Any]]:
"""Check EDPB 9 criteria and return matched criteria."""
matched_criteria: List[Dict[str, Any]] = []
for criterion_id, criterion in EDPB_CRITERIA.items():
matched, keywords = check_keywords(text, criterion["keywords"])
if matched:
matched_criteria.append({
"id": criterion_id,
"number": criterion["number"],
"description": criterion["description"],
"matched_keywords": keywords,
})
return matched_criteria
def determine_verdict(
art35_triggers: List[Dict[str, Any]],
edpb_matches: List[Dict[str, Any]],
) -> Tuple[str, str]:
"""Determine DPIA verdict. Returns (verdict, reasoning)."""
# Art. 35(3) mandatory triggers
if art35_triggers:
trigger_names = [t["article"] for t in art35_triggers]
return (
"REQUIRED",
f"Art. 35(3) mandatory trigger(s) matched: {', '.join(trigger_names)}. "
f"DPIA is legally required before processing begins.",
)
# Two-criterion presumption (WP 248 rev.01)
edpb_count = len(edpb_matches)
if edpb_count >= 2:
criteria_nums = [str(m["number"]) for m in edpb_matches]
return (
"REQUIRED",
f"{edpb_count} of 9 EDPB criteria met (criteria {', '.join(criteria_nums)}). "
f"Two-criterion presumption applies per WP 248 rev.01. "
f"DPIA is presumptively required. Controller may rebut with documented justification.",
)
# Single criterion — recommended
if edpb_count == 1:
return (
"RECOMMENDED",
f"1 of 9 EDPB criteria met (criterion {edpb_matches[0]['number']}). "
f"Two-criterion presumption not triggered, but DPIA is recommended as good practice. "
f"Document rationale if not conducting DPIA.",
)
# No matches
return (
"NOT_REQUIRED",
"No Art. 35(3) triggers matched and no EDPB criteria met. "
"DPIA is not required based on the information provided. "
"Document this assessment. Re-evaluate if processing scope changes.",
)
def format_human(
verdict: str,
reasoning: str,
art35_triggers: List[Dict[str, Any]],
edpb_matches: List[Dict[str, Any]],
) -> str:
"""Format results for human-readable output."""
lines: List[str] = [
"=" * 65,
"DPIA THRESHOLD ASSESSMENT",
f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M')}",
"=" * 65,
"",
f"VERDICT: {verdict}",
"",
f"Reasoning: {reasoning}",
"",
]
if art35_triggers:
lines.append("ART. 35(3) MANDATORY TRIGGERS MATCHED:")
lines.append("-" * 45)
for t in art35_triggers:
lines.append(f" [{t['article']}] {t['description']}")
lines.append(f" Matched indicators: {', '.join(t['matched_keywords'][:5])}")
lines.append("")
lines.append(f"EDPB CRITERIA ASSESSMENT ({len(edpb_matches)} of 9 met):")
lines.append("-" * 45)
all_criteria_ids = sorted(EDPB_CRITERIA.keys(), key=lambda k: EDPB_CRITERIA[k]["number"])
matched_ids = {m["id"] for m in edpb_matches}
for cid in all_criteria_ids:
criterion = EDPB_CRITERIA[cid]
status = "MET" if cid in matched_ids else "---"
match_info = ""
if cid in matched_ids:
match = next(m for m in edpb_matches if m["id"] == cid)
match_info = f" (indicators: {', '.join(match['matched_keywords'][:3])})"
lines.append(f" [{status}] {criterion['number']}. {criterion['description']}{match_info}")
lines.append("")
two_crit = len(edpb_matches) >= 2
lines.append(f"Two-criterion presumption: {'APPLIES' if two_crit else 'Does not apply'}")
lines.append("")
# Recommendations
lines.append("NEXT STEPS:")
lines.append("-" * 45)
if verdict == "REQUIRED":
lines.append(" 1. Conduct full DPIA before processing begins (Art. 35(1))")
lines.append(" 2. Document processing description, necessity, proportionality")
lines.append(" 3. Identify and assess risks from data subject perspective")
lines.append(" 4. Apply mitigations and calculate residual risk")
lines.append(" 5. Consult DPO (Art. 35(2))")
lines.append(" 6. If residual risk high, consider Art. 36 prior consultation with SA")
elif verdict == "RECOMMENDED":
lines.append(" 1. Consider conducting DPIA as best practice")
lines.append(" 2. Document rationale if not conducting DPIA")
lines.append(" 3. Monitor for changes that could trigger additional criteria")
else:
lines.append(" 1. Document this threshold assessment")
lines.append(" 2. Re-evaluate if processing scope or nature changes")
lines.append(" 3. Check national SA blacklists for jurisdiction-specific requirements")
lines.append("")
lines.append("=" * 65)
return "\n".join(lines)
def format_json(
activity_text: str,
verdict: str,
reasoning: str,
art35_triggers: List[Dict[str, Any]],
edpb_matches: List[Dict[str, Any]],
) -> Dict[str, Any]:
"""Format results as JSON."""
return {
"assessment_date": datetime.now().isoformat(),
"verdict": verdict,
"reasoning": reasoning,
"art35_triggers": art35_triggers,
"edpb_criteria": {
"total_met": len(edpb_matches),
"two_criterion_presumption": len(edpb_matches) >= 2,
"matched": edpb_matches,
},
"activity_summary": activity_text[:200] if activity_text else "",
}
def main() -> None:
parser = argparse.ArgumentParser(
description="DPIA Threshold Checker — Art. 35(3) triggers and EDPB criteria"
)
parser.add_argument("--activity", type=str, help="Processing activity description text")
parser.add_argument("--input", type=str, help="JSON file with processing activity details")
parser.add_argument("--template", action="store_true", help="Generate blank input template")
parser.add_argument("--json", action="store_true", help="Output in JSON format")
args = parser.parse_args()
if args.template:
print(json.dumps(generate_template(), indent=2))
return
# Get activity text
activity_text: str = ""
if args.input:
path = Path(args.input)
if not path.exists():
print(f"Error: File not found: {args.input}", file=sys.stderr)
sys.exit(1)
try:
with open(path, "r") as f:
data = json.load(f)
activity_text = build_activity_text(data)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON: {e}", file=sys.stderr)
sys.exit(1)
elif args.activity:
activity_text = args.activity
else:
parser.error("Provide --activity, --input, or --template")
if not activity_text.strip():
print("Error: Activity description is empty", file=sys.stderr)
sys.exit(1)
# Run assessment
art35_triggers = assess_art35_triggers(activity_text)
edpb_matches = assess_edpb_criteria(activity_text)
verdict, reasoning = determine_verdict(art35_triggers, edpb_matches)
# Output
if args.json:
result = format_json(activity_text, verdict, reasoning, art35_triggers, edpb_matches)
print(json.dumps(result, indent=2))
else:
print(format_human(verdict, reasoning, art35_triggers, edpb_matches))
if __name__ == "__main__":
main()
Related skills
FAQ
How does it decide if a DPIA is required?
It checks the Art. 35(3) mandatory triggers and the 9 EDPB criteria from WP 248 rev.01, applying the two-criterion presumption rule, and returns Required, Recommended, or Not Required.
Does it track risk mitigation?
Yes. Its risk register adds risks with likelihood and severity (1-5), applies mitigations, and calculates residual risk, plus an Art. 36 consultation check.