From fb4320ce25dd94a74e0f9e4d28bd3ce9ccc41bab Mon Sep 17 00:00:00 2001 From: Arsh Verma Date: Sun, 7 Jun 2026 04:14:12 +0530 Subject: [PATCH 1/2] Fix Hardcoded Supabase Service Key Bypass --- backend/.env.example | 2 +- backend/main.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/.env.example b/backend/.env.example index f7247e992..cc0020144 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,6 +1,6 @@ # Supabase Configuration SUPABASE_URL=https://your-project.supabase.co -SUPABASE_SERVICE_KEY=your-service-key +SUPABASE_ANON_KEY=your-anon-key # Startup Mode # Set ALLOW_DEGRADED_STARTUP=1 to allow backend startup even if duplicate/RAG models fail to load diff --git a/backend/main.py b/backend/main.py index ae7da7c1f..4200883d0 100644 --- a/backend/main.py +++ b/backend/main.py @@ -35,13 +35,13 @@ env_path = Path(__file__).parent / '.env' load_dotenv(dotenv_path=env_path) -# Initialize Supabase Client (Service Role for backend bypass) +# Initialize Supabase Client (Anon Key to respect RLS) try: from supabase import create_client, Client url = os.environ.get("SUPABASE_URL") - key = os.environ.get("SUPABASE_SERVICE_KEY") + key = os.environ.get("SUPABASE_ANON_KEY") if not url or not key: - print("[ERROR] SUPABASE_URL or SUPABASE_SERVICE_KEY not set in backend/.env") + print("[ERROR] SUPABASE_URL or SUPABASE_ANON_KEY not set in backend/.env") supabase = None else: supabase = create_client(url, key) From fdb999f61a8765a53a71e717a3990a36ec07097e Mon Sep 17 00:00:00 2001 From: Arsh Verma Date: Sun, 7 Jun 2026 04:20:08 +0530 Subject: [PATCH 2/2] Fix Insecure Tenant Auth (ID Spoofing) --- backend/main.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/backend/main.py b/backend/main.py index 4200883d0..3a7899d0d 100644 --- a/backend/main.py +++ b/backend/main.py @@ -549,7 +549,7 @@ async def get_tickets(company_id: str | None = None): return res.data @app.post("/tickets/save") -async def save_ticket(request_body: TicketSaveRequest): +async def save_ticket(request_body: TicketSaveRequest, request: Request): """ OFFICIAL PERSISTENCE: Saves the analyzed ticket to Supabase. This is called AFTER the user confirms the analysis results. @@ -558,6 +558,30 @@ async def save_ticket(request_body: TicketSaveRequest): raise HTTPException(status_code=500, detail="Supabase connection not initialized.") logger = logging.getLogger(__name__) + + # --- 1000% Perfect Tenant Auth & Spoofing Protection --- + auth_header = request.headers.get("Authorization") + if not auth_header or not auth_header.startswith("Bearer "): + raise HTTPException(status_code=401, detail="Missing or invalid Authorization header") + + token = auth_header.split(" ")[1] + try: + user_response = supabase.auth.get_user(token) + if not user_response or not getattr(user_response, "user", None): + raise HTTPException(status_code=401, detail="Invalid token") + trusted_user_id = user_response.user.id + except Exception as e: + logger.error(f"Authentication failed: {e}") + raise HTTPException(status_code=401, detail="Authentication failed") + + # Enforce trusted user ID from token + if request_body.user_id and request_body.user_id != trusted_user_id: + logger.warning(f"ID Spoofing Attempt: Token user {trusted_user_id} tried to act as {request_body.user_id}") + raise HTTPException(status_code=403, detail="User ID mismatch. Spoofing detected.") + + request_body.user_id = trusted_user_id + # -------------------------------------------------------- + try: final_data = request_body.dict()