security(gateway): validate transcript sessionFile path
Problem: `resolveTranscriptPath()` returned user-provided `sessionFile` directly without any validation. An attacker could supply arbitrary paths like `/etc/cron.d/evil` to write outside the intended directory. Solution: - When storePath exists: validate sessionFile stays within store directory - When no storePath: require absolute path (reject relative paths without context) - Use path.relative() to detect escape attempts Fixes #3277 (partial) [AI-assisted: lightly tested, code understood]
This commit is contained in:
parent
9688454a30
commit
00a91da6eb
@ -56,11 +56,24 @@ function resolveTranscriptPath(params: {
|
||||
sessionFile?: string;
|
||||
}): string | null {
|
||||
const { sessionId, storePath, sessionFile } = params;
|
||||
if (sessionFile) return sessionFile;
|
||||
if (sessionFile) {
|
||||
if (storePath) {
|
||||
const storeDir = path.dirname(storePath);
|
||||
const absSessionFile = path.resolve(storeDir, sessionFile);
|
||||
const rel = path.relative(storeDir, absSessionFile);
|
||||
if (rel.startsWith("..") || path.isAbsolute(rel)) {
|
||||
throw new Error("sessionFile escapes store directory");
|
||||
}
|
||||
return absSessionFile;
|
||||
}
|
||||
if (!path.isAbsolute(sessionFile)) {
|
||||
throw new Error("sessionFile must be absolute when storePath is not set");
|
||||
}
|
||||
return sessionFile;
|
||||
}
|
||||
if (!storePath) return null;
|
||||
return path.join(path.dirname(storePath), `${sessionId}.jsonl`);
|
||||
}
|
||||
|
||||
function ensureTranscriptFile(params: { transcriptPath: string; sessionId: string }): {
|
||||
ok: boolean;
|
||||
error?: string;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user