security: protect ingest endpoint with shared secret

Ingest API now requires X-Ingest-Key header matching INGEST_SECRET
from credentials. IP-based check was insufficient since NPM proxies
all external traffic from the same internal IP.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mikkel Georgsen 2026-03-30 11:47:22 +00:00
parent d60b0208db
commit 2a88b528d4

View file

@ -148,11 +148,10 @@ INTERNAL_PREFIXES = ("127.", "10.5.0.", "::1", "100.79.") # localhost, LAN, Net
async def ingest_message(request: Request) -> JSONResponse: async def ingest_message(request: Request) -> JSONResponse:
"""HTTP endpoint for local services to log messages into the bridge.""" """HTTP endpoint for local services to log messages into the bridge."""
# Check real client IP (X-Forwarded-For from NPM, or direct connection) # Require shared secret for ingest (only the homelab bot knows this)
forwarded = request.headers.get("x-forwarded-for", "") ingest_key = creds.get("INGEST_SECRET", "")
real_ip = request.headers.get("x-real-ip", "") provided_key = request.headers.get("x-ingest-key", "")
client_ip = forwarded.split(",")[0].strip() or real_ip or (request.client.host if request.client else "") if not ingest_key or not provided_key or ingest_key != provided_key:
if not any(client_ip.startswith(p) for p in INTERNAL_PREFIXES):
return JSONResponse({"error": "forbidden"}, status_code=403) return JSONResponse({"error": "forbidden"}, status_code=403)
try: try: