Skip to content

Commit 09d5ac9

Browse files
committed
fix: re-apply path traversal containment to export endpoints
The path traversal fix was lost when upstream extracted routes from server/index.ts to server/routes/uploads.ts and server/routes/posters.ts. Re-applies containment check to both export endpoints.
1 parent b585521 commit 09d5ac9

2 files changed

Lines changed: 26 additions & 13 deletions

File tree

server/routes/posters.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,17 +1200,23 @@ router.get('/templates/:id/export', async (req, res, next) => {
12001200
}
12011201
}
12021202
} else {
1203-
// This might be a raster image path - check in different possible locations
1204-
const possiblePaths = [
1205-
path.join(process.cwd(), 'config', 'uploads', assetPath),
1206-
path.join(process.cwd(), 'config', 'posters', assetPath),
1207-
path.join(process.cwd(), assetPath),
1203+
const allowedDirs = [
1204+
path.join(process.cwd(), 'config', 'uploads'),
1205+
path.join(process.cwd(), 'config', 'posters'),
12081206
];
1207+
const possiblePaths = allowedDirs.map((dir) =>
1208+
path.join(dir, assetPath)
1209+
);
12091210

12101211
for (const possiblePath of possiblePaths) {
1211-
if (fs.existsSync(possiblePath)) {
1212+
const resolvedPath = path.resolve(possiblePath);
1213+
const isContained = allowedDirs.some((dir) =>
1214+
resolvedPath.startsWith(path.resolve(dir) + path.sep)
1215+
);
1216+
if (!isContained) continue;
1217+
if (fs.existsSync(resolvedPath)) {
12121218
const relativeName = `assets/images/${path.basename(assetPath)}`;
1213-
archive.file(possiblePath, { name: relativeName });
1219+
archive.file(resolvedPath, { name: relativeName });
12141220
logger.debug(`Added raster image to archive: ${relativeName}`);
12151221
break;
12161222
}

server/routes/uploads.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -502,15 +502,22 @@ router.get('/overlay-template-export/:id', async (req, res) => {
502502
}
503503
}
504504
} else {
505-
const possiblePaths = [
506-
path.join(process.cwd(), 'config', 'uploads', assetPath),
507-
path.join(process.cwd(), 'config', 'posters', assetPath),
508-
path.join(process.cwd(), assetPath),
505+
const allowedDirs = [
506+
path.join(process.cwd(), 'config', 'uploads'),
507+
path.join(process.cwd(), 'config', 'posters'),
509508
];
509+
const possiblePaths = allowedDirs.map((dir) =>
510+
path.join(dir, assetPath)
511+
);
510512

511513
for (const possiblePath of possiblePaths) {
512-
if (fs.existsSync(possiblePath)) {
513-
archive.file(possiblePath, {
514+
const resolvedPath = path.resolve(possiblePath);
515+
const isContained = allowedDirs.some((dir) =>
516+
resolvedPath.startsWith(path.resolve(dir) + path.sep)
517+
);
518+
if (!isContained) continue;
519+
if (fs.existsSync(resolvedPath)) {
520+
archive.file(resolvedPath, {
514521
name: `assets/images/${path.basename(assetPath)}`,
515522
});
516523
logger.debug(

0 commit comments

Comments
 (0)