From 8f21a2e2ae6a0772cc4fb27793beee48aed5d8d2 Mon Sep 17 00:00:00 2001 From: Subrata Paitandi Date: Thu, 11 Dec 2025 16:11:14 +0530 Subject: [PATCH 1/2] security issue SEC101/037 : SQLLegacyCredentials fix --- tests/test_002_types.py | 10 ++++-- tests/test_013_sqlwchar_conversions.py | 46 ++++++++++++------------ tests/test_014_ddbc_bindings_coverage.py | 18 +++++----- 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/tests/test_002_types.py b/tests/test_002_types.py index 6c435340..5be4e9ae 100644 --- a/tests/test_002_types.py +++ b/tests/test_002_types.py @@ -531,6 +531,7 @@ def test_invalid_surrogate_handling(): This validates the fix for unix_utils.cpp to match ddbc_bindings.h behavior. """ import mssql_python + import os # Test connection strings with various surrogate-related edge cases # These should be handled gracefully without introducing invalid Unicode @@ -539,7 +540,10 @@ def test_invalid_surrogate_handling(): # In UTF-16, high surrogates (0xD800-0xDBFF) must be followed by low surrogates try: # Create a connection string that would exercise the conversion path - conn_str = "Server=test_server;Database=TestDB;UID=user;PWD=password" + # Use environment variables or placeholder values to avoid SEC101/037 security warnings + test_server = os.getenv("TEST_SERVER", "localhost") + test_db = os.getenv("TEST_DATABASE", "TestDB") + conn_str = f"Server={test_server};Database={test_db};Trusted_Connection=yes" conn = mssql_python.connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -548,7 +552,7 @@ def test_invalid_surrogate_handling(): # Low surrogate without high surrogate (invalid) # In UTF-16, low surrogates (0xDC00-0xDFFF) must be preceded by high surrogates try: - conn_str = "Server=test;Database=DB;ApplicationName=TestApp;UID=u;PWD=p" + conn_str = f"Server={os.getenv('TEST_SERVER', 'localhost')};Database=DB;ApplicationName=TestApp;Trusted_Connection=yes" conn = mssql_python.connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -564,7 +568,7 @@ def test_invalid_surrogate_handling(): for test_str in emoji_tests: try: - conn_str = f"Server=test;{test_str};UID=user;PWD=pass" + conn_str = f"Server=test;{test_str};Trusted_Connection=yes" conn = mssql_python.connect(conn_str, autoconnect=False) conn.close() except Exception: diff --git a/tests/test_013_sqlwchar_conversions.py b/tests/test_013_sqlwchar_conversions.py index c9f6fcc3..c0f77ba0 100644 --- a/tests/test_013_sqlwchar_conversions.py +++ b/tests/test_013_sqlwchar_conversions.py @@ -40,7 +40,7 @@ def test_surrogate_pair_high_without_low(self): # This tests the else branch at lines 112-115 try: # Use a connection string to exercise the conversion path - conn_str = f"Server=test;Database={test_str};UID=user;PWD=pass" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -49,7 +49,7 @@ def test_surrogate_pair_high_without_low(self): # High surrogate followed by non-surrogate test_str2 = "Test\ud800X" # High surrogate followed by ASCII try: - conn_str = f"Server=test;ApplicationName={test_str2};UID=u;PWD=p" + conn_str = f"Server=test;ApplicationName={test_str2};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -71,7 +71,7 @@ def test_surrogate_pair_low_without_high(self): test_str = "\udc00Hello" # Low surrogate at start try: - conn_str = f"Server=test;Database={test_str};UID=user;PWD=pass" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -80,7 +80,7 @@ def test_surrogate_pair_low_without_high(self): # Low surrogate in middle (not preceded by high surrogate) test_str2 = "A\udc00B" # Low surrogate between ASCII try: - conn_str = f"Server=test;ApplicationName={test_str2};UID=u;PWD=p" + conn_str = f"Server=test;ApplicationName={test_str2};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -111,7 +111,7 @@ def test_valid_surrogate_pairs(self): for test_str in emoji_tests: try: - conn_str = f"Server=test;Database={test_str};UID=user;PWD=pass" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -144,7 +144,7 @@ def test_bmp_characters(self): for test_str in bmp_tests: try: - conn_str = f"Server=test;Database={test_str};UID=user;PWD=pass" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -170,7 +170,7 @@ def test_invalid_scalar_values(self): # High surrogate alone try: test_str = "Test\ud800End" - conn_str = f"Server=test;Database={test_str};UID=user;PWD=pass" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -179,7 +179,7 @@ def test_invalid_scalar_values(self): # Low surrogate alone try: test_str = "Start\udc00Test" - conn_str = f"Server=test;Database={test_str};UID=user;PWD=pass" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -188,7 +188,7 @@ def test_invalid_scalar_values(self): # Mixed invalid surrogates try: test_str = "\ud800\ud801\udc00" # High, high, low (invalid pairing) - conn_str = f"Server=test;Database={test_str};UID=user;PWD=pass" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -220,7 +220,7 @@ def test_wstring_to_sqlwchar_bmp(self): for test_char in single_unit_tests: try: - conn_str = f"Server=test;Database=DB_{test_char};UID=u;PWD=p" + conn_str = f"Server=test;Database=DB_{test_char};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -253,7 +253,7 @@ def test_wstring_to_sqlwchar_surrogate_pairs(self): for emoji in emoji_chars: try: - conn_str = f"Server=test;Database=DB{emoji};UID=u;PWD=p" + conn_str = f"Server=test;Database=DB{emoji};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -282,7 +282,7 @@ def test_wstring_to_sqlwchar_invalid_scalars(self): for test_str, desc in invalid_tests: try: - conn_str = f"Server=test;Database={test_str};UID=u;PWD=p" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -301,7 +301,7 @@ def test_empty_and_null_strings(self): # Empty string try: - conn_str = "Server=test;Database=;UID=user;PWD=pass" + conn_str = "Server=test;Database=;Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -309,7 +309,7 @@ def test_empty_and_null_strings(self): # Very short strings try: - conn_str = "Server=a;Database=b;UID=c;PWD=d" + conn_str = "Server=a;Database=b;Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -337,7 +337,7 @@ def test_mixed_character_sets(self): for test_str in mixed_tests: try: - conn_str = f"Server=test;Database={test_str};UID=u;PWD=p" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -371,7 +371,7 @@ def test_boundary_code_points(self): for test_char, desc in boundary_tests: try: - conn_str = f"Server=test;Database=DB{test_char};UID=u;PWD=p" + conn_str = f"Server=test;Database=DB{test_char};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -403,7 +403,7 @@ def test_surrogate_pair_calculations(self): # low = (0 & 0x3FF) + 0xDC00 = 0xDC00 min_supp = "\U00010000" try: - conn_str = f"Server=test;Database=DB{min_supp};UID=u;PWD=p" + conn_str = f"Server=test;Database=DB{min_supp};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -415,7 +415,7 @@ def test_surrogate_pair_calculations(self): # low = (0xF600 & 0x3FF) + 0xDC00 = 0x200 + 0xDC00 = 0xDE00 emoji = "😀" try: - conn_str = f"Server=test;Database={emoji};UID=u;PWD=p" + conn_str = f"Server=test;Database={emoji};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -427,7 +427,7 @@ def test_surrogate_pair_calculations(self): # low = (0xFFFFF & 0x3FF) + 0xDC00 = 0x3FF + 0xDC00 = 0xDFFF max_unicode = "\U0010ffff" try: - conn_str = f"Server=test;Database=DB{max_unicode};UID=u;PWD=p" + conn_str = f"Server=test;Database=DB{max_unicode};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -455,7 +455,7 @@ def test_null_terminator_handling(self): for test_str in length_tests: try: - conn_str = f"Server=test;Database={test_str};UID=u;PWD=p" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -475,7 +475,7 @@ def test_unicode_round_trip_ascii(self): for test_str in ascii_tests: try: - conn_str = f"Server=test;Database={test_str};UID=u;PWD=p" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -490,7 +490,7 @@ def test_unicode_round_trip_emoji(self): for emoji in emoji_tests: try: - conn_str = f"Server=test;Database=DB{emoji};UID=u;PWD=p" + conn_str = f"Server=test;Database=DB{emoji};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -513,7 +513,7 @@ def test_unicode_round_trip_multilingual(self): for test_str in multilingual_tests: try: - conn_str = f"Server=test;Database={test_str};UID=u;PWD=p" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: diff --git a/tests/test_014_ddbc_bindings_coverage.py b/tests/test_014_ddbc_bindings_coverage.py index 6b56f301..f82fb11e 100644 --- a/tests/test_014_ddbc_bindings_coverage.py +++ b/tests/test_014_ddbc_bindings_coverage.py @@ -38,7 +38,7 @@ def test_valid_scalar_values(self): for char in valid_chars: try: - conn_str = f"Server=test;Database=DB{char};UID=u;PWD=p" + conn_str = f"Server=test;Database=DB{char};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -72,7 +72,7 @@ def test_surrogate_range(self): # Just before surrogate range (valid) try: - conn_str = "Server=test;Database=DB\ud7ff;UID=u;PWD=p" + conn_str = "Server=test;Database=DB\ud7ff;Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -80,14 +80,14 @@ def test_surrogate_range(self): # Inside surrogate range (invalid) try: - conn_str = "Server=test;Database=DB\ud800;UID=u;PWD=p" + conn_str = "Server=test;Database=DB\ud800;Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: pass try: - conn_str = "Server=test;Database=DB\udfff;UID=u;PWD=p" + conn_str = "Server=test;Database=DB\udfff;Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -95,7 +95,7 @@ def test_surrogate_range(self): # Just after surrogate range (valid) try: - conn_str = "Server=test;Database=DB\ue000;UID=u;PWD=p" + conn_str = "Server=test;Database=DB\ue000;Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -123,7 +123,7 @@ def test_utf32_valid_scalars(self): for test_str in valid_tests: try: - conn_str = f"Server=test;Database={test_str};UID=u;PWD=p" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -143,7 +143,7 @@ def test_utf32_invalid_scalars(self): for test_str in invalid_tests: try: - conn_str = f"Server=test;Database={test_str};UID=u;PWD=p" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -169,7 +169,7 @@ def test_utf32_encode_valid(self): for test_str in valid_tests: try: - conn_str = f"Server=test;Database={test_str};UID=u;PWD=p" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: @@ -188,7 +188,7 @@ def test_utf32_encode_invalid(self): for test_str in invalid_tests: try: - conn_str = f"Server=test;Database={test_str};UID=u;PWD=p" + conn_str = f"Server=test;Database={test_str};Trusted_Connection=yes" conn = connect(conn_str, autoconnect=False) conn.close() except Exception: From 79b1eca87487995269f973bb09ae93f0c6377527 Mon Sep 17 00:00:00 2001 From: Subrata Paitandi Date: Fri, 12 Dec 2025 13:20:46 +0530 Subject: [PATCH 2/2] fix for review comments --- tests/test_002_types.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/test_002_types.py b/tests/test_002_types.py index 5be4e9ae..4828d72e 100644 --- a/tests/test_002_types.py +++ b/tests/test_002_types.py @@ -1,6 +1,7 @@ import pytest import datetime import time +import os from mssql_python.type import ( STRING, BINARY, @@ -531,7 +532,6 @@ def test_invalid_surrogate_handling(): This validates the fix for unix_utils.cpp to match ddbc_bindings.h behavior. """ import mssql_python - import os # Test connection strings with various surrogate-related edge cases # These should be handled gracefully without introducing invalid Unicode @@ -541,7 +541,7 @@ def test_invalid_surrogate_handling(): try: # Create a connection string that would exercise the conversion path # Use environment variables or placeholder values to avoid SEC101/037 security warnings - test_server = os.getenv("TEST_SERVER", "localhost") + test_server = os.getenv("TEST_SERVER", "testserver") test_db = os.getenv("TEST_DATABASE", "TestDB") conn_str = f"Server={test_server};Database={test_db};Trusted_Connection=yes" conn = mssql_python.connect(conn_str, autoconnect=False) @@ -552,7 +552,10 @@ def test_invalid_surrogate_handling(): # Low surrogate without high surrogate (invalid) # In UTF-16, low surrogates (0xDC00-0xDFFF) must be preceded by high surrogates try: - conn_str = f"Server={os.getenv('TEST_SERVER', 'localhost')};Database=DB;ApplicationName=TestApp;Trusted_Connection=yes" + test_server = os.getenv("TEST_SERVER", "testserver") + conn_str = ( + f"Server={test_server};Database=DB;ApplicationName=TestApp;Trusted_Connection=yes" + ) conn = mssql_python.connect(conn_str, autoconnect=False) conn.close() except Exception: