Skip to content

VNX-PY-010: SSL verification disabled in requests

Detect TLS certificate verification turned off in requests or httpx: verify=False on a request call or on an httpx Client, AsyncClient or HTTPTransport (multi-line calls too), and session.verify = False, outside tests, strings, docstrings and comments.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-PY-010
Severity High
SARIF level error
Kind sast
Languages Python
CWE CWE-295
CAPEC CAPEC-94
ATT&CK T1557
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 tls ssl mitm requests
Source internal/sast/rules/vnx-py-010.rego

Overview

This rule flags HTTP method calls on the requests library (get, post, put, patch, delete, head, options) that include verify=False. The verify parameter controls whether requests validates the server’s TLS certificate against trusted Certificate Authorities. Setting it to False disables this validation entirely, meaning any server, including one presenting a self-signed, expired, or forged certificate, will be trusted. This makes HTTPS connections functionally equivalent to plain HTTP from a confidentiality and integrity perspective. This maps to CWE-295: Improper Certificate Validation.

Why This Matters

TLS certificate validation is the mechanism that proves you are actually talking to the server you intended to reach. Without it, any network-adjacent attacker can intercept the connection, present their own certificate, and read or modify all traffic in both directions, a man-in-the-middle (MITM) attack. This matters most for:

  • Credentials and tokens, login requests, API authentication headers, OAuth flows
  • Sensitive data, health records, financial data, PII transmitted in request or response bodies
  • Webhooks and internal service calls, an attacker on the internal network can impersonate internal services, poisoning data or issuing forged commands
  • Software download and update calls, a MITM can replace a downloaded binary or configuration with a malicious version

The verify=False shortcut is often introduced as a temporary workaround for certificate problems (expired certs, self-signed internal CA, wrong hostname) and then forgotten. The underlying certificate problem needs to be fixed, not bypassed.

What Gets Flagged

A requests or httpx request call, or an httpx Client/AsyncClient/HTTPTransport, given verify=False (on the call line or a continuation line), and session.verify = False. Test files, docstrings and comments are not reported.

# FLAGGED: SSL verification disabled on a GET request
response = requests.get("https://api.example.com/data", verify=False)

# FLAGGED: POST with credentials, credentials transmitted without protection
response = requests.post(
    "https://auth.internal/token",
    data={"username": user, "password": password},
    verify=False,
)

# FLAGGED: all HTTP methods are flagged
session.put("https://service.internal/update", json=payload, verify=False)

Remediation

  1. Remove verify=False and fix the underlying certificate issue. This is the correct long-term fix. If the request works after removing verify=False, the certificate is valid and no further action is needed.

  2. For internal services using a private CA, provide the CA bundle path. Pass verify the path to your CA certificate or bundle instead of disabling verification entirely:

import requests

# SAFE: verify against a specific CA certificate
response = requests.get(
    "https://internal.service.example",
    verify="/etc/ssl/certs/internal-ca.crt",
)

# SAFE: verify against a CA bundle file
response = requests.get(
    "https://internal.service.example",
    verify="/path/to/ca-bundle.crt",
)
  1. Use the REQUESTS_CA_BUNDLE environment variable for system-wide CA configuration. This avoids hardcoding paths in code and allows the CA bundle path to be configured per environment:
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/internal-ca.crt
# SAFE: requests automatically uses REQUESTS_CA_BUNDLE if set
response = requests.get("https://internal.service.example")
  1. For mutual TLS (mTLS), use the cert parameter alongside proper verify.
# SAFE: mTLS with certificate verification enabled
response = requests.get(
    "https://api.example.com",
    cert=("/path/to/client.crt", "/path/to/client.key"),
    verify="/path/to/ca-bundle.crt",
)
  1. Use a requests.Session to set verification once for all calls in the session. This prevents accidentally omitting the parameter on individual calls:
import requests

session = requests.Session()
session.verify = "/etc/ssl/certs/ca-certificates.crt"

# All requests through this session use the configured CA bundle
response = session.get("https://api.example.com/data")
  1. Do not suppress the InsecureRequestWarning. Some codebases call urllib3.disable_warnings(InsecureRequestWarning) alongside verify=False to silence console noise. Remove both, the warning is there to alert you that verification is disabled.

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-py-010
// nosec vnx-py-010

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

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