CWE-209: Generation of Error Message Containing Sensitive Information - Remediation Guide
In short CWE-209 is an application putting sensitive information, such as PII, into its error messages, where it can help attackers with further attacks. Prevent it by omitting sensitive data from error messages, masking parts of it, and encrypting data where it must be included.
Introduction
Section titled “Introduction”CWE-209: Generation of Error Message Containing Sensitive Information occurs when an application exposes sensitive information in its error messages that could be used for further attacks. This kind of information exposure becomes particularly concerning when it involves Personally Identifiable Information (PII). This article explores the risks associated with PII exposure due to CWE-209 and offers detailed remediation strategies, with coding examples in Java, JavaScript, and Python.
Understanding the Risks
Section titled “Understanding the Risks”Direct Risks
Section titled “Direct Risks”-
Spear Phishing: Attackers can use exposed PII from error messages to craft convincing phishing attacks.
-
Credential Stuffing: If error messages reveal details about login mechanisms, attackers might use leaked PII for credential stuffing attacks.
-
Personalized Scams: Exposure of personal details can lead to targeted scams, exploiting the victim’s known preferences or behaviors.
Indirect Risks
Section titled “Indirect Risks”-
Regulatory Non-Compliance: Leakage of PII can result in violations of privacy laws such as GDPR, potentially resulting in fines and sanctions.
-
Loss of Consumer Confidence: Customers are likely to lose trust in a brand that fails to protect their personal data.
-
Legal Consequences: Apart from regulatory fines, companies might face lawsuits from affected parties.
Remediation Techniques
Section titled “Remediation Techniques”Effective remediation involves careful handling of error messages to ensure they do not disclose sensitive information. Key strategies include omitting sensitive data from error messages, masking parts of the data, and encrypting data to add a layer of security.
Omitting Data
Section titled “Omitting Data”public class ErrorHandler { public String sanitizeErrorMessage(Exception e) { return "An error occurred. Please contact support."; // Avoid including any detailed error information or PII }}function sanitizeErrorMessage(error) { return "An error occurred. Please try again later."; // Exclude detailed stack traces or any PII from error messages}def sanitize_error_message(exception): return "An error has occurred. Support has been notified." # Do not return exception details or any PIIMasking Data
Section titled “Masking Data”public class ErrorHandling { public String maskUserID(String userID) { return "User ID: " + userID.replaceAll(".(?=.{4})", "*"); // Masks all but the last four characters of the userID }}function maskUserID(userID) { return 'User ID: ' + userID.replace(/.(?=.{4})/g, '*'); // Replaces all but the last four characters with asterisks}def mask_user_id(user_id): return "User ID: " + '*' * (len(user_id) - 4) + user_id[-4:] # Masks all but the last four characters of the user IDEncrypting Data
Section titled “Encrypting Data”import javax.crypto.Cipher;import javax.crypto.SecretKey;import javax.crypto.spec.GCMParameterSpec;import java.nio.ByteBuffer;import java.nio.charset.StandardCharsets;import java.security.SecureRandom;
public class SecureLogging { // secretKey is supplied by the caller, sourced from your KMS or secret store public String encryptLog(String log, SecretKey secretKey) throws Exception { byte[] iv = new byte[12]; new SecureRandom().nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(128, iv)); byte[] encrypted = cipher.doFinal(log.getBytes(StandardCharsets.UTF_8));
byte[] payload = ByteBuffer.allocate(iv.length + encrypted.length).put(iv).put(encrypted).array(); return java.util.Base64.getEncoder().encodeToString(payload); }}const crypto = require('crypto');
// key: 32-byte Buffer loaded from your KMS or secret storefunction encryptLog(data, key) { const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-cbc', key, iv); const encrypted = Buffer.concat([cipher.update(data, 'utf8'), cipher.final()]); return iv.toString('hex') + ':' + encrypted.toString('hex');}from cryptography.fernet import Fernet
# key: Fernet key loaded from your secret store, never generated per calldef encrypt_log(data, key): cipher_suite = Fernet(key) encrypted = cipher_suite.encrypt(data.encode()) return encrypted.decode()Detecting this with HoundDog.ai
Section titled “Detecting this with HoundDog.ai”HoundDog.ai’s Privacy Code Scanner (hounddog scan) reports CWE-209 when unsanitized sensitive data reaches the
standard output or standard error streams. It identifies sensitive data elements in source code and traces them through
assignments, transformations, string interpolations, and function calls to the sinks they reach.
-
Sensitive data types. The scanner ships with over 100 data element definitions covering common PII, PHI, CHD, PIFI, and secret data (tags
PII,PHI,CHD,PIFI,SECRET); the full list is in the scanner’s data-elements.md. A finding names the data element involved, such as Email or Social Security Number. -
Sinks. CWE-209 is reported on the Standard Output (
stdout) and Standard Error (stderr) data sinks, which cover console output calls such asprint,console.log, andSystem.out. Standard Output findings also carry CWE-1295 (Debug Messages Revealing Unnecessary Information). Data written to application logs is reported separately as CWE-532. -
Languages. Dataflows are reported for Python, JavaScript, TypeScript, Java, C#/.NET, and Go. Other supported languages are scanned for data elements only and produce no dataflows. See Supported Languages.
-
Sanitizers. If the data passes through a recognized sanitizer (masking, hashing, encryption, redaction) before it reaches the sink, the dataflow is treated as safe and is not flagged. Organizations can add their own patterns under Sanitizers.
For example, scanning a Python file that prints a user’s email address produces a finding like this (console output, excerpt; the file path is shortened):
print(f"Failed to process {user.email}")🟨 LOW: Email sent to Standard Output in /path/to/project/app.py:2:5
2 │ print(f"Failed to process {user.email}")
Associated Compliance Frameworks────────────────────────────────CWE: CWE-1295, CWE-209OWASP: A04:2021Privacy: CCPA, GDPR-A5-32, NIST-800-53To run a scan, see the quickstart. For how data elements, data sinks, and sanitizers are defined and customized, see the scanner rules reference.
Conclusion
Section titled “Conclusion”Preventing PII exposure through error messages (CWE-209) is critical for maintaining data security and regulatory compliance. By implementing the above remediation techniques, organizations can significantly reduce the risks associated with sensitive information leaks in error messages.
