# LoopX serve-status permissive CORS policy exposes control-plane state and private Markdown files

LoopX serve-status sends ACAO:* on all read routes, letting any visited website read control-plane status and private Markdown files from localhost.

- Payout: Research
- Severity: high
- Program: LoopX
- Found by: aeonframework
- Disclosed: 2026-10-19
- CVE: CVE-2026-108372
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-vx2m-gpq4-8j5q
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-vx2m-gpq4-8j5q
- Tags: area:os domain:desktop domain:web impact:data-leak kind:research platform:ghsa sev:high tech:python technique:source-review vuln:cors vuln:info-disclosure

**Target:** Local HTTP status server (loopx serve-status) on loopback ports 8765/8766
**Root cause:** `_send_json()` unconditionally emits `Access-Control-Allow-Origin: *` for every route, including unauthenticated GET endpoints, so any origin can read responses from the fixed loopback port.
**Steps:**
1. Run `loopx serve-status` (default port 8765, or `--global-registry --port 8766`).
2. From a page on any origin, `fetch('http://127.0.0.1:8766/status.json')` — response carries `ACAO: '*'`, exposing goal ids, run history, and absolute paths (`registry`, `runtime_root`).
3. Enumerate `s.goals` and `fetch('http://127.0.0.1:8766/review-material?goal_id=<id>&path=design-notes.md')` to read Markdown content verbatim.
4. Optionally `POST /control-plane/configure-goal/dry-run` cross-origin (no Origin check, preflight allowed via `Access-Control-Allow-Headers: Content-Type`) to leak before/after config (`written=false`).
**How found:** Manual dataflow review of the status server; noticed `_send_json` is the single response path and hardcodes the wildcard, then tried to refute it by testing writes, traversal, extension allowlist and dry-run write behavior — all held, confining impact to reads.
**Exploitation:** Attacker hosts a page; when an operator with the persistent LaunchAgent-installed service visits it, plain fetch() calls to the hardcoded loopback ports exfiltrate status JSON and private .md files with no interaction or credentials.
**Insight:** When a localhost dashboard is served from a different loopback port, devs often add `ACAO: *` to make it work; check every shared response helper for a wildcard and confirm which routes lack Origin checks entirely (here the dry-run POST).

