@@ -32,8 +32,12 @@ func MapSQLError(err error) error {
3232 return parsePostgresError (pqErr )
3333 }
3434
35- // Return original error if it could not be classified as a database
36- // specific error.
35+ // As a last step, check if this is a connection error that needs
36+ // sanitization to prevent leaking sensitive information.
37+ err = sanitizeConnectionError (err )
38+
39+ // Return the error (potentially sanitized) if it could not be
40+ // classified as a database specific error.
3741 return err
3842}
3943
@@ -109,7 +113,8 @@ func parsePostgresError(pqErr *pgconn.PgError) error {
109113 }
110114
111115 default :
112- return fmt .Errorf ("unknown postgres error: %w" , pqErr )
116+ return fmt .Errorf ("unknown postgres error: %w" ,
117+ sanitizeConnectionError (pqErr ))
113118 }
114119}
115120
@@ -196,3 +201,68 @@ func IsSchemaError(err error) bool {
196201 var schemaError * ErrSchemaError
197202 return errors .As (err , & schemaError )
198203}
204+
205+ // ErrDatabaseConnectionError is an error type which represents a database
206+ // connection error with sensitive information sanitized.
207+ type ErrDatabaseConnectionError struct {
208+ DbError error
209+ }
210+
211+ // Unwrap returns the wrapped error.
212+ func (e ErrDatabaseConnectionError ) Unwrap () error {
213+ return e .DbError
214+ }
215+
216+ // Error returns a generic error message without revealing connection details.
217+ func (e ErrDatabaseConnectionError ) Error () string {
218+ // Return a generic error message that doesn't reveal any connection
219+ // details to prevent information leakage.
220+ return "database connection failed"
221+ }
222+
223+ // isConnectionError checks if an error message contains patterns that indicate
224+ // a database connection error with potentially sensitive information.
225+ func isConnectionError (errStr string ) bool {
226+ // List of patterns that indicate connection errors with sensitive info.
227+ patterns := []string {
228+ "failed to connect to" ,
229+ "dial tcp" ,
230+ "user=" ,
231+ "password=" ,
232+ "host=" ,
233+ "dbname=" ,
234+ "sslmode=" ,
235+ "connection refused" ,
236+ "no route to host" ,
237+ "password authentication failed" ,
238+ }
239+
240+ for _ , pattern := range patterns {
241+ if strings .Contains (errStr , pattern ) {
242+ return true
243+ }
244+ }
245+
246+ return false
247+ }
248+
249+ // sanitizeConnectionError checks if an error contains database connection
250+ // information and returns a sanitized version if it does.
251+ func sanitizeConnectionError (err error ) error {
252+ if err == nil {
253+ return nil
254+ }
255+
256+ // Check if the error message contains connection parameters that could
257+ // leak sensitive information.
258+ if isConnectionError (err .Error ()) {
259+ // Log the original error for debugging purposes, but return a
260+ // sanitized version to prevent information leakage.
261+ log .Errorf ("Database connection error (sanitized): %v" , err )
262+ return & ErrDatabaseConnectionError {
263+ DbError : err ,
264+ }
265+ }
266+
267+ return err
268+ }
0 commit comments