From 2a7743723a5761839b3b1bd2db50f50d414ccaff Mon Sep 17 00:00:00 2001 From: Rodrigo Delduca Date: Mon, 22 Jun 2026 12:27:18 -0300 Subject: [PATCH] fix(api): sanitize error responses in HTTP handlers Why: HTTP handlers wrote raw upstream error strings into client responses, disclosing driver, schema and internal error details to external clients -- the same information-disclosure class as the userspace login credential leak. What: Route HTTP handler error responses through a per-namespace api_error helper that logs the raw error server-side via logger and returns only a static public message. Status codes and other response fields are preserved; text (non-JSON) handlers log the error and write a static message. --- src/voice/_index.yaml | 11 +++++++++++ src/voice/api_error.lua | 17 +++++++++++++++++ src/voice/ask.lua | 4 ++-- src/voice/tts_token.lua | 4 ++-- 4 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 src/voice/api_error.lua diff --git a/src/voice/_index.yaml b/src/voice/_index.yaml index ecbc80f..838bcfb 100644 --- a/src/voice/_index.yaml +++ b/src/voice/_index.yaml @@ -65,6 +65,14 @@ entries: description: Given page context (page, params), returns the agent ID to use for this page # ── Libraries ── + - name: api_error + kind: library.lua + meta: + comment: Sanitized API error responses with server-side logging + source: file://api_error.lua + modules: + - logger + - name: agents kind: library.lua source: file://agents.lua @@ -92,6 +100,7 @@ entries: source: file://ask.lua method: handler imports: + api_error: wippy-swiss.voice:api_error session: wippy-swiss.voice:session context: wippy-swiss.voice:context agents: wippy-swiss.voice:agents @@ -124,6 +133,8 @@ entries: kind: function.lua source: file://tts_token.lua method: handler + imports: + api_error: wippy-swiss.voice:api_error modules: - http - json diff --git a/src/voice/api_error.lua b/src/voice/api_error.lua new file mode 100644 index 0000000..88d13aa --- /dev/null +++ b/src/voice/api_error.lua @@ -0,0 +1,17 @@ +local log = require("logger"):named("wippy-swiss.voice") + +local api_error = {} + +function api_error.fail(res, status, message, err) + if err ~= nil then + log:error(message, { error = tostring(err) }) + end + + res:set_status(status) + res:write_json({ + success = false, + error = message + }) +end + +return api_error diff --git a/src/voice/ask.lua b/src/voice/ask.lua index be98a65..3179c98 100644 --- a/src/voice/ask.lua +++ b/src/voice/ask.lua @@ -7,6 +7,7 @@ local security = require("security") local time = require("time") local logger = require("logger"):named("voice") local contract = require("contract") +local api_error = require("api_error") local session = require("session") local context = require("context") @@ -142,8 +143,7 @@ local function handler() ) if not ok then - res:set_status(http.STATUS.INTERNAL_ERROR) - res:write_json({ success = false, error = "send failed: " .. tostring(send_err) }) + api_error.fail(res, http.STATUS.INTERNAL_ERROR, "send failed", send_err) return end diff --git a/src/voice/tts_token.lua b/src/voice/tts_token.lua index d583266..d9e7cde 100644 --- a/src/voice/tts_token.lua +++ b/src/voice/tts_token.lua @@ -3,6 +3,7 @@ local json = require("json") local env = require("env") local security = require("security") local http_client = require("http_client") +local api_error = require("api_error") local NS = "voice.env:" @@ -82,8 +83,7 @@ local function handler() local tts, tts_err = get_tts_config() if not tts then - res:set_status(http.STATUS.INTERNAL_ERROR) - res:write_json({ success = false, error = tts_err }) + api_error.fail(res, http.STATUS.INTERNAL_ERROR, tts_err, nil) return end