openai / openai/codex

MCP App UI blocks public HTTPS images under VPN Fake-IP DNS with local address space permission error

Open
#43,741 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app bug connectivity mcp
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

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

26.901.51231 (build 8109)

Bundled Chromium observed during diagnosis: 152.0.7977.83.

What subscription do you have?

Not specified.

What platform is your computer?

macOS 26.6.2, Apple Silicon (arm64).

Network: Clash Verge / mihomo alpha-e26714a, TUN enabled, DNS enhanced mode fake-ip, including synthetic IPv6 addresses.

What issue are you seeing?

A public HTTPS image fails to load inside a Codex MCP App UI sandbox with a Local Network Access permission error. The same image loads successfully as a normal <img> embedded in an HTTPS website in Google Chrome on the same Mac with the same VPN configuration.

The image is publicly accessible without authentication. The MCP UI resource already declares the image origin in _meta.ui.csp.resourceDomains.

Console error (image URL and sandbox identifier redacted):

Access to image at 'https://<public-image-host>/preview.webp'
from origin 'codex-sandbox://mcp-server-<redacted>.web-sandbox.oaiusercontent.com'
has been blocked by CORS policy:
Permission was denied for this request to access the `local` address space.
GET https://<public-image-host>/preview.webp net::ERR_FAILED

This also reproduces with a standalone new Image() probe executed in the Skybridge sandbox console, without the MCP widget's rendering code or tool-result processing.

What steps can reproduce the bug?
  1. Enable Clash/mihomo TUN and Fake-IP DNS, including synthetic IPv6 answers.
  2. Connect an MCP server that supplies an MCP App UI displaying a public HTTPS image. Declare that image origin in the UI resource's resourceDomains.
  3. Open the UI in Codex. The image fails with the error above.
  4. In that sandbox's DevTools Console, run the probe below using the same image URL. It returns result: "failed" and width: 0 with the same permission error.
  5. As a control, insert an ordinary <img> using that URL into a normal HTTPS website in Google Chrome. In the observed case it fires onload and displays the image at a natural size of 2048 × 2048. This is an embedded-image test, not just opening the URL in the address bar.

Minimal probe (replace the placeholder with your public HTTPS image URL):

await new Promise(resolve => {
  const img = new Image();
  const done = result => {
    clearTimeout(timer);
    resolve({
      origin: location.origin,
      result,
      width: img.naturalWidth,
      height: img.naturalHeight
    });
  };
  const timer = setTimeout(() => done("timeout"), 10000);
  img.onload = () => done("loaded");
  img.onerror = () => done("failed");
  img.src = "https://<public-image-host>/preview.webp";
});
Controlled DNS comparison

Before the change, local DNS returned a synthetic IPv4 address in 198.18.0.0/16 and a synthetic IPv6 address in fdfe:dcba:9876::/64 for the image hostname.

We temporarily added only that image hostname to dns.fake-ip-filter, reloaded mihomo, and verified that both the A and AAAA answers became public Cloudflare addresses. The user then confirmed that the image loaded successfully in Codex. The image URL, server response configuration, and MCP UI code were not changed.

The original VPN configuration was subsequently restored and its original file hash verified. DNS again returned synthetic addresses. A second browser failure after restoring the configuration has not yet been recorded.

This isolates synthetic DNS resolution as a trigger in this environment. It does not establish which address family the failing Chromium request used, or the exact internal permission-check path: the failed request's remote endpoint was not available in DevTools.

What is the expected behavior?

Public HTTPS images should remain usable in MCP App UIs in supported VPN/proxy environments, with the declared CSP enforced. Users should not need a per-image-host Fake-IP exclusion merely to view a public image.

If safe compatibility requires a host-mediated resource loader or explicit permission workflow, please provide/document that supported path rather than requiring widget authors to embed image bytes or users to change VPN settings. This is not a request to disable protection for actual private or loopback services.

Additional information
  • Normal Google Chrome used in the successful control: 152.0.7977.76.
  • Command-line HTTP requests returned 200, but these were reachability checks only; curl does not exercise Chromium's Local Network Access enforcement.
  • This report concerns the MCP App UI sandbox, not the CLI command-execution sandbox.
  • Related reports: #33539 (TUN/Fake-IP with in-app browser connection failure and crashes) and #34990 (in-app browser local-network permissions remaining denied). Neither appears to cover this specific MCP image-loading failure and controlled DNS comparison.
  • Private generated-image URLs, account information, and session/init identifiers are omitted.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No repository file or test is named. Start by reproducing the MCP App image failure with Clash/mihomo Fake-IP DNS and the provided new Image probe, then compare it with the filtered public DNS case. Done means public HTTPS images load in the sandbox without per-host Fake-IP exclusions while local-network protections remain enforced.

Written by the indexing model from the issue text.

Assessment

Domain
desktop, networking, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.