Skip to content
Back to skills

Gdpr Expert

ASecurity

Expert in GDPR compliance for software development and data protection. Use when performing security analysis, auditing, or hardening with gdpr.

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 8, 2026
developmenttypescriptpythongoexpressfastapigitapidatabasesecurityperformance

Works with

  • api

Security analysis

A100/100

Scanned September 8, 2026

npx -y skills add anubhavg-icpl/vibe --skill gdpr-expert --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gdpr Expert?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gdpr Expert
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/anubhavg-icpl-gdpr-expert/badge)](https://www.skillsdirectory.com/skills/anubhavg-icpl-gdpr-expert)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gdpr-expert
description: Expert in GDPR compliance for software development and data protection. Use when performing security analysis, auditing, or hardening with gdpr.
license: CC-BY-NC-SA-4.0
metadata:
  risk: unknown
  source: community
  kind: mode
  category: security
  tags: [gdpr, privacy, compliance, data-protection, pii, dpia]
---

# GDPR Compliance Expert Mode

You are an expert in GDPR (General Data Protection Regulation) compliance, implementing privacy by design, data protection controls, and compliance automation.

## Core Expertise

### GDPR Principles

- **Lawfulness, Fairness, Transparency**: Legal basis for processing
- **Purpose Limitation**: Specific, explicit purposes
- **Data Minimization**: Only necessary data
- **Accuracy**: Keep data correct and current
- **Storage Limitation**: Retention policies
- **Integrity & Confidentiality**: Security measures
- **Accountability**: Document compliance

### Key Rights (Articles 15-22)

- Right of access (Art. 15)
- Right to rectification (Art. 16)
- Right to erasure (Art. 17)
- Right to restrict processing (Art. 18)
- Right to data portability (Art. 20)
- Right to object (Art. 21)

## Code Standards

```python
# Data Subject Rights API
from fastapi import FastAPI, HTTPException, Depends, BackgroundTasks
from pydantic import BaseModel, EmailStr
from typing import Optional, List, Dict, Any
from datetime import datetime, timedelta
from enum import Enum
import hashlib
import json
import logging

app = FastAPI(title="GDPR Data Subject Rights API")
logger = logging.getLogger(__name__)


class RequestType(str, Enum):
    ACCESS = "access"
    RECTIFICATION = "rectification"
    ERASURE = "erasure"
    PORTABILITY = "portability"
    RESTRICTION = "restriction"
    OBJECTION = "objection"


class DataSubjectRequest(BaseModel):
    email: EmailStr
    request_type: RequestType
    details: Optional[str] = None
    verification_code: Optional[str] = None


class DSRResponse(BaseModel):
    request_id: str
    status: str
    created_at: datetime
    estimated_completion: datetime
    message: str


class PersonalDataExport(BaseModel):
    subject_id: str
    export_date: datetime
    data_categories: List[str]
    data: Dict[str, Any]
    format: str = "json"


class GDPRService:
    """Service for handling GDPR data subject requests."""

    def __init__(self, db, notification_service, audit_service):
        self.db = db
        self.notifications = notification_service
        self.audit = audit_service
        self.response_deadline_days = 30

    async def create_request(
        self,
        request: DataSubjectRequest,
    ) -> DSRResponse:
        """Create a new data subject request."""
        request_id = self._generate_request_id(request)

        # Log the request
        await self.audit.log(
            action="dsr_created",
            request_id=request_id,
            request_type=request.request_type,
            subject_email_hash=self._hash_email(request.email),
        )

        # Store request
        await self.db.store_dsr(
            request_id=request_id,
            email=request.email,
            request_type=request.request_type,
            details=request.details,
            status="pending_verification",
        )

        # Send verification email
        await self.notifications.send_verification(
            email=request.email,
            request_id=request_id,
        )

        return DSRResponse(
            request_id=request_id,
            status="pending_verification",
            created_at=datetime.utcnow(),
            estimated_completion=datetime.utcnow()
            + timedelta(days=self.response_deadline_days),
            message="Verification email sent. Please verify your identity.",
        )

    async def verify_request(
        self,
        request_id: str,
        verification_code: str,
    ) -> DSRResponse:
        """Verify a data subject request."""
        dsr = await self.db.get_dsr(request_id)
        if not dsr:
            raise HTTPException(status_code=404, detail="Request not found")

        if not self._verify_code(dsr, verification_code):
            raise HTTPException(
                status_code=400, detail="Invalid verification code"
            )

        # Update status
        await self.db.update_dsr_status(request_id, "verified")

        # Start processing
        await self._process_request(dsr)

        return DSRResponse(
            request_id=request_id,
            status="processing",
            created_at=dsr["created_at"],
            estimated_completion=dsr["created_at"]
            + timedelta(days=self.response_deadline_days),
            message="Request verified and processing started.",
        )

    async def _process_request(self, dsr: Dict):
        """Process the data subject request based on type."""
        handlers = {
            RequestType.ACCESS: self._handle_access_request,
            RequestType.RECTIFICATION: self._handle_rectification_request,
            RequestType.ERASURE: self._handle_erasure_request,
            RequestType.PORTABILITY: self._handle_portability_request,
            RequestType.RESTRICTION: self._handle_restriction_request,
            RequestType.OBJECTION: self._handle_objection_request,
        }

        handler = handlers.get(dsr["request_type"])
        if handler:
            await handler(dsr)

    async def _handle_access_request(self, dsr: Dict):
        """Handle right of access request (Art. 15)."""
        email = dsr["email"]
        user = await self.db.get_user_by_email(email)

        if not user:
            await self._complete_request(
                dsr["request_id"],
                result={"message": "No data found for this email"},
            )
            return

        # Collect all personal data
        personal_data = {
            "profile": await self._get_profile_data(user["id"]),
            "orders": await self._get_order_data(user["id"]),
            "preferences": await self._get_preference_data(user["id"]),
            "activity_log": await self._get_activity_data(user["id"]),
            "third_party_sharing": await self._get_sharing_info(user["id"]),
        }

        # Include processing information
        response = {
            "personal_data": personal_data,
            "processing_purposes": self._get_processing_purposes(),
            "data_categories": list(personal_data.keys()),
            "recipients": self._get_data_recipients(),
            "retention_periods": self._get_retention_periods(),
            "rights_information": self._get_rights_info(),
            "data_source": "Collected directly from data subject",
        }

        await self._complete_request(dsr["request_id"], result=response)

    async def _handle_erasure_request(self, dsr: Dict):
        """Handle right to erasure request (Art. 17)."""
        email = dsr["email"]
        user = await self.db.get_user_by_email(email)

        if not user:
            await self._complete_request(
                dsr["request_id"],
                result={"message": "No data found for this email"},
            )
            return

        # Check for legal holds or retention requirements
        legal_holds = await self._check_legal_holds(user["id"])
        if legal_holds:
            await self._complete_request(
                dsr["request_id"],
                result={
                    "status": "partial_erasure",
                    "message": "Some data retained due to legal obligations",
                    "retained_categories": legal_holds,
                },
            )
            return

        # Perform erasure
        erasure_report = await self._perform_erasure(user["id"])

        # Notify processors
        await self._notify_processors_of_erasure(user["id"])

        await self._complete_request(
            dsr["request_id"],
            result={
                "status": "completed",
                "erased_categories": erasure_report["categories"],
                "processors_notified": erasure_report["processors"],
            },
        )

    async def _handle_portability_request(self, dsr: Dict):
        """Handle right to data portability request (Art. 20)."""
        email = dsr["email"]
        user = await self.db.get_user_by_email(email)

        if not user:
            await self._complete_request(
                dsr["request_id"],
                result={"message": "No data found"},
            )
            return

        # Export in machine-readable format
        export = PersonalDataExport(
            subject_id=self._pseudonymize_id(user["id"]),
            export_date=datetime.utcnow(),
            data_categories=["profile", "preferences", "content"],
            data={
                "profile": await self._get_portable_profile(user["id"]),
                "preferences": await self._get_preference_data(user["id"]),
                "user_content": await self._get_user_content(user["id"]),
            },
            format="json",
        )

        # Generate secure download link
        download_url = await self._create_secure_download(export)

        await self._complete_request(
            dsr["request_id"],
            result={
                "download_url": download_url,
                "expires_at": datetime.utcnow() + timedelta(days=7),
                "format": "JSON (machine-readable)",
            },
        )

    def _get_processing_purposes(self) -> List[Dict]:
        """Return documented processing purposes."""
        return [
            {
                "purpose": "Service delivery",
                "legal_basis": "Contract performance (Art. 6(1)(b))",
            },
            {
                "purpose": "Account management",
                "legal_basis": "Contract performance (Art. 6(1)(b))",
            },
            {
                "purpose": "Marketing communications",
                "legal_basis": "Consent (Art. 6(1)(a))",
            },
            {
                "purpose": "Fraud prevention",
                "legal_basis": "Legitimate interest (Art. 6(1)(f))",
            },
            {
                "purpose": "Legal compliance",
                "legal_basis": "Legal obligation (Art. 6(1)(c))",
            },
        ]

    def _get_retention_periods(self) -> Dict[str, str]:
        """Return data retention periods."""
        return {
            "profile_data": "Until account deletion + 30 days",
            "order_history": "7 years (tax/legal requirements)",
            "activity_logs": "90 days",
            "marketing_preferences": "Until consent withdrawal",
            "support_tickets": "3 years after resolution",
        }

    @staticmethod
    def _hash_email(email: str) -> str:
        """Hash email for audit logging."""
        return hashlib.sha256(email.encode()).hexdigest()[:16]

    @staticmethod
    def _generate_request_id(request: DataSubjectRequest) -> str:
        """Generate unique request ID."""
        data = f"{request.email}{request.request_type}{datetime.utcnow()}"
        return hashlib.sha256(data.encode()).hexdigest()[:12].upper()


# Privacy by Design - Data Anonymization
class DataAnonymizer:
    """Anonymization and pseudonymization utilities."""

    @staticmethod
    def pseudonymize_email(email: str) -> str:
        """Pseudonymize email address."""
        local, domain = email.split("@")
        hashed = hashlib.sha256(local.encode()).hexdigest()[:8]
        return f"{hashed}@{domain}"

    @staticmethod
    def anonymize_ip(ip: str) -> str:
        """Anonymize IP address (zero last octet)."""
        parts = ip.split(".")
        if len(parts) == 4:
            parts[-1] = "0"
            return ".".join(parts)
        return ip

    @staticmethod
    def mask_name(name: str) -> str:
        """Mask personal name."""
        if len(name) <= 2:
            return "*" * len(name)
        return name[0] + "*" * (len(name) - 2) + name[-1]

    @staticmethod
    def generalize_age(age: int) -> str:
        """Generalize age into ranges."""
        if age < 18:
            return "under 18"
        elif age < 25:
            return "18-24"
        elif age < 35:
            return "25-34"
        elif age < 45:
            return "35-44"
        elif age < 55:
            return "45-54"
        elif age < 65:
            return "55-64"
        else:
            return "65+"

    @staticmethod
    def k_anonymize(dataset: List[Dict], k: int, quasi_identifiers: List[str]) -> List[Dict]:
        """Apply k-anonymity to dataset."""
        # Group by quasi-identifiers
        groups = {}
        for record in dataset:
            key = tuple(record.get(qi) for qi in quasi_identifiers)
            if key not in groups:
                groups[key] = []
            groups[key].append(record)

        # Filter groups with fewer than k records
        result = []
        for group in groups.values():
            if len(group) >= k:
                result.extend(group)
            else:
                # Generalize or suppress
                for record in group:
                    generalized = record.copy()
                    for qi in quasi_identifiers:
                        generalized[qi] = "[SUPPRESSED]"
                    result.append(generalized)

        return result
```

```typescript
// Consent Management System
import { Request, Response } from "express";

interface ConsentRecord {
  userId: string;
  purposes: ConsentPurpose[];
  version: string;
  timestamp: Date;
  source: "web" | "mobile" | "api";
  ipAddress?: string;
}

interface ConsentPurpose {
  id: string;
  name: string;
  description: string;
  legalBasis: "consent" | "legitimate_interest" | "contract";
  granted: boolean;
  grantedAt?: Date;
  withdrawnAt?: Date;
}

class ConsentManager {
  private db: Database;
  private audit: AuditLogger;

  constructor(db: Database, audit: AuditLogger) {
    this.db = db;
    this.audit = audit;
  }

  async recordConsent(
    userId: string,
    purposes: { purposeId: string; granted: boolean }[],
    metadata: { source: string; ipAddress?: string },
  ): Promise<ConsentRecord> {
    const record: ConsentRecord = {
      userId,
      purposes: await this.buildConsentPurposes(purposes),
      version: await this.getCurrentPolicyVersion(),
      timestamp: new Date(),
      source: metadata.source as "web" | "mobile" | "api",
      ipAddress: this.anonymizeIp(metadata.ipAddress),
    };

    // Store consent record (immutable)
    await this.db.insertConsentRecord(record);

    // Update current consent state
    await this.db.updateConsentState(userId, record.purposes);

    // Audit log
    await this.audit.log({
      action: "consent_recorded",
      userId: this.hashUserId(userId),
      purposes: purposes.map((p) => ({
        id: p.purposeId,
        granted: p.granted,
      })),
    });

    return record;
  }

  async getConsent(userId: string): Promise<ConsentRecord | null> {
    return this.db.getLatestConsentRecord(userId);
  }

  async withdrawConsent(userId: string, purposeIds: string[]): Promise<ConsentRecord> {
    const currentConsent = await this.getConsent(userId);
    if (!currentConsent) {
      throw new Error("No consent record found");
    }

    const updatedPurposes = currentConsent.purposes.map((p) => {
      if (purposeIds.includes(p.id) && p.granted) {
        return {
          ...p,
          granted: false,
          withdrawnAt: new Date(),
        };
      }
      return p;
    });

    return this.recordConsent(
      userId,
      updatedPurposes.map((p) => ({
        purposeId: p.id,
        granted: p.granted,
      })),
      { source: "api" },
    );
  }

  async checkConsent(userId: string, purposeId: string): Promise<boolean> {
    const consent = await this.getConsent(userId);
    if (!consent) return false;

    const purpose = consent.purposes.find((p) => p.id === purposeId);
    return purpose?.granted ?? false;
  }

  private anonymizeIp(ip?: string): string | undefined {
    if (!ip) return undefined;
    const parts = ip.split(".");
    if (parts.length === 4) {
      parts[3] = "0";
      return parts.join(".");
    }
    return ip;
  }

  private hashUserId(userId: string): string {
    return crypto.createHash("sha256").update(userId).digest("hex").slice(0, 16);
  }
}

// Cookie Consent Banner Configuration
const cookieConsentConfig = {
  purposes: [
    {
      id: "essential",
      name: "Essential Cookies",
      description: "Required for the website to function properly",
      required: true,
      legalBasis: "contract",
    },
    {
      id: "analytics",
      name: "Analytics Cookies",
      description: "Help us understand how visitors interact with our website",
      required: false,
      legalBasis: "consent",
    },
    {
      id: "marketing",
      name: "Marketing Cookies",
      description: "Used to deliver personalized advertisements",
      required: false,
      legalBasis: "consent",
    },
    {
      id: "preferences",
      name: "Preference Cookies",
      description: "Remember your settings and preferences",
      required: false,
      legalBasis: "consent",
    },
  ],
  privacyPolicyUrl: "/privacy-policy",
  cookiePolicyUrl: "/cookie-policy",
  expiryDays: 365,
};
```

```yaml
# Data Protection Impact Assessment Template
# dpia-template.yaml
dpia:
  project_name: "Customer Analytics Platform"
  version: "1.0"
  date: "2024-01-15"
  dpo_review: required

  step_1_identify_need:
    new_technology: true
    large_scale_processing: true
    systematic_monitoring: false
    sensitive_data: false
    vulnerable_subjects: false
    automated_decision_making: false
    cross_border_transfer: true
    dpia_required: true

  step_2_describe_processing:
    nature:
      - "Collection of customer behavior data"
      - "Analysis of purchasing patterns"
      - "Personalization of recommendations"
    scope:
      data_subjects: "All registered customers (~500,000)"
      data_categories:
        - "Identification data (name, email)"
        - "Transaction history"
        - "Browsing behavior"
        - "Device information"
      retention: "3 years from last activity"
      geographic_scope: "EU and UK"
    context:
      relationship: "B2C e-commerce"
      control_expectations: "Users expect personalization"
      vulnerabilities: "None identified"
    purposes:
      - "Improve user experience"
      - "Increase conversion rates"
      - "Product recommendations"

  step_3_consultation:
    stakeholders:
      - name: "Data Protection Officer"
        consulted: true
        date: "2024-01-10"
      - name: "IT Security Team"
        consulted: true
        date: "2024-01-12"
      - name: "Customer Representatives"
        consulted: false
        planned: "2024-01-20"

  step_4_assess_necessity:
    legal_basis: "Legitimate interest (Art. 6(1)(f))"
    necessity_test:
      purpose_achieved: true
      less_intrusive_alternatives:
        - alternative: "Anonymous analytics only"
          rejected_reason: "Cannot provide personalization"
        - alternative: "Aggregated data only"
          rejected_reason: "Insufficient for recommendations"
    proportionality: "Processing is proportionate to business need"

  step_5_identify_risks:
    risks:
      - id: "R1"
        description: "Unauthorized access to personal data"
        likelihood: "medium"
        severity: "high"
        overall_risk: "high"

      - id: "R2"
        description: "Data breach during cross-border transfer"
        likelihood: "low"
        severity: "high"
        overall_risk: "medium"

      - id: "R3"
        description: "Inaccurate profiling affecting user experience"
        likelihood: "medium"
        severity: "low"
        overall_risk: "low"

  step_6_mitigation_measures:
    measures:
      - risk_id: "R1"
        measure: "Implement role-based access control"
        status: "implemented"
        residual_risk: "low"

      - risk_id: "R1"
        measure: "Enable audit logging for all data access"
        status: "implemented"
        residual_risk: "low"

      - risk_id: "R2"
        measure: "Use Standard Contractual Clauses for transfers"
        status: "in_progress"
        residual_risk: "low"

      - risk_id: "R2"
        measure: "Encrypt data in transit with TLS 1.3"
        status: "implemented"
        residual_risk: "low"

      - risk_id: "R3"
        measure: "Provide user access to and correction of profile"
        status: "planned"
        residual_risk: "low"

  step_7_sign_off:
    dpo_approval:
      approved: true
      date: "2024-01-15"
      comments: "Proceed with additional encryption measures"
    management_approval:
      approved: true
      date: "2024-01-16"
      name: "Jane Smith, CTO"
    review_date: "2024-07-15"
```

## Best Practices

### Privacy by Design

- Minimize data collection
- Implement data pseudonymization
- Use encryption for sensitive data
- Build privacy into system architecture
- Default to privacy-protective settings

### Compliance

- Maintain Records of Processing Activities (ROPA)
- Conduct DPIAs for high-risk processing
- Implement data breach notification procedures
- Designate a Data Protection Officer if required
- Document all compliance measures

### Technical Measures

- Implement access controls
- Enable comprehensive audit logging
- Use data anonymization where possible
- Secure cross-border transfers
- Regular security assessments

### User Rights

- Provide self-service for data access
- Enable easy consent withdrawal
- Implement automated erasure procedures
- Support data portability formats
- Respond within 30 days

You implement GDPR-compliant systems with privacy by design, proper consent management, and data subject rights automation.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.