Skip to content

VNX-117: Improper Output Neutralization for Logs

Decoded HTTP request data written into a Java, Python or Node log message without CR/LF neutralisation, inline or through a variable assigned from the request.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-117
Severity High
SARIF level error
Kind sast
Languages Java, JavaScript / TypeScript, Python
CWE CWE-117
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:H/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H
Tags log-injection crlf logging cwe-117
Source internal/sast/rules/vnx-117.rego

Overview

VNX-117 maps to CWE-117: Improper Output Neutralization for Logs. It reports a logger call whose arguments carry a decoded request value: Java request.getParameter()/getHeader() or a String handler parameter bound with @RequestParam, @PathVariable, @RequestHeader or @CookieValue; Python request.args/form/json/headers/GET/POST/META; Node req.query/body/params/headers/cookies. The value can be used inline, interpolated, or through a variable assigned from it (or from such a variable) in the 25 lines above.

Not reported: values passed through a CR/LF replace/replaceAll, an escaping or encoding call, JSON.stringify, repr/%r, or a numeric conversion; structured log calls whose first argument is an object literal; still-URL-encoded values such as getRequestURI(), req.originalUrl and request.path.

Why This Matters

A request value containing \r\n starts a new line in a plain-text log. An attacker can forge entries (“login succeeded for admin”), hide their own activity among fake lines, or inject content that log viewers and SIEM parsers interpret as markup or fields.

What Gets Flagged

// FLAGGED
String user = request.getParameter("user");
log.warn("Failed login for user " + user);
log.info("User-Agent: {}", request.getHeader("User-Agent"));
# FLAGGED
username = request.form.get("username")
logger.warning("failed login for %s", username)
app.logger.info(f"login attempt from {request.headers.get('X-Forwarded-For')}")
// FLAGGED
console.log('login attempt for ' + req.body.username);
logger.warn(`bad password for ${req.body.username}`);

Not flagged: log.info("User " + user.replace('\n', '_').replace('\r', '_')), logger.info("query %r", request.args.get("q")), console.log('search for ' + JSON.stringify(req.query.q)), pino.info({ query: req.query.q }, 'search').

Remediation

  1. Strip or replace \r and \n (and other control characters) from request values before logging them.
  2. Prefer a structured (JSON) log encoder, which escapes newlines inside field values, and pass request data as fields rather than inside the message text.
  3. In Python, %r or repr() renders control characters escaped.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-117
// nosec vnx-117

Or record an ignore rule: vulnetix ignore add --rule vnx-117 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-117.rego, cli/internal/sast/docs/vnx-117.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.