fix(06): CR-03 replace raw X-Forwarded-For reads with get_client_ip()

Replace all instances of request.headers.get("X-Forwarded-For") in
cloud.py (connect_webdav, delete_connection) and documents.py (upload,
confirm, delete) with get_client_ip(request) from deps.utils. Add
get_client_ip import to both files. Prevents XFF spoofing in audit logs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
curo1305
2026-06-04 23:15:48 +02:00
co-authored by Claude Sonnet 4.6
parent a8dbb02ff0
commit 23c27efd65
2 changed files with 7 additions and 13 deletions
+3 -2
View File
@@ -37,6 +37,7 @@ from config import settings
from db.models import CloudConnection, User
from deps.auth import get_regular_user
from deps.db import get_db
from deps.utils import get_client_ip
from services.audit import write_audit_log
from services.rate_limiting import account_limiter
from storage.cloud_utils import encrypt_credentials, decrypt_credentials, validate_cloud_url
@@ -626,7 +627,7 @@ async def connect_webdav(
conn = await _upsert_cloud_connection(session, current_user.id, body.provider, credentials_enc)
await session.flush()
_ip = request.headers.get("X-Forwarded-For") or (request.client.host if request.client else None)
_ip = get_client_ip(request)
await write_audit_log(
session,
event_type="cloud.connected",
@@ -763,7 +764,7 @@ async def delete_connection(
from services.cloud_cache import invalidate_provider_cache # lazy import
invalidate_provider_cache(str(current_user.id), provider)
_ip = request.headers.get("X-Forwarded-For") or (request.client.host if request.client else None)
_ip = get_client_ip(request)
await write_audit_log(
session,
+4 -11
View File
@@ -36,6 +36,7 @@ from config import settings
from db.models import CloudConnection, Document, Folder, Quota, Share, User
from deps.auth import get_regular_user
from deps.db import get_db
from deps.utils import get_client_ip
from services import classifier, storage
from services.audit import write_audit_log
from services.rate_limiting import account_limiter
@@ -272,9 +273,7 @@ async def upload_document(
)
session.add(doc)
_ip = (
request.headers.get("X-Forwarded-For") or (request.client.host if request.client else None)
) if request else None
_ip = get_client_ip(request) if request else None
await write_audit_log(
session,
event_type="document.uploaded",
@@ -378,10 +377,7 @@ async def confirm_upload(
doc.status = "uploaded"
# D-13: document uploaded event — size_bytes + storage_backend only, NO filename, NO extracted_text (T-04-07-02)
# TRUST BOUNDARY: X-Forwarded-For is client-controlled — for audit logging only,
# not for auth/access control. Use a trusted reverse proxy in production to
# overwrite this header with the real remote IP before it reaches FastAPI.
_ip = request.headers.get("X-Forwarded-For") or (request.client.host if request.client else None)
_ip = get_client_ip(request)
await write_audit_log(
session,
event_type="document.uploaded",
@@ -664,10 +660,7 @@ async def delete_document(
is_cloud = doc.storage_backend != "minio"
_doc_size = doc.size_bytes
_doc_id = doc.id
# TRUST BOUNDARY: X-Forwarded-For is client-controlled — for audit logging only,
# not for auth/access control. Use a trusted reverse proxy in production to
# overwrite this header with the real remote IP before it reaches FastAPI.
_ip = request.headers.get("X-Forwarded-For") or (request.client.host if request.client else None)
_ip = get_client_ip(request)
# Cloud routing: attempt provider delete unless remove_only is set
if is_cloud and not remove_only: