DeepTutor: any-origin CORS opens the admin API to websites
DeepTutor - credentialed CORS for any origin in the default no-auth mode lets any website call admin API routes, including one that starts a host command, and the web_fetch SSRF guard can be bypassed by DNS rebinding (GHSA-22fg-5qwc-4cpg)
Unpatched. Reported privately via GitHub Security Advisory on 2026-07-17; the 90-day coordinated-disclosure window passed, and the final 2026-11-03 deadline set in our 2026-10-20 notice expired with no response from the maintainer. Related hardening landed since the report (catalog API keys are now redacted and the old tool execute endpoint was removed), but the core CORS issue remains.
- Product
- DeepTutor (FastAPI backend) in HKUDS/DeepTutor
- Affected versions
- DeepTutor through v1.7.1 and main (checked at HEAD f7aed07).
- Severity
- HIGH
- Status
- Unpatched
- Weaknesses
- CWE-306Missing Authentication for Critical Functionality
- CWE-346Origin Validation Error
- CWE-942Permissive Cross-domain Security Policy with Untrusted Domains
- GitHub advisory
- GHSA-22fg-5qwc-4cpg
Private; in triage, not yet published by the maintainer - CVE
- Pending (requested via MITRE CNA-LR)
- Published
- Credit
- Finder: Aaron Elijah Mars of Aeon. Tool: Aeon (https://www.aeon.fun).
What operators should do now
No upstream patch is available yet. Anyone running DeepTutor, even only on their own machine, should apply one of these mitigations until an official fix is released.
- Turn authentication on (
AUTH_ENABLED=true). In that mode the any-origin regex is not used and cross-origin requests are limited to the frontend origins plus any you list inCORS_ORIGINorCORS_ORIGINS. - If you keep authentication off, apply the small patch from our report: in
_build_cors_settingsindeeptutor/api/main.py, stop settingallow_origin_regextohttps?://.*and limit CORS to the configured frontend origins in every mode. Add remote Docker or LAN frontends throughCORS_ORIGINSinstead. - Do not browse untrusted sites in the same browser while a no-auth DeepTutor backend is running, and stop the backend when you are not using it.
- Review the MCP server registry (Settings, MCP) for stdio servers you did not add, and rotate the provider API keys configured in DeepTutor if you suspect it was reached cross-origin.
- For the
web_fetchtool, patchdeeptutor/tools/web_fetch.pyto resolve the host once, check every address, and connect to that checked address, or block private and link-local ranges at the network level for the DeepTutor process.
Impact and reach
Any DeepTutor backend running with authentication off is exposed to every web page its user opens, as far as the browser lets public pages reach the backend's address. A backend reachable over a LAN or a remote Docker host, which is the setup the permissive default exists for, is the easiest case. Because require_admin treats every caller as admin when authentication is off, the page reaches the same admin routes the DeepTutor frontend uses and can read the answers.
Based on code review, that includes POST /api/settings/mcp/test, which connects to the MCP server described in the request body; for a stdio server that means running its command on the host as the DeepTutor user. The rest of the admin settings surface, including the MCP registry and model provider settings, is reachable the same way. The web_fetch rebinding gap lets content that steers the agent make the server fetch internal or metadata addresses. A working exploit is withheld.
How the CORS policy and admin gate combine
_build_cors_settings returns the regex https?://.* whenever authentication is off, and the app installs CORSMiddleware with that regex, allow_credentials=True, and every method and header allowed. CORSMiddleware echoes back any matching Origin, so every website gets a credentialed allow. The admin dependency then accepts every request in no-auth mode:
- Any-origin regex when auth is off: deeptutor/api/main.py#L95-L99
- CORSMiddleware with credentials and all methods and headers: deeptutor/api/main.py#L485-L492
- require_admin treats every caller as admin when auth is off: deeptutor/api/routers/auth.py#L622-L643
- MCP settings router gated only by require_admin: deeptutor/api/routers/mcp_settings.py#L34
- MCP test route probes the server from the request body: deeptutor/api/routers/mcp_settings.py#L121-L133
- Stdio transport starts the configured command: deeptutor/services/mcp/manager.py#L779-L789
- web_fetch checks the host with its own DNS lookup, then the client resolves again: deeptutor/tools/web_fetch.py#L178-L210 and web_fetch.py#L117-L134
Disclosure timeline
- Vulnerability reported privately via GitHub Security Advisory (GHSA-22fg-5qwc-4cpg).
- First follow-up comment posted on the advisory (32 days in triage).
- Second follow-up comment posted on the advisory (62 days in triage).
- Coordinated-disclosure notice posted on the advisory after the 90-day window passed, setting a deadline of 2026-11-03. The notice acknowledged the related hardening (catalog API key redaction, removal of the old tool execute endpoint).
- Coordinated-disclosure deadline expired with no response from the maintainer; sink verified still present at HEAD f7aed07 and in release v1.7.1.
- Public advisory published; CVE requested via MITRE CNA-LR.
References
- Affected repository: HKUDS/DeepTutor
- GitHub Security Advisory: GHSA-22fg-5qwc-4cpg (private; in triage)