# DPDPA Data Flow Diagram Annotation Guide

**Conventions for tagging DFD elements with DPDPA-required metadata before running LINDDUN + STRIDE.**

---

## Why Annotate DFDs for DPDPA?

A standard security DFD shows processes, data stores, external entities, trust boundaries, and data flows. For DPDPA threat modeling, you need four additional dimensions on every element that handles personal data:

1. **DPDPA actor type** — which legal role does this element occupy?
2. **Lawful basis** — under what legal authority does this processing happen?
3. **Purpose tag** — which consented/legitimate-use purpose governs this flow?
4. **Retention clock** — when must the data in this element be erased?

Without these annotations, LINDDUN's Non-compliance and Unawareness categories produce vague findings that cannot be traced to a specific DPDPA obligation.

---

## Element Types and DPDPA Annotations

### 1. External Entities

External entities are people or systems outside the trust boundary.

**Annotation fields:**

| Field | Values | DPDPA Source |
|-------|--------|-------------|
| `dpdpa_actor` | `data_principal` \| `data_processor` \| `consent_manager` \| `third_party` | S.2(j), S.2(k), S.2(g) |
| `trust_level` | `untrusted` \| `contractual` \| `regulated` | — |
| `section16_applies` | `true` \| `false` | S.16 (cross-border) |

**Notation in Mermaid:**
```mermaid
graph LR
    DP["Data Principal<br/>(S.2(j))<br/>untrusted<br/>no cross-border"]
    EXT_PROC["KYC Processor<br/>(S.2(k))<br/>contractual — Rule 6(1)(f)<br/>India only"]
```

**What to check for each external entity:**
- `data_principal` → Does the notice (Section 5) reach them in their language?
- `data_processor` → Is there a Data Processing Agreement per Rule 6(1)(f)?
- Any entity outside India → Section 16 transfer control required; check OPA policy `dpdpa.transfer_allowed`

---

### 2. Processes

Processes are application code, microservices, or business logic units that transform data.

**Annotation fields:**

| Field | Values | DPDPA Source |
|-------|--------|-------------|
| `purposes` | List of purpose IDs | S.6(1) — must stay within consented purposes |
| `lawful_basis` | `consent` \| `legitimate_use` \| `legal_obligation` \| `vital_interest` | S.6(1), S.7 |
| `section5_notice_sent` | `true` \| `false` | S.5(1) — notice before/at collection |
| `languages_supported` | List of BCP-47 codes | S.5(3) — option of English or any of the 22 Eighth Schedule languages |

**Notation in Mermaid:**
```mermaid
graph LR
    API["Loan API<br/>[Purpose: loan_origination]<br/>[Basis: consent S.6(1)]<br/>[Notice: S.5(1) ✓]<br/>[Languages: en, hi, ta, te]"]
```

**Purpose tag rules:**
- Each process may only receive flows tagged with a purpose in its `purposes` list.
- Receiving a flow with purpose `marketing` into a process with purposes `[loan_origination]` is a LINDDUN Linkability finding — it crosses purpose boundaries.

**STRIDE focus for processes:**
- Spoofing: Can an attacker impersonate a Data Principal to trigger processing?
- Tampering: Can input injection alter the process output (e.g., SQL injection changing consent_status)?
- Elevation: Can a caller with `credit_check` scope access `marketing` purpose data?

---

### 3. Data Stores

Data stores are databases, object stores, message queues, caches, and logs.

**Annotation fields:**

| Field | Values | DPDPA Source |
|-------|--------|-------------|
| `encrypted_at_rest` | `true` \| `false` | Rule 6(1)(a) — data security measures such as encryption |
| `retention_days` | Integer | S.8(7) — erase when purpose complete |
| `retention_legal_anchor` | String (e.g. `"S.8(7) + Rule 8(3)"`) | — |
| `erasure_mechanism` | `hard_delete` \| `crypto_shred` \| `anonymise` | S.8(7) |
| `purpose_segregated` | `true` \| `false` | S.6(1) — don't co-mingle purposes in same table |

**Notation in Mermaid:**
```mermaid
graph LR
    DB[("Customer DB<br/>[AES-256-GCM Rule 6(1)(a)]<br/>[Retention: 7y sectoral law + S.8(7)]<br/>[Erasure: crypto_shred]<br/>[Purpose-segregated: ✓]")]
```

**Retention clock rules:**

| Purpose type | Retention period | Anchor |
|-------------|-----------------|--------|
| Consent records (proof of consent) | At least 1 year; longer only where a named sectoral law requires it | Rule 8(3), S.6(10) |
| Post-transaction data | Duration of purpose + legal hold | S.8(7) |
| Marketing data | Until withdrawal | S.6(1), S.8(7) |
| Children's data | Until purpose complete; no tracking or behavioural monitoring | S.9(2)–(3) |
| Backup copies | Must respect same retention as primary | S.8(7) |

**LINDDUN focus for stores:**
- Identifiability: Do quasi-identifiers in this store allow re-identification?
- Non-repudiation: Does immutable logging conflict with erasure rights?
- Non-compliance: Are any records past retention without erasure?

**Erasure mechanism selection:**
```
Is data structurally entangled with other records (immutable log)?
├─ YES → Crypto-shred: destroy per-principal DEK; ciphertext becomes irrecoverable
│        (Reconciles S.6(10) proof-of-consent with S.8(7) erasure)
└─ NO → Hard delete: physical removal from store and all backups within 30 days
```

---

### 4. Data Flows (Arrows)

Flows are the lines between elements. Each arrow carries data; annotate what data, why, and under what authority.

**Annotation fields:**

| Field | Values | DPDPA Source |
|-------|--------|-------------|
| `purpose` | Purpose ID string | S.6(1) |
| `data_categories` | List from personal data taxonomy | S.2(t) |
| `transport_security` | `tls13` \| `mtls` \| `none` | Rule 6(1)(a) |
| `crosses_trust_boundary` | `true` \| `false` | — |
| `section16_transfer` | `true` \| `false` | S.16 |

**Notation in Mermaid:**
```mermaid
sequenceDiagram
    W->>KYC: KYC documents<br/>[purpose=kyc_verification]<br/>[TLS 1.3, mTLS]<br/>[categories: name, aadhaar_hash, face]
```

**Trust boundary rules:**
- Any flow crossing a trust boundary into a Data Processor → Rule 6(1)(f) DPA must exist.
- Any flow to an external entity outside India → Section 16 applies; check OPA policy.
- Flows from a `data_principal` external entity → Section 5 notice obligation triggered.

---

## Annotation Checklist (per DFD element)

Run this before finalising any DFD for threat modeling:

### External Entities
- [ ] `dpdpa_actor` set to correct role
- [ ] DPA exists if actor is a Data Processor (Rule 6(1)(f))
- [ ] Section 16 flag set if entity is outside India

### Processes
- [ ] `purposes` list populated — only listed purposes may be processed
- [ ] `lawful_basis` set and mapped to a DPDPA section
- [ ] Section 5 notice confirmed sent (`section5_notice_sent: true`)
- [ ] Languages list covers all Data Principal locales

### Data Stores
- [ ] `encrypted_at_rest: true` — Rule 6(1)(a) security measure (our baseline)
- [ ] `retention_days` set; `retention_legal_anchor` cites DPDPA section
- [ ] `erasure_mechanism` chosen and implemented
- [ ] `purpose_segregated: true` — avoid cross-purpose co-mingling

### Data Flows
- [ ] `purpose` tagged on every flow
- [ ] `transport_security: tls13` or `mtls` for any flow carrying personal data
- [ ] `section16_transfer: true` flagged for cross-border flows
- [ ] Trust boundary crossings have a corresponding DPA (S.8(2), Rule 6(1)(f)) or Section 16 restricted-country check

---

## Example: Fully Annotated Fintech DFD

```mermaid
sequenceDiagram
    participant DP as Data Principal<br/>(S.2(j)) untrusted
    participant W as Loan API<br/>[P: loan_origination]<br/>[Basis: S.6(1) consent]<br/>[Notice: S.5(1) ✓]<br/>[Lang: en,hi,ta,te,kn]
    participant CM as Consent Service<br/>[S.6(10) ledger]<br/>[Retention: 7y sectoral law + S.8(7)]
    participant KYC as KYC Processor<br/>(S.2(k)) Rule 6(1)(f) DPA<br/>India only
    participant DB as Customer DB<br/>[AES-256-GCM]<br/>[Retention: 7y sectoral law + S.8(7)]<br/>[Crypto-shred on erasure]
    participant DPB as Data Protection Board

    DP->>W: Loan application<br/>[purpose=loan_origination]<br/>[TLS 1.3]<br/>[categories: name,phone,income]
    W->>CM: Record consent<br/>[signed, timestamped]<br/>[lang=ta notice archived]
    CM-->>W: consent_id (HMAC-signed)
    W->>KYC: KYC documents<br/>[purpose=kyc_verification]<br/>[mTLS]<br/>[categories: aadhaar_hash,face]
    KYC-->>W: KYC verdict
    W->>DB: Store application<br/>[field-level encrypted]<br/>[retention_clock=start]
    DP->>W: Section 12 erasure request<br/>[identity verified — S.12]
    W->>CM: Revoke consent<br/>[purpose=loan_origination]
    CM->>DB: Crypto-shred<br/>[destroy per-principal DEK]<br/>[consent hash retained]
    W-->>DP: Erasure confirmation<br/>[logged Rule 6(1)(c)]
    Note over W,DPB: On breach: Rule 7 intimation pipeline (Data Principals + Board)
```

---

## LINDDUN Quick-Reference for DFD Review

After annotating, scan each element with this lookup:

| If the element has... | Check LINDDUN | DPDPA angle |
|----------------------|--------------|-------------|
| Multiple purposes in one store | Linkability | S.6(1) purpose limitation |
| Direct identifiers (phone, Aadhaar) | Identifiability | S.2(t), S.8(5) |
| Immutable audit log | Non-repudiation | S.6(10) vs S.8(7) tension |
| Public or semi-public endpoint | Detectability | S.8(5) |
| Logs or backups without encryption | Disclosure | Rule 6(1)(a), S.8(6) |
| No Section 5 notice | Unawareness | S.5(1), S.5(3) |
| No retention policy | Non-compliance | S.8(7), Rule 8 |

---

**Reference:** [DPDPA Threat Modeling with LINDDUN and STRIDE](./article.md)
