Skip to main content

Incident · Mid

ChatGPT 3/20/2023: redis-py bug exposes other users' data

Real incident. Key points: pool corruption on a canceled request and data-owner check.

12 min read · Incident on 2023-03-20, lasted · Source: OpenAI · Content reviewed on October 23, 2026

Short answer

Real incident. Key points: pool corruption on a canceled request and data-owner check. OpenAI took ChatGPT offline because of a bug in an open-source library: some users saw chat history titles from another active user. The problem came to light on March 20, 2023.

01 · CONTEXT

A user data cache shared by everyone

OpenAI took ChatGPT offline because of a bug in an open-source library: some users saw chat history titles from another active user. The problem came to light on March 20, 2023. It was also possible for the first message of a newly created conversation to appear in another person's history, if the two were active at around the same time.

The server uses Redis as a cache for user information, so it does not query the database on every request, and Redis Cluster to spread the load across several instances. The server is in Python, runs with Asyncio, and talks to Redis through the redis-py library.

  1. The user sends the request to the application server.

    Architecture diagram: User data cache with Redis Cluster
    CLUser
    CPApplication server
    CHRedis Cluster
    DBDatabase
  2. The server queries the cache for the user's information.

    Architecture diagram: User data cache with Redis Cluster
    CLUser
    CPApplication server
    CHRedis Cluster
    DBDatabase
  3. The cache is a Redis Cluster, which spreads the load across several instances.

    Architecture diagram: User data cache with Redis Cluster
    CLUser
    CPApplication server
    CHRedis Clustercluster
    DBDatabase
  4. With the cache, the server avoids querying the database on every request.

    Architecture diagram: User data cache with Redis Cluster
    CLUser
    CPApplication server
    CHRedis Cluster
    DBDatabase

02 · THE BUG

A reused connection carrying data from another request

The library keeps a connection pool shared between the server and the cluster and reuses each connection for another request when the previous one finishes. With Asyncio, request and response behave like two queues: the caller puts the request on the input queue, takes the response off the output queue, and only then returns the connection to the pool.

  1. The server puts A's request on the input queue of a pool connection and will later read the response from the output queue.

    Architecture diagram: Shared connection corrupted by cancellation
    CLUser A
    CLUser B
    CPAsync server
    CHRedis Cluster
  2. A's request is canceled after entering the input queue and before the response leaves the output queue, and the connection is left corrupted.

    Architecture diagram: Shared connection corrupted by cancellation
    CLUser A
    CLUser B
    CPAsync servercorrupted connection
    CHRedis Cluster
  3. An unrelated request, B's, reuses the pool connection and the next response may carry data left on it.

    Architecture diagram: Shared connection corrupted by cancellation
    CLUser A
    CLUser B
    CPAsync server
    CHRedis Cluster
  4. In most cases the leftover data is not of the expected type and the result is a server error, which the user resolves by trying again.

    Architecture diagram: Shared connection corrupted by cancellation
    CLUser A
    CLUser B
    CPAsync server
    CHRedis Cluster
  5. In some cases the data has the expected type, looks valid, and is delivered to B even though it belongs to another user.

    Architecture diagram: Shared connection corrupted by cancellation
    CLUser A
    CLUser Banother user's data
    CPAsync server
    CHRedis Cluster

The weak point is cancellation: if the request is canceled after entering the input queue and before the response leaves the output queue, the connection becomes corrupted and the next response, to an unrelated request, may receive data left on it. The Hacker News coverage describes the same mechanism: canceled requests could corrupt connections and return unexpected data from the cache.

SituationResultado
Data left on the connection is not of the expected type (most cases)Unrecoverable server error; the user has to try again
Data left on the connection is of the expected type (some cases)What comes back from the cache looks valid, even though it belongs to another user

03 · TRIGGER AND REACH

A server change and what became visible

At 1 a.m. Pacific time on Monday, March 20, OpenAI unintentionally introduced a server change that caused a spike in Redis request cancellations. This created a small probability of each connection returning wrong data. The bug only appeared in the redis-py Asyncio client for Redis Cluster, and has since been fixed.

The investigation showed that the same bug may have exposed payment information of 1.2% of active ChatGPT Plus subscribers during a nine-hour window. OpenAI states that full card numbers were not exposed at any time.

WhereWhat could appear
Chat historyTitles of conversations from another active user
History after creating a conversationThe first message of a newly created conversation, if both were active at around the same time
Subscription confirmation emailSome emails in the window were sent to the wrong users
Manage subscriptionName, email, payment address, card type and last four digits, and expiration date of another active subscriber

04 · THE RESPONSE

Fix the library and check the data owner

On identifying the bug, OpenAI reached out to the Redis maintainers with a patch. Among the actions to improve its systems, it added redundant checks to ensure the data returned by the cache matches the user who requested it; The Hacker News coverage records the same measure.

It also examined the logs programmatically to ensure messages were only available to the correct user, correlated several data sources to identify those affected and notify them, improved logging to confirm that the problem had stopped, and improved the robustness and scale of the Redis cluster to reduce connection errors under extreme load.

  1. The server asks the cache for the user data.

    Architecture diagram: Cache with data-owner check
    CLUser
    CPApplication server
    CHRedis Cluster
    NWLogs and monitoring
  2. Before using what came from the cache, a redundant check confirms that the data matches the user who requested it.

    Architecture diagram: Cache with data-owner check
    CLUser
    CPApplication serverchecks the owner
    CHRedis Cluster
    NWLogs and monitoring
  3. Better logging helps identify when the problem occurs and confirm that it has stopped.

    Architecture diagram: Cache with data-owner check
    CLUser
    CPApplication server
    CHRedis Cluster
    NWLogs and monitoringmore visibility
  4. The Redis cluster became more robust and scalable to reduce connection errors under extreme load.

    Architecture diagram: Cache with data-owner check
    CLUser
    CPApplication server
    CHRedis Clustermore robust
    NWLogs and monitoring

05 · LESSONS

Questions for your design

The case suggests questions for your user data cache. Does every value read carry an owner identifier that the server verifies before using it? What happens to a shared connection when a request is canceled midway? Is there an monitoramento that warns when the returned data does not match who asked?

Frequently asked questions

What is ChatGPT 3/20/2023: redis-py bug exposes other users' data?

Real incident. Key points: pool corruption on a canceled request and data-owner check.

What does the ChatGPT 3/20/2023: redis-py bug exposes other users' data design cover?

It is organized in these sections: A user data cache shared by everyone, A reused connection carrying data from another request, A server change and what became visible, Fix the library and check the data owner, and Questions for your design.

How long is ChatGPT 3/20/2023: redis-py bug exposes other users' data and what level is it?

It takes about 12 minutes to read and is rated Mid level.

Now design it yourself

Run this case as an interview in the System Design school: you make the decisions, the tutor challenges them and you see how your design scores.