CWE-359: Exposure of Private Personal Information to an Unauthorized Actor
Overview
Applications expose personal data - names, SSNs, medical data, financial details - through logs, error messages, APIs, URLs, or insufficient access controls. The result is identity theft and fraud for the people affected, and regulatory liability under GDPR, CCPA and HIPAA for the organization.
Relationship to Other CWEs
CWE-359 is the personal-data case of the broader CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor). Use this page when the exposed data identifies a person - names, SSNs, health records, financial details - and regulatory exposure under GDPR, CCPA or HIPAA is the main concern. Use CWE-200 for sensitive data that isn't personal: API keys, internal paths, stack traces.
OWASP Classification
A01:2025 - Broken Access Control
Risk
High: Exposed PII enables identity theft, financial fraud, discrimination and stalking against the people it identifies.
Regulatory exposure depends on which tier the failure falls into. GDPR Article 83(5) allows fines of up to EUR 20 000 000, or up to 4% of total worldwide annual turnover, whichever is higher - but a security-of-processing failure under Article 32, which cleartext or over-exposed PII usually is, sits in the lower Article 83(4) tier of up to EUR 10 000 000 or 2%. HIPAA civil penalties are assessed per violation, not per record, and the figures are inflation-adjusted: as of 2025, $73,011 is the per-violation maximum for tiers 1 to 3 and the per-violation minimum for tier 4, whose range runs up to the $2,190,294 annual cap per identical provision.
Remediation Steps
Core Principle: Minimize and control access to personal data; enforce authorization and least disclosure for PII everywhere.
Locate the PII exposure
- Start from the finding: which file, line and code pattern expose the PII
- Identify what is exposed: names, SSNs, medical data, financial details, addresses, phone numbers, email addresses
- Identify the channel: logs, error messages, APIs, URLs, database queries, analytics, UI display
- Trace the value from the point of collection to the point of exposure
Minimize PII collection and retention (Primary Defense)
- Collect only what you need. Question every PII field in a form
- Delete PII once it is no longer needed. Set a retention period (90 days, one year) and enforce it with a scheduled purge job
- Aggregate or generalize before sending anything to analytics. Hashing an identifier is pseudonymization, not anonymization: a hashed email address, phone number or SSN is recoverable by brute force, and remains personal data under GDPR. An SSN is a 10^9 keyspace, enumerable in seconds. If an analytics tool such as Google Analytics or Mixpanel needs a per-user key, use a random, per-service, rotatable surrogate ID that is never derived from the PII
Implement proper access controls
- Use role-based access control: only users holding a "view_pii" role can read PII fields
- Check the caller's permissions before returning PII in an API response
- Require step-up authentication for bulk or sensitive PII access: re-prompt for credentials or a second factor before a bulk export or a full-record view, so a hijacked session alone isn't enough
- Audit PII access: log who accessed which PII and when, for GDPR and HIPAA compliance
Protect PII in transit and at rest
- Encrypt PII columns at the application level (AES-256). Database-level encryption protects the stored files from a stolen disk but decrypts for any authorized connection, so it complements application-level encryption rather than replacing it. A logical export (
mysqldump,pg_dump,bcp) of a TDE-protected database contains plaintext PII, because it leaves through the SQL layer that TDE decrypts for - Serve every page and API endpoint that handles PII over HTTPS
- Redact PII in logs (XXX-XX-1234) or omit it entirely; never log SSNs, card numbers or passwords
- Tokenize card numbers and SSNs: store an opaque reference (
tok_9f3a1c7e2b4d) instead of the value. The token must carry no derivable relationship to the value it replaces - not the card number, not a hash of it, not the last four digits embedded in the string - or it is just the original data in a different encoding
Avoid PII leakage
- Never log PII, even at debug level
- Keep PII out of URLs: send it in a POST body, not a GET query string (/user?ssn=123-45-6789)
- Keep PII out of error messages and stack traces
- Keep PII out of analytics: send aggregated values or a random surrogate ID, never a hash of the PII, for the reason given above
- Mask PII in the UI: XXX-XX-1234 instead of a full SSN, * **** 4242 for a card number
Test the PII protection fix
- Verify PII is not logged (search logs for SSN patterns, credit card patterns)
- Verify PII is not in URLs (check URL parameters, browser history)
- Test API responses filter PII based on user permissions
- Verify PII is encrypted in the database (inspect the stored rows and see ciphertext, not plaintext)
- Test masking in UI (verify only last 4 digits shown)
- Re-scan with the security scanner to confirm the finding is resolved
Common Vulnerable Patterns
- SSN/credit cards in logs
- PII in URL parameters
- Returning all user data without filtering
- PII in error messages/stack traces
- Unencrypted PII in databases
Additional Resources
- CWE-359: Exposure of Private Personal Information to an Unauthorized Actor
- HHS Annual Civil Monetary Penalties Inflation Adjustment - the rule that sets the $73,011 per-violation and $2,190,294 annual figures quoted above; HHS re-adjusts them for inflation each year, so confirm the current amounts before relying on them
- OWASP Cheat Sheet Series
- OWASP Top 10 2025
- OWASP Top 10 2025 A01: Broken Access Control
- Regulation (EU) 2016/679 (GDPR), full text on EUR-Lex - Article 83(4) and 83(5) are the two administrative-fine tiers quoted above