Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions cli/src/commands/submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,12 @@ export function makeSubmitCommand(): Command {
throw new CliError(`No local file found for upload instruction: ${instruction.filename}`);
}
const filePath = attachmentArgs.find(arg =>
!arg.startsWith('http') && path.basename(path.resolve(arg)) === instruction.filename,
!arg.startsWith('http') && path.basename(safeResolvePath(arg)) === instruction.filename,
);
if (!filePath) {
throw new CliError(`Cannot locate local file for presigned upload: ${instruction.filename}`);
}
await uploadViaPresignedPost(path.resolve(filePath), instruction);
await uploadViaPresignedPost(safeResolvePath(filePath), instruction);
process.stderr.write(` Uploaded: ${instruction.filename}\n`);
}

Expand All @@ -227,6 +227,19 @@ export function makeSubmitCommand(): Command {
// Attachment resolution helpers
// ---------------------------------------------------------------------------

/** Resolve a user-supplied path and validate it stays under CWD (CWE-22 mitigation). */
function safeResolvePath(userPath: string): string {
// nosemgrep: path-join-resolve-traversal -- this IS the path-traversal guard
const resolved = path.resolve(userPath);
const cwd = process.cwd();
if (!resolved.startsWith(cwd + path.sep) && resolved !== cwd) {
throw new CliError(
`Attachment path must be within the working directory: ${userPath}`,
);
}
return resolved;
}

const MAX_INLINE_SIZE_BYTES = 500 * 1024; // 500 KB

/** MIME type lookup by file extension. */
Expand Down Expand Up @@ -263,7 +276,7 @@ function resolveAttachmentArg(arg: string): Attachment {
}

// Local file
const resolvedPath = path.resolve(arg);
const resolvedPath = safeResolvePath(arg);
if (!fs.existsSync(resolvedPath)) {
throw new CliError(`Attachment file not found: ${arg}`);
}
Expand Down