Release v1.4.26 with remaining bug audit fixes

- AllDebrid: add HTML response detection to unrestrictLink
- Cleanup: skip symlinks/junctions in all directory traversals
- Blob URL: increase revoke delay from 0ms to 60s
- Extractor: per-package progress file to prevent collision
- ADD_CONTAINERS: reject path traversal and relative paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sucukdeluxe
2026-02-28 13:09:59 +01:00
co-authored by Claude Opus 4.6
parent 06a272ccbd
commit cbc423e4b7
7 changed files with 200 additions and 92 deletions
+21 -5
View File
@@ -30,7 +30,7 @@ export function cleanupCancelledPackageArtifacts(packageDir: string): number {
const current = stack.pop() as string;
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
const full = path.join(current, entry.name);
if (entry.isDirectory()) {
if (entry.isDirectory() && !entry.isSymbolicLink()) {
stack.push(full);
} else if (entry.isFile() && isArchiveOrTempFile(full)) {
try {
@@ -66,7 +66,7 @@ export async function cleanupCancelledPackageArtifactsAsync(packageDir: string):
for (const entry of entries) {
const full = path.join(current, entry.name);
if (entry.isDirectory()) {
if (entry.isDirectory() && !entry.isSymbolicLink()) {
stack.push(full);
} else if (entry.isFile() && isArchiveOrTempFile(full)) {
try {
@@ -96,7 +96,7 @@ export function removeDownloadLinkArtifacts(extractDir: string): number {
const current = stack.pop() as string;
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
const full = path.join(current, entry.name);
if (entry.isDirectory()) {
if (entry.isDirectory() && !entry.isSymbolicLink()) {
stack.push(full);
continue;
}
@@ -158,6 +158,14 @@ export function removeSampleArtifacts(extractDir: string): { files: number; dirs
for (const entry of entries) {
const full = path.join(current, entry.name);
if (entry.isDirectory()) {
try {
const stat = fs.lstatSync(full);
if (stat.isSymbolicLink()) {
continue;
}
} catch {
continue;
}
dirs.push(full);
} else if (entry.isFile()) {
count += 1;
@@ -171,13 +179,15 @@ export function removeSampleArtifacts(extractDir: string): { files: number; dirs
const current = stack.pop() as string;
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
const full = path.join(current, entry.name);
if (entry.isDirectory()) {
if (entry.isDirectory() || entry.isSymbolicLink()) {
const base = entry.name.toLowerCase();
if (SAMPLE_DIR_NAMES.has(base)) {
sampleDirs.push(full);
continue;
}
stack.push(full);
if (entry.isDirectory()) {
stack.push(full);
}
continue;
}
if (!entry.isFile()) {
@@ -202,6 +212,12 @@ export function removeSampleArtifacts(extractDir: string): { files: number; dirs
sampleDirs.sort((a, b) => b.length - a.length);
for (const dir of sampleDirs) {
try {
const stat = fs.lstatSync(dir);
if (stat.isSymbolicLink()) {
fs.rmSync(dir, { force: true });
removedDirs += 1;
continue;
}
const filesInDir = countFilesRecursive(dir);
fs.rmSync(dir, { recursive: true, force: true });
removedFiles += filesInDir;