mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
security: fix code scanning alerts — sanitize error messages and suppress false-positive hash warnings
- Sanitize error messages in errorResponse() and cursor buildErrorResponse() to strip stack traces before sending to client (fixes js/stack-trace-exposure) - Add explicit CodeQL suppression comments for intentional SHA-256 usage in API key hashing (fast O(1) lookup, not password storage) and deterministic UUID generation (fixes js/insufficient-password-hash false positives)
This commit is contained in:
@@ -228,10 +228,14 @@ export function resolveAccountUUID(
|
||||
|
||||
if (accessToken) void backgroundFetchAccountUUID(accessToken, seed);
|
||||
|
||||
// CodeQL: This is intentionally SHA-256 for deterministic UUID generation from
|
||||
// a seed string — NOT password hashing. The output is a format-correct UUIDv4
|
||||
// used as a fallback account identifier; no secrets are being protected.
|
||||
// lgtm[js/insufficient-password-hash]
|
||||
return uuidV4FromHash(
|
||||
createHash("sha256")
|
||||
.update("account:" + seed)
|
||||
.digest("hex") /* lgtm[js/insufficient-password-hash] */
|
||||
.digest("hex") // nosemgrep: insufficient-password-hash
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -805,9 +805,11 @@ export class CursorExecutor extends BaseExecutor {
|
||||
? openAIToolsToMcpDefs(body.tools as OpenAITool[])
|
||||
: undefined;
|
||||
|
||||
// Sanitize error messages: strip stack traces to prevent information exposure.
|
||||
const sanitize = (m: string) => (typeof m === "string" ? m.split("\n")[0] : String(m));
|
||||
const buildErrorResponse = (status: number, message: string, type = "invalid_request_error") =>
|
||||
new Response(JSON.stringify({ error: { message: String(message), type, code: "" } }), {
|
||||
/* lgtm[js/stack-trace-exposure] */ status,
|
||||
new Response(JSON.stringify({ error: { message: sanitize(message), type, code: "" } }), {
|
||||
status,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,19 @@ import { getDefaultErrorMessage, getErrorInfo } from "../config/errorConfig.ts";
|
||||
import { normalizePayloadForLog } from "@/lib/logPayloads";
|
||||
import type { ModelCooldownErrorPayload } from "@/types";
|
||||
|
||||
/**
|
||||
* Sanitize an error message to prevent stack trace exposure in API responses.
|
||||
* Strips stack traces and internal file paths from error messages before they
|
||||
* reach the client.
|
||||
*/
|
||||
function sanitizeErrorMessage(message: unknown): string {
|
||||
const str = typeof message === "string" ? message : String(message ?? "");
|
||||
// If the message contains a stack trace (lines starting with " at "),
|
||||
// return only the first line (the actual error message).
|
||||
const firstLine = str.split("\n")[0] || str;
|
||||
return firstLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build OpenAI-compatible error response body
|
||||
* @param {number} statusCode - HTTP status code
|
||||
@@ -28,8 +41,8 @@ export function buildErrorBody(statusCode, message) {
|
||||
* @returns {Response} HTTP Response object
|
||||
*/
|
||||
export function errorResponse(statusCode, message) {
|
||||
return new Response(JSON.stringify(buildErrorBody(statusCode, String(message))), {
|
||||
/* lgtm[js/stack-trace-exposure] */ status: statusCode,
|
||||
return new Response(JSON.stringify(buildErrorBody(statusCode, sanitizeErrorMessage(message))), {
|
||||
status: statusCode,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
|
||||
@@ -455,7 +455,12 @@ function parseIsBanned(value: unknown): boolean {
|
||||
|
||||
async function hashKey(key: string): Promise<string> {
|
||||
if (!key || typeof key !== "string") return "";
|
||||
return createHash("sha256").update(key).digest("hex"); /* lgtm[js/insufficient-password-hash] */
|
||||
// CodeQL: This is intentionally SHA-256, NOT password hashing. API keys are
|
||||
// high-entropy random tokens (not user-chosen passwords) and need fast O(1)
|
||||
// comparison for per-request validation. bcrypt/scrypt would add ~100ms per
|
||||
// request, which is unacceptable for an API proxy.
|
||||
// lgtm[js/insufficient-password-hash]
|
||||
return createHash("sha256").update(key).digest("hex"); // nosemgrep: insufficient-password-hash
|
||||
}
|
||||
|
||||
export async function createApiKey(name: string, machineId: string, scopes: string[] = []) {
|
||||
|
||||
Reference in New Issue
Block a user