WDP Part 11: Security Considerations
Security requirements and best practices for WDP implementations
Abstract
This document specifies security considerations for the Waddling Diagnostic Protocol (WDP). It defines requirements and best practices for handling sensitive data, personally identifiable information (PII), authentication tokens, and other security-critical information within diagnostic messages and catalogs.
Key Concepts
- PII detection and sanitization
- Sensitive field handling
- Secure catalog distribution
- Access control for diagnostic data
- Security incident diagnostics
1. Introduction
1.1 Purpose
Security is a critical concern when transmitting diagnostic information. This specification provides guidance on:
- PII Protection - Preventing leakage of user data in error messages
- Sensitive Data - Handling credentials, tokens, and secrets
- Data Minimization - Only including necessary information
- Secure Distribution - Protecting catalog integrity
- Compliance - Meeting GDPR, CCPA, HIPAA requirements
1.2 Scope
This document covers security considerations for:
- Diagnostic message content
- Field interpolation values
- Catalog file distribution
- Logging and persistence
- Cross-system diagnostic transmission
1.3 Threat Model
WDP implementations should consider these threat vectors:
- Information Disclosure - Leaking PII/secrets in error messages
- Catalog Tampering - Malicious modification of catalog files
- Man-in-the-Middle - Interception of diagnostic data
- Log Injection - Malicious data in diagnostic fields
- Denial of Service - Resource exhaustion via diagnostics
- Privacy Violations - Correlation of user activities
1.4 Security Principles
┌─────────────────────────────────────────┐
│ 1. Prevention (Don't include PII) │
│ 2. Detection (Sanitize before output) │
│ 3. Mitigation (Redact in logs) │
│ 4. Monitoring (Alert on violations) │
└─────────────────────────────────────────┘2. Personally Identifiable Information (PII)
2.1 PII Location Rules
CRITICAL PRINCIPLE: PII MUST be placed in the pii.data field and referenced via {{pii/field}} placeholders in message templates.
Where PII is PROHIBITED
| Location | Rule | Example Violation |
|---|---|---|
| Catalog Message Templates (hardcoded) | PROHIBITED: NEVER hardcode PII | "User john@example.com failed login" |
| Catalog Descriptions | PROHIBITED: NEVER include PII | "Contact admin@company.com for help" |
| Catalog Hints | PROHIBITED: NEVER include PII | "Call +1-555-0100 for support" |
| Diagnostic Code | PROHIBITED: NEVER include PII | E.Auth.JohnDoe.001 |
| Named Sequences | PROHIBITED: NEVER include PII | TOKEN_JOHN_DOE_EXPIRED |
| Component Names | PROHIBITED: NEVER include PII | UserJohnDoeAuth |
| Primary Names | PROHIBITED: NEVER include PII | JohnDoeToken |
| Tags | PROHIBITED: NEVER include PII | ["user:john@example.com"] |
| f field | PROHIBITED: NEVER put PII here | {"f": {"email": "john@example.com"}} |
| ctx field | PROHIBITED: NEVER put PII here | {"ctx": {"user": {"email": "..."}}} |
| Stack Traces | PROHIBITED: NEVER include PII | Remove username from /home/john/... |
| Namespace | CONDITIONAL: Org names OK | "acme-corp" (OK), "john-doe" (BAD) |
Where PII MUST Appear (if needed)
| Location | Rule | Syntax |
|---|---|---|
| pii.data field | ✅ ONLY place for PII | {"pii": {"v": 1, "data": {"email": "..."}}} |
| Message template placeholders | ✅ Use pii/ prefix | "Login failed for {{pii/email}}" |
Architectural Principle
┌──────────────────────────────────────────────────────────┐
│ CATALOG (Static, Distributed, Cached) │
│ REQUIRED: NO PII EVER │
│ - Message templates with {{field}} placeholders │
│ - PII placeholders use {{pii/field}} syntax │
│ - Generic descriptions and hints │
│ - No hardcoded personal information │
└──────────────────────────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ RUNTIME RESPONSE (Dynamic, Ephemeral) │
│ REQUIRED: PII ONLY IN pii.data FIELD │
│ - Regular fields in `f` object │
│ - PII fields in `pii.data` object │
│ - Referenced via {{pii/field}} in templates │
│ - Access control enforced at render time │
└──────────────────────────────────────────────────────────┘Example - CORRECT (No PII in message)
{
"xY9Kp": {
"code": "E.Auth.Login.001",
"message": "Invalid credentials for user {{user_id}}",
"description": "Authentication failed due to incorrect credentials",
"hints": ["Verify your password", "Check if account is locked"]
}
}{
"xY9Kp": {
"f": {
"user_id": "usr_8d7f9a2b" // Correct: Opaque identifier (not PII)
}
}
}Example - CORRECT (With PII using pii/ syntax)
{
"Ay75d": {
"code": "E.Auth.Token.001",
"message": "Token for {{pii/email}} expired at {{timestamp}}",
"description": "Your session has expired. Please log in again."
}
}{
"Ay75d": {
"f": {
"timestamp": "2024-01-15T10:30:00Z" // Correct: Non-PII in f
},
"pii": {
"v": 1,
"data": {
"email": "john@example.com" // Correct: PII in pii.data
}
}
}
}
// Rendered (with PII access):
// "Token for john@example.com expired at 2024-01-15T10:30:00Z"
// Rendered (without PII access):
// "Token for [REDACTED] expired at 2024-01-15T10:30:00Z"Example - WRONG
// ❌ WRONG: Catalog with hardcoded PII
{
"xY9Kp": {
"code": "E.Auth.Login.001",
"message": "Invalid credentials for user john.doe@example.com", // Violation!
"description": "Contact support at +1-555-0100", // Violation!
"hints": ["Email admin@company.com for password reset"] // Violation!
}
}
// WRONG: Runtime with PII in wrong field
{
"xY9Kp": {
"f": {
"email": "john.doe@example.com", // Violation: Should be in pii.data
"password": "secret123" // CRITICAL: NEVER include passwords!
}
}
}2.2 Comprehensive PII Leak Vector Analysis
PII can leak through many channels. This section provides a systematic analysis of all potential leak vectors.
2.2.1 Catalog-Level Vectors (Static, High Impact)
Catalog leaks are the MOST DANGEROUS because they are:
- Distributed to all clients
- Cached indefinitely
- Difficult to recall once published
- Often version-controlled (permanent history)
| Vector | Risk | Example Violation | Mitigation |
|---|---|---|---|
| Message Template | CRITICAL | "User {{name}} at {{email}} failed" | Use only technical placeholders |
| Description Field | HIGH | "This affects user john@example.com" | Generic descriptions only |
| Hints Array | MEDIUM | ["Contact John Doe at ext. 5555"] | Generic help only |
| Tags Array | MEDIUM | ["user:alice", "ip:192.168.1.1"] | Technical tags only |
| Docs URL | MEDIUM | "https://wiki/users/john-doe/auth" | Generic documentation URLs |
| Field Names | LOW | "john_doe_email" | Use generic: email, user_id |
2.2.2 Runtime Field Vectors (Dynamic, Per-Request)
Runtime leaks occur in the f field (which should NEVER contain PII):
| Field Type | Risk | Safe Alternative |
|---|---|---|
| 🔴 CRITICAL | user_id: "usr_abc123" | |
| Phone | 🔴 CRITICAL | contact_id: "con_xyz789" |
| Name | 🔴 CRITICAL | user_id: "usr_abc123" |
| Address | 🔴 CRITICAL | location_id: "loc_def456" |
| SSN/Tax ID | 🔴 CRITICAL | Never include |
| Credit Card | 🔴 CRITICAL | last4: "1111" |
| Password | 🔴 CRITICAL | NEVER include |
| Token | 🔴 CRITICAL | NEVER include |
| IP Address | 🟡 MEDIUM | ip_hash: "a1b2c3..." |
| User Agent | 🟡 MEDIUM | browser: "chrome" |
| Cookie | 🟡 MEDIUM | session_id: "sess_xyz" |
| File Path | 🟡 MEDIUM | "config.json" (relative) |
| Username | 🟡 MEDIUM | user_id: "usr_abc123" |
| Device ID | 🟡 MEDIUM | device_id: "dev_abc123" |
2.2.3 Stack Trace Vectors
Stack traces can inadvertently expose PII:
| Vector | Risk | Example | Mitigation |
|---|---|---|---|
| File Paths | MEDIUM | /home/john/app/config.js | Strip username: /app/config.js |
| Usernames in Paths | MEDIUM | C:\Users\JohnDoe\Documents\ | Strip: \Documents\ |
| Environment Variables | HIGH | USER_EMAIL=john@example.com | Sanitize env vars |
| Query Strings | CRITICAL | ?email=john@example.com | Strip params |
| Database Values | CRITICAL | WHERE email='john@...' | Never log queries |
2.2.4 Context Field Vectors
The ctx field is for DEBUGGING context, NOT user data:
{
"ctx": {
"user": {
"email": "john@example.com",
"name": "John Doe"
}
}
}{
"ctx": {
"request_id": "req_abc123",
"correlation_id": "corr_xyz789",
"service": "auth-service",
"version": "1.2.3"
}
}2.3 PII Field Structure
The pii field is an OPTIONAL object at the same level as f,st, src, and ctx:
{
"h": "Ay75d",
"f": {
"timestamp": "2024-01-15T10:30:00Z",
"count": 42
},
"pii": {
"v": 1,
"data": {
"email": "john@example.com",
"ip": "192.168.1.1"
}
}
}Required fields in pii object:
v(integer): Version number (currently 1)data(object): Contains PII key-value pairs
Single Source of Truth:
- If it's PII → goes in
pii.data, referenced as{{pii/field}} - If it's not PII → goes in
f, referenced as{{field}} - NEVER duplicate data across both fields
2.4 What is PII?
Personally Identifiable Information (PII) is any data that can be used to identify, contact, or locate a specific individual.
| Category | Examples | Risk Level |
|---|---|---|
| Direct Identifiers | Full name, SSN, passport number | CRITICAL |
| Contact Information | Email, phone, physical address | HIGH |
| Financial Data | Credit card, bank account, tax ID | CRITICAL |
| Government IDs | Driver's license, national ID | CRITICAL |
| Biometric Data | Fingerprints, facial recognition | CRITICAL |
| Health Information | Medical records, diagnoses | CRITICAL (HIPAA) |
| Online Identifiers | IP address, device ID, cookie ID | MEDIUM |
| Authentication | Passwords, tokens, API keys | CRITICAL |
2.5 PII Detection Patterns
const PII_PATTERNS = {
email: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/,
phone: /\b(\+\d{1,3}[- ]?)?\(?\d{3}\)?[- ]?\d{3}[- ]?\d{4}\b/,
ssn: /\b\d{3}-\d{2}-\d{4}\b/,
credit_card: /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/,
ip_address: /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,
jwt: /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/
};
function containsPII(text: string): boolean {
return Object.values(PII_PATTERNS).some(pattern => pattern.test(text));
}2.6 Quick Decision Guide
| Data Type | In Catalog? | In Runtime Fields? | Best Practice |
|---|---|---|---|
| User email | ❌ NEVER | ⚠️ Avoid | user_id: "usr_abc123" |
| Password | ❌ NEVER | ❌ NEVER | NEVER INCLUDE |
| Token/API key | ❌ NEVER | ❌ NEVER | NEVER INCLUDE |
| IP address | ❌ NEVER | ⚠️ Hash only | ip_hash: "a1b2c3..." |
| User ID (opaque) | ✅ Placeholder | ✅ YES | {{user_id}} → usr_abc123 |
| Timestamp | ✅ Placeholder | ✅ YES | {{timestamp}} → 2024-01-15T... |
| Error type | ✅ YES | ✅ YES | validation_failed |
Golden Rule:
If you're not sure whether something is PII → DON'T INCLUDE IT
Use opaque identifiers instead2.10 PII Audit Checklist
Use this checklist when reviewing WDP implementations for PII compliance. All items marked CRITICAL must pass before deployment.
| Audit Item | Location | Check | Severity |
|---|---|---|---|
| Catalog message templates | Catalog | No hardcoded PII in message strings | 🔴 CRITICAL |
| Catalog description fields | Catalog | No PII in description or hints | 🔴 CRITICAL |
| Field placeholders | Catalog | PII uses {{pii/field}} syntax | 🔴 CRITICAL |
| Runtime f field | Runtime | No PII in f object | 🔴 CRITICAL |
| Runtime pii.data field | Runtime | All PII in pii.data object | 🟢 REQUIRED |
| Stack traces | Runtime/Logs | File paths are relative, no user data in args | 🟡 HIGH |
| Context field (ctx) | Runtime | Only technical metadata, no user data | 🟡 HIGH |
| Source field (src) | Runtime | No PII in source locations | 🟡 HIGH |
| Log output | Logs | pii.data excluded or redacted in logs | 🔴 CRITICAL |
| Error responses | API | PII not exposed in API responses | 🔴 CRITICAL |
| Metrics/telemetry | Observability | No high-cardinality PII in metrics | 🟡 HIGH |
| Cache keys | Cache | No PII in cache key names | 🟡 HIGH |
Automated Audit Commands
# Scan catalogs for PII patterns
wdp-lint --check-pii catalogs/
# Validate placeholder syntax
wdp-lint --check-placeholders catalogs/
# Verify runtime field compliance
wdp-lint --check-runtime-fields logs/
# Full security audit
wdp-audit --security --verbose2.11 PII Quick Reference Summary
Quick reference for the 10 essential PII rules. Print this and keep it visible during development.
| Rule # | Rule | Violation Example | Correct Example |
|---|---|---|---|
| R1 | No PII in catalogs | "Hello john@example.com" | "Hello {{pii/email}}" |
| R2 | PII uses pii/ prefix | {{email}} | {{pii/email}} |
| R3 | Runtime PII in pii.data | f: { email: "..." } | pii: { data: { email: "..." } } |
| R4 | Never include passwords | password: "secret" | (omit entirely) |
| R5 | Never include tokens | token: "eyJ..." | (omit entirely) |
| R6 | Hash IP addresses | ip: "192.168.1.1" | ip_hash: "a1b2c3..." |
| R7 | Use opaque identifiers | user: "John Doe" | user_id: "usr_abc123" |
| R8 | Relative file paths only | "/home/john/app/..." | "./src/config.json" |
| R9 | No PII in ctx field | ctx: { user_email: "..." } | ctx: { request_id: "..." } |
| R10 | Redact PII in logs | log(pii.data) | log("[PII REDACTED]") |
One-Liner Summary
Catalogs: Never contain PII, use {{pii/field}} placeholders
Runtime: PII goes in pii.data only, never in f/ctx/src/st
Logging: Always redact or exclude pii.data
Always: When in doubt, leave it out3. Sensitive Data in Diagnostics
3.1 Types of Sensitive Data
| Data Type | Examples | Protection |
|---|---|---|
| Credentials | Passwords, API keys | NEVER include |
| Tokens | JWT, OAuth tokens | NEVER include |
| Secrets | Encryption keys, certificates | NEVER include |
| Session Data | Session IDs, cookies | Use opaque IDs |
| Business Logic | Pricing, algorithms | Limit exposure |
| System Info | Internal paths, versions | Sanitize for production |
3.2 Authentication Errors
{
"E.Auth.Token.001": {
"message": "Invalid token: {{token}}",
"fields": ["token"]
}
}
// Runtime:
{
"xY9Kp": {
"f": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
}{
"E.Auth.Token.001": {
"message": "Token validation failed",
"fields": []
}
}
// Runtime:
{
"xY9Kp": {}
}{
"E.Auth.Token.002": {
"message": "Token expired at {{expired_at}}",
"fields": ["expired_at"]
}
}
// Runtime:
{
"xY9Kp": {
"f": {
"expired_at": "2024-01-15T10:30:00Z"
}
}
}3.3 Database Errors
{
"message": "Query failed: SELECT * FROM users WHERE email='{{email}}'"
}{
"message": "Database query failed",
"fields": []
}3.4 File System Errors
{
"message": "File not found: /home/admin/.ssh/id_rsa"
}{
"message": "Configuration file not found: {{filename}}",
"fields": ["filename"]
}
// Runtime:
{
"f": {
"filename": "config.json" // Relative path only
}
}4. Field-Level Security
4.1 Sensitive Field Declaration
{
"diags": {
"xY9Kp": {
"code": "E.Payment.Process.001",
"message": "Payment failed for order {{order_id}}",
"fields": ["order_id"],
"field_security": {
"order_id": {
"sensitive": false,
"redact_in_logs": false
}
}
},
"mN3Yr": {
"code": "E.Payment.Card.002",
"message": "Card validation failed",
"fields": ["last4"],
"field_security": {
"last4": {
"sensitive": true,
"redact_in_logs": true,
"max_log_level": "warn"
}
}
}
}
}4.2 Runtime Field Sanitization
interface FieldSecurityPolicy {
sensitive: boolean;
redact_in_logs: boolean;
redaction_strategy: 'hash' | 'mask' | 'remove';
allowed_contexts: ('api' | 'logs' | 'monitoring')[];
}
function sanitizeField(
value: any,
policy: FieldSecurityPolicy,
context: string
): any {
if (!policy.sensitive) {
return value;
}
if (!policy.allowed_contexts.includes(context)) {
return '[REDACTED]';
}
switch (policy.redaction_strategy) {
case 'hash':
return hashValue(value);
case 'mask':
return maskValue(value);
case 'remove':
return undefined;
default:
return value;
}
}4.3 Field Value Limits
const FIELD_LIMITS = {
max_string_length: 1000,
max_array_length: 100,
max_object_depth: 3,
max_total_size: 10 * 1024 // 10KB
};
function validateFieldSize(fields: Record<string, any>): void {
const json = JSON.stringify(fields);
if (json.length > FIELD_LIMITS.max_total_size) {
throw new Error('Diagnostic fields exceed size limit');
}
}4.4 Field Injection Prevention
function sanitizeForLogs(value: string): string {
return value
// Remove control characters
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '')
// Replace newlines and tabs with a space
.replace(/[\r\n\t]/g, ' ')
.trim()
.slice(0, 500); // Max length
}
// Usage:
logger.error(`Validation failed`, {
diagnostic: "E.Validation.Field.001",
field: sanitizeForLogs(userInput)
});5. Catalog Security
5.1 Catalog Integrity
Use Subresource Integrity (SRI) for catalog files:
<script
src="https://cdn.example.com/wdp/catalog-v1.0.0.json"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"
></script>5.2 Catalog Signing
{
"version": "1.0.0",
"generated": "2024-01-15T10:30:00Z",
"diags": { /* ... */ },
"signature": {
"algorithm": "RS256",
"public_key_url": "https://example.com/wdp/public-key.pem",
"signature": "MEUCIQDx..."
}
}async function verifyCatalog(catalog: any): Promise<boolean> {
const { signature, ...content } = catalog;
const publicKey = await fetchPublicKey(signature.public_key_url);
return verifySignature(
JSON.stringify(content),
signature.signature,
publicKey,
signature.algorithm
);
}5.3 Catalog Access Control
async function serveCatalog(req: Request): Promise<Response> {
const user = await authenticate(req);
if (!user.hasRole('admin')) {
// Return public catalog only
return sendFile('catalog-public.json');
}
// Return full catalog with internal diagnostics
return sendFile('catalog-internal.json');
}5.4 Catalog Content Security
Prevent XSS in catalog messages:
function displayDiagnostic(diagnostic: ExpandedDiagnostic): string {
// Always escape user-provided values
const escaped = escapeHtml(diagnostic.message);
return escaped;
}
function escapeHtml(text: string): string {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}6. Transport Security
6.1 HTTPS Requirements
MUST use HTTPS for:
- Catalog distribution
- Diagnostic API responses
- Any transmission containing diagnostics
// Enforce HTTPS in production
if (process.env.NODE_ENV === 'production') {
if (req.protocol !== 'https') {
return res.redirect(301, `https://${req.hostname}${req.url}`);
}
}6.2 TLS Configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;6.3 Rate Limiting
const rateLimiter = new RateLimiter({
windowMs: 60 * 1000, // 1 minute
max: 100, // Max 100 diagnostics per minute per IP
message: {
"C.RateLimit.Exceeded.001": {
"f": {
"retry_after": "60"
}
}
}
});
app.use('/api/diagnostics', rateLimiter);7. Logging and Storage
7.1 Log Sanitization
class SecureLogger {
private sanitize(message: string, fields: Record<string, any>): void {
// Check for PII
if (containsPII(message)) {
throw new Error('PII detected in log message');
}
// Redact sensitive fields
const sanitized = { ...fields };
for (const [key, value] of Object.entries(sanitized)) {
if (SENSITIVE_FIELD_NAMES.includes(key)) {
sanitized[key] = '[REDACTED]';
}
}
return sanitized;
}
error(message: string, fields?: Record<string, any>): void {
const sanitized = this.sanitize(message, fields || {});
console.error(message, sanitized);
}
}7.2 Log Retention
interface LogRetentionPolicy {
severity: string;
retention_days: number;
archive_after_days: number;
purge_pii: boolean;
}
const RETENTION_POLICIES: Record<string, LogRetentionPolicy> = {
'E': { retention_days: 90, archive_after_days: 30, purge_pii: true },
'W': { retention_days: 60, archive_after_days: 30, purge_pii: true },
'C': { retention_days: 365, archive_after_days: 90, purge_pii: false },
'I': { retention_days: 30, archive_after_days: 7, purge_pii: true }
};7.3 Audit Logging
interface AuditLog {
timestamp: string;
user_id?: string;
ip_address?: string;
diagnostic_code: string;
compact_id: string;
severity: string;
action: string;
result: 'success' | 'failure';
}
function logSecurityEvent(diagnostic: Diagnostic, context: AuditContext): void {
if (SECURITY_DIAGNOSTICS.includes(diagnostic.code)) {
auditLogger.log({
timestamp: new Date().toISOString(),
user_id: context.userId,
ip_address: hashIP(context.ipAddress), // Hash IP for privacy
diagnostic_code: diagnostic.code,
compact_id: diagnostic.compactId,
severity: diagnostic.severity,
action: context.action,
result: context.result
});
}
}8. Access Control
8.1 Diagnostic Visibility Levels
enum VisibilityLevel {
PUBLIC = 0, // User-facing diagnostics
INTERNAL = 1, // Internal team only
CONFIDENTIAL = 2, // Security team only
RESTRICTED = 3 // Admin only
}
interface DiagnosticMetadata {
code: string;
visibility: VisibilityLevel;
requires_role?: string[];
}8.2 Role-Based Diagnostic Filtering
function filterDiagnosticsByRole(
diagnostics: Diagnostic[],
userRole: string
): Diagnostic[] {
const roleLevel = ROLE_LEVELS[userRole] || 0;
return diagnostics.filter(diag => {
const metadata = DIAGNOSTIC_METADATA[diag.code];
return metadata.visibility <= roleLevel;
});
}
// Usage:
app.get('/api/diagnostics', authenticate, (req, res) => {
const allDiagnostics = getDiagnostics();
const filtered = filterDiagnosticsByRole(allDiagnostics, req.user.role);
res.json({ diagnostics: filtered });
});8.3 Context-Aware Diagnostics
function generateDiagnostic(
code: string,
context: 'api' | 'internal' | 'monitoring'
): Diagnostic {
const base = DIAGNOSTICS[code];
switch (context) {
case 'api':
// Minimal details for external API
return {
code: base.code,
compact_id: base.compact_id,
message: base.message_public,
severity: base.severity
};
case 'internal':
// Full details for internal use
return {
code: base.code,
compact_id: base.compact_id,
message: base.message_internal,
severity: base.severity,
description: base.description,
hints: base.hints,
stack_trace: base.stack_trace
};
case 'monitoring':
// Metrics-focused
return {
code: base.code,
compact_id: base.compact_id,
severity: base.severity,
tags: base.tags,
metrics: base.metrics
};
}
}9. Security Incident Diagnostics
9.1 Security-Specific Severity
Use Critical (C) for security incidents:
{
"C.Security.Breach.001": {
"code": "C.Security.Breach.001",
"severity": "C",
"message": "Unauthorized access attempt detected",
"description": "Multiple failed authentication attempts from {{ip_hash}}",
"fields": ["ip_hash"],
"security_level": "critical",
"alert_team": "security",
"requires_investigation": true
}
}9.2 Security Diagnostic Categories
| Code Pattern | Use Case | Example |
|---|---|---|
| C.Security.Auth.* | Authentication failures | Brute force, credential stuffing |
| C.Security.Access.* | Authorization failures | Privilege escalation attempts |
| C.Security.Injection.* | Injection attacks | SQL injection, XSS attempts |
| C.Security.Integrity.* | Data tampering | Checksum failures, replay attacks |
| W.Security.Config.* | Configuration issues | Weak passwords, missing encryption |
9.3 Incident Response Integration
interface SecurityIncident {
diagnostic_code: string;
compact_id: string;
severity: 'C' | 'E' | 'W';
timestamp: string;
source_ip_hash: string;
user_id_hash?: string;
attack_vector: string;
automated_response: boolean;
}
async function handleSecurityDiagnostic(
diagnostic: Diagnostic,
context: RequestContext
): Promise<void> {
if (diagnostic.severity === 'C') {
// Create incident
const incident: SecurityIncident = {
diagnostic_code: diagnostic.code,
compact_id: diagnostic.compact_id,
severity: diagnostic.severity,
timestamp: new Date().toISOString(),
source_ip_hash: hashIP(context.ip),
attack_vector: classifyAttack(diagnostic),
automated_response: true
};
// Alert security team
await alertSecurityTeam(incident);
// Take automated action
if (shouldBlockIP(incident)) {
await blockIP(context.ip, '1h');
}
}
}9.4 Security Diagnostic Best Practices
Recommended practices:
- Log security diagnostics to separate, secured audit log
- Use generic messages for authentication failures
- Include metadata for investigation (hashed IPs, timestamps)
- Alert security team for critical diagnostics
- Implement automated responses (IP blocking, rate limiting)
Practices to avoid:
- Include sensitive data in security diagnostics
- Expose system internals in error messages
- Log raw IP addresses (hash them)
- Provide detailed feedback to attackers
- Mix security logs with application logs
10. Regulatory Compliance Disclaimer
WDP provides mechanisms for separating, redacting, and controlling access to sensitive data (see PII handling in Sections 2-4). However, WDP conformance does NOT guarantee compliance with any regulatory framework including but not limited to GDPR, CCPA, HIPAA, PCI DSS, or SOC 2.
Compliance with applicable data protection laws and industry standards is the sole responsibility of the implementer. Organizations SHOULD consult qualified legal and security professionals when implementing systems that handle regulated data.
WDP provides tools, not compliance:
- PII field separation (
pii.data) — enables access control - Redaction suffixes (
:masked,:raw) — enables data minimization - Structured logging patterns — enables audit trails
- Field validation examples — demonstrates security patterns
Implementers are responsible for:
- Determining which data constitutes PII in their jurisdiction
- Implementing appropriate retention and deletion policies
- Ensuring encryption in transit and at rest
- Conducting security audits and compliance assessments
- Training personnel on data handling requirements
11. Implementation Guidelines
11.1 Secure by Default
const wdpConfig = {
security: {
// PII Detection
pii_detection: {
enabled: true,
mode: 'strict', // 'strict' | 'moderate' | 'disabled'
patterns: [...DEFAULT_PII_PATTERNS, ...CUSTOM_PATTERNS],
on_violation: 'throw' // 'throw' | 'redact' | 'warn'
},
// Field Sanitization
field_sanitization: {
enabled: true,
max_field_length: 1000,
max_fields: 50,
sanitize_html: true,
sanitize_sql: true
},
// Logging
logging: {
redact_sensitive_fields: true,
sensitive_field_patterns: [/password/i, /token/i, /secret/i],
log_level: 'info',
include_stack_trace: process.env.NODE_ENV !== 'production'
},
// Transport
transport: {
require_https: process.env.NODE_ENV === 'production',
enforce_cors: true,
allowed_origins: ['https://example.com']
}
}
};11.2 Security Testing
describe('PII Detection', () => {
it('should detect email addresses', () => {
const text = 'User john.doe@example.com failed login';
expect(containsPII(text)).toBe(true);
});
it('should detect credit card numbers', () => {
const text = 'Payment failed for card 4111-1111-1111-1111';
expect(containsPII(text)).toBe(true);
});
it('should not flag safe content', () => {
const text = 'Authentication failed for user usr_123abc';
expect(containsPII(text)).toBe(false);
});
});describe('Diagnostic Security', () => {
it('should reject diagnostics with PII', async () => {
const diagnostic = {
code: 'E.Test.001',
fields: {
email: 'test@example.com' // PII!
}
};
await expect(
generateDiagnostic(diagnostic)
).rejects.toThrow('PII detected');
});
it('should sanitize fields before logging', () => {
const diagnostic = {
code: 'E.Test.001',
fields: {
password: 'secret123' // Sensitive!
}
};
const logged = sanitizeForLogs(diagnostic);
expect(logged.fields.password).toBe('[REDACTED]');
});
});11.3 Security Monitoring
interface SecurityMetrics {
pii_violations_detected: number;
pii_violations_blocked: number;
sensitive_field_redactions: number;
security_diagnostics_generated: number;
failed_catalog_integrity_checks: number;
rate_limit_violations: number;
}
// Monitor and alert
const metrics = new MetricsCollector();
metrics.increment('wdp.security.pii_violations_detected');
metrics.increment('wdp.security.field_redactions');
// Alert on anomalies
if (metrics.get('wdp.security.pii_violations_detected') > THRESHOLD) {
alertSecurityTeam('High number of PII violations detected');
}12. Security Checklist
12.1 Development Checklist
- ☐ Define PII policy for your organization
- ☐ Create list of sensitive field names
- ☐ Configure PII detection patterns
- ☐ Implement field sanitization
- ☐ Set up secure catalog distribution (HTTPS)
- ☐ Configure log sanitization
- ☐ Implement catalog integrity verification
- ☐ Define security diagnostic codes
- ☐ Set up security incident response workflow
- ☐ Configure rate limiting
- ☐ Implement role-based diagnostic filtering
- ☐ Set up audit logging for security events
12.2 Pre-Production Checklist
- ☐ Review all diagnostic messages for PII
- ☐ Test PII detection with real data samples
- ☐ Verify HTTPS enforcement
- ☐ Test catalog signature verification
- ☐ Review log sanitization output
- ☐ Test security diagnostic alerting
- ☐ Verify sensitive field redaction
- ☐ Test rate limiting thresholds
- ☐ Review access control policies
- ☐ Conduct security code review
- ☐ Run security-focused integration tests
- ☐ Document security procedures
12.3 Production Checklist
- ☐ Monitor PII violation metrics
- ☐ Review security diagnostic logs daily
- ☐ Test incident response procedures
- ☐ Audit catalog access logs
- ☐ Review and rotate encryption keys
- ☐ Update PII detection patterns as needed
- ☐ Conduct regular security assessments
- ☐ Train team on security best practices
- ☐ Review compliance requirements
- ☐ Update security documentation
12.4 Code Review Checklist
- ☐ No PII in diagnostic messages
- ☐ No credentials, tokens, or secrets in fields
- ☐ Field values are validated and sanitized
- ☐ Sensitive fields are marked in metadata
- ☐ Messages don't expose system internals
- ☐ HTTPS is enforced for catalog distribution
- ☐ Catalog integrity verification is implemented
- ☐ Logs are sanitized before writing
- ☐ Rate limiting is configured
- ☐ Audit logging is enabled for security diagnostics
Appendix A: PII Detection Patterns
This appendix provides comprehensive regex patterns for detecting common PII types. These patterns are language-agnostic and can be adapted to your implementation.
A.1 Email Addresses
// Standard email pattern (RFC 5322 simplified)
const EMAIL_PATTERN = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/gi;
// Examples matched:
// - user@example.com
// - john.doe@company.co.uk
// - test+label@domain.orgA.2 Phone Numbers
// International phone patterns
const PHONE_PATTERNS = [
// US format: (123) 456-7890, 123-456-7890, 1234567890
/\b(\+1[- ]?)?\(?\d{3}\)?[- ]?\d{3}[- ]?\d{4}\b/g,
// International format: +44 20 7123 4567
/\b\+\d{1,3}[- ]?\d{1,4}[- ]?\d{3,4}[- ]?\d{3,4}\b/g,
// E.164 format: +14155552671
/\b\+[1-9]\d{6,14}\b/g
];A.3 Social Security Numbers (SSN)
// US SSN patterns
const SSN_PATTERNS = [
// Standard format: 123-45-6789
/\b\d{3}-\d{2}-\d{4}\b/g,
// No dashes: 123456789 (9 consecutive digits)
/\b(?!000|666|9\d{2})\d{3}(?!00)\d{2}(?!0000)\d{4}\b/g
];
// Note: Be careful with 9-digit patterns as they may match other numbersA.4 Credit Card Numbers
// Credit card patterns by issuer
const CC_PATTERNS = {
// Visa: starts with 4
visa: /\b4\d{3}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/g,
// Mastercard: starts with 51-55 or 2221-2720
mastercard: /\b(?:5[1-5]\d{2}|2(?:2(?:2[1-9]|[3-9]\d)|[3-6]\d{2}|7(?:[01]\d|20)))[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/g,
// Amex: starts with 34 or 37
amex: /\b3[47]\d{2}[- ]?\d{6}[- ]?\d{5}\b/g,
// Generic 16-digit
generic: /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/g
};
// Luhn check for validation
function luhnCheck(cardNumber) {
const digits = cardNumber.replace(/\D/g, '');
let sum = 0;
for (let i = digits.length - 1; i >= 0; i--) {
let digit = parseInt(digits[i], 10);
if ((digits.length - i) % 2 === 0) {
digit *= 2;
if (digit > 9) digit -= 9;
}
sum += digit;
}
return sum % 10 === 0;
}A.5 IP Addresses
// IPv4 pattern
const IPV4_PATTERN = /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/g;
// IPv6 pattern (simplified)
const IPV6_PATTERN = /\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b/g;
// Note: Consider whether internal IPs (10.x, 192.168.x) should be treated as PIIA.6 Tokens and Secrets
// JWT pattern
const JWT_PATTERN = /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g;
// API key patterns (common formats)
const API_KEY_PATTERNS = [
/\b[A-Za-z0-9]{32,}\b/g, // 32+ alphanumeric
/\bsk_(?:live|test)_[A-Za-z0-9]{24,}\b/g, // Stripe-style
/\bAIza[A-Za-z0-9_-]{35}\b/g, // Google API
/\bghp_[A-Za-z0-9]{36}\b/g, // GitHub PAT
];
// AWS patterns
const AWS_PATTERNS = {
accessKeyId: /\bAKIA[0-9A-Z]{16}\b/g,
secretKey: /\b[A-Za-z0-9/+=]{40}\b/g // May have false positives
};Appendix B: Security Code Examples
Complete, production-ready code examples for implementing WDP security features.
B.1 PII Sanitizer Implementation
import { PII_PATTERNS } from './patterns';
interface SanitizeOptions {
replacement?: string;
preserve_format?: boolean;
log_detections?: boolean;
}
export class PIISanitizer {
private patterns: Map<string, RegExp>;
private options: SanitizeOptions;
constructor(options: SanitizeOptions = {}) {
this.patterns = new Map(Object.entries(PII_PATTERNS));
this.options = {
replacement: '[REDACTED]',
preserve_format: false,
log_detections: false,
...options
};
}
sanitize(text: string): string {
let result = text;
const detections: { type: string; count: number }[] = [];
for (const [type, pattern] of this.patterns) {
const matches = result.match(pattern);
if (matches) {
detections.push({ type, count: matches.length });
result = result.replace(pattern, this.getReplacement(type));
}
}
if (this.options.log_detections && detections.length > 0) {
console.warn('PII detected and sanitized:', detections);
}
return result;
}
private getReplacement(type: string): string {
if (!this.options.preserve_format) {
return this.options.replacement!;
}
// Format-preserving replacements
const formats: Record<string, string> = {
email: '[email@redacted.com]',
phone: '[XXX-XXX-XXXX]',
ssn: '[XXX-XX-XXXX]',
credit_card: '[XXXX-XXXX-XXXX-XXXX]',
ip_address: '[X.X.X.X]'
};
return formats[type] || this.options.replacement!;
}
containsPII(text: string): boolean {
for (const pattern of this.patterns.values()) {
if (pattern.test(text)) return true;
}
return false;
}
}B.2 WDP Message Validator
import { PIISanitizer } from './pii-sanitizer';
interface WDPMessage {
h: string;
f?: Record<string, unknown>;
pii?: {
v: number;
data: Record<string, unknown>;
};
ctx?: Record<string, unknown>;
src?: unknown;
st?: unknown;
}
interface ValidationResult {
valid: boolean;
errors: string[];
warnings: string[];
}
export class WDPValidator {
private sanitizer: PIISanitizer;
constructor() {
this.sanitizer = new PIISanitizer();
}
validate(message: WDPMessage): ValidationResult {
const result: ValidationResult = {
valid: true,
errors: [],
warnings: []
};
// Check f field for PII
if (message.f) {
for (const [key, value] of Object.entries(message.f)) {
if (typeof value === 'string' && this.sanitizer.containsPII(value)) {
result.valid = false;
result.errors.push(
`PII detected in f.${key}. Move to pii.data using {{pii/${key}}} syntax.`
);
}
}
}
// Validate pii structure
if (message.pii) {
if (message.pii.v !== 1) {
result.warnings.push('Unknown PII version. Expected v: 1');
}
if (!message.pii.data || typeof message.pii.data !== 'object') {
result.errors.push('pii.data must be an object');
result.valid = false;
}
}
// Check ctx for PII
if (message.ctx) {
const ctxString = JSON.stringify(message.ctx);
if (this.sanitizer.containsPII(ctxString)) {
result.valid = false;
result.errors.push('PII detected in ctx field. ctx is for technical context only.');
}
}
return result;
}
}B.3 Express Middleware Example
import { Request, Response, NextFunction } from 'express';
import { WDPValidator } from './wdp-validator';
import { PIISanitizer } from './pii-sanitizer';
const validator = new WDPValidator();
const sanitizer = new PIISanitizer({ log_detections: true });
export function wdpSecurityMiddleware(
req: Request,
res: Response,
next: NextFunction
) {
// Intercept JSON responses
const originalJson = res.json.bind(res);
res.json = (body: any) => {
// If response contains WDP diagnostic
if (body && body.h && typeof body.h === 'string') {
const validation = validator.validate(body);
if (!validation.valid) {
console.error('WDP Security Violation:', validation.errors);
// In production, sanitize instead of blocking
if (process.env.NODE_ENV === 'production') {
body = sanitizeWDPMessage(body);
} else {
return res.status(500).json({
error: 'WDP Security Violation',
details: validation.errors
});
}
}
}
return originalJson(body);
};
next();
}
function sanitizeWDPMessage(message: any): any {
const sanitized = { ...message };
// Remove pii.data from response
if (sanitized.pii) {
sanitized.pii = {
v: sanitized.pii.v,
data: '[REDACTED - Access controlled]'
};
}
// Sanitize any remaining PII in f
if (sanitized.f) {
for (const key of Object.keys(sanitized.f)) {
if (typeof sanitized.f[key] === 'string') {
sanitized.f[key] = sanitizer.sanitize(sanitized.f[key]);
}
}
}
return sanitized;
}