The ChatGPT Redis Bug: Cross-Tenant Leaks in One Line

📋 Key Takeaways
  • What happened
  • Why a client-library bug became a cross-tenant leak
  • The disclosure pattern worth copying
  • Timeline
  • Defensive lessons
5 min read · 975 words
Educational & Ethical Use Only — This article is provided for educational and ethical cybersecurity research purposes only. The techniques described should only be used on systems you own or have explicit permission to test. Always follow responsible disclosure and the laws applicable to you. Mitigations are included so engineers can harden real systems.

Quick Answer — On March 24, 2023, OpenAI disclosed that a bug in an open-source Redis client library (redis-py’s async version) — combined with a misconfigured cache key prefix — had, for a ~9-hour window on March 20, let some ChatGPT users see fragments of other users’ chat histories: titles from strangers’ conversations, and for a subset of ChatGPT Plus subscribers, payment-related data (name, email, payment address, last four digits + expiry of the card) in the billing UI. Roughly 1.2% of hourly-active users were exposed to the chat-title leakage per the post-mortem. The lesson: a one-line client-library cancellation bug plus a disabled safety check equals cross-tenant disclosure at platform scale — shared caches inherit multi-tenancy’s blast radius.

What happened

  • Date of bug window: March 20, 2023, ~UTC early hours. A specific sequence — cancel a running request — triggered a redis-py async bug that could leave a connection with corrupted/poisoned state returning someone else’s cache entries.
  • The config amplifier: A key-prefix setting meant to isolate tenants per-user was mistakenly disabled during a debugging session days earlier, so the poisoned connection could read across users’ keys — that’s the single-tenant-no-more moment.
  • What leaked: (a) chat-titles visible in some users’ history sidebars that weren’t theirs; (b) during the same window, ~1.2% of ChatGPT Plus subscribers had another user’s name, email, payment address, card last-four and expiry surface in their own billing pop-up; (c) a small set saw first-message snippets.
  • The response: OpenAI took ChatGPT offline mid-launch-week, patched the redis-py bug upstream (a contributed fix), audited logs, notified affected users and regulators, and published one of the more candid post-mortems of the AI era.

Why a client-library bug became a cross-tenant leak

Layer Failure mode
redis-py async cancellation bug Aborted requests leave connections in corrupted state; subsequent reads fetch wrong keys’ data
Disabled key prefix Removed the per-user namespace that would have contained the poisoned reads
Shared cache topology All tenants’ hot data in one logical cluster — one bad connection reaches everyone
No cross-tenant canary Nothing asserted “user A must never see user B’s keys” as an invariant test
UI trust in cache Frontend rendered cache returns verbatim into sidebars and billing widgets
data-hmmnm-seam="2">

The disclosure pattern worth copying

Three things separated OpenAI’s handling from the standard breach-notice boilerplate. First, specific math: the 1.2%-of-hourly-active framing gave users and reporters an honest denominator instead of vague “a small number.” Second, technical candor: naming the exact library, the cancellation path, and the config mistake let every other platform on redis-py self-audit within days — the fix rippled far past OpenAI. Third, visible remediation: the sidebar came off, the service went dark during peak launch-week hype, and the bug bounty followed. The cost of that transparency was low; the trust yield was lasting.

data-hmmnm-seam="3">

Timeline

Date Event
2023-03 ~15 Debugging change disables cache-key prefix isolation (per post-mortem timeline)
2023-03-20 redis-py bug window: canceled requests → poisoned connections → cross-user reads, ~9 hours
2023-03-20 → 21 ChatGPT intermittently unavailable; history sidebar disabled (the visible symptom)
2023-03-24 Disclosure + post-mortem: 1.2% chat-title exposure; billing-data subset; redis-py patch details
2023-04 → 05 OpenAI ships bug bounty, trust-boundary reviews; privacy regulators absorb the incident into AI-governance debates
data-hmmnm-seam="4">

Defensive lessons

  • Cancellation is a correctness edge. Async request-abort paths corrupt state in subtle ways; chaos-style testing that cancels requests at random moments is how you find them before strangers’ data does.
  • Isolation flags are load-bearing. The prefix-disable was a debug convenience that production paid for. Any isolation control that can be toggled for debugging will eventually ship off — config-gate it, alarm on it, make re-enabling mandatory pre-deploy.
  • Tenant-boundary invariant tests. “No query path may return rows/keys not owned by the requester” is a testable property; write it as an always-on suite for every cache and store fronting multi-tenant UIs.
  • Credit-card fields: surface less. Last-four + expiry is ‘safe’ only by convention; a billing widget that receives it unprompted is a disclosure waiting for a rendering bug. Fetch payment data on explicit action only.
  • Post-mortems build trust. OpenAI’s engineering-detail disclosure became the template AI platforms are measured against — honesty about the 1.2% math, the exact bug, and the config error.
data-hmmnm-seam="5">

Why it still matters in 2026

This incident is the founding case study for multi-tenant data planes under AI workloads: conversations are intimate data, chat UIs render server state eagerly, and the caching layers that make platforms responsive inherit every tenancy risk databases spent decades walling off. In 2026 — RAM-hot vector stores, shared prompt caches, and agent memory systems all humming on similar open-source plumbing — the redis-py episode reads as prophecy: open-source dependencies plus hasty config equal cross-tenant breach, and nobody audits the cancel path. The platforms that survived the subsequent rounds were those that adopted tenant-invariant tests and config-drift alarms as policy. Everyone else became a future post-mortem.

Was any full conversation content exposed?

Per the post-mortem: chat titles (sidebar fragments) for the ~1.2%, plus first messages for a much smaller set where a title was absent and the UI fell back to message text. The billing-data exposure was its own subset. Full conversation bodies were not in the leaked surface — but a title alone can be plenty: they’re written like search queries and confessions.

Why did the sidebar show strangers’ chats before the billing data did?

Because the sidebar was the highest-frequency reader of the cache: every page load fetched the user’s chat list, so poisoned connections manifested there first. The billing widget surfaced data only when users opened it — meaning some affected Plus subscribers may never have looked at the stranger’s card details that were technically delivered to their browser. Client-visible-but-unrendered is still a reportable disclosure, which the post-mortem correctly treated it as.

What happened to redis-py?

The maintainers patched the cancellation-flush bug family across affected releases, and OpenAI contributed upstream fixes and detail — a quiet landmark in vendors-take-open-source-seriously arc. The deeper lesson stuck with platform engineers: the client library between your app and your cache is security-critical code, even though it never touches a password.

Part of the hmmnm.com security-timeline series — one event per month, 2021–2024, indexed here.

data-hmmnm-seam="end">

Prabhu Kalyan Samal

Application Security Consultant at TCS. Certifications: CompTIA SecurityX, Burp Suite Certified Practitioner, Azure Security Engineer, Azure AI Engineer, Certified Red Team Operator, eWPTX v3, LPT, CompTIA PenTest+, Professional Cloud Security Engineer, SC-900, SC-200, PSPO I, CEH, Oracle Java SE 8, ISP, Six Sigma Green Belt, DELF, AutoCAD. Writing about ethical hacking, security tutorials, and tech education at Hmmnm.