From 1238173414ff86eb6871e48e3b950291f715d384 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2026 23:02:57 +0000 Subject: [PATCH] Fix sensitive error detail leakage in auth login_required decorator Co-authored-by: Pmaster-dev <293764797+Pmaster-dev@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ auth/utils.py | 4 ++-- src/handoff/__init__.py | 1 + tests/test_auth.py | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 .jules/sentinel.md create mode 100644 src/handoff/__init__.py create mode 100644 tests/test_auth.py diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..4e51679 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2025-09-12 - Prevent Error Details Leakage in Auth Decorators +**Vulnerability:** Exception details (`str(e)`) were returned in HTTP 401 responses inside the `login_required` decorator, leaking internal error messages and system internals to unauthenticated users. +**Learning:** Returning exception text in authentication failure handlers risks exposing sensitive database or internal application state to attackers. +**Prevention:** Always fail securely by returning generic error messages (e.g. `{"error": "Unauthorized"}`) on authentication failures. diff --git a/auth/utils.py b/auth/utils.py index 4bded89..a060433 100644 --- a/auth/utils.py +++ b/auth/utils.py @@ -128,8 +128,8 @@ def decorated_function(*args, **kwargs): g.user_id = user_id g.user = user_data return f(*args, **kwargs) - except Exception as e: - return jsonify({'error': 'Unauthorized', 'details': str(e)}), 401 + except Exception: + return jsonify({'error': 'Unauthorized'}), 401 return decorated_function diff --git a/src/handoff/__init__.py b/src/handoff/__init__.py new file mode 100644 index 0000000..0f55842 --- /dev/null +++ b/src/handoff/__init__.py @@ -0,0 +1 @@ +"""Handoff module package.""" diff --git a/tests/test_auth.py b/tests/test_auth.py new file mode 100644 index 0000000..05d79ae --- /dev/null +++ b/tests/test_auth.py @@ -0,0 +1,33 @@ +import sys +from unittest.mock import MagicMock + +# Mock external cache_db dependency before importing auth.utils +mock_cache_db = MagicMock() +sys.modules['cache_db'] = mock_cache_db +sys.modules['cache_db.redis_client'] = mock_cache_db.redis_client +sys.modules['cache_db.models'] = mock_cache_db.models + +from flask import Flask, jsonify +from auth.utils import login_required + +def test_login_required_unauthorized_does_not_leak_details(monkeypatch): + app = Flask(__name__) + + @app.route("/protected") + @login_required + def protected_route(): + return jsonify({"message": "success"}) + + # Force verify_jwt_in_request to raise an Exception with sensitive details + def mock_verify(): + raise RuntimeError("Sensitive internal database stack trace or token parsing error") + + monkeypatch.setattr("auth.utils.verify_jwt_in_request", mock_verify) + + with app.test_client() as client: + response = client.get("/protected") + assert response.status_code == 401 + data = response.get_json() + assert data == {"error": "Unauthorized"} + assert "details" not in data + assert "Sensitive internal" not in str(data)