The below text was written by gemini. I am publishing this because I ran into issues vibe coding a chatbot on a Mac with Cloudveil filter installed and want to allow other uses/llm agents to find this helpful.
This document outlines an issue where Python scripts and local containers fail to connect to LLM APIs due to local content-filtering software, along with the diagnostic steps and a practical workaround.
Symptom
Python-based tools on macOS (such as chat.py or scripts utilizing requests and urllib) fail to reach API endpoints including api.deepseek.com, api.openai.com, and api.anthropic.com. The scripts output the following error:
Plaintext
SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed:
self-signed certificate in certificate chain
This failure also applies to traffic originating from inside Docker containers, as Docker on macOS routes its traffic through the host’s network path.
Root Cause
The root cause of the error is Cloudveil, a content-filtering application installed on the machine. Cloudveil performs transparent TLS interception at the network and process level, rather than relying on a standard HTTP or HTTPS proxy configuration. Command-line checks using scutil --proxy or environment variable inspections confirm no proxy is configured.
Cloudveil applies this interception based on the specific requesting process:
- Trusted processes: System binaries such as the browser, the native
curl, and the notarized Claude Code CLI are permitted to pass through without interception. Accessing the API domains directly via a web browser successfully returns a standard 200 OK JSON response. - Unrecognized processes: Network traffic initiated by
python3scripts or Docker containers is intercepted. Because Cloudveil cannot generate a valid certificate for the requested domain on behalf of an untrusted client, it serves a fake certificate (issuer: O=Cloudveil Filtering Certificate,subject: O=GoProxy untrusted MITM proxy Inc). Python’s native TLS stack correctly rejects this certificate because it is not present in any trusted Certificate Authority (CA) store.
This behavior is not a domain-level block. The actual AI chat interfaces load successfully in the browser, indicating that only non-browser and non-signed application traffic is being targeted by the interception.
Diagnostic Commands
To verify if this specific process-level interception mechanism is causing connection issues on a new domain or tool, execute the following commands:
Bash
# Compare the certificate seen by an untrusted TLS probe vs. a trusted curl client
echo | openssl s_client -connect <host>:443 -servername <host> 2>/dev/null \
| openssl x509 -noout -issuer -subject
curl -sv "https://<host>" --max-time 8 -o /dev/null 2>&1 \
| grep -i -E "issuer|subject:|SSL certificate"
# Confirm that no standard proxy is configured on the system
scutil --proxy
env | grep -i proxy
If the openssl command returns the Cloudveil MITM certificate while curl returns the actual CA for the same host, process-level interception is actively modifying the traffic.
Workaround and Fix
Subprocess curl Implementation
A functional workaround is to modify the Python script to bypass the requests library and instead execute the system’s trusted curl binary via subprocess.Popen. Because curl is recognized as a trusted process by Cloudveil, the traffic is passed through successfully.
To implement this securely:
- API Key Security: Supply the API key using a
curl -Kconfig file containing the authorization header (header = "Authorization: Bearer ..."). Avoid using the-Hcommand-line argument, which would expose the key inps auxoutput to other local users. Set the configuration file permissions tochmod 600and delete the file immediately upon request completion. - Request Body: Stream the JSON payload directly to
curloverstdin(data-binary = @-) to avoid shell execution and argument-length constraints. - Streaming Responses: Parse Server-Sent Events (SSE) responses line-by-line from the
stdoutstream of thecurlsubprocess.
Permanent Resolution
For a permanent fix, the Cloudveil configuration must be modified by an administrator. This requires either allowlisting the specific AI API domains (api.deepseek.com, api.openai.com, api.anthropic.com) or broadly exempting Python and script-based traffic from interception.