mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-05-13 16:07:30 +00:00
🔐 fix: Redact Metadata in debugTraverse for Warn and Error
Relaxing the debug-only gate in debugTraverse (in commit59371be0) routed warn/error records through the traversal path, which emits leaf string values verbatim (via truncateLongStrings only). Because DEBUG_LOGGING defaults to true, those records are also written to the rotating debug log file — which means payloads like `{ auth: 'Bearer ...' }` or `{ openaiKey: 'sk-...' }` were persisted unredacted once my earlier change took effect. Apply redactMessage to the final formatted string when the level is warn or error. Debug-level behavior is unchanged (matching prior art). Includes regression tests covering error/warn redaction and debug-level preservation. Reviewed-by: Codex (P1 finding on PR #12737, commite288f7fd).
This commit is contained in:
parent
e288f7fda7
commit
c09d293d47
2 changed files with 55 additions and 10 deletions
|
|
@ -1,4 +1,7 @@
|
|||
const { formatConsoleMeta, redactMessage } = jest.requireActual('../parsers');
|
||||
jest.unmock('winston');
|
||||
|
||||
const { formatConsoleMeta, redactMessage, debugTraverse } = jest.requireActual('../parsers');
|
||||
const SPLAT_SYMBOL = Symbol.for('splat');
|
||||
|
||||
describe('formatConsoleMeta', () => {
|
||||
it('returns empty string when there is no user metadata', () => {
|
||||
|
|
@ -134,3 +137,44 @@ describe('redactMessage', () => {
|
|||
expect(redactMessage(undefined)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('debugTraverse', () => {
|
||||
const runFormatter = (info) => {
|
||||
const transformed = debugTraverse.transform(info);
|
||||
const MESSAGE = Symbol.for('message');
|
||||
if (transformed && typeof transformed === 'object') {
|
||||
return transformed[MESSAGE] ?? String(transformed);
|
||||
}
|
||||
return String(transformed);
|
||||
};
|
||||
|
||||
const buildInfo = (level, meta) => {
|
||||
const info = {
|
||||
level,
|
||||
message: 'test',
|
||||
timestamp: 'ts',
|
||||
...meta,
|
||||
};
|
||||
info[SPLAT_SYMBOL] = [meta];
|
||||
return info;
|
||||
};
|
||||
|
||||
it('redacts sensitive strings in metadata for error level', () => {
|
||||
const out = runFormatter(buildInfo('error', { auth: 'Bearer eyJabc123', openai: 'sk-abc123' }));
|
||||
expect(out).not.toContain('eyJabc123');
|
||||
expect(out).not.toContain('sk-abc123');
|
||||
expect(out).toContain('Bearer [REDACTED]');
|
||||
expect(out).toContain('sk-[REDACTED]');
|
||||
});
|
||||
|
||||
it('redacts sensitive strings in metadata for warn level', () => {
|
||||
const out = runFormatter(buildInfo('warn', { header: 'Bearer supersecrettoken' }));
|
||||
expect(out).not.toContain('supersecrettoken');
|
||||
expect(out).toContain('Bearer [REDACTED]');
|
||||
});
|
||||
|
||||
it('preserves debug-level metadata unmodified (existing behavior)', () => {
|
||||
const out = runFormatter(buildInfo('debug', { someField: 'not-sensitive' }));
|
||||
expect(out).toContain('not-sensitive');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -164,30 +164,31 @@ const debugTraverse = winston.format.printf(({ level, message, timestamp, ...met
|
|||
}
|
||||
|
||||
let msg = `${timestamp} ${level}: ${truncateLongStrings(message?.trim(), DEBUG_MESSAGE_LENGTH)}`;
|
||||
const levelStr = typeof level === 'string' ? level : String(level);
|
||||
const isErrorOrWarn = levelStr.includes('error') || levelStr.includes('warn');
|
||||
const finalize = (text) => (isErrorOrWarn ? redactMessage(text) : text);
|
||||
try {
|
||||
const levelStr = typeof level === 'string' ? level : String(level);
|
||||
const isErrorOrWarn = levelStr.includes('error') || levelStr.includes('warn');
|
||||
if (level !== 'debug' && !isErrorOrWarn) {
|
||||
return msg;
|
||||
return finalize(msg);
|
||||
}
|
||||
|
||||
if (!metadata) {
|
||||
return msg;
|
||||
return finalize(msg);
|
||||
}
|
||||
|
||||
const debugValue = metadata[SPLAT_SYMBOL]?.[0] ?? extractMetaObject(metadata);
|
||||
|
||||
if (!debugValue) {
|
||||
return msg;
|
||||
return finalize(msg);
|
||||
}
|
||||
|
||||
if (debugValue && Array.isArray(debugValue)) {
|
||||
msg += `\n${JSON.stringify(debugValue.map(condenseArray))}`;
|
||||
return msg;
|
||||
return finalize(msg);
|
||||
}
|
||||
|
||||
if (typeof debugValue !== 'object') {
|
||||
return (msg += ` ${debugValue}`);
|
||||
return finalize((msg += ` ${debugValue}`));
|
||||
}
|
||||
|
||||
msg += '\n{';
|
||||
|
|
@ -228,9 +229,9 @@ const debugTraverse = winston.format.printf(({ level, message, timestamp, ...met
|
|||
});
|
||||
|
||||
msg += '\n}';
|
||||
return msg;
|
||||
return finalize(msg);
|
||||
} catch (e) {
|
||||
return (msg += `\n[LOGGER PARSING ERROR] ${e.message}`);
|
||||
return finalize((msg += `\n[LOGGER PARSING ERROR] ${e.message}`));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue