@@ -163,62 +163,76 @@ func checkConfigFileExists() bool {
163163
164164// sanitizeErrorMessage removes potentially sensitive data from error messages
165165func sanitizeErrorMessage (msg string ) string {
166- // Remove potential API tokens (sk_, ghp_, glpat_, npm_, pypi_, etc.)
167- tokenPattern := regexp .MustCompile (`\b(sk|ghp|gh[pousr]|glpat|pypi|npm)_[A-Za-z0-9_-]+` )
166+ // Order matters! Process in this sequence to avoid conflicts
167+
168+ // 1. Remove URLs with embedded credentials FIRST (before email pattern catches them)
169+ urlCredsPattern := regexp .MustCompile (`https?://[^:]+:[^@]+@[^\s]+` )
170+ msg = urlCredsPattern .ReplaceAllString (msg , "[URL]" )
171+
172+ // 2. Remove database/connection strings (enhanced to cover more protocols)
173+ connStringPattern := regexp .MustCompile (`(?i)(mongodb(\+srv)?|mysql|mariadb|postgresql|postgres|redis|mssql|oracle)://[^\s]+` )
174+ msg = connStringPattern .ReplaceAllString (msg , "$1://[CONNECTION]" )
175+
176+ // 3. Remove potential API tokens - Fixed to include glpat with dash or underscore separator
177+ tokenPattern := regexp .MustCompile (`\b(sk|ghp|gh[pousr]|pypi|npm)_[A-Za-z0-9_-]+|\bglpat[-_][A-Za-z0-9_-]+` )
168178 msg = tokenPattern .ReplaceAllString (msg , "[TOKEN]" )
169179
170- // Remove AWS access keys (AKIA...)
180+ // 4. Remove AWS access keys (AKIA...)
171181 awsKeyPattern := regexp .MustCompile (`AKIA[0-9A-Z]{16}` )
172182 msg = awsKeyPattern .ReplaceAllString (msg , "[AWS_KEY]" )
173183
174- // Remove email addresses
184+ // 5. Remove email addresses (after URL credentials to avoid conflicts)
175185 emailPattern := regexp .MustCompile (`[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}` )
176186 msg = emailPattern .ReplaceAllString (msg , "[EMAIL]" )
177187
178- // Remove URLs with embedded credentials (https://user:pass@host)
179- urlCredsPattern := regexp .MustCompile (`https?://[^:]+:[^@]+@[^\s]+` )
180- msg = urlCredsPattern .ReplaceAllString (msg , "[URL]" )
181-
182- // Remove database/connection strings (enhanced to cover more protocols)
183- connStringPattern := regexp .MustCompile (`(?i)(mongodb(\+srv)?|mysql|mariadb|postgresql|postgres|redis|mssql|oracle)://[^\s]+` )
184- msg = connStringPattern .ReplaceAllString (msg , "$1://[CONNECTION]" )
185-
186- // Remove IPv4 addresses
188+ // 6. Remove IPv4 addresses
187189 ipv4Pattern := regexp .MustCompile (`\b(?:\d{1,3}\.){3}\d{1,3}\b` )
188190 msg = ipv4Pattern .ReplaceAllString (msg , "[IP]" )
189191
190- // Remove IPv6 addresses (simplified pattern covering common formats)
192+ // 7. Remove IPv6 addresses - Fixed to handle :: notation properly
191193 ipv6Pattern := regexp .MustCompile (`\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b|` +
194+ `\b(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}\b|` +
192195 `\b(?:[0-9a-fA-F]{1,4}:){1,7}:\b|` +
193- `\b:(?::[0-9a-fA-F]{1,4}){1,7}\b` )
196+ `\b::(?:[0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}\b|` +
197+ `\b[0-9a-fA-F]{1,4}::(?:[0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4}\b|` +
198+ `\bfe80::[0-9a-fA-F:]+\b` )
194199 msg = ipv6Pattern .ReplaceAllString (msg , "[IP]" )
195200
196- // Remove file system paths - conservative to avoid API path false positives
197- // Focus on protecting actual filesystem locations
198- // Home directories
199- homePattern := regexp .MustCompile (`(?:/(?:home|Users)/[^\s/]+|C:\\Users\\[^\s\\]+)` )
201+ // 8. Remove file system paths - order matters, most specific first
202+ // Home directories (exact match)
203+ homePattern := regexp .MustCompile (`/(?:home|Users)/[^\s/]+` )
200204 msg = homePattern .ReplaceAllString (msg , "[HOME]" )
201205
206+ // Windows home directories
207+ windowsHomePattern := regexp .MustCompile (`C:\\Users\\[^\s\\]+` )
208+ msg = windowsHomePattern .ReplaceAllString (msg , "[HOME]" )
209+
202210 // Temp directories
203- tempPattern := regexp .MustCompile (`(?: /(?:tmp|var/tmp)/[^\s:]+) ` )
211+ tempPattern := regexp .MustCompile (`/(?:tmp|var/tmp)/[^\s:]+` )
204212 msg = tempPattern .ReplaceAllString (msg , "[TEMP]" )
205213
206- // Absolute file paths with 3+ segments (likely filesystem, not API )
207- absolutePathPattern := regexp .MustCompile (`(?:^|\s)(/[a-z]+(?:/[ ^\s:]+){2,}) ` )
208- msg = absolutePathPattern .ReplaceAllString (msg , " [PATH]" )
214+ // Home-relative paths - Fixed to accept single segment (~/file.txt )
215+ homeRelativePattern := regexp .MustCompile (`~ (?:/[ ^\s:]+){1,} ` )
216+ msg = homeRelativePattern .ReplaceAllString (msg , "[PATH]" )
209217
210- // Windows paths with backslashes
211- windowsPathPattern := regexp .MustCompile (`[A-Z]:\\[^\s]+` )
212- msg = windowsPathPattern .ReplaceAllString (msg , "[PATH]" )
218+ // Absolute file paths - Only match known filesystem roots to avoid API false positives
219+ // Fixed: Don't include leading space in replacement
220+ absolutePathPattern := regexp .MustCompile (`(?:^|\s)(/(usr|home|var|opt|etc|srv|tmp|mnt)(?:/[^\s:]+)+)` )
221+ msg = absolutePathPattern .ReplaceAllStringFunc (msg , func (match string ) string {
222+ if strings .HasPrefix (match , " " ) {
223+ return " [PATH]" // Preserve single space
224+ }
225+ return "[PATH]" // Start of string
226+ })
213227
214- // Home-relative paths
215- homeRelativePattern := regexp .MustCompile (`~(?:/[^\s :]+){2,} ` )
216- msg = homeRelativePattern .ReplaceAllString (msg , "[PATH]" )
228+ // Windows paths - Fixed to handle spaces in paths (Program Files)
229+ windowsPathPattern := regexp .MustCompile (`[A-Z]:[\\][^\n :]+` )
230+ msg = windowsPathPattern .ReplaceAllString (msg , "[PATH]" )
217231
218- // Remove potential passwords/secrets in error messages
219- // Matches: password=xxx, password= "xxx", password: xxx, api_key= xxx
220- // Bounded to 100 chars to prevent runaway matching
221- passwordPattern := regexp .MustCompile (`(?i)(password|passwd|pwd|secret|api[_-]? key)[\s=:]["']? ([^\s,;"']{1,100})["']? ` )
232+ // 9. Remove potential passwords/secrets - Fixed to handle colons and quotes properly
233+ // Matches: password=xxx, password: "xxx", password: xxx, api_key: xxx
234+ // Handle quoted values specially to avoid partial matches
235+ passwordPattern := regexp .MustCompile (`(?i)(password|passwd|pwd|secret|api[_-]key)[\s=:]+(?:"([^"]{1,100})"|'([^']{1,100})'| ([^\s,;"'\n ]{1,100})) ` )
222236 msg = passwordPattern .ReplaceAllString (msg , "$1=[REDACTED]" )
223237
224238 return msg
0 commit comments