VNX-439: Behavioral Change in New Version or Environment
Reports Python security APIs whose behaviour depends on the interpreter version: hmac.new() or hmac.HMAC() without a digest, ssl.SSLContext() with no or the generic PROTOCOL_TLS/PROTOCOL_SSLv23 protocol, module-level ssl.wrap_socket(), ssl.match_hostname() and cgi.escape().
| Field | Value |
|---|---|
| Rule ID | VNX-439 |
| Severity | Low |
| SARIF level | note |
| Kind | sast |
| Languages | Python |
| CWE | CWE-439 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:L/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:L/DI:H/EX:L/EC:N/P:L |
| Tags | behavioral-change-new-version python-version cwe-439 |
| Source | internal/sast/rules/vnx-439.rego |
Overview
VNX-439 maps to CWE-439: Behavioral Change in New Version or Environment. The same line of code is weak on one Python version and broken, or silently different, on another, so its security depends on the runtime it happens to be deployed on.
What Gets Flagged
hmac.new()orhmac.HMAC()with nodigestmod=and fewer than three positional arguments: MD5 before Python 3.8,TypeErrorfrom 3.8.ssl.SSLContext()with no protocol, or withssl.PROTOCOL_TLS/PROTOCOL_SSLv23: role and verification defaults vary by version (deprecated since 3.10).- Module-level
ssl.wrap_socket(): no certificate or hostname verification by default, removed in 3.12. ssl.match_hostname(): removed in 3.12.cgi.escape(): removed in 3.8, and leaves quotes unescaped by default.
From-imported names (from ssl import wrap_socket, from cgi import escape) are recognised.
mac = hmac.new(SECRET, payload) # FLAGGED
ctx = ssl.SSLContext() # FLAGGED
tls = ssl.wrap_socket(raw) # FLAGGED
mac = hmac.new(SECRET, payload, hashlib.sha256) # not flagged
ctx = ssl.create_default_context() # not flagged
Not reported: hmac.digest(), SSLContext(ssl.PROTOCOL_TLS_CLIENT)/PROTOCOL_TLS_SERVER, context.wrap_socket(), html.escape(), comments and strings. Explicitly obsolete TLS versions are VNX-PY-021; tar extraction without a filter is VNX-409.
Remediation
- Always pass
digestmodtohmac.new(). - Use
ssl.create_default_context()orSSLContext(ssl.PROTOCOL_TLS_CLIENT)and wrap sockets through the context withserver_hostname=. - Replace
cgi.escape()withhtml.escape().
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-439
// nosec vnx-439
Or record an ignore rule: vulnetix ignore add --rule vnx-439 --reason "...". See Suppressing findings.