From 6721f180fc7d4703ed50f71edc2c0d86add1009c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 18 Sep 2026 23:03:34 +0000 Subject: [PATCH] fix(auth): prevent information disclosure in login_required decorator Co-authored-by: Pmaster-dev <293764797+Pmaster-dev@users.noreply.github.com> --- auth/utils.py | 5 ++-- src/handoff/__init__.py | 0 tests/test_auth_utils.py | 51 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 src/handoff/__init__.py create mode 100644 tests/test_auth_utils.py diff --git a/auth/utils.py b/auth/utils.py index 4bded89..22dfe4f 100644 --- a/auth/utils.py +++ b/auth/utils.py @@ -128,8 +128,9 @@ 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: + # Do not leak exception details to the client + 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..e69de29 diff --git a/tests/test_auth_utils.py b/tests/test_auth_utils.py new file mode 100644 index 0000000..5a4d9dc --- /dev/null +++ b/tests/test_auth_utils.py @@ -0,0 +1,51 @@ +import unittest +from unittest.mock import MagicMock, patch +import sys + +# Mock cache_db module before importing auth.utils +cache_db_mock = MagicMock() +sys.modules['cache_db'] = cache_db_mock +sys.modules['cache_db.redis_client'] = cache_db_mock.redis_client +sys.modules['cache_db.models'] = cache_db_mock.models + +from flask import Flask +from auth.utils import login_required, PasswordUtils, JWTUtils + + +class TestAuthUtils(unittest.TestCase): + def setUp(self): + self.app = Flask(__name__) + self.app.config['TESTING'] = True + + def test_login_required_does_not_leak_exception_details(self): + @self.app.route('/protected') + @login_required + def protected_route(): + return "success" + + with patch('auth.utils.verify_jwt_in_request', side_effect=RuntimeError("Internal database connection error - secret_db_uri")): + client = self.app.test_client() + response = client.get('/protected') + + self.assertEqual(response.status_code, 401) + data = response.get_json() + self.assertEqual(data, {'error': 'Unauthorized'}) + # Verify details or stack trace are not in response payload + self.assertNotIn('details', data) + self.assertNotIn('secret_db_uri', str(data)) + + def test_password_utils_hash_and_verify(self): + hashed = PasswordUtils.hash_password("supersecret123") + self.assertTrue(PasswordUtils.verify_password("supersecret123", hashed)) + self.assertFalse(PasswordUtils.verify_password("wrongpassword", hashed)) + + def test_jwt_utils_create_and_decode(self): + access_token, refresh_token = JWTUtils.create_tokens("user123", "testuser") + decoded = JWTUtils.decode_token(access_token) + self.assertIsNotNone(decoded) + self.assertEqual(decoded['user_id'], "user123") + self.assertEqual(decoded['username'], "testuser") + + +if __name__ == '__main__': + unittest.main()