ChatGPT Chrome Extension Causes a Controlled Renderer to Grow by ~0.65 GiB/min Until It Reaches 10+ GiB

Open 💬 0 comments Opened Jul 29, 2026 by aceHubert

What version of the Codex App are you using (From “About Codex” dialog)?

26.721.41059

What subscription do you have?

Plus

What platform is your computer?

_No response_

What issue are you seeing?

Summary

The official ChatGPT Chrome extension causes a controlled webpage renderer to consume memory at a sustained rate of approximately 0.65 GiB per minute during a Codex browser-control operation.

The affected renderer grew from 7.8 GiB to approximately 13.0 GiB in about eight minutes. It also consumed more than 80% CPU and forced approximately 12.4 GiB of memory into swap.

Terminating only the affected renderer immediately stopped the growth and reduced total Chrome child-process RSS from approximately 4–5 GiB to approximately 2.1 GiB. System-wide free memory recovered from approximately 32% to 56%.

This appears to be a renderer-side retention issue triggered by the extension's browser-control pipeline, rather than ordinary Chrome cache growth or a leak in the extension service worker alone.

Environment

  • Date observed: July 29, 2026
  • Operating system: macOS 26.5.2 (25F84)
  • Architecture: Apple Silicon / ARM64
  • Google Chrome: 150.0.7871.187
  • ChatGPT Chrome extension ID: hehggadaopoacecdllhhajmbjkdcmajg
  • ChatGPT Chrome extension version: 1.2.27221.15725
  • Extension description: Control Chrome with ChatGPT.
  • Extension background implementation: Manifest V3 service worker
  • Chrome parent process PID during the reproduction: 37204
  • Affected renderer PID: 77035
  • Codex/ChatGPT desktop version: 26.721.41059

Impact

  • Severe memory pressure and swap growth within minutes.
  • Sustained high CPU usage.
  • Potential system-wide UI stalls or hangs.
  • Risk of out-of-memory termination or forced reboot.
  • The problem can continue after a browser-control operation stalls or times out.
  • Recovery currently requires terminating the affected renderer or restarting the extension/browser-control session.

What steps can reproduce the bug?

Steps to Reproduce

The precise prompt and target webpage can be added if needed, but the observed sequence was:

  1. Install and enable the official ChatGPT Chrome extension.
  2. Connect Codex/ChatGPT to the existing Chrome profile through the extension.
  3. Start a browser-control task that operates on an existing webpage.
  4. Allow Codex to inspect or manipulate the page using DOM, JavaScript evaluation, screenshot, page-context, or related browser-control operations.
  5. Observe Chrome processes in Activity Monitor or with ps and vmmap.
  6. A newly created Google Chrome Helper (Renderer) process begins using high CPU and grows by hundreds of MiB per minute.
  7. The growth continues after the browser operation stalls or times out.

What is the expected behavior?

Expected Behavior

  • Browser-control operations should use bounded memory.
  • CDP commands and page-context operations should release temporary values when they complete, fail, time out, or are canceled.
  • The extension should stop high-volume event producers and detach its debugger session when a turn or browser-control session ends.
  • A failed DOM/evaluation operation should not leave the controlled renderer allocating memory indefinitely.

Actual Behavior

The controlled renderer continued allocating memory while using high CPU.

Additional information

Follow-up measurement

At approximately 2026-07-29 04:22 UTC+00:00:

Physical footprint:         12.9G–13.0G
Physical footprint (peak):  13.1G
Writable regions:           13.7G total, 12.9G written
Swapped out:                approximately 12.4G
CPU:                        approximately 80% or higher

This is an increase of approximately 5.2 GiB in eight minutes, or about 0.65 GiB/min.

Memory Breakdown

vmmap -summary 77035 reported:

Memory Tag 253: approximately 5.8G swapped
Memory Tag 255: approximately 6.6G swapped

Chromium defines these tags as:

kPartitionAlloc = 253;
kChromium = 254;
kV8 = 255;

This indicates that the growth consisted primarily of:

  • V8 heap pages;
  • Chromium PartitionAlloc allocations;
  • likely JavaScript objects, strings, ArrayBuffer backing stores, serialized CDP results, page-context data, or related temporary values that remained strongly referenced.

This memory profile does not look like ordinary disk cache or a purely GPU/image-cache problem.

Process Identification

The runaway process command line included:

--type=renderer
--renderer-client-id=4063

It did not include:

--extension-process

Therefore, the 13 GiB allocation was not located in the extension service worker itself. It was located in a normal webpage renderer being controlled by the extension.

The Chrome parent process remained much smaller, with an observed physical footprint of approximately 0.8–1.1 GiB. Activity Monitor may visually associate the renderer's usage with the parent Chrome application, but the actual runaway allocation was owned by renderer PID 77035.

CPU Sample Observations

The attached macOS sample report shows:

  • sustained work on the renderer main thread;
  • repeated execution through addresses outside static binary images, consistent with V8 JIT-generated code;
  • continued renderer activity rather than an idle process waiting to be reclaimed;
  • no evidence that the majority of the footprint was an IOSurface or GPU allocation.

The sample report is useful for proving the process identity, CPU activity, launch time, and 7.8 GiB footprint. Because the Chrome framework is stripped, it does not identify the exact JavaScript function responsible for the allocation.

Extension Code Paths That May Be Relevant

The following findings are based on a read-only inspection of extension version 1.2.27221.15725. They are hypotheses for investigation, not a claim that one specific path has already been proven as the sole root cause.

1. Unbounded CDP event forwarding

The extension registers a global chrome.debugger.onEvent listener and forwards every event to the native host without an apparent method filter, byte limit, bounded queue, sampling policy, or transport backpressure.

The effective data path is:

chrome.debugger.onEvent
  -> onCDPEvent JSON-RPC notification
  -> chrome.runtime.Port.postMessage
  -> native messaging transport
  -> com.openai.codexextension

The dynamic CDP command path ultimately calls:

chrome.debugger.sendCommand(target, request.method, request.commandParams)

This means the native host can dynamically enable high-volume domains or methods such as:

  • Page.startScreencast;
  • Page.captureScreenshot;
  • Runtime.evaluate;
  • DOMSnapshot.captureSnapshot;
  • Network.enable;
  • Network.getResponseBody;
  • WebSocket frame events.

If event production is faster than the native host or app server can consume it, multiple layers may retain serialized event payloads.

2. Runtime or DOM objects may survive timeout/cancellation

The renderer-side V8 allocation suggests that CDP or injected-page values may remain alive after a failed operation.

Please verify that all completion, timeout, cancellation, disconnect, and turn-finalization paths perform the equivalent of:

Page.stopScreencast
Network.disable
Runtime.releaseObject / Runtime.releaseObjectGroup
Target.setAutoAttach(autoAttach=false)
chrome.debugger.detach

In particular, Runtime.evaluate calls should use a bounded lifetime for remote objects and release their objectGroup in a finally block.

3. Large getTabContext values and base64 duplication

The extension's page-context code can read content from the controlled tab and transform it through a pipeline resembling:

ReadableStream chunks
  -> Uint8Array[]
  -> Blob
  -> data URL
  -> full base64 string
  -> structured clone
  -> native messaging chunks

The binary path allows up to 100 MiB of raw content, which becomes approximately 133 MiB after base64 encoding before accounting for duplicate representations and structured-clone/IPC copies.

The text path does not appear to have the same 100 MiB total-size limit.

The full dataBase64 value can remain captured by an asynchronous upload closure until all native-host chunks finish. Some native-host asset requests do not appear to have a default timeout. Multiple concurrent requests could therefore retain multiple complete payloads.

4. High-volume screenshot or screencast traffic

A screencast frame is a base64-encoded compressed image. For example:

500 KiB/frame * 4/3 base64 expansion * 30 fps * 60 seconds
~= 1.17 GiB/min of payload

This makes screencast/event backpressure worth investigating. However, the large V8 portion in the affected webpage renderer means a pure image-buffer leak does not fully explain this reproduction. Screencast or screenshot traffic may be a trigger or amplifier rather than the only retained object type.

Cleanup Result

After collecting the process sample and vmmap evidence, renderer PID 77035 was terminated with SIGTERM.

Observed result:

Affected renderer: exited
Chrome child-process RSS before: approximately 4–5 GiB
Chrome child-process RSS after:  approximately 2.1 GiB
System-wide free memory before:  approximately 32%
System-wide free memory after:   approximately 56%

Chrome itself remained running. The associated controlled tab was expected to crash or reload.

This confirms that the majority of the active memory pressure belonged to the single runaway renderer.

View original on GitHub ↗