| Title | demsking image-downloader 4.3.0 Path Traversal |
|---|
| Description | CVE-2026-103648 (already assigned and published by GitLab as CNA — this submission documents an existing CVE, no new CVE requested).
Path traversal (CWE-22) in image-downloader 4.3.0, an npm package (~38,000 downloads/month) maintained by demsking (Sebastien Demanou): https://gitlab.com/demsking/image-downloader
Summary:
An attacker who controls the path component of a URL passed to download.image({ url, dest }) can write files outside the configured destination directory.
Root cause (verified against the published 4.3.0 source, index.js):
const basename = path.basename(pathname); // called before decoding
const decodedBasename = decodeURIComponent(basename); // decoding happens after
options.dest = path.join(options.dest, decodedBasename);
path.basename() runs on the still percent-encoded URL pathname. A sequence such as %2e%2e%2f contains no literal slash at that point, so it passes through basename() unchanged. decodeURIComponent() is only applied afterward, turning it into a literal ../, and path.join() normalizes that, resolving the final write path outside the intended destination directory.
Preconditions:
- The consuming application passes an attacker-influenceable URL to download.image() (user-submitted image import, webhook payload, content feed entry)
- Default automatic filename extraction is in use (the default)
- The destination directory is writable by the process
Impact: arbitrary file write/overwrite outside the configured destination directory. In processes with broad filesystem access this can escalate to code execution.
CVSS vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H (9.1 Critical)
Proof of Concept (minimal, local loopback only, no real target involved):
mkdir vuln-test && cd vuln-test
npm init -y && npm install [email protected]
mkdir dest
exploit.js:
const download = require('image-downloader');
download.image({
url: 'http://127.0.0.1:8888/%2e%2e%2fpwned.sh',
dest: __dirname + '/dest'
}).then(function (result) { console.log('Saved to:', result.filename); }).catch(console.error);
Result: the file is saved one directory above dest, escaping the intended destination directory.
Full working PoC script, Docker lab, and patch analysis are publicly available at: https://github.com/EterNullSec/CVE-2026-103648
Fixed in image-downloader 4.3.1 (commit fb44543): reorders the operations to decode before extracting the basename, and adds an explicit path.relative containment check plus NUL-byte rejection as defense in depth. https://gitlab.com/demsking/image-downloader/-/commit/fb4454304276e2439fb19b98836b3ba903b3aaea
Disclosure timeline:
2026-10-01: CVE reserved (GitLab, as CNA)
2026-10-02: Patch released in image-downloader 4.3.1
2026-10-02: CVE-2026-103648 published (MITRE/NVD)
2026-10-03: Public PoC repository and write-up released
This vulnerability was responsibly disclosed to the maintainer (Sebastien Demanou) prior to public release.
References:
CVE Record: https://www.cve.org/CVERecord?id=CVE-2026-103648
NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2026-103648
npm package: https://www.npmjs.com/package/image-downloader
Reporter: Amirhossein Roustaei (EterNullSec), Eternull Security, https://roustaei.info |
|---|
| Source | ⚠️ https://github.com/EterNullSec/CVE-2026-103648 |
|---|
| User | Eternullsec (UID 101919) |
|---|
| Submission | 10/05/2026 22:57 (24 days ago) |
|---|
| Moderation | 10/18/2026 21:38 (13 days later) |
|---|
| Status | Duplicate |
|---|
| VulDB entry | 413181 [demsking image-downloader up to 4.3.0 download URL path traversal] |
|---|
| Points | 0 |
|---|