← All Articles 📝 Code Patterns Medium By Nishant Kumar Verma Updated

console.log() in Production: How Debug Statements Leak User Data and Secrets

AI-generated code is full of console.log statements that leak user data, tokens, and database queries in production. Here is how to find and remove them.

CFG-006 WEB-001

Quick Answer

AI-generated code is full of console.log() statements that dump user credentials, API responses, session tokens, and personal data to the browser console and server logs. In production, these debug statements become security vulnerabilities - anyone with browser DevTools can see sensitive data, and server logs often end up in third-party monitoring services without proper redaction.

How Debug Statements Become Data Leaks

When you prompt an AI tool to build a login form, it adds console.log() for debugging. When you ask for Stripe integration, it logs the full webhook payload. When you build an API, it logs every request body. These statements are invisible to the UI, but they create persistent data exposure in two places: the browser console (client-side) and server/container logs (server-side).

GitGuardian's State of Secrets Sprawl 2023 found 10 million new secrets exposed on GitHub in 2022 alone. Security logging and alerting failures are A09 in the OWASP Top 10 (2025), but excessive logging of sensitive data is equally dangerous.

What AI-Generated Code Logs

// ❌ BAD - Typical AI-generated auth handler
app.post('/api/login', async (req, res) => {
  console.log('Login request:', req.body);
  // Logs: { email: "user@email.com", password: "MyP@ssw0rd!" }

  const user = await db.users.findByEmail(req.body.email);
  console.log('Found user:', user);
  // Logs: { id: 1, email: "...", passwordHash: "...", ssn: "..." }

  const token = generateToken(user);
  console.log('Generated token:', token);
  // Logs: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

  res.json({ token });
});
// ✅ GOOD - Structured logging without sensitive data
import pino from 'pino';
import bcrypt from 'bcrypt';
const logger = pino({ level: process.env.LOG_LEVEL || 'info' });

app.post('/api/login', async (req, res) => {
  logger.info({ email: req.body.email }, 'Login attempt');
  // Logs: { email: "user@email.com", msg: "Login attempt" }
  // Never logs password, token, or full user object

  const user = await db.users.findByEmail(req.body.email);
  const valid = user && await bcrypt.compare(req.body.password, user.passwordHash);
  if (!valid) {
    logger.warn({ email: req.body.email }, 'Login failed');
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  const token = generateToken(user);
  logger.info({ userId: user.id }, 'Login successful');
  // Only logs a non-sensitive identifier

  res.json({ token });
});

The Three Places Your Logs Leak

Location Who Can See It Risk
Browser console Any user with DevTools (F12) Exposes tokens, API keys, user data in the client
Server stdout/stderr Anyone with server access Passwords, full request bodies in container logs
Log aggregation services Third-party vendor (Datadog, LogRocket, Sentry) Sensitive data stored in external systems you do not control

Sensitive Data Types Found in Logs

Data Type Typical AI Log Statement GDPR / PCI Impact
Passwords console.log('body:', req.body) Direct credential exposure
JWT tokens console.log('token:', token) Session hijacking vector
Credit card numbers console.log('payment:', payload) PCI-DSS violation
Email / phone / SSN console.log('user:', userData) Risks breaching GDPR Article 5 (data minimisation)
API keys / secrets console.log('config:', config) Full system compromise

How to Remove and Prevent Log Leaks

  1. Search your entire codebase for console.log, console.debug, console.warn, and console.error. Remove any that log request bodies, user objects, tokens, or API responses.
  2. Use a structured logger like Pino or Winston. Structured loggers make it easy to control what fields are included and support log-level filtering per environment.
  3. Add an ESLint rule: "no-console": "error" to catch new console.log statements at build time.
  4. Configure log levels: Use debug level for development and info or warn for production. Never deploy with debug-level logging enabled.
  5. Redact sensitive fields in your logger configuration. Pino supports redact: ['req.headers.authorization', 'req.body.password'].
  6. Scan automatically. VibeDoctor's Vibe Check flags every console.log and console.debug call in JavaScript and TypeScript code outside tests, scripts, docs and examples, with the file and line. In Python web apps it flags files with more than five print() calls and no logging library (CFG-006). It flags the call, not what it logs, so the redaction steps above still matter. Free to sign up.

ESLint Configuration to Block console.log

ESLint 10 only reads the flat config file, eslint.config.js. The old .eslintrc.json format is no longer supported.

// eslint.config.js
export default [
  {
    rules: {
      'no-console': ['error', { allow: ['warn', 'error'] }],
    },
  },
];

// For files where you need console.log (dev scripts, CLIs):
// eslint-disable-next-line no-console
console.log('This is intentional');

FAQ

Is console.log() a real security vulnerability?

Yes. Logging sensitive data (passwords, tokens, PII) to the browser console or server logs is classified as CWE-532 (Insertion of Sensitive Information into Log File). It can lead to credential theft, session hijacking, and regulatory violations (GDPR, PCI-DSS, HIPAA). It is not theoretical - it is a documented, exploitable vulnerability class.

Can I just strip console.log in production builds?

Build tools like Terser can remove console.log from client-side bundles, but this does not help with server-side code (Node.js, Express, Fastify). Server-side console.log still writes to container logs. You need a proper logging library with redaction and level filtering for full coverage.

What should I log instead?

Log events, not data. Log "Login attempt for user 42" instead of "Login with body: {email, password}". Log "Payment processed, order 123" instead of "Stripe payload: {card_number, ...}". Log identifiers and outcomes, never raw input or credentials.

How many console.log statements are too many?

In production code, the answer is generally zero. Every console.log in production should be replaced with a structured logger call at an appropriate log level. Development-only debug logging should be removed or gated behind a debug flag before deployment.

Diagnose your codebase - free

VibeDoctor checks for CFG-006, WEB-001 and 148 other issues across 21 diagnostic areas - security, performance, code quality, and more.

SCAN MY APP →