Skip to content

VNX-140: Improper Neutralization of Delimiters

Reports Python and JavaScript/TypeScript code that writes a CSV, TSV, pipe- or colon-delimited record to a file or stream by joining request data with the delimiter, without quoting or escaping it.

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

Overview

VNX-140 maps to CWE-140: Improper Neutralization of Delimiters. It reports a delimited record built by gluing request data together with a delimiter (,, |, ;, \t, :) and written to a file or stream: f-strings and template literals, + concatenation, "|".join(...) / .join(','), "%s,%s" % and "{},{}".format(...), either on the write itself or in a record variable built in the 6 lines above it. A value that contains the delimiter or a newline then adds fields or whole records.

The data must come from the request on that line (Flask/Django request.form/args/values/json/data/cookies/headers/GET/POST, Express/Koa req/ctx body/query/params/cookies/headers) or from a variable assigned from it in the 10 lines above. Sinks are .write(), .writelines(), print(..., file=...) and fs.appendFile/writeFile (and their Sync forms).

What Gets Flagged

name = request.form["name"]
email = request.form["email"]
f.write(f"{name},{email}\n")                     # FLAGGED
out.write(user + ":" + role + "\n")              # FLAGGED
fs.appendFileSync('audit.csv', `${req.body.user},${req.body.action}\n`)   // FLAGGED
const line = [req.body.item, req.body.qty, req.ip].join(',')
sink.write(line + '\n')                                                   // FLAGGED

What Is Not Flagged

  • csv.writer/DictWriter, csv-stringify, json.dumps/JSON.stringify.
  • Values passed through .replace(), re.sub(), quote() or an escape function first.
  • Constant header rows, and data that does not come from the request.
  • HTTP response writes (res.write, response.write, self.wfile), which are a different weakness.
  • Splitting input on a delimiter, which is VNX-166.

Remediation

Write delimited files with a CSV library that quotes fields (csv.writer, csv-stringify), or reject or escape the delimiter and newlines in every value before joining.

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-140
// nosec vnx-140

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

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