mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:30:43 +00:00
fix(security): sanitize QQBot debug log values
Sanitizes QQBot debug log values to remediate CodeQL alert 230.
This commit is contained in:
28
extensions/qqbot/src/engine/utils/log.test.ts
Normal file
28
extensions/qqbot/src/engine/utils/log.test.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { debugLog, sanitizeDebugLogValue } from "./log.js";
|
||||
|
||||
const originalDebug = process.env.QQBOT_DEBUG;
|
||||
|
||||
afterEach(() => {
|
||||
if (originalDebug === undefined) {
|
||||
delete process.env.QQBOT_DEBUG;
|
||||
} else {
|
||||
process.env.QQBOT_DEBUG = originalDebug;
|
||||
}
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("QQBot debug logging", () => {
|
||||
it("neutralizes control characters in log values", () => {
|
||||
expect(sanitizeDebugLogValue("before\nforged\r\tentry")).toBe("before forged entry");
|
||||
});
|
||||
|
||||
it("sanitizes arguments before debug console output", () => {
|
||||
process.env.QQBOT_DEBUG = "1";
|
||||
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
||||
|
||||
debugLog("prefix", "line one\nline two");
|
||||
|
||||
expect(logSpy).toHaveBeenCalledWith("prefix", "line one line two");
|
||||
});
|
||||
});
|
||||
@@ -9,24 +9,53 @@
|
||||
*/
|
||||
|
||||
const isDebug = () => !!process.env.QQBOT_DEBUG;
|
||||
const MAX_LOG_VALUE_CHARS = 4096;
|
||||
|
||||
export function sanitizeDebugLogValue(value: unknown): string {
|
||||
let text: string;
|
||||
if (typeof value === "string") {
|
||||
text = value;
|
||||
} else if (value instanceof Error) {
|
||||
text = value.stack || value.message;
|
||||
} else {
|
||||
try {
|
||||
text = JSON.stringify(value) ?? String(value);
|
||||
} catch {
|
||||
text = String(value);
|
||||
}
|
||||
}
|
||||
|
||||
const sanitized = text
|
||||
.replace(/\p{Cc}/gu, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
if (sanitized.length <= MAX_LOG_VALUE_CHARS) {
|
||||
return sanitized;
|
||||
}
|
||||
return `${sanitized.slice(0, MAX_LOG_VALUE_CHARS)}...`;
|
||||
}
|
||||
|
||||
function sanitizeDebugLogArgs(args: unknown[]): string[] {
|
||||
return args.map(sanitizeDebugLogValue);
|
||||
}
|
||||
|
||||
/** Debug-level log; only outputs when QQBOT_DEBUG is enabled. */
|
||||
export function debugLog(...args: unknown[]): void {
|
||||
if (isDebug()) {
|
||||
console.log(...args);
|
||||
console.log(...sanitizeDebugLogArgs(args));
|
||||
}
|
||||
}
|
||||
|
||||
/** Debug-level warning; only outputs when QQBOT_DEBUG is enabled. */
|
||||
export function debugWarn(...args: unknown[]): void {
|
||||
if (isDebug()) {
|
||||
console.warn(...args);
|
||||
console.warn(...sanitizeDebugLogArgs(args));
|
||||
}
|
||||
}
|
||||
|
||||
/** Debug-level error; only outputs when QQBOT_DEBUG is enabled. */
|
||||
export function debugError(...args: unknown[]): void {
|
||||
if (isDebug()) {
|
||||
console.error(...args);
|
||||
console.error(...sanitizeDebugLogArgs(args));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user