Open dev tools on almost any n8n Chat Trigger widget and you'll find the webhook URL sitting in plain text, either in the page source or in the first XHR request the widget fires. Anyone who views source gets a live URL that talks directly to your n8n instance.
That's the actual problem. Not "is n8n secure," but "why does my chat widget hand out the address of my automation server to every visitor, and what do I do about it."
What "exposing a webhook URL" actually means
An n8n webhook node generates a URL like https://your-instance.app.n8n.cloud/webhook/abc123. That URL is the entire authentication model. Anyone who has it can POST to it directly, no login, no API key, nothing standing between them and your workflow.
The n8n Chat Trigger widget is designed to call that URL straight from the browser. That means the URL has to ship in client-side JavaScript. There's no version of "embed a chat widget that calls n8n directly" where the URL doesn't end up in the browser, because the browser is the thing making the request.
Once it's out, three things follow. People scrape it and call your webhook from scripts, curl, or Postman, outside your widget entirely. Your workflow runs on whatever traffic shows up, and any spend behind it (OpenAI calls, paid APIs) runs with it. And if the workflow does anything sensitive, the webhook URL is the only thing standing between "chat widget" and "unauthenticated API into my internal automation."
This isn't a hypothetical. A CORS thread on n8n's own forum about the Chat Trigger embed is one of more than ten separate threads on the same failure mode since 2023. People trying to lock the widget down to their own domain keep hitting it, which tells you the "just restrict origins" answer isn't holding up in practice.
Why CORS and origin checks don't hide anything
The instinctive fix is to lock down allowed origins in n8n's webhook settings, or drop a Cloudflare rule in front of it. Worth doing. Doesn't hide the URL.
CORS is a browser-enforced policy that stops browsers from reading cross-origin responses. It does nothing to stop a request sent with curl, a Python script, or Postman, none of which are browsers and none of which care what your Access-Control-Allow-Origin header says. The URL is still sitting in your page source either way.
One n8n user building a public-facing chatbot asked exactly this on the forum: "what you guys do to avoid potential DDOS and save credits". The answer they landed on was hand-rolling a Cloudflare WAF rule plus JS obfuscation on top of it. Obfuscated JavaScript still runs in the browser, so the URL is still extractable, just with extra steps. That's a real workaround, and also a sign the actual fix (never sending the URL to the browser in the first place) doesn't exist yet in n8n itself.
The correct fix: don't let the browser see the URL at all
If the webhook URL should never be scraped, the browser should never receive it. That means putting something between the chat widget and n8n: a proxy that holds the real webhook URL server-side, and gives the browser a different address to talk to.
The browser calls your proxy. Your proxy calls n8n. The webhook URL never crosses the network boundary into client-side code, so there's nothing in page source or dev tools to copy.
This is also where the rate-limiting problem gets solved for free, because you now have a place to put it. n8n's own core doesn't give you fine-grained control here, which shows up constantly on the forum: one thread asks for an env variable to raise n8n's hardcoded 5-concurrent-webhook-call limit, another describes a single Shopify product update firing multiple parallel executions that burst-call OpenAI and eat 429s. A proxy layer is the natural place to dedupe, throttle, and queue before any of that reaches n8n.
Building that proxy yourself
Nothing here is exotic. A minimal version is a few lines: a Cloudflare Worker or small Express app with one route, forward the POST body, add the real webhook URL from an environment variable, return the response.
The gap is everything past "it forwards requests." A proxy that's actually safe to point at the internet needs:
- Origin validation and domain allowlisting, so only your embedded widget can call it, not any random site that finds the proxy URL.
- Rate limiting per IP and per session, or you've just moved the DDoS problem one layer over.
- Signed sessions, so a client can't replay someone else's session or spoof one.
- SSRF protection, since a proxy that accepts a target and forwards it is a classic SSRF vector if it's ever made configurable.
- Somewhere to run it, and someone to patch it.
None of this is hard individually. Together, it's a small backend service you now own: infra, monitoring, and security patching included. If you're running this for one internal workflow, that might be a reasonable Friday afternoon. If you're an agency running this setup for fifteen clients, you're maintaining fifteen copies of it, or one shared instance you now have to make multi-tenant.
That second case comes up a lot. Agencies ask n8n directly how to white-label and manage multiple clients from one setup, and the answer from n8n's own team is usually a pointer to the enterprise Embedded license just to get a per-client dashboard: "this sounds like you might need our Embedded license. Please contact our Sales team". Another agency owner asked if a single Pro plan could serve multiple clients and was told "your clients will need separate instances". If the proxy needs to serve more than one client, roll-your-own stops being a Friday afternoon and starts being a product.
Using a hosted gateway instead
This is the exact gap ChatFlowGate is built for: a gateway that sits between your chat widget and your n8n webhook so the browser never sees the real URL, without you standing up and patching your own proxy.
The webhook URL is stored server-side and never sent to the client. Origin validation and domain allowlisting are built in. Requests get HMAC-SHA256-signed, bot-bound sessions with a 24-hour expiry, so a scraped session token isn't a standing key to your workflow. Rate limiting runs as a token bucket per IP and per session, so a Shopify-style burst or a scraper hitting the endpoint gets throttled before it reaches n8n. SSRF protection includes DNS resolution checks. IP banning, country allow/block lists, and spam traps handle abuse at the edge. And no chat content gets stored, only metadata, so you're not adding a new place for conversation data to leak.
For agencies, the workspace model handles the case n8n's own team keeps redirecting to their enterprise license: one white-labeled widget per client (colors, logo, greeting, RTL), run from shared multi-tenant infrastructure instead of a separate n8n instance or a paid-for Embedded license per client.
To set it up:
- Create a bot in ChatFlowGate and paste in your existing n8n webhook URL. It's stored server-side, never returned to the browser.
- Set your allowed origins to the domain(s) the widget will run on.
- Drop in the one-script embed. It talks to ChatFlowGate's gateway, not your n8n instance.
- Your n8n workflow doesn't change. It still receives a webhook call, just from the gateway instead of directly from a browser.
Free tier covers 500 messages a month on one bot, enough to try it against a real workflow before deciding anything.
FAQ
Does hiding the webhook URL replace n8n's own security settings?
No. Keep IP allowlisting, basic auth, or any other protection you already have on the n8n side. A gateway removes the browser as an exposure point; it doesn't replace defense on the n8n side.
Will this work with n8n Cloud, or only self-hosted?
Both. The gateway only needs the webhook URL, and n8n Cloud and self-hosted instances both expose one in the same format.
Does CORS configuration alone hide the webhook URL?
No. CORS stops browsers from reading cross-origin responses, but the URL is still visible in your page's source and network requests, and CORS does nothing against requests sent outside a browser (curl, scripts, Postman).
What if I only have one workflow and one client?
A small serverless function you write and maintain yourself is a reasonable option at that scale. The build-your-own-proxy math changes once you add rate limiting, signed sessions, SSRF checks, and a second client to manage.
If you're currently staring at a webhook URL in your own dev tools, that's the thing to fix first. chatflowgate.com has the docs for the embed and the free tier if you want to see the proxy behavior against a live n8n workflow.

Top comments (0)