logo

Technical information leak - Print Functions - Javascript


Need

Protection of sensitive information by removing or disabling console logging in production environment


Context

  1. Usage of JavaScript for building web applications
  2. Usage of Express.js for handling HTTP requests and responses
  3. Usage of console functions for debugging purposes

Description

Insecure Code Example

const express = require('express');
const app = express();

app.get('/', (req, res) => {
    try {
        // Some code that might throw an error
    } catch (err) {
        console.error(err);  // This is the vulnerability!
    }
});

app.listen(3000, () => {
    console.log('Server running on port 3000');
});

In the provided code snippet, we have an Express.js application that defines a simple route using the `app.get` method. Inside the route handler, a try-catch block is used to handle potential errors. The vulnerability lies in the `catch` block, where we use `console.error(err)`. This method prints the error details, including stack traces, to the console. While useful during development for debugging, this can lead to sensitive information leakage in a production environment. Attackers may deliberately trigger errors to extract information about the application's internal structure, such as file paths, dependencies, and API details. This can help them craft targeted attacks. To fix this vulnerability, it is recommended to use a logging framework like `winston` or `pino` to store error logs securely. Logs should be properly secured, monitored, and should not contain sensitive data.

Steps

  1. Remove or comment out direct console logging (e.g., console.log, console.error) in production code.
  2. Use a structured logging framework such as `winston` or `pino` to securely handle logs.
  3. Ensure that logged error messages do not expose sensitive details.
  4. Store logs securely and restrict access to authorized personnel.
  5. Regularly review logs for security monitoring and anomaly detection.

Secure Code Example

const express = require('express');
const winston = require('winston');

const app = express();
const logger = winston.createLogger({
    level: 'error',
    format: winston.format.json(),
    transports: [
        new winston.transports.File({ filename: 'error.log' })
    ]
});

app.get('/', (req, res) => {
    try {
        // Some code that might throw an error
    } catch (err) {
        logger.error('An error occurred', { error: err.message });
    }
});

app.listen(3000, () => {
    console.log('Server running on port 3000');
});

The original code was vulnerable due to the use of `console.error(err)`, which could potentially expose sensitive information about the application's internals. This is especially risky in a production environment. The revised code mitigates this risk by replacing `console.error(err)` with a structured logging approach using the `winston` library, a widely used logging framework for Node.js applications. A `logger` instance is created with different logging levels, allowing for better control over log messages. Instead of directly logging to the console, errors are logged securely with `logger.error()`. This ensures that sensitive information is not exposed in production logs. By using a logging framework, logs can be directed to secure storage, access-controlled, and monitored for unusual activity, reducing the risk of information leaks.


References

  • 237 - Technical information leak - Print Functions

  • Last updated

    2025/04/02