Skip to content

fix(dev): restrict default CORS origins and WebSocket allowed origins to localhost#1222

Open
g0w6y wants to merge 3 commits into
google:mainfrom
g0w6y:fix/dev-server-wildcard-cors-websocket-origin
Open

fix(dev): restrict default CORS origins and WebSocket allowed origins to localhost#1222
g0w6y wants to merge 3 commits into
google:mainfrom
g0w6y:fix/dev-server-wildcard-cors-websocket-origin

Conversation

@g0w6y

@g0w6y g0w6y commented May 26, 2026

Copy link
Copy Markdown

Problem

The dev server (AdkWebServer / adk web) ships two independent wildcard origin policies:

  1. HTTP CORSAdkWebCorsProperties falls back to ["*"] when no origins are configured, so every response carries Access-Control-Allow-Origin: *. Any page on the internet can therefore read agent responses cross-origin.

  2. WebSocket (/run_live)WebSocketConfig calls .setAllowedOrigins("*"), making the endpoint accept upgrade requests from any Origin header. This allows Cross-Site WebSocket Hijacking (CSWSH): a malicious page can open a live session against a dev server that is reachable from the victim's browser.

Combined, these let a remote origin read HTTP responses and drive the agent over WebSocket without any user interaction beyond visiting a page.

Fix

AdkWebCorsProperties.java – change the default origins fallback from ["*"] to ["http://localhost:8080", "http://127.0.0.1:8080"]. The dev UI (served on the same host) continues to work; all other origins are blocked by the browser.

WebSocketConfig.java – inject AdkWebCorsProperties and derive setAllowedOrigins from the same property instead of a separate hardcoded wildcard, so both policies stay in sync. Users who need a broader origin allowlist can set adk.web.cors.origins explicitly in their application properties.

Impact

  • No change to users running the standard dev workflow (UI on localhost:8080).
  • Users who access the dev server from a custom host/port need to add that origin via adk.web.cors.origins.
  • Eliminates wildcard CORS and CSWSH exposure on /run_live for all default-configuration deployments.

… to localhost

The dev server defaulted to a wildcard CORS policy (Access-Control-Allow-Origin: *)
and registered the /run_live WebSocket endpoint with setAllowedOrigins("*"). Any page
loaded from an arbitrary origin could therefore read HTTP responses and complete a
cross-origin WebSocket handshake against a locally running dev server, giving a remote
site read and drive access to the agent.

- AdkWebCorsProperties: change the default allowed-origins fallback from ["*"] to
  ["http://localhost:8080", "http://127.0.0.1:8080"] so the dev UI keeps working out
  of the box while all other origins are rejected by the browser.
- WebSocketConfig: inject AdkWebCorsProperties and derive the WebSocket allowed-origins
  list from the same property, eliminating the separate hardcoded wildcard and keeping
  both policies in sync. Users who need a broader allowlist can set
  adk.web.cors.origins explicitly.
@hemasekhar-p hemasekhar-p self-assigned this Jun 1, 2026
@hemasekhar-p

Copy link
Copy Markdown
Contributor

Hi @g0w6y, Thank you for your contribution! We appreciate you taking the time to submit this pull request. Currently this PR is under review by our team, we will keep you posted if any additional information is required. thank you.

@hemasekhar-p

Copy link
Copy Markdown
Contributor

@sherryfox, Could you please review this.

Comment thread dev/src/main/java/com/google/adk/web/config/AdkWebCorsProperties.java Outdated
@krwc krwc added needs update waiting on reporter Waiting for reaction by reporter. Failing that, maintainers will eventually closed it as stale. and removed needs review labels Jun 29, 2026
Replace the hardcoded :8080 default origins with the localhost
port-wildcard pattern (http://localhost:[*], http://127.0.0.1:[*]) so the
allowlist no longer assumes the server runs on 8080 (it may run on any
port, e.g. ng serve on 4200 or a user-set server.port).

Switch both origin sinks from setAllowedOrigins to setAllowedOriginPatterns
(AdkWebCorsConfig HTTP CORS and WebSocketConfig /run_live), since the [*]
port pattern is only honored by the *Patterns API; with setAllowedOrigins
it would be treated as a literal and match nothing.

Security posture is unchanged: any localhost port is allowed, while remote
origins, suffix tricks (evil.localhost.com) and non-http schemes remain
blocked.
@g0w6y g0w6y requested a review from krwc June 29, 2026 16:35
@krwc

krwc commented Jul 1, 2026

Copy link
Copy Markdown

Thanks for iterating on this @g0w6y, and sorry for the extra round-trip.

We've discussed this with the team, and realized that if we changed the default origins now to a fixed list of hosts, we would potentially break existing customers' workflow. Admittedly, * is not the best choice as a default, and should be changed in the future major release (we track this internally now), however for now, we'd like to retain backwards compatibility.

As such, I'd propose to do the following:

  1. Let's keep the default as * (no change wrt to HEAD)
  2. Let's also use the origins for websockets (new behaviour).
  3. Let's add a warning log that using * is not secure by default and that it should be changed via origins field by the user.

While it doesn't address the originally stated goal, it leaves a way for the user to configure it correctly, so it's still an improvement compared to the current state.

… warn on '*'

Per review, retain backwards compatibility instead of changing the default
origin allowlist:

- Revert the default origins back to "*" (no change vs HEAD).
- Derive the /run_live WebSocket allowed origins from adk.web.cors.origins
  instead of a hardcoded "*", so both HTTP CORS and the WebSocket can be
  locked down via the single property.
- Log a startup WARN when origins is "*", noting it is insecure (dev only)
  and pointing users to set adk.web.cors.origins.
@g0w6y

g0w6y commented Jul 1, 2026

Copy link
Copy Markdown
Author

Done, updated per the team's decision:

  1. Default origins kept as * (no change vs HEAD).
  2. /run_live now derives its allowed origins from adk.web.cors.origins instead of a hardcoded *, so both HTTP CORS and the WebSocket are controlled by the single property.
  3. Added a startup WARN when origins is *, flagging it as insecure (dev only) and pointing users to set adk.web.cors.origins.

Net diff is 2 files and default behaviour is unchanged. Verified against Boot 4.0.2 / Spring 7.0.3: with the default the WARN fires and * still allows all origins; with an explicit list (e.g. http://localhost:4200) there is no warning and remote origins are blocked.

@g0w6y

g0w6y commented Jul 1, 2026

Copy link
Copy Markdown
Author

Hi @krwc, could you please review the latest changes when you have a moment?

Also, would the team consider publishing a GitHub Security Advisory for this, so the wildcard CORS and WebSocket origin exposure is tracked publicly? Happy to help with the writeup if useful. Thank you.

@krwc krwc added ready to pull and removed waiting on reporter Waiting for reaction by reporter. Failing that, maintainers will eventually closed it as stale. needs update labels Jul 2, 2026
@krwc

krwc commented Jul 2, 2026

Copy link
Copy Markdown

Hi @g0w6y! Thanks for updating the PR. Should get merged soon :-)

Answering your question: the intent behind ADK Web Server is to be for development purposes only (link, direct quote: ADK Web is not meant for use in production deployments. You should use ADK Web for development and debugging purposes only).

As such we're not convinced it deserves Github Security Advisory. LMK what you think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants