Webhook returns 403 host_not_allowed when called via browser fetch since update to 1.123.69

Since today (19.08.2026) our dashboard stopped working. We serve an HTML page via an n8n webhook that uses a browser fetch() call to retrieve data from a second n8n webhook on the same instance.

This setup worked fine until today. After what appears to be an automatic update to version 1.123.69, the browser fetch returns “signal is aborted without reason”. When we test the data webhook URL directly in the browser, it returns data correctly.

From a server-side curl test we get: 403 host_not_allowed with header x-deny-reason: host_not_allowed.

The data webhook is active, credentials are correct, CORS header Access-Control-Allow-Origin: * is set. Toggling the workflow active/inactive does not fix it permanently.

This appears to be a breaking change in 1.123.69 that blocks self-referencing webhook calls from browser clients on the same n8n Cloud instance.

Can you please advise or revert this behavior?

Hey @Anne_See, while you wait for a response, here are some things that might help:

Suggested resources

Automatically matched to your question.

Docs:

Forum:

@Anshul_Namdev, @encryptman, @jabbson - you’ve helped with similar issues before, can you take a look?

Automatically suggested by n8n’s community bot. It’s a pilot - please share feedback here.

Hi @Anne_See Welcome!
The 403 isn’t from n8n. x-deny-reason: host_not_allowed with server: envoy is an egress proxy allowlist rejecting the destination before the request leaves the machine you ran curl from, which is why the same URL returns data fine in a browser.
Since 1.103.0 n8n wraps HTML webhook responses in a sandboxed <iframe>, and the binary response path skipped that wrapping until it was patched in 1.123.55, so your dashboard page is sandboxed now where it wasn’t before. Inside the sandbox the document has an opaque origin, so relative URLs stop resolving and the call to the data webhook is no longer same origin.
Make the fetch URL absolute rather than relative, and set CORS from the data webhook’s own option instead of a manual response header: open the Webhook node, Add Option > Allowed Origins (CORS), set it to *. If the fetch sends credentials: 'include', drop it, * and credentials can’t be combined.

Both webhooks now have Allowed Origins set to *. The fetch URL is absolute. No credentials: include. Still getting signal aborted. The sandbox restriction seems to be blocking the fetch regardless of CORS settings.

Plus: I simply don’t understand why the system crashed from Tuesday afternoon to yesterday without any minor or major changes internally…

The sandbox is applied to the response as a CSP header, and the only switch for it, N8N_INSECURE_DISABLE_WEBHOOK_IFRAME_SANDBOX, is an env var you can’t set on Cloud, so no combination of CORS options gets the page out of it. Build the data into the page instead of fetching it: in the dashboard workflow, put the nodes the data webhook runs in front of the response, pass their output into an HTML node (Generate HTML template) and interpolate the values with {{ }}, then Respond to Webhook with Content-Type text/html. The page then arrives with its data already in it and makes no request of its own.
For refresh, a plain link back to the page URL with no target attribute re-runs the workflow:

<a href="https://your-instance.app.n8n.cloud/webhook/your-dashboard-path">Refresh</a>

Nothing changed on your side, the workspace picked up a new release on its update track, which you can set under Manage > Workspace > Updates & maintenance.

The CSP sandbox only applies to pages n8n itself serves, so the fetch pattern still works if the HTML stops coming out of a webhook. Host that dashboard page on any static host (GitHub Pages, Cloudflare Pages, your own web server) and leave the data webhook exactly as it is, then in that Webhook node’s options set Allowed Origins (CORS) to the page’s origin instead of *.

The page is then on a normal origin, so the preflight passes and the call is no longer aborted. On the timing question: Cloud takes patch releases automatically, which is why the response wrapping changed on Tuesday with no change on your side.

Open the page from the new host and check the Network tab shows the data webhook returning 200 instead of an aborted request.

One thing I’d try next is separating the two failures completely. Put the same absolute fetch call into a tiny static HTML file outside n8n, even locally, and call the data webhook from there. If that works, the data webhook and CORS are probably fine and the problem is the HTML webhook wrapper/sandbox. If it fails there too, the Network tab should show the real request URL, status, and blocked reason. As a workaround, I’d avoid having an n8n-served HTML webhook call a sibling webhook until this is clearer: either return the dashboard data from the same webhook response or host the thin HTML page somewhere outside n8n and let n8n only serve JSON.

The data webhook returning 200 in a raw browser tab and aborting from the HTML page is the reporting handoff: n8n is serving the dashboard and then blocking the page from calling itself.

Next diagnostic: save a 10-line HTML file on your laptop that fetch()es the data webhook with the same absolute URL. If that works, stop fighting CORS on Cloud and either bake the numbers into the HTML response (one webhook) or host the page off n8n. If that local file also aborts, the data webhook isn’t actually open to that Origin.

What settles it: Network tab showing the data webhook 200 from a page that is not served by n8n, plus a screenshot of the fields the dashboard actually needs. Until that 200 exists outside the sandbox, changing CORS on Cloud won’t bring the dashboard back.

Thanks for all your input - highly appreciated :slight_smile: