ulysses/scripts
@aaronjmars 108ee1e32b
fix(security): close DNS-rebinding hole on diffusion_server (wildcard CORS + missing Host check) (#347)
* fix(security): close DNS-rebinding hole on diffusion_server

scripts/diffusion_server.py used to ship `allow_origins=["*"]` with the
default `--host=127.0.0.1` bind. Combined, that left the OpenAI-compatible
image API reachable from any browser tab via DNS-rebinding: an attacker page
resolves its own domain to 127.0.0.1 mid-fetch, the browser forwards the
request to the loopback server, the server processes it (no Host check), and
the wildcard CORS reply lets the attacker page read the result + drive the
GPU. CWE-346 + CWE-942 + CWE-352 (DNS-rebinding bridge).

Fix:
  - Drop the wildcard CORS at module load (default-deny).
  - Install `TrustedHostMiddleware` with a loopback allowlist so DNS-rebound
    requests are rejected by the middleware before any route runs.
  - Add additive `--allowed-host` / `--allowed-origin` CLI flags so operators
    who need browser access on a specific origin can opt in explicitly without
    re-introducing the wildcard.

Tests: tests/test_diffusion_server_security.py (9 cases) pin the allowlist
helpers, the default-deny CORS behavior, and the live middleware paths via
Starlette's TestClient.

Detected by Aeon + semgrep + manual review.
Severity: medium.
CWE-346 / CWE-942 / CWE-352.

* test(diffusion-server): drive ASGI app via httpx, not TestClient portal

The TrustedHost/CORS integration tests used `with TestClient(app) as
client:`, whose context-manager form spins up an anyio blocking portal to
run the app lifespan. Under the repo's pytest setup (anyio plugin active, a
stray asyncio_mode option, no pytest-asyncio) that portal deadlocks —
`test_trusted_host_middleware_rejects_attacker_host` hung indefinitely in
review before emitting any assertion output.

Replace the TestClient usage with a tiny _asgi_get() helper that drives the
ASGI app over httpx.ASGITransport on a fresh event loop (asyncio.run). No
portal, no lifespan, no dependency on the host project's async test plugins.
Host is taken from the request URL so TrustedHostMiddleware sees the exact
hostname under test; Origin goes through headers. Assertions are unchanged.

Focused test now passes in 0.12s; full file 9 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: aeonframework <aeonframework@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 23:34:39 +01:00
..
_completion Odysseus v1.0 2026-05-31 23:58:26 +09:00
_lib Odysseus v1.0 2026-05-31 23:58:26 +09:00
demo_email Odysseus v1.0 2026-05-31 23:58:26 +09:00
add_hwfit_models.py Hwfit: estimate params from config.json fallback 2026-06-02 20:33:25 +09:00
check-docker-amd-gpu.sh Parse all AMD GPU check args (#1586) 2026-06-03 08:56:48 +09:00
check-docker-gpu.sh Improve Docker GPU setup diagnostics (#705) 2026-06-02 12:30:40 +09:00
claim_ownerless.py Skip invalid ownerless JSON rows (#1540) 2026-06-03 14:06:57 +09:00
diffusion_server.py fix(security): close DNS-rebinding hole on diffusion_server (wildcard CORS + missing Host check) (#347) 2026-06-06 23:34:39 +01:00
encode_previews.sh Odysseus v1.0 2026-05-31 23:58:26 +09:00
fix_paths.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
hf_download.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
index_documents.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
migrate_faiss_to_chroma.py Skip invalid FAISS migration JSON (#1547) 2026-06-03 14:11:49 +09:00
odysseus Require runnable dispatcher subcommands (#1585) 2026-06-03 08:56:56 +09:00
odysseus-backup Reject backup output inside data dir (#1587) 2026-06-03 08:38:27 +09:00
odysseus-calendar Handle missing calendar CLI relation (#1574) 2026-06-03 14:11:17 +09:00
odysseus-contacts Skip invalid contacts CLI rows (#1569) 2026-06-03 14:11:21 +09:00
odysseus-cookbook Reject invalid cookbook CLI state (#1531) 2026-06-03 14:11:56 +09:00
odysseus-docs Ignore non-string docs CLI content lengths (#1561) 2026-06-03 14:06:46 +09:00
odysseus-gallery Handle missing gallery album images (#1563) 2026-06-03 14:11:24 +09:00
odysseus-logs fix: logs CLI _resolve crashes on a non-string name (#1631) 2026-06-03 08:59:30 +09:00
odysseus-mail fix: odysseus-mail read crashes on an empty IMAP fetch payload (#1730) 2026-06-03 13:31:10 +09:00
odysseus-mcp Normalize stored MCP CLI JSON (#1554) 2026-06-03 14:11:35 +09:00
odysseus-memory Skip invalid memory CLI rows (#1552) 2026-06-03 14:11:42 +09:00
odysseus-notes Ignore invalid note CLI items (#1539) 2026-06-03 14:11:53 +09:00
odysseus-personal Skip invalid personal CLI index rows (#1571) 2026-06-03 14:06:42 +09:00
odysseus-preset Let preset set replace corrupt entries (#1650) 2026-06-03 14:10:58 +09:00
odysseus-research Research CLI: alias --status complete to the stored done value (#2515) 2026-06-05 08:50:33 +01:00
odysseus-sessions Normalize session CLI counters (#1578) 2026-06-03 08:57:41 +09:00
odysseus-signature Reject non-PNG signature export data (#1651) 2026-06-03 14:10:54 +09:00
odysseus-skills Skip invalid skills CLI rows (#1553) 2026-06-03 14:11:38 +09:00
odysseus-tasks Ignore non-string task CLI previews (#1559) 2026-06-03 14:06:49 +09:00
odysseus-theme Reject invalid theme CLI prefs (#1396) 2026-06-03 14:12:35 +09:00
odysseus-webhook Mask short webhook CLI tokens (#1558) 2026-06-03 14:11:28 +09:00
pr_blocker_audit.py tools: add read-only PR blocker audit helper 2026-06-04 12:51:48 +01:00
update_database.py Remove duplicate update database body (#1584) 2026-06-03 08:57:03 +09:00