Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
SecurityJune 24, 20264 min read

Log Injection Prevention: Securing Node.js and PHP Logs (CWE-117)

Log injection can lead to log forging and XSS. Learn how to sanitize user input in Node.js and PHP to secure your logs against CWE-117 vulnerabilities.

securitynodejsphploggingweb-developmentcwe-117WebBackend

Last month, during a routine audit of our production logs, I noticed a series of "successful" login entries that didn't match our actual authentication timestamps. It turned out an attacker was injecting newline characters into the username field, effectively forging log entries to mask their activity and confuse our monitoring tools.

What is Log Injection?

Log injection (often tracked as CWE-117) occurs when an application includes untrusted data in a log file without proper validation or sanitization. If an attacker can inject control characters—specifically carriage returns (\r) and line feeds (\n)—they can write fake log entries.

If your log aggregator or dashboard renders these logs in a web browser, that injected data can also execute scripts, leading to log-based XSS. It's a subtle but dangerous vector that turns your diagnostic tools into an attack surface.

We Tried Simple Stripping First

My first instinct was to just strip out \n and \r. We wrote a quick regex utility in Node.js to clean every incoming request body before logging.

It worked for a few days, but then we ran into issues with multiline error stack traces. By aggressively stripping all newlines, we destroyed the readability of legitimate error logs. We were flying blind when production started throwing 500s because the stack traces looked like a single, massive, unreadable line.

We needed a more nuanced approach than just "delete everything."

Implementing Secure Logging in Node.js

In Node.js, libraries like winston or pino are industry standards. However, they aren't magic—they don't automatically sanitize user-provided strings. You must handle this before the data hits the logger.

Here is how I recommend handling it:

JAVASCRIPT
// A simple sanitizer for log data
function sanitizeLog(input) {
  if (typeof input !== CE9178">'string') return input;
  // Replace newlines with a safe representation
  return input.replace(/[\r\n]+/g, CE9178">' [newline] ');
}

// Usage
const username = req.body.username;
logger.info(CE9178">`User login attempt: ${sanitizeLog(username)}`);

By replacing the control characters with a literal string like [newline], you preserve the intent of the log entry without allowing the attacker to break the log format.

Handling Logs in PHP

PHP presents a different set of challenges, especially with legacy codebases. If you're using error_log() or a PSR-3 compliant logger like monolog, you should apply a similar transformation layer.

If you're dealing with Insecure Deserialization: How to Secure Object Hydration in Node.js and PHP, you're already aware that untrusted input is never safe. Logging is just another sink for that input.

PHP
#6A9955">// PHP sanitization example
function sanitizeLog($data) {
    return str_replace(["\r", "\n"], ['\\r', '\\n'], $data);
}

$username = $_POST['username'];
error_log("User login attempt: " . sanitizeLog($username));

This approach encodes the characters rather than stripping them entirely. It keeps the log entry on a single line while making it obvious to any human reviewer that the input was tampered with.

Why Log Forgery Matters

Log forging isn't just about confusing developers. If your logs feed into a SIEM (Security Information and Event Management) system, an attacker can inject fake "success" messages or "system maintenance" alerts. This can trigger automated scripts or distract the security team while the attacker performs unauthorized actions elsewhere.

If you don't secure your logs, you’re effectively handing over the keys to your audit trail. When you're managing complex systems, you also need to worry about Preventing Uncontrolled Resource Consumption in Node.js and PHP Apps, but log injection is often overlooked because developers assume logs are "read-only" files.

Best Practices for Secure Logging

  1. Never trust user input: Treat every variable from req.body, $_POST, or headers as potentially malicious.
  2. Use structured logging: If possible, log in JSON format. Most modern log aggregators can parse JSON, which inherently handles newlines within field values without breaking the log structure.
  3. Sanitize at the perimeter: If you have a middleware layer, sanitize the data as soon as it enters your application.
  4. Limit log size: Truncate extremely long input strings to prevent log-based denial-of-service where an attacker floods your disk space.

Frequently Asked Questions

Does JSON logging prevent log injection? Yes, mostly. Because JSON formatters escape control characters (like \n becomes \\n) when serializing an object, the injected characters are treated as literal text rather than structure-breaking newlines.

Should I use a library for this? Yes. If you're using a logging framework, check if it has a built-in "sanitizer" or "masking" plugin. Don't reinvent the wheel if you don't have to.

Is it really XSS if it happens in the log viewer? Yes, it's called "Stored XSS in Log Management." If your log dashboard renders HTML, an attacker can inject <script> tags via the log file. Always ensure your log viewer treats log output as plain text.

I'm still not entirely convinced that sanitizing at the application level is enough. In a perfect world, our log aggregators would be hardened enough to ignore control characters entirely. Until then, I'll keep scrubbing my logs. It’s a small bit of boilerplate that saves a massive headache during an incident response.

Back to Blog

Similar Posts

SecurityJune 24, 20264 min read

Preventing Integer Overflow and Underflow in Node.js and PHP

Learn to prevent integer overflow and underflow in Node.js and PHP. Discover how to handle large numbers securely and avoid silent data corruption today.

Read more
SecurityJune 24, 20264 min read

Preventing Mass Assignment: A Guide to Secure DTO Implementation

Mass assignment vulnerabilities happen when apps blindly map user input to database models. Learn to stop them using explicit DTO allow-lists in your code.

Read more
SecurityJune 23, 20264 min read

Dependency Confusion Attacks: Securing Your Node.js and PHP Supply Chains

Dependency confusion attacks can silently compromise your app. Learn how to secure your Node.js and PHP supply chains using scoped registries and lockfiles.

Read more