You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 5e7ef3e
Browse filesBrowse the repository at this point in the historyBrowse files
authored
fix: Restrict UI server CORS to trusted origins (#6986)
* fix: Restrict UI server CORS to trusted origins
The Feast UI server configured CORS with allow_origins=["*"] together with
allow_credentials=True, so any website a user visited could issue
authenticated cross-origin requests to the server and read the responses
(CVE-2024-11602 / CWE-346, Origin Validation Error).
The bundled Web UI is served from the same FastAPI app as the API, so it is
same-origin and needs no permissive CORS policy. Disable CORS by default and
let operators opt in to cross-origin access with an explicit allowlist of
trusted origins. Following MLflow's convention, this is exposed as
`feast ui --cors-allowed-origins` or the FEAST_UI_CORS_ALLOWED_ORIGINS
environment variable (comma-separated). The wildcard origin is never combined
with credentials again.
Signed-off-by: ntkathole <[email protected]>
* ci: Use pinned env for unit tests to fix protobuf gencode/runtime skew
The unit-test-python jobs install an exact, mutually compatible dependency
set via `uv pip sync` from the pinned pyXX-ci-requirements.txt
(protobuf==7.36.2 alongside grpcio-health-checking==1.84.0, whose generated
code targets protobuf gencode 7.35.1).
The Test Python step then runs `uv run`, which auto-syncs the environment.
Because uv.lock is not committed, that sync re-resolves the uncapped
pyproject dependencies (`protobuf>=4.24.0`) and leaves the environment with
protobuf 6.33.6 while grpcio's health_pb2 still targets gencode 7.35.1. Every
test that imports grpc_health/v1/health.proto (registry/UI/MCP/feature-server
servers) then fails at import time with:
VersionError: ... grpc_health/v1/health.proto: gencode 7.35.1 runtime
6.33.6. Runtime version cannot be older than the linked gencode version.
Set UV_NO_SYNC=1 for the step so `uv run` uses the already-installed, pinned
environment instead of re-resolving. This is unrelated to the CORS change in
this PR; it is a pre-existing CI hazard that surfaces for any test importing
the health proto.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: ntkathole <[email protected]>
* ci: Disable uv auto-sync for all Makefile test targets
The previous commit set UV_NO_SYNC only for the unit-test workflow step. The
same protobuf gencode/runtime skew also breaks every other uv-based test
workflow (integration-test-python-local, and the label-gated
integration/remote-rbac/dbt/master/nightly jobs), because they all run
`make install-python-dependencies-ci` (pinned `uv pip sync`) followed by a
`make test-python-*` target that invokes `uv run`, which auto-syncs and
re-resolves the uncapped pyproject deps.
Export UV_NO_SYNC=1 from the Makefile so every `uv run` recipe uses the
already-installed, pinned environment instead of re-resolving. pixi-based
targets (ray/duckdb/registration) are unaffected. This generalizes the
unit-test fix to all uv-based test targets in one place; the unit-test
workflow keeps its step-level env because it also runs a standalone `uv run`
outside make.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: ntkathole <[email protected]>
* fix: Warn on wildcard CORS origin and document origin format
Address review feedback on the CORS allowlist:
- When `*` is configured (an explicit, opt-in operator choice, like Feast's
own documented `auth_type=no_auth`), keep honoring it but log a warning:
with credentials, Starlette reflects the caller's origin for any site, so
the wildcard is intended for local development only. This keeps the operator
in control while making the risk visible instead of silent.
- Document that each origin must be a bare scheme+host[:port] with no path or
trailing slash, since browsers send the Origin header without a path and a
value like `https://app.example.com/ui` would silently never match.
- Add a unit test asserting `*` is accepted and warns.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: ntkathole <[email protected]>
---------
Signed-off-by: ntkathole <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: Jitendra Yejare <[email protected]>
Copy file name to clipboardExpand all lines: docs/reference/alpha-web-ui.md
+34Lines changed: 34 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,11 +30,45 @@ Options:
30
30
-h, --host TEXT Specify a host for the server [default: 0.0.0.0]
31
31
-p, --port INTEGER Specify a port for the server [default: 8888]
32
32
-r, --registry_ttl_sec INTEGER Number of seconds after which the registry is refreshed. Default is 5 seconds.
33
+
--cors-allowed-origins TEXT Comma-separated list of trusted origins allowed to make cross-origin (CORS) requests.
33
34
--help Show this message and exit.
34
35
```
35
36
36
37
This will spin up a Web UI on localhost which automatically refreshes its view of the registry every `registry_ttl_sec`
37
38
39
+
#### Cross-Origin Resource Sharing (CORS)
40
+
41
+
By default the UI server does **not** allow cross-origin requests: the bundled
42
+
Web UI is served from the same origin as the API, so it keeps working without
43
+
any CORS policy. This avoids [CVE-2024-11602](https://nvd.nist.gov/vuln/detail/CVE-2024-11602),
44
+
where the server previously reflected every origin (`Access-Control-Allow-Origin: *`)
45
+
together with credentials, letting any site a user visited issue authenticated
46
+
requests to the server.
47
+
48
+
If you host the UI (or another browser client) on a different origin, opt in by
49
+
passing an explicit allowlist of trusted origins, either with the
50
+
`--cors-allowed-origins` flag or the `FEAST_UI_CORS_ALLOWED_ORIGINS`
Each value must be a bare origin — scheme and host with an optional port, and
62
+
**no path, query, or trailing slash** (e.g. `https://app.example.com` or
63
+
`http://localhost:3000`, not `https://app.example.com/ui`). Browsers send the
64
+
`Origin` header without a path, so a value that includes one never matches and
65
+
the request is silently rejected.
66
+
67
+
For production, list the exact origins you trust. Passing `*` is accepted but
68
+
**allows credentialed cross-origin requests from any site** (the CVE-2024-11602
69
+
pattern) and is intended for local development only; the server logs a warning
70
+
when it is used.
71
+
38
72
#### Curl Generator Feature Server URL
39
73
40
74
The Curl Generator uses a default Feature Server URL when building the example curl command. You can configure
Copy file name to clipboardExpand all lines: sdk/python/feast/cli/ui.py
+21Lines changed: 21 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -44,6 +44,22 @@
44
44
show_default=False,
45
45
help="path to TLS(SSL) certificate public key. You need to pass --key arg as well to start server in TLS mode",
46
46
)
47
+
@click.option(
48
+
"--cors-allowed-origins",
49
+
"cors_allowed_origins",
50
+
type=click.STRING,
51
+
default="",
52
+
envvar="FEAST_UI_CORS_ALLOWED_ORIGINS",
53
+
show_default=False,
54
+
help=(
55
+
"Comma-separated list of trusted origins allowed to make cross-origin "
56
+
"(CORS) requests to the UI server, e.g. "
57
+
"'https://feast.example.com,https://app.example.com'. May also be set "
58
+
"via the FEAST_UI_CORS_ALLOWED_ORIGINS environment variable. By default "
59
+
"no cross-origin requests are allowed. Avoid '*', which combined with "
60
+
"credentials exposes the server to CVE-2024-11602."
61
+
),
62
+
)
47
63
@click.pass_context
48
64
defui(
49
65
ctx: click.Context,
@@ -52,6 +68,7 @@ def ui(
52
68
root_path: str="",
53
69
tls_key_path: str="",
54
70
tls_cert_path: str="",
71
+
cors_allowed_origins: str="",
55
72
):
56
73
"""
57
74
Shows the Feast UI over the current directory
@@ -60,11 +77,15 @@ def ui(
60
77
raiseclick.BadParameter(
61
78
"Please configure --key and --cert args to start the feature server in SSL mode."
0 commit comments