@@ -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
@@ -111,7 +115,8 @@ func parsePostgresError(pqErr *pgconn.PgError) error {
111115 }
112116
113117 default :
114- return fmt .Errorf ("unknown postgres error: %w" , pqErr )
118+ return fmt .Errorf ("unknown postgres error: %w" ,
119+ sanitizeConnectionError (pqErr ))
115120 }
116121}
117122
@@ -198,3 +203,68 @@ func IsSchemaError(err error) bool {
198203 var schemaError * ErrSchemaError
199204 return errors .As (err , & schemaError )
200205}
206+
207+ // ErrDatabaseConnectionError is an error type which represents a database
208+ // connection error with sensitive information sanitized.
209+ type ErrDatabaseConnectionError struct {
210+ DbError error
211+ }
212+
213+ // Unwrap returns the wrapped error.
214+ func (e ErrDatabaseConnectionError ) Unwrap () error {
215+ return e .DbError
216+ }
217+
218+ // Error returns a generic error message without revealing connection details.
219+ func (e ErrDatabaseConnectionError ) Error () string {
220+ // Return a generic error message that doesn't reveal any connection
221+ // details to prevent information leakage.
222+ return "database connection failed"
223+ }
224+
225+ // isConnectionError checks if an error message contains patterns that indicate
226+ // a database connection error with potentially sensitive information.
227+ func isConnectionError (errStr string ) bool {
228+ // List of patterns that indicate connection errors with sensitive info.
229+ patterns := []string {
230+ "failed to connect to" ,
231+ "dial tcp" ,
232+ "user=" ,
233+ "password=" ,
234+ "host=" ,
235+ "dbname=" ,
236+ "sslmode=" ,
237+ "connection refused" ,
238+ "no route to host" ,
239+ "password authentication failed" ,
240+ }
241+
242+ for _ , pattern := range patterns {
243+ if strings .Contains (errStr , pattern ) {
244+ return true
245+ }
246+ }
247+
248+ return false
249+ }
250+
251+ // sanitizeConnectionError checks if an error contains database connection
252+ // information and returns a sanitized version if it does.
253+ func sanitizeConnectionError (err error ) error {
254+ if err == nil {
255+ return nil
256+ }
257+
258+ // Check if the error message contains connection parameters that could
259+ // leak sensitive information.
260+ if isConnectionError (err .Error ()) {
261+ // Log the original error for debugging purposes, but return a
262+ // sanitized version to prevent information leakage.
263+ log .Errorf ("Database connection error (sanitized): %v" , err )
264+ return & ErrDatabaseConnectionError {
265+ DbError : err ,
266+ }
267+ }
268+
269+ return err
270+ }
0 commit comments