Harden API-token chat endpoint selection #598

Merged
alteixeira20 merged 2 commits from alteixeira20/harden-api-token-chat-endpoints into main 2026-06-01 20:15:52 +02:00
alteixeira20 commented 2026-06-01 17:33:22 +02:00 (Migrated from github.com)

Summary

Hardens /api/v1/chat endpoint selection for private/self-hosted deployments.

This PR tightens handling of API-token supplied OpenAI-compatible base_url values before Odysseus sends server-side chat traffic to them. The validator rejects URLs that point to localhost, private networks, link-local/metadata addresses, multicast, unspecified/reserved addresses, internal hostnames, or DNS names resolving to blocked addresses.

Configured admin-created ModelEndpoint rows remain trusted, so local/private providers such as Ollama, vLLM, llama.cpp, LAN, or Tailscale endpoints continue to work when explicitly configured inside Odysseus.

Changes

  • Add src/url_security.py with focused public HTTP(S) endpoint validation.
  • Validate direct API-token supplied /api/v1/chat base_url values before building the chat URL.
  • Scope /api/v1/chat configured endpoint fallback to the API token owner.
  • Allow token-owned fallback to use owned or shared/null-owner endpoints.
  • Restrict ownerless token fallback to shared/null-owner endpoints only.
  • Add focused tests for blocked URL classes, DNS-to-private blocking, and fallback endpoint scoping.

Motivation

I’m evaluating Odysseus for a private self-hosted deployment and wanted to harden this path before running it behind a reverse proxy / Cloudflare Access.

The goal is to keep the patch small, reviewable, and useful for deployment safety without changing normal admin-configured local model behavior.

Tests

  • python3 -m py_compile src/url_security.py routes/webhook_routes.py tests/test_api_chat_security.py
  • python3 -m pytest tests/test_api_chat_security.py
  • git diff --check

Notes

This intentionally does not change admin-configured model endpoint behavior. Private/local model endpoints remain supported when created through Odysseus admin settings.

Redirect-aware URL validation is intentionally out of scope for this PR because /api/v1/chat does not follow redirects in this path.

## Summary Hardens `/api/v1/chat` endpoint selection for private/self-hosted deployments. This PR tightens handling of API-token supplied OpenAI-compatible `base_url` values before Odysseus sends server-side chat traffic to them. The validator rejects URLs that point to localhost, private networks, link-local/metadata addresses, multicast, unspecified/reserved addresses, internal hostnames, or DNS names resolving to blocked addresses. Configured admin-created `ModelEndpoint` rows remain trusted, so local/private providers such as Ollama, vLLM, llama.cpp, LAN, or Tailscale endpoints continue to work when explicitly configured inside Odysseus. ## Changes - Add `src/url_security.py` with focused public HTTP(S) endpoint validation. - Validate direct API-token supplied `/api/v1/chat` `base_url` values before building the chat URL. - Scope `/api/v1/chat` configured endpoint fallback to the API token owner. - Allow token-owned fallback to use owned or shared/null-owner endpoints. - Restrict ownerless token fallback to shared/null-owner endpoints only. - Add focused tests for blocked URL classes, DNS-to-private blocking, and fallback endpoint scoping. ## Motivation I’m evaluating Odysseus for a private self-hosted deployment and wanted to harden this path before running it behind a reverse proxy / Cloudflare Access. The goal is to keep the patch small, reviewable, and useful for deployment safety without changing normal admin-configured local model behavior. ## Tests - `python3 -m py_compile src/url_security.py routes/webhook_routes.py tests/test_api_chat_security.py` - `python3 -m pytest tests/test_api_chat_security.py` - `git diff --check` ## Notes This intentionally does not change admin-configured model endpoint behavior. Private/local model endpoints remain supported when created through Odysseus admin settings. Redirect-aware URL validation is intentionally out of scope for this PR because `/api/v1/chat` does not follow redirects in this path.
sleepy merged commit 4f05df8c6f into main 2026-06-01 20:15:52 +02:00
Owner

Merged via squash. URL validator blocks internal/private/metadata/loopback/multicast addresses including DNS-resolved private IPs. Fallback endpoint scoping tightened to owned-or-shared-only. 16 tests pass.

Merged via squash. URL validator blocks internal/private/metadata/loopback/multicast addresses including DNS-resolved private IPs. Fallback endpoint scoping tightened to owned-or-shared-only. 16 tests pass.
Sign in to join this conversation.
No description provided.