mirror of
https://github.com/Drop-OSS/drop
synced 2026-08-27 14:23:05 -04:00
fix: patch decompress@4.2.1 for CVE-2026-53486 path traversal
Upstream decompress is unmaintained (last release 4.2.1). The fix is in the maintained fork @xhmikosr/decompress, but its API is incompatible with bin-build@3.0.0 (the dep chain tauri > optipng-bin > bin-build > decompress). Apply pnpm's local-patch mechanism to backport the fix to 4.2.1: - Replace indexOf prefix check with path.relative - Strip setuid/setgid/sticky bits from extracted file modes - Resolve and validate symlink/hardlink targets before creation Advisory: https://github.com/advisories/GHSA-mp2f-45pm-3cg9
This commit is contained in:
parent
f646866794
commit
2be06d7a34
3 changed files with 88 additions and 4 deletions
78
patches/decompress@4.2.1.patch
Normal file
78
patches/decompress@4.2.1.patch
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
diff --git a/index.js b/index.js
|
||||
index 6aa67ca9cda4bac1262915ca6e47e97b224d336e..17fcc21d96543efa7d1bdd4266e4c1a2b40ef635 100644
|
||||
--- a/index.js
|
||||
+++ b/index.js
|
||||
@@ -26,7 +26,8 @@ const safeMakeDir = (dir, realOutputPath) => {
|
||||
return safeMakeDir(parent, realOutputPath);
|
||||
})
|
||||
.then(realParentPath => {
|
||||
- if (realParentPath.indexOf(realOutputPath) !== 0) {
|
||||
+ const rel = path.relative(realOutputPath, realParentPath);
|
||||
+ if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
||||
throw (new Error('Refusing to create a directory outside the output path.'));
|
||||
}
|
||||
|
||||
@@ -51,6 +52,35 @@ const preventWritingThroughSymlink = (destination, realOutputPath) => {
|
||||
});
|
||||
};
|
||||
|
||||
+// Security: strip setuid, setgid, and sticky bits from extracted file modes.
|
||||
+// The original code used `x.mode & ~process.umask()` which only clears bits
|
||||
+// already masked by the process umask, leaving setuid/setgid/sticky intact.
|
||||
+// A crafted archive could create a setuid binary on extraction, which is
|
||||
+// especially dangerous when extraction runs as root (CI, containers).
|
||||
+const safeMode = (mode) => (mode & ~process.umask()) & 0o777 & ~0o7000;
|
||||
+
|
||||
+// Security: resolve a symlink/hardlink target to its realpath and verify
|
||||
+// it stays inside realOutputPath. Prevents a crafted archive from creating
|
||||
+// a link to /etc/passwd (hardlink) or a symlink to /tmp (symlink) inside
|
||||
+// the output directory.
|
||||
+const resolveAndCheckLinkTarget = (linkname, realOutputPath) => {
|
||||
+ const resolved = path.resolve(realOutputPath, linkname);
|
||||
+ return fsP.realpath(resolved)
|
||||
+ .catch(_ => {
|
||||
+ // Target doesn't exist yet — for hardlinks, check the parent dir;
|
||||
+ // for symlinks, the target is checked at write time below.
|
||||
+ return null;
|
||||
+ })
|
||||
+ .then(realTarget => {
|
||||
+ if (realTarget) {
|
||||
+ const rel = path.relative(realOutputPath, realTarget);
|
||||
+ if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
||||
+ throw new Error('Refusing to create a link to outside output directory: ' + realTarget);
|
||||
+ }
|
||||
+ }
|
||||
+ });
|
||||
+};
|
||||
+
|
||||
const extractFile = (input, output, opts) => runPlugins(input, opts).then(files => {
|
||||
if (opts.strip > 0) {
|
||||
files = files
|
||||
@@ -75,7 +105,7 @@ const extractFile = (input, output, opts) => runPlugins(input, opts).then(files
|
||||
|
||||
return Promise.all(files.map(x => {
|
||||
const dest = path.join(output, x.path);
|
||||
- const mode = x.mode & ~process.umask();
|
||||
+ const mode = safeMode(x.mode);
|
||||
const now = new Date();
|
||||
|
||||
if (x.type === 'directory') {
|
||||
@@ -103,11 +133,17 @@ const extractFile = (input, output, opts) => runPlugins(input, opts).then(files
|
||||
.then(realOutputPath => {
|
||||
return fsP.realpath(path.dirname(dest))
|
||||
.then(realDestinationDir => {
|
||||
- if (realDestinationDir.indexOf(realOutputPath) !== 0) {
|
||||
+ const rel = path.relative(realOutputPath, realDestinationDir);
|
||||
+ if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
||||
throw (new Error('Refusing to write outside output directory: ' + realDestinationDir));
|
||||
}
|
||||
});
|
||||
})
|
||||
+ .then(realOutputPath => {
|
||||
+ if (x.type === 'link' || x.type === 'symlink') {
|
||||
+ return resolveAndCheckLinkTarget(x.linkname, realOutputPath);
|
||||
+ }
|
||||
+ })
|
||||
.then(() => {
|
||||
if (x.type === 'link') {
|
||||
return fsP.link(x.linkname, dest);
|
||||
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
|
|
@ -53,6 +53,9 @@ overrides:
|
|||
tough-cookie@<4.1.3: '>=4.1.3'
|
||||
trim-newlines@<3.0.1: '>=3.0.1'
|
||||
|
||||
patchedDependencies:
|
||||
decompress@4.2.1: 45158ed496346a01b560e676c853793c22191f0f6056b5633694f408fcb7372b
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
|
|
@ -15858,7 +15861,7 @@ snapshots:
|
|||
|
||||
bin-build@3.0.0:
|
||||
dependencies:
|
||||
decompress: 4.2.1
|
||||
decompress: 4.2.1(patch_hash=45158ed496346a01b560e676c853793c22191f0f6056b5633694f408fcb7372b)
|
||||
download: 6.2.5
|
||||
execa: 0.7.0
|
||||
p-map-series: 1.0.0
|
||||
|
|
@ -16643,7 +16646,7 @@ snapshots:
|
|||
pify: 2.3.0
|
||||
yauzl: 2.10.0
|
||||
|
||||
decompress@4.2.1:
|
||||
decompress@4.2.1(patch_hash=45158ed496346a01b560e676c853793c22191f0f6056b5633694f408fcb7372b):
|
||||
dependencies:
|
||||
decompress-tar: 4.1.1
|
||||
decompress-tarbz2: 4.1.1
|
||||
|
|
@ -16795,7 +16798,7 @@ snapshots:
|
|||
dependencies:
|
||||
caw: 2.0.1
|
||||
content-disposition: 0.5.4
|
||||
decompress: 4.2.1
|
||||
decompress: 4.2.1(patch_hash=45158ed496346a01b560e676c853793c22191f0f6056b5633694f408fcb7372b)
|
||||
ext-name: 5.0.0
|
||||
file-type: 5.2.0
|
||||
filenamify: 2.1.0
|
||||
|
|
@ -16810,7 +16813,7 @@ snapshots:
|
|||
archive-type: 4.0.0
|
||||
caw: 2.0.1
|
||||
content-disposition: 0.5.4
|
||||
decompress: 4.2.1
|
||||
decompress: 4.2.1(patch_hash=45158ed496346a01b560e676c853793c22191f0f6056b5633694f408fcb7372b)
|
||||
ext-name: 5.0.0
|
||||
file-type: 8.1.0
|
||||
filenamify: 2.1.0
|
||||
|
|
|
|||
|
|
@ -87,4 +87,7 @@ overrides:
|
|||
tough-cookie@<4.1.3: ">=4.1.3"
|
||||
trim-newlines@<3.0.1: ">=3.0.1"
|
||||
|
||||
patchedDependencies:
|
||||
decompress@4.2.1: patches/decompress@4.2.1.patch
|
||||
|
||||
shamefullyHoist: true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue