DocumentWDP-11
TitleSecurity Considerations
Version0.1.0-draft
Last Updated2025-12-25
StatusDraft
CategoryStandards Track (Extended)
Created2025-12-01

WDP Part 11: Security Considerations

Requirements and best practices for handling sensitive data, PII, and security-critical information.

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 covered in this document:

  • PII detection and sanitization
  • Sensitive field handling
  • Secure catalog distribution
  • Access control for diagnostic data
  • Security incident diagnostics

Specification Navigation: See STRUCTURE for an overview of all WDP specification parts.

Conformance#

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

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: Including only necessary information
  • Secure Distribution: Protecting catalog integrity
  • Compliance: Meeting GDPR, CCPA, and 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 the following threat vectors:

  1. Information Disclosure: Leaking PII or 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 (Do not 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: Organization names OK"acme-corp" (OK), "john-doe" (BAD)

Where PII MUST appear (if needed):

LocationRuleSyntax
pii.data fieldREQUIRED: ONLY place for PII{"pii": {"v": 1, "data": {"email": "..."}}}
Message template placeholdersREQUIRED: 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):

Json
// 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, no PII):
{
  "xY9Kp": {
    "f": {
      "user_id": "usr_8d7f9a2b"  // Correct: Opaque identifier (not PII)
    }
  }
}

Example - CORRECT (With PII using pii/ syntax):

Json
// 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:

Json
// Incorrect: Catalog with hardcoded PII (NEVER DO THIS):
{
  "xY9Kp": {
    "code": "E.Auth.Login.001",
    "message": "Invalid credentials for user john.doe@example.com",  // Violation: Hardcoded PII
    "description": "Contact support at +1-555-0100",  // Violation: Phone number
    "hints": ["Email admin@company.com for password reset"]  // Violation: Email
  }
}

// Incorrect: Runtime with PII in wrong field:
{
  "xY9Kp": {
    "f": {
      "email": "john.doe@example.com",  // Violation: PII in f field (should be in pii.data)
      "password": "secret123"  // CRITICAL VIOLATION: NEVER include passwords anywhere!
    }
  }
}

// Incorrect: Using wrong placeholder syntax:
{
  "message": "Login failed for {{email}}",  // Violation: Should be {{pii/email}}
  "f": {"email": "john@example.com"}  // Violation: And shouldn't be in f at all
}

// Incorrect: PII in ctx field:
{
  "ctx": {
    "v": 1,
    "user": {
      "email": "john@example.com"  // Violation: PII in ctx (should be in pii.data)
    }
  }
}

2.2 Comprehensive PII Leak Vector Analysis#

The following sections enumerate all possible locations where PII could leak in WDP.

2.2.1 Catalog-Level Vectors (Static Content)

Catalog-level vectors are especially dangerous because catalogs are cached and distributed:

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.internal/users/john-doe/auth"Generic documentation URLs
Field NamesLOW"john_doe_email"Use generic names: email, user_id
NamespaceLOW"john-doe-project"OK for organization names
Generated TimestampSAFE"2024-01-15T10:30:00Z"Not PII

Code Examples:

Json
// Incorrect: PII in catalog
{
  "diags": {
    "xY9Kp": {
      "code": "E.Auth.Login.001",
      "message": "Login failed for john.doe@example.com",  // Violation: Hardcoded email
      "description": "User John Doe from IP 192.168.1.100 failed authentication",  // Violation: Name + IP
      "hints": [
        "Contact John at +1-555-0100",  // Violation: Name + phone
        "Your session ID is abc123xyz"  // Violation: Session data
      ],
      "tags": ["user:john-doe", "email:john@example.com"],  // Violation: PII in tags
      "docs_url": "https://docs.example.com/users/john-doe/auth"  // Violation: Username in URL
    }
  }
}

// Correct: No PII in catalog
{
  "diags": {
    "xY9Kp": {
      "code": "E.Auth.Login.001",
      "message": "Authentication failed for user {{user_id}}",  // Correct: Placeholder
      "description": "Login attempt failed due to invalid credentials",  // Correct: Generic
      "hints": [
        "Verify your password is correct",  // Correct: Generic help
        "Check if your account is locked"  // Correct: No personal info
      ],
      "tags": ["auth", "login", "security"],  // Correct: Technical tags
      "docs_url": "https://docs.example.com/auth/troubleshooting"  // Correct: Generic URL
    }
  }
}

2.2.2 Runtime Field Vectors (Dynamic Content)

Field values are interpolated at runtime. This is where PII is most likely to appear:

Field TypeRiskExampleSafe Alternative
EmailCRITICAL"email": "john@example.com""user_id": "usr_abc123"
PhoneCRITICAL"phone": "+1-555-0100""contact_id": "con_xyz789"
NameCRITICAL"name": "John Doe""user_id": "usr_abc123"
AddressCRITICAL"address": "123 Main St""location_id": "loc_def456"
SSN/Tax IDCRITICAL"ssn": "123-45-6789"Never include
Credit CardCRITICAL"card": "4111-1111-1111-1111""last4": "1111"
PasswordCRITICAL"password": "secret123"NEVER include
TokenCRITICAL"token": "eyJhbGc..."NEVER include
IP AddressMEDIUM"ip": "192.168.1.100""ip_hash": "a1b2c3..."
User AgentMEDIUM"ua": "Mozilla/5.0...""browser": "chrome"
CookieMEDIUM"cookie": "session=abc...""session_id": "sess_xyz"
File PathMEDIUM"/home/john/.ssh/key""config.json" (relative)
UsernameMEDIUM"username": "johndoe""user_id": "usr_abc123"
Device IDMEDIUM"device": "iPhone-John""device_id": "dev_abc123"

2.2.3 Code Structure Vectors

PII MAY be inadvertently encoded in the diagnostic code itself:

Typescript
// Incorrect: PII in code components
"E.Auth.JohnDoe.001"           // Username in Component
"E.JohnDoeService.Token.001"   // Username in Component
"E.Auth.JohnDoeToken.001"      // Username in Primary
"E.Auth.Token.JOHN_DOE_001"    // Username in Sequence

// Correct: Generic code components
"E.Auth.User.001"              // Generic Component
"E.UserService.Token.001"      // Generic Component
"E.Auth.Token.001"             // Generic Primary
"E.Auth.Token.EXPIRED"         // Generic Sequence name

2.2.4 Stack Trace and Error Context Vectors

System-generated error information can leak PII:

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

Example - Sanitizing Stack Traces:

Typescript
function sanitizeStackTrace(stack: string): string {
  return stack
    .replace(/\/home\/[^\/]+\//g, '/home/USER/')  // Remove username
    .replace(/C:\\Users\\[^\\]+\\/g, 'C:\\Users\\USER\\')  // Windows
    .replace(/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g, '[EMAIL]')  // Emails
    .replace(/\b\d{3}-\d{2}-\d{4}\b/g, '[SSN]')  // SSN
    .slice(0, 2000);  // Limit length
}

2.2.5 Logging and Monitoring Vectors#

Logs and monitoring systems can accumulate PII:

| Vector          | Risk | Example | Mitigation |
|-----------------|------|---------|------------|
| Log Messages    | HIGH | logger.info('User john@example.com logged in') | Use user_id |
| Structured Logs | HIGH | {user: {email: "..."}} | Sanitize before logging |
| Metrics Tags    | MEDIUM | user:john-doe | Use hashed IDs |
| Trace IDs       | SAFE | trace_abc123 | Safe if opaque |

2.2.6 API Response Vectors#

Responses can leak PII in multiple locations:

Incorrect: PII in various response fields
{
  "success": false,
  "error": "Authentication failed for john.doe@example.com",  // Violation: Message
  "user": {
    "email": "john.doe@example.com",  // Violation: Application data
    "phone": "+1-555-0100"  // Violation: Application data
  },
  "wd": {
    "xY9Kp": {
      "f": {
        "email": "john.doe@example.com",  // Violation: Diagnostic field
        "ip_address": "192.168.1.100",  // Violation: Diagnostic field
        "session_token": "abc123xyz"  // Violation: Diagnostic field
      }
    }
  }
}

2.3 PII Field Structure#

The pii field is an OPTIONAL object at the same level as f, st, src, and ctx.

Wire Format:

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"
    }
  }
}

2.4 PII Definition#

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
DemographicsAge, gender, ethnicity, locationMEDIUM
AuthenticationPasswords, tokens, API keysCRITICAL

2.5 PII In WDP Context#

Diagnostics MUST NOT include PII directly. Use generic identifiers instead.

2.6 PII Sanitization Rules#

Rule 1: Use Opaque IDs Instead of PII

Typescript
// Incorrect:
const diagnostic = {
  compactId: "aG8eT",
  fields: {
    email: "alice@example.com",
    name: "Alice Johnson"
  }
};

// Correct:
const diagnostic = {
  compactId: "aG8eT",
  fields: {
    user_id: "usr_9k3m2n1p",
    field: "email"
  }
};

2.7 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.8 Catalog Metadata for PII Warnings#

Catalog entries SHOULD indicate whether a diagnostic uses PII placeholders:

Json
{
  "Ay75d": {
    "code": "E.AUTH.TOKEN.001",
    "message": "Token for {{pii/email}} expired at {{timestamp}}",
    "description": "Your session has expired.",
    "contains_pii": true,
    "pii_fields": ["email"],
    "requires_pii_access": true
  }
}

2.10 PII Audit Checklist#

Use this checklist when creating or reviewing diagnostics:

Catalog Files (Static Content)
[ ] No hardcoded PII in messages
[ ] PII uses {{pii/field}} placeholder syntax
[ ] Regular fields use {{field}} syntax
[ ] contains_pii: true metadata present when using {{pii/...}}

Diagnostic Codes (Structure)
[ ] Component name does not contain PII
[ ] Primary name does not contain PII
[ ] Sequence does not contain PII

Runtime Fields (Wire Format)
[ ] PII data is in pii.data field ONLY
[ ] Non-PII data is in f field
[ ] No PII in ctx field
[ ] No PII in st (stack trace) field

2.11 PII Quick Reference Summary#

Data TypeIn Catalog?In Runtime Fields?Best Practice
User emailPROHIBITEDCONDITIONAL: Avoid (use user_id)user_id: "usr_abc123"
User namePROHIBITEDCONDITIONAL: Avoid (use user_id)user_id: "usr_abc123"
Phone numberPROHIBITEDPROHIBITEDUse contact ID instead
IP addressPROHIBITEDCONDITIONAL: Hash onlyip_hash: "a1b2c3..."
PasswordPROHIBITEDPROHIBITEDNEVER INCLUDE
Token/API keyPROHIBITEDPROHIBITEDNEVER INCLUDE
Credit cardPROHIBITEDCONDITIONAL: Last 4 onlylast4: "1111"
SSN/Tax IDPROHIBITEDPROHIBITEDNEVER INCLUDE
Session IDPROHIBITEDCONDITIONAL: Opaque onlysession_id: "sess_xyz"
User ID (opaque)ALLOWED: PlaceholderALLOWED{{user_id}} -> usr_abc123
Order IDALLOWED: PlaceholderALLOWED{{order_id}} -> ord_xyz789
TimestampALLOWED: PlaceholderALLOWED{{timestamp}} -> 2024-01-15T...
Error typeALLOWEDALLOWEDvalidation_failed
Field nameALLOWEDALLOWED"field": "email" (not the value)
File pathPROHIBITED: Full pathCONDITIONAL: Relative onlyconfig.json not /home/user/...
Stack tracePROHIBITEDCONDITIONAL: Sanitized onlyRemove usernames from paths

3. Sensitive Data in Diagnostics#

3.1 Types of Sensitive Data#

Beyond PII, the following categories of sensitive data require protection:

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}}' AND password_hash='{{hash}}'"
}
Correct (generic error)
{
  "message": "Database query failed",
  "fields": []
}
Acceptable (metadata only)
{
  "message": "Database query failed on table {{table}}",
  "fields": ["table"]
}

// Runtime:
{
  "f": {
    "table": "users" // Table name OK, no data
  }
}

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#

Sensitive fields SHOULD be marked in the catalog:

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#

To prevent exfiltration via oversized fields, implementations SHOULD enforce 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');
  }
  
  // Additional validation...
}

4.4 Field Injection Prevention#

To prevent log injection attacks, implementations MUST sanitize field values:

Typescript
function sanitizeForLogs(value: string): string {
  return value
    // Remove control characters, but keep \t, \n, \r for now
    .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#

Implementations SHOULD 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>

SRI Hash Generation:

Bash
openssl dgst -sha384 -binary catalog.json | openssl base64 -A

5.2 Catalog Signing#

Catalog files SHOULD be signed for authenticity:

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:

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

Implementations SHOULD restrict access to sensitive catalogs:

Http
GET /api/wdp/catalog-internal.json HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Server-side validation example:

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#

Implementations MUST prevent XSS vulnerabilities in catalog messages:

Json
{
  "diags": {
    "xY9Kp": {
      "code": "E.Input.Validation.001",
      "message": "Invalid value: {{value}}",
      "fields": ["value"]
    }
  }
}

Client-side escaping example:

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#

Implementations 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#

Implementations SHOULD enforce minimum TLS version requirements:

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

6.3 Certificate Pinning#

For mobile and desktop applications, implementations MAY use certificate pinning:

Typescript
const trustedCertificates = [
  '-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----'
];

async function fetchCatalogSecure(url: string): Promise<Catalog> {
  const response = await fetch(url, {
    // Verify certificate
    agent: new https.Agent({
      ca: trustedCertificates
    })
  });
  
  return response.json();
}

6.4 Rate Limiting#

To prevent denial-of-service attacks via diagnostic flooding, implementations SHOULD implement 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#

Implementations MUST sanitize diagnostic data before logging:

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#

Implementations SHOULD implement retention policies:

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 Encrypted Storage#

Implementations SHOULD encrypt diagnostic logs at rest:

Typescript
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';

class EncryptedLogStorage {
  private algorithm = 'aes-256-gcm';
  private key: Buffer;
  
  constructor(encryptionKey: string) {
    this.key = Buffer.from(encryptionKey, 'hex');
  }
  
  encrypt(data: string): { encrypted: string; iv: string; tag: string } {
    const iv = randomBytes(16);
    const cipher = createCipheriv(this.algorithm, this.key, iv);
    
    let encrypted = cipher.update(data, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    
    const tag = cipher.getAuthTag();
    
    return {
      encrypted,
      iv: iv.toString('hex'),
      tag: tag.toString('hex')
    };
  }
}

7.4 Audit Logging#

Implementations SHOULD log security-relevant diagnostics:

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#

Implementations SHOULD define visibility levels for diagnostic content:

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#

Implementations SHOULD provide different detail levels for different contexts:

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#

Implementations SHOULD use Critical (C) severity 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#

The following table defines common security diagnostic code patterns:

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. Compliance Considerations#

WDP provides mechanisms for separating, redacting, and controlling access to sensitive data (see PII handling in Sections 3-6). 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#

Framework configuration example:

Typescript
// 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
    }
  }
}

12. Security Checklist#

Use this final checklist before deploying WDP-based systems:

[ ] PII Separation: All PII is in pii.data or redacted
[ ] Sanitization: Logs are free of secrets and PII
[ ] Access Control: Diagnostic API enforces roles
[ ] Transport: HTTPS enforced for all traffic
[ ] Integrity: Catalogs use SRI and signing
[ ] Validation: Input fields sanitized securely
[ ] Compliance: Legal team reviewed data handling
[ ] Audit: Security events are logged to audit trail