mirror of https://github.com/openclaw/openclaw.git
fix(security): sanitize error responses to prevent information leakage (#5)
* fix(security): sanitize error responses to prevent information leakage Replace raw error messages in HTTP responses with generic messages. Internal error details (stack traces, module paths, error messages) were being returned to clients in 4 gateway endpoints. * fix: sanitize 2 additional error response leaks in openresponses-http Address CodeRabbit feedback: non-stream and streaming error paths in openresponses-http.ts were still returning String(err) to clients. * fix: add server-side error logging to sanitized catch blocks Restore err parameter and add logWarn() calls so errors are still captured server-side for diagnostics while keeping client responses sanitized. Addresses CodeRabbit feedback about silently discarded errors.
This commit is contained in:
parent
de7d94d9e2
commit
f788de30c8
|
|
@ -5,6 +5,7 @@ import { buildHistoryContextFromEntries, type HistoryEntry } from "../auto-reply
|
|||
import { createDefaultDeps } from "../cli/deps.js";
|
||||
import { agentCommand } from "../commands/agent.js";
|
||||
import { emitAgentEvent, onAgentEvent } from "../infra/agent-events.js";
|
||||
import { logWarn } from "../logger.js";
|
||||
import { defaultRuntime } from "../runtime.js";
|
||||
import { authorizeGatewayConnect, type ResolvedGatewayAuth } from "./auth.js";
|
||||
import {
|
||||
|
|
@ -264,8 +265,9 @@ export async function handleOpenAiHttpRequest(
|
|||
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
|
||||
});
|
||||
} catch (err) {
|
||||
logWarn(`openai-compat: chat completion failed: ${String(err)}`);
|
||||
sendJson(res, 500, {
|
||||
error: { message: String(err), type: "api_error" },
|
||||
error: { message: "internal error", type: "api_error" },
|
||||
});
|
||||
}
|
||||
return true;
|
||||
|
|
@ -394,6 +396,7 @@ export async function handleOpenAiHttpRequest(
|
|||
});
|
||||
}
|
||||
} catch (err) {
|
||||
logWarn(`openai-compat: streaming chat completion failed: ${String(err)}`);
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -405,7 +408,7 @@ export async function handleOpenAiHttpRequest(
|
|||
choices: [
|
||||
{
|
||||
index: 0,
|
||||
delta: { content: `Error: ${String(err)}` },
|
||||
delta: { content: "Error: internal error" },
|
||||
finish_reason: "stop",
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { buildHistoryContextFromEntries, type HistoryEntry } from "../auto-reply
|
|||
import { createDefaultDeps } from "../cli/deps.js";
|
||||
import { agentCommand } from "../commands/agent.js";
|
||||
import { emitAgentEvent, onAgentEvent } from "../infra/agent-events.js";
|
||||
import { logWarn } from "../logger.js";
|
||||
import {
|
||||
DEFAULT_INPUT_FILE_MAX_BYTES,
|
||||
DEFAULT_INPUT_FILE_MAX_CHARS,
|
||||
|
|
@ -485,8 +486,9 @@ export async function handleOpenResponsesHttpRequest(
|
|||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logWarn(`openresponses: request parsing failed: ${String(err)}`);
|
||||
sendJson(res, 400, {
|
||||
error: { message: String(err), type: "invalid_request_error" },
|
||||
error: { message: "invalid request", type: "invalid_request_error" },
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
|
@ -502,8 +504,9 @@ export async function handleOpenResponsesHttpRequest(
|
|||
resolvedClientTools = toolChoiceResult.tools;
|
||||
toolChoicePrompt = toolChoiceResult.extraSystemPrompt;
|
||||
} catch (err) {
|
||||
logWarn(`openresponses: tool configuration failed: ${String(err)}`);
|
||||
sendJson(res, 400, {
|
||||
error: { message: String(err), type: "invalid_request_error" },
|
||||
error: { message: "invalid tool configuration", type: "invalid_request_error" },
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
|
@ -617,12 +620,13 @@ export async function handleOpenResponsesHttpRequest(
|
|||
|
||||
sendJson(res, 200, response);
|
||||
} catch (err) {
|
||||
logWarn(`openresponses: non-stream response failed: ${String(err)}`);
|
||||
const response = createResponseResource({
|
||||
id: responseId,
|
||||
model,
|
||||
status: "failed",
|
||||
output: [],
|
||||
error: { code: "api_error", message: String(err) },
|
||||
error: { code: "api_error", message: "internal error" },
|
||||
});
|
||||
sendJson(res, 500, response);
|
||||
}
|
||||
|
|
@ -912,6 +916,7 @@ export async function handleOpenResponsesHttpRequest(
|
|||
});
|
||||
}
|
||||
} catch (err) {
|
||||
logWarn(`openresponses: streaming response failed: ${String(err)}`);
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -922,7 +927,7 @@ export async function handleOpenResponsesHttpRequest(
|
|||
model,
|
||||
status: "failed",
|
||||
output: [],
|
||||
error: { code: "api_error", message: String(err) },
|
||||
error: { code: "api_error", message: "internal error" },
|
||||
usage: finalUsage,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -348,9 +348,10 @@ export async function handleToolsInvokeHttpRequest(
|
|||
const result = await (tool as any).execute?.(`http-${Date.now()}`, toolArgs);
|
||||
sendJson(res, 200, { ok: true, result });
|
||||
} catch (err) {
|
||||
logWarn(`tools-invoke: tool execution failed: ${String(err)}`);
|
||||
sendJson(res, 400, {
|
||||
ok: false,
|
||||
error: { type: "tool_error", message: err instanceof Error ? err.message : String(err) },
|
||||
error: { type: "tool_error", message: "tool execution failed" },
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue