Describe the bug
SqlConnection.Open() includes the full connection string (including Password=...) in the exception message when the server is unreachable. This leaks credentials into application logs, error monitoring tools (Sentry, Application Insights, etc.), and crash dumps.
To reproduce
using Microsoft.Data.SqlClient;
var builder = new SqlConnectionStringBuilder
{
DataSource = "nonexistent-server.example.com",
InitialCatalog = "mydb",
UserID = "sa",
Password = "MySecretP@ssw0rd!",
ConnectTimeout = 5,
Encrypt = SqlConnectionEncryptOption.Optional
};
try
{
using var conn = new SqlConnection(builder.ConnectionString);
conn.Open();
}
catch (SqlException ex)
{
Console.WriteLine(ex.Message);
// Output includes: "...Password=MySecretP@ssw0rd!..."
// The password is visible in the exception message
}
Expected behavior
Exception messages from SqlConnection.Open() should never include the Password value from the connection string. The password should be redacted (e.g., replaced with ****) or the connection string should be omitted entirely from exception messages.
ADO.NET's DbConnectionStringBuilder.ConnectionString property already redacts passwords by default when PersistSecurityInfo=false, but the internal error path in SqlInternalConnectionTds constructs its own error message using the raw connection options, bypassing this redaction.
Actual behavior
The full connection string including Password=MySecretP@ssw0rd! appears in the SqlException.Message text, which typically gets:
- Written to
ILogger / console logs
- Captured by error monitoring (App Insights, Sentry, Datadog)
- Stored in Windows Event Log
- Included in crash dumps
Further technical details
Microsoft.Data.SqlClient version: 6.0.0
Target framework: .NET 8.0
SQL Server version: N/A (server unreachable, issue is in client error handling)
Operating system: Windows 11 23H2
The issue appears to be in SqlInternalConnectionTds.LoginNoFailover() and SqlInternalConnectionTds.LoginWithFailover() where error messages are constructed using ConnectionOptions without going through the redaction path.
Describe the bug
SqlConnection.Open()includes the full connection string (includingPassword=...) in the exception message when the server is unreachable. This leaks credentials into application logs, error monitoring tools (Sentry, Application Insights, etc.), and crash dumps.To reproduce
Expected behavior
Exception messages from
SqlConnection.Open()should never include thePasswordvalue from the connection string. The password should be redacted (e.g., replaced with****) or the connection string should be omitted entirely from exception messages.ADO.NET's
DbConnectionStringBuilder.ConnectionStringproperty already redacts passwords by default whenPersistSecurityInfo=false, but the internal error path inSqlInternalConnectionTdsconstructs its own error message using the raw connection options, bypassing this redaction.Actual behavior
The full connection string including
Password=MySecretP@ssw0rd!appears in theSqlException.Messagetext, which typically gets:ILogger/ console logsFurther technical details
Microsoft.Data.SqlClient version: 6.0.0
Target framework: .NET 8.0
SQL Server version: N/A (server unreachable, issue is in client error handling)
Operating system: Windows 11 23H2
The issue appears to be in
SqlInternalConnectionTds.LoginNoFailover()andSqlInternalConnectionTds.LoginWithFailover()where error messages are constructed usingConnectionOptionswithout going through the redaction path.