@musashishao/agent-kit 1.6.1 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
- package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
- package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
- package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
- package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
- package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
- package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
- package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
- package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +487 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/search.py +76 -0
- package/.agent/adr/ADR-TEMPLATE.md +57 -0
- package/.agent/adr/README.md +30 -0
- package/.agent/agents/backend-specialist.md +1 -1
- package/.agent/agents/devops-engineer.md +1 -1
- package/.agent/agents/performance-optimizer.md +1 -1
- package/.agent/agents/security-auditor.md +1 -1
- package/.agent/dashboard/index.html +169 -0
- package/.agent/rules/REFERENCE.md +14 -0
- package/.agent/skills/ai-incident-management/SKILL.md +517 -0
- package/.agent/skills/ai-security-guardrails/SKILL.md +405 -0
- package/.agent/skills/ai-security-guardrails/owasp-llm-top10.md +160 -0
- package/.agent/skills/ai-security-guardrails/scripts/prompt_injection_scanner.py +230 -0
- package/.agent/skills/compliance-for-ai/SKILL.md +411 -0
- package/.agent/skills/observability-patterns/SKILL.md +484 -0
- package/.agent/skills/observability-patterns/scripts/otel_validator.py +330 -0
- package/.agent/skills/opentelemetry-expert/SKILL.md +738 -0
- package/.agent/skills/opentelemetry-expert/scripts/trace_analyzer.py +351 -0
- package/.agent/skills/privacy-preserving-dev/SKILL.md +442 -0
- package/.agent/skills/privacy-preserving-dev/scripts/pii_scanner.py +285 -0
- package/package.json +4 -1
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: privacy-preserving-dev
|
|
3
|
+
description: PII detection & redaction patterns, data anonymization techniques, secure prompt engineering, and data retention policies for AI systems.
|
|
4
|
+
allowed-tools: Read, Glob, Grep, Bash
|
|
5
|
+
skills:
|
|
6
|
+
- ai-security-guardrails
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Privacy-Preserving Development
|
|
10
|
+
|
|
11
|
+
> Protect user data in AI systems. Privacy by design, not afterthought.
|
|
12
|
+
|
|
13
|
+
## 🔧 Runtime Scripts
|
|
14
|
+
|
|
15
|
+
**Execute for automated validation:**
|
|
16
|
+
|
|
17
|
+
| Script | Purpose | Usage |
|
|
18
|
+
|--------|---------|-------|
|
|
19
|
+
| `scripts/pii_scanner.py` | Detect PII in code and prompts | `python scripts/pii_scanner.py <project_path>` |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. PII Categories & Risk Levels
|
|
24
|
+
|
|
25
|
+
### High-Risk PII (Requires Protection)
|
|
26
|
+
|
|
27
|
+
| Category | Examples | Risk |
|
|
28
|
+
|----------|----------|------|
|
|
29
|
+
| **Identifiers** | SSN, Passport, Driver License | Critical |
|
|
30
|
+
| **Financial** | Credit Card, Bank Account, Tax ID | Critical |
|
|
31
|
+
| **Health** | Medical Records, Diagnosis, Prescriptions | Critical |
|
|
32
|
+
| **Auth** | Passwords, API Keys, Tokens | Critical |
|
|
33
|
+
| **Contact** | Email, Phone, Address | High |
|
|
34
|
+
| **Personal** | Full Name, DOB, Gender | High |
|
|
35
|
+
| **Biometric** | Fingerprint, Face ID, Voice | Critical |
|
|
36
|
+
|
|
37
|
+
### Context-Dependent
|
|
38
|
+
|
|
39
|
+
| Data | Risk When Combined |
|
|
40
|
+
|------|---------------------|
|
|
41
|
+
| IP Address | + User ID = Tracking |
|
|
42
|
+
| Location | + Timestamp = Surveillance |
|
|
43
|
+
| Device ID | + Behavior = Profiling |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 2. PII Detection Patterns
|
|
48
|
+
|
|
49
|
+
### Regex Patterns
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
PII_PATTERNS = {
|
|
53
|
+
# Critical
|
|
54
|
+
"SSN": r"\b\d{3}-\d{2}-\d{4}\b",
|
|
55
|
+
"Credit Card": r"\b(?:\d{4}[-\s]?){3}\d{4}\b",
|
|
56
|
+
"IBAN": r"\b[A-Z]{2}\d{2}[A-Z0-9]{4,30}\b",
|
|
57
|
+
|
|
58
|
+
# High
|
|
59
|
+
"Email": r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b",
|
|
60
|
+
"Phone (US)": r"\b(?:\+1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b",
|
|
61
|
+
"Phone (Intl)": r"\+\d{1,3}[-.\s]?\d{4,14}",
|
|
62
|
+
|
|
63
|
+
# Medium
|
|
64
|
+
"IP Address": r"\b(?:\d{1,3}\.){3}\d{1,3}\b",
|
|
65
|
+
"Date of Birth": r"\b(?:\d{1,2}[-/]\d{1,2}[-/]\d{2,4})|(?:\d{4}[-/]\d{1,2}[-/]\d{1,2})\b",
|
|
66
|
+
|
|
67
|
+
# Auth (Critical)
|
|
68
|
+
"API Key": r"\b(?:sk|pk|api)[_-]?(?:live|test)?[_-]?[a-zA-Z0-9]{20,}\b",
|
|
69
|
+
"JWT": r"eyJ[A-Za-z0-9-_]+\.eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_.+/=]+",
|
|
70
|
+
"AWS Key": r"\bAKIA[0-9A-Z]{16}\b",
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 3. Redaction Strategies
|
|
77
|
+
|
|
78
|
+
### Strategy Selection
|
|
79
|
+
|
|
80
|
+
| Context | Strategy | Example |
|
|
81
|
+
|---------|----------|---------|
|
|
82
|
+
| **Logs** | Full redaction | `***REDACTED***` |
|
|
83
|
+
| **Analytics** | Hash + salt | `usr_a1b2c3d4` |
|
|
84
|
+
| **Display** | Partial mask | `john***@email.com` |
|
|
85
|
+
| **Export** | Pseudonymization | `User_12345` |
|
|
86
|
+
|
|
87
|
+
### Implementation
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
interface RedactionConfig {
|
|
91
|
+
strategy: 'full' | 'partial' | 'hash' | 'tokenize';
|
|
92
|
+
salt?: string;
|
|
93
|
+
preserveFormat?: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function redactPII(text: string, config: RedactionConfig): string {
|
|
97
|
+
const patterns = Object.entries(PII_PATTERNS);
|
|
98
|
+
let result = text;
|
|
99
|
+
|
|
100
|
+
for (const [type, pattern] of patterns) {
|
|
101
|
+
const regex = new RegExp(pattern, 'gi');
|
|
102
|
+
|
|
103
|
+
result = result.replace(regex, (match) => {
|
|
104
|
+
switch (config.strategy) {
|
|
105
|
+
case 'full':
|
|
106
|
+
return `[${type.toUpperCase()}_REDACTED]`;
|
|
107
|
+
|
|
108
|
+
case 'partial':
|
|
109
|
+
// Keep first and last characters
|
|
110
|
+
if (match.length > 4) {
|
|
111
|
+
return match[0] + '*'.repeat(match.length - 2) + match.slice(-1);
|
|
112
|
+
}
|
|
113
|
+
return '****';
|
|
114
|
+
|
|
115
|
+
case 'hash':
|
|
116
|
+
return hashWithSalt(match, config.salt || 'default');
|
|
117
|
+
|
|
118
|
+
case 'tokenize':
|
|
119
|
+
return getOrCreateToken(match, type);
|
|
120
|
+
|
|
121
|
+
default:
|
|
122
|
+
return '[REDACTED]';
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 4. Secure Prompt Engineering
|
|
134
|
+
|
|
135
|
+
### Data Minimization
|
|
136
|
+
|
|
137
|
+
| Principle | Implementation |
|
|
138
|
+
|-----------|----------------|
|
|
139
|
+
| **Need-to-know** | Only include data required for task |
|
|
140
|
+
| **Aggregation** | Use summaries instead of raw data |
|
|
141
|
+
| **Abstraction** | Reference IDs instead of full records |
|
|
142
|
+
| **Time-boxing** | Remove data after processing |
|
|
143
|
+
|
|
144
|
+
### Safe Prompt Template
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
def build_private_prompt(user_query: str, context: dict) -> str:
|
|
148
|
+
"""Build prompt with PII protection."""
|
|
149
|
+
|
|
150
|
+
# 1. Redact PII from user query
|
|
151
|
+
safe_query = redact_pii(user_query)
|
|
152
|
+
|
|
153
|
+
# 2. Use reference IDs instead of full data
|
|
154
|
+
safe_context = {
|
|
155
|
+
"user_id": context.get("user_id"), # Just ID, not full profile
|
|
156
|
+
"account_type": context.get("account_type"), # Category, not details
|
|
157
|
+
"request_category": classify_request(safe_query),
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# 3. Add privacy instructions
|
|
161
|
+
return f"""
|
|
162
|
+
<PRIVACY_RULES>
|
|
163
|
+
- Never output personal information in responses
|
|
164
|
+
- Use reference IDs instead of names
|
|
165
|
+
- Do not memorize or repeat user data
|
|
166
|
+
</PRIVACY_RULES>
|
|
167
|
+
|
|
168
|
+
<CONTEXT>
|
|
169
|
+
User Type: {safe_context['account_type']}
|
|
170
|
+
Request Category: {safe_context['request_category']}
|
|
171
|
+
</CONTEXT>
|
|
172
|
+
|
|
173
|
+
<QUERY>
|
|
174
|
+
{safe_query}
|
|
175
|
+
</QUERY>
|
|
176
|
+
|
|
177
|
+
Respond helpfully while respecting privacy rules.
|
|
178
|
+
"""
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 5. Data Anonymization Techniques
|
|
184
|
+
|
|
185
|
+
### Technique Selection
|
|
186
|
+
|
|
187
|
+
| Technique | Use Case | Reversible? |
|
|
188
|
+
|-----------|----------|-------------|
|
|
189
|
+
| **Masking** | Display, logs | No |
|
|
190
|
+
| **Hashing** | Analytics | No |
|
|
191
|
+
| **Tokenization** | Database storage | Yes (with key) |
|
|
192
|
+
| **Encryption** | Transit, storage | Yes (with key) |
|
|
193
|
+
| **Generalization** | Analytics | No |
|
|
194
|
+
| **Perturbation** | ML training | No |
|
|
195
|
+
|
|
196
|
+
### Generalization Examples
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
def generalize_data(data: dict) -> dict:
|
|
200
|
+
"""Convert specific data to general categories."""
|
|
201
|
+
|
|
202
|
+
result = {}
|
|
203
|
+
|
|
204
|
+
# Age → Age range
|
|
205
|
+
if "age" in data:
|
|
206
|
+
age = data["age"]
|
|
207
|
+
if age < 18: result["age_group"] = "minor"
|
|
208
|
+
elif age < 30: result["age_group"] = "young_adult"
|
|
209
|
+
elif age < 50: result["age_group"] = "adult"
|
|
210
|
+
else: result["age_group"] = "senior"
|
|
211
|
+
|
|
212
|
+
# Location → Region
|
|
213
|
+
if "city" in data:
|
|
214
|
+
result["region"] = get_region(data["city"]) # "San Francisco" → "West Coast"
|
|
215
|
+
|
|
216
|
+
# Salary → Range
|
|
217
|
+
if "salary" in data:
|
|
218
|
+
salary = data["salary"]
|
|
219
|
+
result["income_bracket"] = categorize_income(salary) # 75000 → "70-80k"
|
|
220
|
+
|
|
221
|
+
return result
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 6. Differential Privacy
|
|
227
|
+
|
|
228
|
+
### Concept
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
True Answer + Calibrated Noise = Private Answer
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### When to Use
|
|
235
|
+
|
|
236
|
+
| Scenario | Apply Differential Privacy? |
|
|
237
|
+
|----------|----------------------------|
|
|
238
|
+
| Aggregate statistics | ✅ Yes |
|
|
239
|
+
| Individual records | ❌ Use other methods |
|
|
240
|
+
| Model training | ✅ Yes (DP-SGD) |
|
|
241
|
+
| Analytics dashboards | ✅ Yes |
|
|
242
|
+
|
|
243
|
+
### Simple Implementation
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
import numpy as np
|
|
247
|
+
|
|
248
|
+
def add_laplace_noise(value: float, sensitivity: float, epsilon: float) -> float:
|
|
249
|
+
"""Add Laplace noise for differential privacy.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
value: True value
|
|
253
|
+
sensitivity: Maximum change one record can cause
|
|
254
|
+
epsilon: Privacy budget (lower = more private)
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
Noisy value
|
|
258
|
+
"""
|
|
259
|
+
scale = sensitivity / epsilon
|
|
260
|
+
noise = np.random.laplace(0, scale)
|
|
261
|
+
return value + noise
|
|
262
|
+
|
|
263
|
+
# Example: Private count
|
|
264
|
+
def private_count(data: list, epsilon: float = 1.0) -> float:
|
|
265
|
+
true_count = len(data)
|
|
266
|
+
return add_laplace_noise(true_count, sensitivity=1, epsilon=epsilon)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## 7. Data Retention Policies
|
|
272
|
+
|
|
273
|
+
### Retention Matrix
|
|
274
|
+
|
|
275
|
+
| Data Type | Retention Period | Action After |
|
|
276
|
+
|-----------|------------------|--------------|
|
|
277
|
+
| **Session data** | Until logout | Delete |
|
|
278
|
+
| **Conversation logs** | 30 days | Anonymize |
|
|
279
|
+
| **User profiles** | Account lifetime + 30 days | Delete |
|
|
280
|
+
| **Analytics** | 1 year (aggregated) | Archive |
|
|
281
|
+
| **Audit logs** | 7 years | Secure archive |
|
|
282
|
+
|
|
283
|
+
### Implementation
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
interface RetentionPolicy {
|
|
287
|
+
dataType: string;
|
|
288
|
+
retentionDays: number;
|
|
289
|
+
actionAfter: 'delete' | 'anonymize' | 'archive';
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async function enforceRetention(policy: RetentionPolicy): Promise<void> {
|
|
293
|
+
const cutoffDate = new Date();
|
|
294
|
+
cutoffDate.setDate(cutoffDate.getDate() - policy.retentionDays);
|
|
295
|
+
|
|
296
|
+
const expiredRecords = await db.findExpired(policy.dataType, cutoffDate);
|
|
297
|
+
|
|
298
|
+
for (const record of expiredRecords) {
|
|
299
|
+
switch (policy.actionAfter) {
|
|
300
|
+
case 'delete':
|
|
301
|
+
await db.delete(record.id);
|
|
302
|
+
break;
|
|
303
|
+
|
|
304
|
+
case 'anonymize':
|
|
305
|
+
await db.update(record.id, anonymize(record));
|
|
306
|
+
break;
|
|
307
|
+
|
|
308
|
+
case 'archive':
|
|
309
|
+
await archiveService.store(record);
|
|
310
|
+
await db.delete(record.id);
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
log.info(`Processed ${expiredRecords.length} ${policy.dataType} records`);
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## 8. Consent Management
|
|
322
|
+
|
|
323
|
+
### Consent Types
|
|
324
|
+
|
|
325
|
+
| Type | Required For | Revocable? |
|
|
326
|
+
|------|--------------|------------|
|
|
327
|
+
| **Essential** | Core service | No |
|
|
328
|
+
| **Analytics** | Usage tracking | Yes |
|
|
329
|
+
| **Marketing** | Promotions | Yes |
|
|
330
|
+
| **AI Training** | Model improvement | Yes |
|
|
331
|
+
|
|
332
|
+
### Implementation Pattern
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
interface UserConsent {
|
|
336
|
+
userId: string;
|
|
337
|
+
consents: {
|
|
338
|
+
essential: true; // Always true
|
|
339
|
+
analytics: boolean;
|
|
340
|
+
marketing: boolean;
|
|
341
|
+
aiTraining: boolean;
|
|
342
|
+
};
|
|
343
|
+
updatedAt: Date;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function canProcessForPurpose(consent: UserConsent, purpose: string): boolean {
|
|
347
|
+
if (purpose === 'essential') return true;
|
|
348
|
+
return consent.consents[purpose] === true;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Before AI processing
|
|
352
|
+
async function processWithConsent(userId: string, data: any): Promise<void> {
|
|
353
|
+
const consent = await getConsent(userId);
|
|
354
|
+
|
|
355
|
+
if (!canProcessForPurpose(consent, 'aiTraining')) {
|
|
356
|
+
// Use data for this request only, don't store for training
|
|
357
|
+
return processWithoutStorage(data);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return processAndStore(data);
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## 9. Audit Trail
|
|
367
|
+
|
|
368
|
+
### What to Log
|
|
369
|
+
|
|
370
|
+
| Event | Required Fields |
|
|
371
|
+
|-------|-----------------|
|
|
372
|
+
| **Data access** | Who, What, When, Why |
|
|
373
|
+
| **Data modification** | Before, After, Reason |
|
|
374
|
+
| **Data deletion** | What, When, By whom |
|
|
375
|
+
| **Consent change** | Old, New, Timestamp |
|
|
376
|
+
|
|
377
|
+
### Secure Logging
|
|
378
|
+
|
|
379
|
+
```python
|
|
380
|
+
import hashlib
|
|
381
|
+
from datetime import datetime
|
|
382
|
+
|
|
383
|
+
def log_data_access(user_id: str, data_type: str, purpose: str, accessor: str):
|
|
384
|
+
"""Log data access with privacy protection."""
|
|
385
|
+
|
|
386
|
+
# Hash user ID for log privacy
|
|
387
|
+
hashed_user = hashlib.sha256(f"{user_id}:audit_salt".encode()).hexdigest()[:16]
|
|
388
|
+
|
|
389
|
+
audit_entry = {
|
|
390
|
+
"timestamp": datetime.utcnow().isoformat(),
|
|
391
|
+
"subject_hash": hashed_user,
|
|
392
|
+
"data_type": data_type,
|
|
393
|
+
"purpose": purpose,
|
|
394
|
+
"accessor": accessor,
|
|
395
|
+
"action": "access"
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
# Append-only audit log
|
|
399
|
+
audit_log.append(audit_entry)
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## 10. Checklist
|
|
405
|
+
|
|
406
|
+
### Before Processing User Data
|
|
407
|
+
|
|
408
|
+
- [ ] PII identified and classified
|
|
409
|
+
- [ ] Redaction/anonymization applied
|
|
410
|
+
- [ ] Consent verified for purpose
|
|
411
|
+
- [ ] Data minimization applied
|
|
412
|
+
- [ ] Retention policy set
|
|
413
|
+
|
|
414
|
+
### For AI/LLM Processing
|
|
415
|
+
|
|
416
|
+
- [ ] PII redacted from prompts
|
|
417
|
+
- [ ] Output checked for PII leakage
|
|
418
|
+
- [ ] No training on personal data without consent
|
|
419
|
+
- [ ] Audit trail enabled
|
|
420
|
+
|
|
421
|
+
### For Data Storage
|
|
422
|
+
|
|
423
|
+
- [ ] Encryption at rest
|
|
424
|
+
- [ ] Access controls implemented
|
|
425
|
+
- [ ] Retention automation configured
|
|
426
|
+
- [ ] Deletion verification
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## 11. Anti-Patterns
|
|
431
|
+
|
|
432
|
+
| ❌ Don't | ✅ Do |
|
|
433
|
+
|----------|-------|
|
|
434
|
+
| Log full PII | Log hashed/tokenized references |
|
|
435
|
+
| Store "just in case" | Apply data minimization |
|
|
436
|
+
| Use PII as identifiers | Use synthetic IDs |
|
|
437
|
+
| Ignore consent | Check consent before processing |
|
|
438
|
+
| Hard-delete only | Verify deletion, maintain audit |
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
> **Remember:** Privacy is not about hiding data—it's about respecting user control over their information.
|