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:

  1. Information Disclosure - Leaking PII/secrets in error messages
  2. Catalog Tampering - Malicious modification of catalog files
  3. Man-in-the-Middle - Interception of diagnostic data
  4. Log Injection - Malicious data in diagnostic fields
  5. Denial of Service - Resource exhaustion via diagnostics
  6. Privacy Violations - Correlation of user activities

1.4 Security Principles

Defense in Depth
┌─────────────────────────────────────────┐
│ 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

LocationRuleExample Violation
Catalog Message Templates (hardcoded)PROHIBITED: NEVER hardcode PII"User john@example.com failed login"
Catalog DescriptionsPROHIBITED: NEVER include PII"Contact admin@company.com for help"
Catalog HintsPROHIBITED: NEVER include PII"Call +1-555-0100 for support"
Diagnostic CodePROHIBITED: NEVER include PIIE.Auth.JohnDoe.001
Named SequencesPROHIBITED: NEVER include PIITOKEN_JOHN_DOE_EXPIRED
Component NamesPROHIBITED: NEVER include PIIUserJohnDoeAuth
Primary NamesPROHIBITED: NEVER include PIIJohnDoeToken
TagsPROHIBITED: NEVER include PII["user:john@example.com"]
f fieldPROHIBITED: NEVER put PII here{"f": {"email": "john@example.com"}}
ctx fieldPROHIBITED: NEVER put PII here{"ctx": {"user": {"email": "..."}}}
Stack TracesPROHIBITED: NEVER include PIIRemove username from /home/john/...
NamespaceCONDITIONAL: Org names OK"acme-corp" (OK), "john-doe" (BAD)

Where PII MUST Appear (if needed)

LocationRuleSyntax
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)

Catalog
{
  "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"]
  }
}
Runtime (opaque ID only)
{
  "xY9Kp": {
    "f": {
      "user_id": "usr_8d7f9a2b"  // Correct: Opaque identifier (not PII)
    }
  }
}

Example - CORRECT (With PII using pii/ syntax)

Catalog (PII placeholder)
{
  "Ay75d": {
    "code": "E.Auth.Token.001",
    "message": "Token for {{pii/email}} expired at {{timestamp}}",
    "description": "Your session has expired. Please log in again."
  }
}
Runtime (PII in pii.data field)
{
  "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

Incorrect: PII in wrong locations
// ❌ 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)
VectorRiskExample ViolationMitigation
Message TemplateCRITICAL"User {{name}} at {{email}} failed"Use only technical placeholders
Description FieldHIGH"This affects user john@example.com"Generic descriptions only
Hints ArrayMEDIUM["Contact John Doe at ext. 5555"]Generic help only
Tags ArrayMEDIUM["user:alice", "ip:192.168.1.1"]Technical tags only
Docs URLMEDIUM"https://wiki/users/john-doe/auth"Generic documentation URLs
Field NamesLOW"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 TypeRiskSafe Alternative
Email🔴 CRITICALuser_id: "usr_abc123"
Phone🔴 CRITICALcontact_id: "con_xyz789"
Name🔴 CRITICALuser_id: "usr_abc123"
Address🔴 CRITICALlocation_id: "loc_def456"
SSN/Tax ID🔴 CRITICALNever include
Credit Card🔴 CRITICALlast4: "1111"
Password🔴 CRITICALNEVER include
Token🔴 CRITICALNEVER include
IP Address🟡 MEDIUMip_hash: "a1b2c3..."
User Agent🟡 MEDIUMbrowser: "chrome"
Cookie🟡 MEDIUMsession_id: "sess_xyz"
File Path🟡 MEDIUM"config.json" (relative)
Username🟡 MEDIUMuser_id: "usr_abc123"
Device ID🟡 MEDIUMdevice_id: "dev_abc123"

2.2.3 Stack Trace Vectors

Stack traces can inadvertently expose PII:

VectorRiskExampleMitigation
File PathsMEDIUM/home/john/app/config.jsStrip username: /app/config.js
Usernames in PathsMEDIUMC:\Users\JohnDoe\Documents\Strip: \Documents\
Environment VariablesHIGHUSER_EMAIL=john@example.comSanitize env vars
Query StringsCRITICAL?email=john@example.comStrip params
Database ValuesCRITICALWHERE email='john@...'Never log queries

2.2.4 Context Field Vectors

The ctx field is for DEBUGGING context, NOT user data:

WRONG - User data in ctx
{
  "ctx": {
    "user": {
      "email": "john@example.com",
      "name": "John Doe"
    }
  }
}
CORRECT - Technical context only
{
  "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:

Json
{
  "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.

CategoryExamplesRisk Level
Direct IdentifiersFull name, SSN, passport numberCRITICAL
Contact InformationEmail, phone, physical addressHIGH
Financial DataCredit card, bank account, tax IDCRITICAL
Government IDsDriver's license, national IDCRITICAL
Biometric DataFingerprints, facial recognitionCRITICAL
Health InformationMedical records, diagnosesCRITICAL (HIPAA)
Online IdentifiersIP address, device ID, cookie IDMEDIUM
AuthenticationPasswords, tokens, API keysCRITICAL

2.5 PII Detection Patterns

Typescript
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 TypeIn Catalog?In Runtime Fields?Best Practice
User email❌ NEVER⚠️ Avoiduser_id: "usr_abc123"
Password❌ NEVER❌ NEVERNEVER INCLUDE
Token/API key❌ NEVER❌ NEVERNEVER INCLUDE
IP address❌ NEVER⚠️ Hash onlyip_hash: "a1b2c3..."
User ID (opaque)✅ Placeholder✅ YES{{user_id}} → usr_abc123
Timestamp✅ Placeholder✅ YES{{timestamp}} → 2024-01-15T...
Error type✅ YES✅ YESvalidation_failed

Golden Rule:

If you're not sure whether something is PII → DON'T INCLUDE IT
Use opaque identifiers instead

2.10 PII Audit Checklist

Use this checklist when reviewing WDP implementations for PII compliance. All items marked CRITICAL must pass before deployment.

Audit ItemLocationCheckSeverity
Catalog message templatesCatalogNo hardcoded PII in message strings🔴 CRITICAL
Catalog description fieldsCatalogNo PII in description or hints🔴 CRITICAL
Field placeholdersCatalogPII uses {{pii/field}} syntax🔴 CRITICAL
Runtime f fieldRuntimeNo PII in f object🔴 CRITICAL
Runtime pii.data fieldRuntimeAll PII in pii.data object🟢 REQUIRED
Stack tracesRuntime/LogsFile paths are relative, no user data in args🟡 HIGH
Context field (ctx)RuntimeOnly technical metadata, no user data🟡 HIGH
Source field (src)RuntimeNo PII in source locations🟡 HIGH
Log outputLogspii.data excluded or redacted in logs🔴 CRITICAL
Error responsesAPIPII not exposed in API responses🔴 CRITICAL
Metrics/telemetryObservabilityNo high-cardinality PII in metrics🟡 HIGH
Cache keysCacheNo PII in cache key names🟡 HIGH

Automated Audit Commands

CI/CD Pipeline Checks
# 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 --verbose

2.11 PII Quick Reference Summary

Quick reference for the 10 essential PII rules. Print this and keep it visible during development.

Rule #RuleViolation ExampleCorrect Example
R1No PII in catalogs"Hello john@example.com""Hello {{pii/email}}"
R2PII uses pii/ prefix{{email}}{{pii/email}}
R3Runtime PII in pii.dataf: { email: "..." }pii: { data: { email: "..." } }
R4Never include passwordspassword: "secret"(omit entirely)
R5Never include tokenstoken: "eyJ..."(omit entirely)
R6Hash IP addressesip: "192.168.1.1"ip_hash: "a1b2c3..."
R7Use opaque identifiersuser: "John Doe"user_id: "usr_abc123"
R8Relative file paths only"/home/john/app/...""./src/config.json"
R9No PII in ctx fieldctx: { user_email: "..." }ctx: { request_id: "..." }
R10Redact PII in logslog(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 out

3. Sensitive Data in Diagnostics

3.1 Types of Sensitive Data

Data TypeExamplesProtection
CredentialsPasswords, API keysNEVER include
TokensJWT, OAuth tokensNEVER include
SecretsEncryption keys, certificatesNEVER include
Session DataSession IDs, cookiesUse opaque IDs
Business LogicPricing, algorithmsLimit exposure
System InfoInternal paths, versionsSanitize for production

3.2 Authentication Errors

Incorrect - Exposes token content
{
  "E.Auth.Token.001": {
    "message": "Invalid token: {{token}}",
    "fields": ["token"]
  }
}

// Runtime:
{
  "xY9Kp": {
    "f": {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
    }
  }
}
Correct - Generic error
{
  "E.Auth.Token.001": {
    "message": "Token validation failed",
    "fields": []
  }
}

// Runtime:
{
  "xY9Kp": {}
}
Acceptable - Metadata only
{
  "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

Incorrect - Exposes schema
{
  "message": "Query failed: SELECT * FROM users WHERE email='{{email}}'"
}
Correct - Generic error
{
  "message": "Database query failed",
  "fields": []
}

3.4 File System Errors

Incorrect - Exposes internal paths
{
  "message": "File not found: /home/admin/.ssh/id_rsa"
}
Correct - Sanitized paths
{
  "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

Json
{
  "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

Typescript
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

Typescript
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

Typescript
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:

Html
<script 
  src="https://cdn.example.com/wdp/catalog-v1.0.0.json"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"
></script>

5.2 Catalog Signing

Json
{
  "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..."
  }
}
Verification
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

Typescript
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:

Typescript
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, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

6. Transport Security

6.1 HTTPS Requirements

MUST use HTTPS for:

  • Catalog distribution
  • Diagnostic API responses
  • Any transmission containing diagnostics
Typescript
// 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

Nginx
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

6.3 Rate Limiting

Typescript
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

Typescript
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

Typescript
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

Typescript
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

Typescript
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

Typescript
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

Typescript
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:

Json
{
  "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 PatternUse CaseExample
C.Security.Auth.*Authentication failuresBrute force, credential stuffing
C.Security.Access.*Authorization failuresPrivilege escalation attempts
C.Security.Injection.*Injection attacksSQL injection, XSS attempts
C.Security.Integrity.*Data tamperingChecksum failures, replay attacks
W.Security.Config.*Configuration issuesWeak passwords, missing encryption

9.3 Incident Response Integration

Typescript
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

WDP Configuration
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

Unit Tests
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);
  });
});
Integration Tests
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

Typescript
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

Email Detection
// 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.org

A.2 Phone Numbers

Phone Number Detection
// 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)

SSN Detection
// 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 numbers

A.4 Credit Card Numbers

Credit Card Detection
// 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

IP Address Detection
// 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 PII

A.6 Tokens and Secrets

Token Detection
// 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

pii-sanitizer.ts
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

wdp-validator.ts
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

wdp-security-middleware.ts
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;
}

End of Part 11: Security Considerations

Copyright © 2025 Ashutosh Mahala. This specification is licensed under CC BY 4.0.

View on GitLab