Skip to content
Open
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
4 changes: 4 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@
**Vulnerability:** The `extract_project` endpoint in `backend/main.py` used a generic exception handler that directly returned the string representation of any caught exception (via `detail=str(e)`) in a 400 Bad Request response.
**Learning:** Returning `str(e)` directly to API clients can unintentionally expose internal system details, tracebacks, database schema info, or file paths, leading to Information Leakage. Additionally, placing a broad `except Exception` without specifically handling `HTTPException` first will swallow intentional API errors.
**Prevention:** Always log the full exception securely server-side using `logger.error(..., exc_info=True)` and return a generic "Internal server error" string to the client. Ensure `except HTTPException: raise` is placed before the catch-all `Exception` block.
## 2024-05-02 - [HIGH] Overly permissive CORS configuration allowing wildcards and invalid URLs
**Vulnerability:** The `get_cors_origins` function accepted any string from the `CORS_ORIGINS` environment variable, which could include wildcards (`*`) or invalid URL structures. Allowing `*` when `allow_credentials=True` is enabled in `CORSMiddleware` causes application startup/runtime errors, and allowing arbitrary strings bypasses intended origin restrictions.
**Learning:** When generating a list of allowed CORS origins from environment variables, all origins must be strictly validated. Furthermore, wildcard origins must be explicitly rejected if the API intends to support credentials (cookies/authorization headers).
**Prevention:** Use `urllib.parse.urlparse` to validate that each candidate origin has a valid scheme (`http` or `https`) and a valid host (`netloc`). Explicitly filter out the `*` wildcard origin before passing the list to `CORSMiddleware`.
33 changes: 24 additions & 9 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from pydantic import BaseModel, Field
from pathlib import Path
import time
import urllib.parse

from scanner import scan_directory_for_videos
from extractor import async_extract_keyframes_parallel, async_get_video_duration
Expand Down Expand Up @@ -146,17 +147,31 @@ async def lifespan(app: FastAPI):
def get_cors_origins():
"""Build CORS origins list, auto-detecting Render deployments."""
explicit = os.getenv("CORS_ORIGINS")
if explicit:
return [o.strip() for o in explicit.split(",") if o.strip()]

origins = ["http://localhost:5173", "http://localhost:3000"]

# Auto-detect Render deployments: add the frontend service URL
frontend_url = os.getenv("FRONTEND_URL")
if frontend_url:
origins.append(frontend_url)
raw_origins = []
if explicit:
raw_origins = [o.strip() for o in explicit.split(",") if o.strip()]
else:
raw_origins = ["http://localhost:5173", "http://localhost:3000"]

# Auto-detect Render deployments: add the frontend service URL
frontend_url = os.getenv("FRONTEND_URL")
if frontend_url:
raw_origins.append(frontend_url)

valid_origins = []
for origin in raw_origins:
if origin == "*":
# Skip wildcard to prevent runtime errors with allow_credentials=True
continue
try:
parsed = urllib.parse.urlparse(origin)
if parsed.scheme in ["http", "https"] and parsed.netloc:
valid_origins.append(origin)
except Exception:
pass

return origins
return valid_origins

cors_origins = get_cors_origins()
app.add_middleware(
Expand Down
Loading