Back to Blog
critical SEVERITY3 min read

`requests.get()`/`delete()`/`post()` with `verify=False` in Release

A critical security vulnerability in a release automation script disabled SSL certificate verification on every HTTPS request to GitHub's API. By passing `verify=False` to `requests.get()`, `requests.delete()`, and `requests.post()`, the script exposed OAuth tokens and release binaries to man-in-the-middle attacks on any network the script ran from.

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published September 15, 2026•Reviewed September 16, 2026

Answer Summary

The `upload-release-asset.py` release script used `verify=False` on four HTTP requests to `api.github.com` and `uploads.github.com`. An attacker on the same network—via ARP spoofing, rogue Wi-Fi, or compromised infrastructure—could intercept these connections, steal the `Authorization` header bearing the OAuth token, and substitute malicious release assets for legitimate ones. The fix removes all four `verify=False` parameters, restoring Python Requests' default certificate validation. No CVE or CWE has been assigned. This is first-party code, not a packaged dependency.

Vulnerability at a Glance

cweunknown
fixRemove `verify=False` to restore default TLS certificate validation
riskMan-in-the-middle attack exposing OAuth tokens and enabling asset substitution
languagePython
root cause`verify=False` passed to `requests.get()`, `requests.delete()`, and `requests.post()`
vulnerabilityImproper Certificate Validation (CWE-295)

Affected Versions

Affected upload-release-asset.py (all versions prior to fix)
Fixed in unknown (first-party code fix)
Ecosystem pypi
CVE / GHSA not assigned
CWE unknown

The Vulnerability Explained

The upload-release-asset.py script automates GitHub release asset management through four HTTPS requests. Each call to the Python requests library included verify=False:

# Vulnerable pattern - repeated four times
r = requests.get(api, headers=h, timeout=60, verify=False)
r = requests.get(assets_url, headers=h, timeout=60, verify=False)
dr = requests.delete("...", headers=h, timeout=60, verify=False)
up = requests.post(url, headers=dict(h, **{"Content-Type": "application/octet-stream"}), 
                   data=f, timeout=900, verify=False)

The verify=False parameter disables TLS certificate validation entirely. When Python Requests encounters this flag, it accepts any certificate presented by the server—even invalid, expired, or attacker-controlled ones—without raising SSLError.

This creates a certificate validation bypass (CWE-295) with two distinct attack surfaces:

  1. Token theft: The headers=h dictionary contains an Authorization: token <oauth_token> header. An attacker intercepting the connection captures this bearer token, gaining the script's full GitHub permissions (typically repo scope for release management).

  2. Asset substitution: The 15-minute upload window (timeout=900) sends binary data to uploads.github.com. An attacker can terminate the TLS connection, serve a malicious file in place of the legitimate release asset, and forward the (now compromised) token to complete the upload—poisoning the release with attacker-controlled code.

The attack requires network-level access: ARP spoofing on a corporate LAN, a compromised VPN concentrator, DNS hijacking, or simply a rogue Wi-Fi access point at a coffee shop where a developer runs the release process.

The Fix

The remediation removes verify=False from all four request sites, restoring Python Requests' default behavior of validating server certificates against system trust stores:

# Fixed: certificate validation now enforced
r = requests.get(api, headers=h, timeout=60)
r = requests.get(assets_url, headers=h, timeout=60)
dr = requests.delete("...", headers=h, timeout=60)
up = requests.post(url, headers=dict(h, **{"Content-Type": "application/octet-stream"}), 
                   data=f, timeout=900)

This single change eliminates the vulnerability because:

  • requests now validates that api.github.com and uploads.github.com present certificates chained to a trusted root CA
  • Certificate mismatches, expiration, or revocation trigger requests.exceptions.SSLError, halting execution before token transmission
  • No code changes are needed elsewhere—the same headers and timeout parameters function identically

Key Takeaways

  • verify=False is never appropriate for production API clients: The parameter exists only for testing against self-signed certificates in controlled environments. Production code using it against public APIs like GitHub's introduces immediate, exploitable MITM risk.

  • Release scripts are supply-chain critical paths: Compromised release assets propagate automatically to users via package managers and update mechanisms. The integrity of these scripts matters as much as the application itself.

  • OAuth tokens in automation require transport-layer protection: Unlike interactive browser flows with PKCE or short-lived codes, bearer tokens in scripts are long-lived and high-privilege. Their exposure grants persistent repository access.

  • Python Requests' defaults are safe; overrides must be justified: The library validates certificates by default. Any override—verify=False, cert_reqs='CERT_NONE' in urllib3, or custom SSLContext—demands explicit risk assessment and documentation.

How Orbis AppSec Detected This

Source: The repo and tag parameters constructing GitHub API URLs (though static in this script, the pattern generalizes to dynamic URL building)

Sink: requests.get(), requests.delete(), and requests.post() invoked with verify=False

Missing control: Certificate validation was explicitly disabled where the default trusted validation should apply; no REQUESTS_CA_BUNDLE override or pinned certificate was present to mitigate

CWE: unknown (vulnerability class: Improper Certificate Validation, CWE-295)

Fix: Remove verify=False from all four HTTP request calls to restore TLS certificate validation against system trust stores

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

The verify=False pattern in upload-release-asset.py exemplifies how a single parameter—often added during development to bypass certificate errors—can persist into production with critical consequences. The fix demonstrates that secure defaults, when not overridden, provide adequate protection against network-level attackers. For teams maintaining release automation, audit all HTTP client configurations: any explicit verify=False, ssl=False, or insecure flag warrants immediate review and removal.

Prevention and further reading

Frequently Asked Questions

Why did the script use `verify=False` on GitHub API calls rather than trusting the system CA store?

The original code explicitly disabled verification on all four requests. This was unnecessary—Python Requests validates certificates against system trust stores by default—and created a critical vulnerability where any attacker controlling network path could impersonate GitHub's API.

Which of the four HTTP methods in the release script was most dangerous to leave unverified?

The `POST` to `uploads.github.com` carried the binary release asset, making asset substitution possible; however, the `DELETE` and two `GET` requests were equally severe because their `Authorization` headers contained the OAuth token usable for repository-wide access.

Does removing `verify=False` alone suffice, or does the script need pinned certificates or certificate pinning?

Removing `verify=False` restores standard TLS validation against the system CA store, which is sufficient for GitHub's publicly trusted certificates. Pinning would add fragility without meaningful security gain against this threat model.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #19

Related Articles

critical

Hybridauth Telegram OAuth Timing Attack in `authenticateCheckError()`

The Telegram OAuth provider in Hybridauth relied on `strcmp()` to validate HMAC-SHA256 signatures, exposing a timing side-channel that could allow attackers to forge authentication tokens character by character. The fix replaces this with PHP's timing-safe `hash_equals()` function, eliminating the information leak.

high

undici 7.29.0 TLS Bypass: BalancedPool Drops Connect Options

A critical flaw in undici's BalancedPool implementation silently discards TLS certificate validation settings when routing requests through certain connection paths. Attackers on the network could intercept HTTPS traffic without triggering validation errors. The fix preserves connect options throughout the connection lifecycle.

critical

Model Fetching Without Integrity Verification in ONNX Loading

A machine learning application was fetching ONNX model files and chunks over the network without verifying their integrity, creating an opening for model poisoning attacks. The fix adds cryptographic integrity verification at the point where downloaded chunks are reassembled and cached, ensuring models have not been modified in transit or at rest.

high

nanoid 3.3.11 Integer Overflow: Predictable ID Generation

An integer overflow in nanoid 3.3.11's internal randomness generation causes the library to fall back to predictable ID sequences, undermining the cryptographic guarantees of its supposedly unguessable identifiers. The fix upgrades the dependency tree to patched versions 3.3.12 or 5.1.11.

high

generateUUID() Ditches MD5 for SHA-256 to Fix CWE-328

The `generateUUID()` helper built request-identifying UUIDs by hashing an input string with MD5, a cryptographically broken algorithm susceptible to collisions. The fix swaps the hash function for SHA-256, reducing the chance that two different inputs produce the same generated identifier.

high

API_URL Defaults to HTTP Without HTTPS Enforcement

An API client defaults to unencrypted HTTP connections, leaving all API communications—including sensitive project data—vulnerable to interception. Although an `upgradeToHttps()` helper function existed, it was applied inconsistently across the codebase. The fix ensures HTTPS enforcement is applied uniformly before every HTTP request.