← Back to PRs

#20251: fix: sanitize error messages to prevent internal details and PII from leaking to end users

by aldoeliacim open 2026-02-18 18:04 View on GitHub →
channel: whatsapp-web agents size: L trusted-contributor
## Summary Internal error details were leaking to end users via messaging channels through multiple code paths. This PR hardens error sanitization across the entire outbound error pipeline — addressing **10 open issues** spanning LLM errors, media errors, auth leaks, tool errors, stream parse failures, and post-compaction corruption. ### Leak vectors fixed | Vector | What leaked | Issue(s) | |--------|------------|----------| | LLM transient errors | Raw `api_error`, `server_error`, `internal_error` JSON with request_ids | #20250 | | Media fetch errors | URLs, redirect targets, HTTP response body with conversation metadata, phone numbers, group IDs | #20279 | | Auth/permission errors | `authentication_error`, `permission_error` with credential details | #18937 | | Failover wrapper messages | `FailoverError:` and `All models failed (N):` exposing provider/model chains | #20250 | | `invalid_request_error` paths | `messages.N.content.N.thinking.signature: Field required` — session internals | #16825 | | Tool error warnings | Stack traces, file paths, long internal error text in `⚠️ tool failed:` messages | #17828 | | SSE/JSON stream parse errors | `Bad control character in string literal in JSON at position N` | #14321 | | Post-compaction orphaned tool calls | `No tool call found for function call output with call_id toolu01...` | #16948 | | Fallback catch-all | JSON payloads, HTML error pages, stack traces, and long strings slipping past specific checks | #12928, #11038 | | `formatRawAssistantErrorForUi` | Raw `HTTP code`, error `type`, and `request_id` exposed in parsed API errors | #7867 | ### Changes **`src/agents/pi-embedded-helpers/errors.ts`** - `isTransientApiError()` — detect transient server errors from API JSON payloads - `isAuthApiError()` — detect 401/403 auth errors from API payloads - `isFailoverWrapperMessage()` — detect failover wrapper strings - `invalid_request_error` handler: suppress message path indices (`messages.N.content.N...`) and `thinking.signature` errors - SSE/JSON parse errors (`Bad control character`, `Unexpected token`, `JSON at position`) → generic message - Orphaned tool call errors (`No tool call found for call_id`) → format error message - `formatRawAssistantErrorForUi()`: strip `request_id` and HTTP prefix from parsed errors; catch-all suppresses JSON, HTML, stack traces, and long strings - `formatAssistantErrorText()`: same hardening for the catch-all fallback path **`src/agents/pi-embedded-runner/run/payloads.ts`** - Sanitize tool error text — strip stack traces, file paths, and long error text from `⚠️ tool failed:` user-facing warnings **`src/web/auto-reply/deliver-reply.ts`** - Strip `err.message` from `⚠️ Media failed` warning — always shows just `⚠️ Media failed.` ### Tests - New test file: `errors.sanitize-leak-vectors.test.ts` (16 tests covering all new sanitization paths) - Updated TUI formatter tests for new sanitized output - Updated deliver-reply test to assert error internals don't leak - All 7591+ tests passing **No debugging information is lost** — all raw errors remain in server logs (`console.warn`, `whatsappOutboundLog`, `replyLogger`). ### Supersedes - PR #18970 (`fix/issue-18937`) — narrower fix for auth error leaks, fully covered here ### Related issues Fixes #20250 Fixes #20279 Fixes #18937 Fixes #16825 Fixes #14321 Fixes #16948 Addresses leak vectors reported in: #7867, #9951, #11038, #12928, #17828 Related architecture discussion: #16521, #16673

Most Similar PRs