Skip to content

VNX-345: Insufficient Verification of Data Authenticity

Python code loads request, socket or downloaded bytes with marshal, executes code fetched over the network, or runs a downloaded file, with no signature or digest check in between.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-345
Severity Medium
SARIF level warning
Kind sast
Languages Python
CWE CWE-345
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 data-authenticity cwe-345 deserialization python
Source internal/sast/rules/vnx-345.rego

Overview

VNX-345 maps to CWE-345: Insufficient Verification of Data Authenticity. It reports Python code that acts on data from an untrusted channel as though it were authentic:

  1. marshal.load()/loads() (also through an import marshal as m alias or from marshal import loads) applied to request data (body, form, args, cookies, files, headers), bytes read from a socket, or a body downloaded with requests, httpx or urlopen(), inline or through a variable assigned from it (one further assignment, such as a base64 decode, is followed) within 12 lines;
  2. exec()/eval() of content fetched with requests, httpx or urlopen();
  3. a file downloaded with urlretrieve() and then run with subprocess, os.system or os.exec*.

Why This Matters

Bytes from a cookie, a form or a socket are written by whoever sent them. marshal builds code objects from them; executing downloaded code hands the process to whoever controls the server or the connection. Without an HMAC, a signature or a pinned digest, nothing establishes that the data came from where the code assumes.

Not reported: when the 15 lines above verify an HMAC or signature (hmac.compare_digest, hmac.new, itsdangerous signers, .verify()) or a downloaded file’s hash; json.loads and ast.literal_eval; marshal of local files or of the program’s own dumps(); comments and string literals.

Unpickling untrusted bytes is the same weakness, so it is reported once, by the rule that owns the call: pickle, cPickle, _pickle, dill, cloudpickle and jsonpickle are reported by VNX-PY-003, and the loaders that unpickle under the hood (torch.load, joblib.load, pandas.read_pickle, numpy.load(..., allow_pickle=True)) by VNX-PY-013, wherever the bytes come from.

What Gets Flagged

raw = base64.b64decode(request.form["code"])
code = marshal.loads(raw)

exec(requests.get(f"https://plugins.example.com/{name}.py").text)

path, _ = urllib.request.urlretrieve("https://downloads.example.com/agent.sh", "/tmp/agent.sh")
subprocess.run(["sh", path], check=True)

Remediation

  1. Exchange data in a format that cannot carry code (JSON) and validate it.
  2. When a serialised object must round-trip through a client, sign it (itsdangerous, hmac.new over the bytes) and verify with hmac.compare_digest before loading.
  3. Pin downloaded code by SHA-256 or verify its signature before executing it.

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

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

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