@sun-asterisk/sunlint
Version:
☀️ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards
148 lines • 4.32 kB
JSON
{
"rule": {
"id": "S056",
"name": "Protect against Log Injection attacks",
"description": "Protect against Log Injection attacks. Log injection occurs when user-controlled data is written to log files without proper sanitization, potentially allowing attackers to manipulate log entries, inject malicious content, or exploit log processing systems.",
"category": "security",
"severity": "error",
"languages": ["typescript", "javascript"],
"frameworks": ["express", "nestjs", "node"],
"version": "1.0.0",
"status": "stable",
"tags": ["security", "logging", "injection", "owasp", "crlf"],
"references": [
"https://owasp.org/www-community/attacks/Log_Injection",
"https://cwe.mitre.org/data/definitions/117.html",
"https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html",
"https://portswigger.net/kb/issues/00200200_log-injection"
]
},
"configuration": {
"enableLogInjectionDetection": true,
"checkUserInputSources": [
"req",
"request",
"params",
"query",
"body",
"headers",
"cookies",
"session"
],
"vulnerableLogMethods": [
"log",
"info",
"warn",
"error",
"debug",
"trace",
"write",
"writeSync"
],
"vulnerableLogLibraries": [
"winston",
"bunyan",
"pino",
"log4js",
"console",
"morgan",
"debug"
],
"dangerousCharacters": [
"\\r",
"\\n",
"\\r\\n",
"\\u000a",
"\\u000d",
"%0a",
"%0d",
"\\x0a",
"\\x0d"
],
"secureLogPatterns": [
"sanitize",
"escape",
"clean",
"filter",
"validate",
"replace",
"strip"
]
},
"examples": {
"violations": [
{
"description": "Direct user input in log message",
"code": "logger.info('User login: ' + req.body.username);"
},
{
"description": "Template literal with user input",
"code": "console.log(`User ${req.query.user} attempted login`);"
},
{
"description": "User input containing CRLF in log",
"code": "winston.error('Authentication failed for: ' + req.headers['user-agent']);"
},
{
"description": "Session data in log message",
"code": "logger.debug('Session: ' + JSON.stringify(req.session));"
}
],
"fixes": [
{
"description": "Sanitize user input before logging",
"code": "const sanitizedUser = sanitize(req.body.username);\nlogger.info('User login: ' + sanitizedUser);"
},
{
"description": "Use structured logging with safe values",
"code": "logger.info('User login', { username: sanitize(req.body.username) });"
},
{
"description": "Filter dangerous characters",
"code": "const cleanInput = req.query.user.replace(/[\\r\\n]/g, '_');\nconsole.log(`User ${cleanInput} attempted login`);"
},
{
"description": "Validate input before logging",
"code": "if (validateInput(req.headers['user-agent'])) {\n winston.error('Authentication failed for: ' + req.headers['user-agent']);\n}"
}
]
},
"testing": {
"testCases": [
{
"name": "log_injection_direct_input",
"type": "violation",
"description": "Direct user input in log message"
},
{
"name": "log_injection_template_literal",
"type": "violation",
"description": "Template literal with user input"
},
{
"name": "log_injection_crlf",
"type": "violation",
"description": "User input containing CRLF characters"
},
{
"name": "log_injection_json_stringify",
"type": "violation",
"description": "JSON.stringify with user input"
},
{
"name": "secure_log_sanitized",
"type": "clean",
"description": "Sanitized user input in log"
},
{
"name": "secure_log_structured",
"type": "clean",
"description": "Structured logging with safe values"
}
]
},
"performance": {
"complexity": "O(n)",
"description": "Linear complexity based on number of function calls and expressions in the source code"
}
}