Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions agentstore/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,26 @@ def _cors_origins() -> list[str]:
return ["*"]


def _allow_credentials_for(origins: list[str]) -> bool:
"""Only allow credentialed cross-origin requests for an explicit origin list.

Wildcard origin + allow_credentials=True is an unsafe combination: browsers
refuse a literal "*" on the response to a credentialed request, so CORS
middlewares (including Starlette's) work around that by reflecting back
whatever Origin header the request sent. That means any site can have its
origin accepted and make credentialed requests, which defeats CORS
entirely. Only enable credentials once real, explicit origins are
configured — never for the wildcard fallback above.
"""
return "*" not in origins


_ALLOWED_ORIGINS = _cors_origins()

app.add_middleware(
CORSMiddleware,
allow_origins=_cors_origins(),
allow_credentials=True,
allow_origins=_ALLOWED_ORIGINS,
allow_credentials=_allow_credentials_for(_ALLOWED_ORIGINS),
allow_methods=["*"],
allow_headers=["*"],
)
Expand Down
20 changes: 19 additions & 1 deletion tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from fastapi.testclient import TestClient
from langchain_core.messages import AIMessage

from agentstore.server import app
from agentstore.server import _allow_credentials_for, app


def test_health_returns_ok():
Expand Down Expand Up @@ -43,3 +43,21 @@ def test_chat_rejects_empty_query():
with TestClient(app) as client:
r = client.post("/api/chat", json={"query": ""})
assert r.status_code == 422


# ── CORS ─────────────────────────────────────────────────────────────────────
#
# Wildcard origin + allow_credentials=True is an unsafe combination: browsers
# refuse a literal "*" on a credentialed response, so CORS middlewares
# (including Starlette's) reflect back whatever Origin header the request
# sent instead — meaning any site could get its origin accepted and make
# credentialed requests, defeating CORS entirely. Credentials must only be
# enabled once explicit, non-wildcard origins are configured.


def test_wildcard_origin_disallows_credentials():
assert _allow_credentials_for(["*"]) is False


def test_explicit_origins_allow_credentials():
assert _allow_credentials_for(["https://example.com", "http://localhost:5173"]) is True
Loading