CVE-2026-56834
PraisonAI dynamic-context artifact tools read arbitrary host files outside artifact storage
PraisonAI is a multi-agent teams system. From version 3.8.1 to before version 4.6.59, PraisonAI's Dynamic Context Discovery feature exposes artifact helper tools through ctx.get_tools(). The implemented artifact tools do not enforce that the supplied artifact_path is an artifact created by the configured store or that it lives under the configured artifact base directory. Instead, artifact_head, artifact_tail, artifact_grep, and artifact_chunk wrap the caller-supplied path directly into an ArtifactRef and then read it from the host filesystem. As a result, any prompt/user/tool-caller that can influence those tool arguments can read files readable by the PraisonAI process, such as project .env files, cloud credentials, SSH keys, source files, or other local data. This issue has been patched in version 4.6.59.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
7.5
PraisonAI dynamic-context artifact tools read arbitrary host files outside artifact storage
PraisonAI is a multi-agent teams system. From version 3.8.1 to before version 4.6.59, PraisonAI's Dynamic Context Discovery feature exposes artifact helper tools through ctx.get_tools(). The implemented artifact tools do not enforce that the supplied artifact_path is an artifact created by the configured store or that it lives under the configured artifact base directory. Instead, artifact_head, artifact_tail, artifact_grep, and artifact_chunk wrap the caller-supplied path directly into an ArtifactRef and then read it from the host filesystem. As a result, any prompt/user/tool-caller that can influence those tool arguments can read files readable by the PraisonAI process, such as project .env files, cloud credentials, SSH keys, source files, or other local data. This issue has been patched in version 4.6.59.
- Record
CVE-2026-56834- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-22, CWE-200
- Updated
- 2026-11-02
EUVDEUVD-2026-108875
7.5
PraisonAI is a multi-agent teams system. From version 3.8.1 to before version 4.6.59, PraisonAI's Dynamic Context Discovery feature exposes artifact helper tools through ctx.get_tools(). The implemented artifact tools do not enforce that the supplied artifact_path is an artifact created by the configured store or that it lives under the configured artifact base directory. Instead, artifact_head, artifact_tail, artifact_grep, and artifact_chunk wrap the caller-supplied path directly into an ArtifactRef and then read it from the host filesystem. As a result, any prompt/user/tool-caller that can influence those tool arguments can read files readable by the PraisonAI process, such as project .env files, cloud credentials, SSH keys, source files, or other local data. This issue has been patched in version 4.6.59.
- Record
EUVD-2026-108875- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-j7qx-p75m-wp7g
7.5
PraisonAI dynamic-context artifact tools read arbitrary host files outside artifact storage
PraisonAI dynamic-context artifact tools read arbitrary host files outside artifact storage
Summary
PraisonAI's Dynamic Context Discovery feature exposes artifact helper tools
through ctx.get_tools():
ctx = setup_dynamic_context()
agent = Agent(
instructions="You are a data analyst.",
tools=ctx.get_tools(),
hooks=[ctx.get_middleware()],
)
The official documentation describes these helpers as a way for the agent to explore large tool-output artifacts that were queued by the middleware:
- large tool outputs are saved as artifacts;
- the agent receives compact artifact references; and
- the agent uses
artifact_tailandartifact_grepto explore that data.
The implemented artifact tools do not enforce that the supplied
artifact_path is an artifact created by the configured store or that it lives
under the configured artifact base directory. Instead, artifact_head,
artifact_tail, artifact_grep, and artifact_chunk wrap the caller-supplied
path directly into an ArtifactRef and then read it from the host filesystem.
As a result, any prompt/user/tool-caller that can influence those tool
arguments can read files readable by the PraisonAI process, such as project
.env files, cloud credentials, SSH keys, source files, or other local data.
Affected Product
- Repository:
MervinPraison/PraisonAI - Ecosystem:
pip - Package:
praisonai - Component: Dynamic Context Discovery artifact tools
- Current source path:
src/praisonai/praisonai/context/queue.py - Artifact store path:
src/praisonai/praisonai/context/artifact_store.py - Latest PyPI version validated:
4.6.58 - Current
origin/mainvalidated:1ad58ca02975ff1398efeda694ea2ab78f20cf3e - Current
origin/maintag validated:v4.6.58
Suggested affected range:
pip:praisonai >= 3.8.1, <= 4.6.58
Representative local sweep:
3.8.1: vulnerable4.0.0: vulnerable4.5.113: vulnerable4.6.33: vulnerable4.6.34: vulnerable4.6.40: vulnerable4.6.50: vulnerable4.6.58: vulnerable
Root Cause
create_artifact_tools() creates an artifact store bound to base_dir, but the
read tools do not use base_dir for containment.
For example, artifact_head() accepts artifact_path and immediately creates
an ArtifactRef with that path:
def artifact_head(artifact_path: str, lines: int = 50) -> str:
ref = ArtifactRef(path=artifact_path, summary="", size_bytes=0)
try:
return artifact_store.head(ref, lines=lines)
except FileNotFoundError:
return f"Error: Artifact not found: {artifact_path}"
artifact_tail(), artifact_grep(), and artifact_chunk() have the same
pattern. They trust the caller-supplied path rather than resolving it through
an artifact identifier, store lookup, manifest, or base-directory containment
check.
The store methods then read that path directly:
def head(self, ref: ArtifactRef, lines: int = 50) -> str:
file_path = Path(ref.path)
if not file_path.exists():
raise FileNotFoundError(f"Artifact not found: {ref.path}")
result_lines = []
with open(file_path, "r", encoding="utf-8", errors="replace") as f:
...
There is no check equivalent to:
resolved = Path(ref.path).resolve()
base = self.base_dir.resolve()
resolved.relative_to(base)
There is also no check that the file has a valid .meta sidecar or appears in
artifact_list().
Local PoV
Run against the latest PyPI package:
uv run --with 'praisonai==4.6.58' \
python poc/pov_prai_cand_026_artifact_tools_arbitrary_file_read.py --json
The PoV:
- Creates a temporary artifact base directory.
- Creates a separate
outside-secret.txtfile outside that base directory. - Stores one legitimate artifact through
FileSystemArtifactStore.store(). - Calls
artifact_head()on the legitimate artifact as a positive control. - Calls
artifact_head(),artifact_grep(), andartifact_chunk()on…
- Record
GHSA-j7qx-p75m-wp7g- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-22, CWE-200
- Updated
- 2026-11-02
NVD
7.5
PraisonAI is a multi-agent teams system. From version 3.8.1 to before version 4.6.59, PraisonAI's Dynamic Context Discovery feature exposes artifact helper tools through ctx.get_tools(). The implemented artifact tools do not enforce that the supplied artifact_path is an artifact created by the configured store or that it lives under the configured artifact base directory. Instead, artifact_head, artifact_tail, artifact_grep, and artifact_chunk wrap the caller-supplied path directly into an ArtifactRef and then read it from the host filesystem. As a result, any prompt/user/tool-caller that can influence those tool arguments can read files readable by the PraisonAI process, such as project .env files, cloud credentials, SSH keys, source files, or other local data. This issue has been patched in version 4.6.59.
- Record
CVE-2026-56834- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-22, CWE-200
- Updated
- 2026-11-02
OSV
7.5
PraisonAI dynamic-context artifact tools read arbitrary host files outside artifact storage
PraisonAI is a multi-agent teams system. From version 3.8.1 to before version 4.6.59, PraisonAI's Dynamic Context Discovery feature exposes artifact helper tools through ctx.get_tools(). The implemented artifact tools do not enforce that the supplied artifact_path is an artifact created by the configured store or that it lives under the configured artifact base directory. Instead, artifact_head, artifact_tail, artifact_grep, and artifact_chunk wrap the caller-supplied path directly into an ArtifactRef and then read it from the host filesystem. As a result, any prompt/user/tool-caller that can influence those tool arguments can read files readable by the PraisonAI process, such as project .env files, cloud credentials, SSH keys, source files, or other local data. This issue has been patched in version 4.6.59.
- Record
CVE-2026-56834- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-200, CWE-22
- Updated
- 2026-11-02
OSVGHSA-j7qx-p75m-wp7g
7.5
PraisonAI dynamic-context artifact tools read arbitrary host files outside artifact storage
PraisonAI dynamic-context artifact tools read arbitrary host files outside artifact storage
Summary
PraisonAI's Dynamic Context Discovery feature exposes artifact helper tools
through ctx.get_tools():
ctx = setup_dynamic_context()
agent = Agent(
instructions="You are a data analyst.",
tools=ctx.get_tools(),
hooks=[ctx.get_middleware()],
)
The official documentation describes these helpers as a way for the agent to explore large tool-output artifacts that were queued by the middleware:
- large tool outputs are saved as artifacts;
- the agent receives compact artifact references; and
- the agent uses
artifact_tailandartifact_grepto explore that data.
The implemented artifact tools do not enforce that the supplied
artifact_path is an artifact created by the configured store or that it lives
under the configured artifact base directory. Instead, artifact_head,
artifact_tail, artifact_grep, and artifact_chunk wrap the caller-supplied
path directly into an ArtifactRef and then read it from the host filesystem.
As a result, any prompt/user/tool-caller that can influence those tool
arguments can read files readable by the PraisonAI process, such as project
.env files, cloud credentials, SSH keys, source files, or other local data.
Affected Product
- Repository:
MervinPraison/PraisonAI - Ecosystem:
pip - Package:
praisonai - Component: Dynamic Context Discovery artifact tools
- Current source path:
src/praisonai/praisonai/context/queue.py - Artifact store path:
src/praisonai/praisonai/context/artifact_store.py - Latest PyPI version validated:
4.6.58 - Current
origin/mainvalidated:1ad58ca02975ff1398efeda694ea2ab78f20cf3e - Current
origin/maintag validated:v4.6.58
Suggested affected range:
pip:praisonai >= 3.8.1, <= 4.6.58
Representative local sweep:
3.8.1: vulnerable4.0.0: vulnerable4.5.113: vulnerable4.6.33: vulnerable4.6.34: vulnerable4.6.40: vulnerable4.6.50: vulnerable4.6.58: vulnerable
Root Cause
create_artifact_tools() creates an artifact store bound to base_dir, but the
read tools do not use base_dir for containment.
For example, artifact_head() accepts artifact_path and immediately creates
an ArtifactRef with that path:
def artifact_head(artifact_path: str, lines: int = 50) -> str:
ref = ArtifactRef(path=artifact_path, summary="", size_bytes=0)
try:
return artifact_store.head(ref, lines=lines)
except FileNotFoundError:
return f"Error: Artifact not found: {artifact_path}"
artifact_tail(), artifact_grep(), and artifact_chunk() have the same
pattern. They trust the caller-supplied path rather than resolving it through
an artifact identifier, store lookup, manifest, or base-directory containment
check.
The store methods then read that path directly:
def head(self, ref: ArtifactRef, lines: int = 50) -> str:
file_path = Path(ref.path)
if not file_path.exists():
raise FileNotFoundError(f"Artifact not found: {ref.path}")
result_lines = []
with open(file_path, "r", encoding="utf-8", errors="replace") as f:
...
There is no check equivalent to:
resolved = Path(ref.path).resolve()
base = self.base_dir.resolve()
resolved.relative_to(base)
There is also no check that the file has a valid .meta sidecar or appears in
artifact_list().
Local PoV
Run against the latest PyPI package:
uv run --with 'praisonai==4.6.58' \
python poc/pov_prai_cand_026_artifact_tools_arbitrary_file_read.py --json
The PoV:
- Creates a temporary artifact base directory.
- Creates a separate
outside-secret.txtfile outside that base directory. - Stores one legitimate artifact through
FileSystemArtifactStore.store(). - Calls
artifact_head()on the legitimate artifact as a positive control. - Calls
artifact_head(),artifact_grep(), andartifact_chunk()on…
- Record
GHSA-j7qx-p75m-wp7g- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-200, CWE-22
- Updated
- 2026-11-02
OSVPYSEC-2026-3514
7.5
PraisonAI dynamic-context artifact tools read arbitrary host files outside artifact storage
PraisonAI dynamic-context artifact tools read arbitrary host files outside artifact storage
Summary
PraisonAI's Dynamic Context Discovery feature exposes artifact helper tools
through ctx.get_tools():
ctx = setup_dynamic_context()
agent = Agent(
instructions="You are a data analyst.",
tools=ctx.get_tools(),
hooks=[ctx.get_middleware()],
)
The official documentation describes these helpers as a way for the agent to explore large tool-output artifacts that were queued by the middleware:
- large tool outputs are saved as artifacts;
- the agent receives compact artifact references; and
- the agent uses
artifact_tailandartifact_grepto explore that data.
The implemented artifact tools do not enforce that the supplied
artifact_path is an artifact created by the configured store or that it lives
under the configured artifact base directory. Instead, artifact_head,
artifact_tail, artifact_grep, and artifact_chunk wrap the caller-supplied
path directly into an ArtifactRef and then read it from the host filesystem.
As a result, any prompt/user/tool-caller that can influence those tool
arguments can read files readable by the PraisonAI process, such as project
.env files, cloud credentials, SSH keys, source files, or other local data.
Affected Product
- Repository:
MervinPraison/PraisonAI - Ecosystem:
pip - Package:
praisonai - Component: Dynamic Context Discovery artifact tools
- Current source path:
src/praisonai/praisonai/context/queue.py - Artifact store path:
src/praisonai/praisonai/context/artifact_store.py - Latest PyPI version validated:
4.6.58 - Current
origin/mainvalidated:1ad58ca02975ff1398efeda694ea2ab78f20cf3e - Current
origin/maintag validated:v4.6.58
Suggested affected range:
pip:praisonai >= 3.8.1, <= 4.6.58
Representative local sweep:
3.8.1: vulnerable4.0.0: vulnerable4.5.113: vulnerable4.6.33: vulnerable4.6.34: vulnerable4.6.40: vulnerable4.6.50: vulnerable4.6.58: vulnerable
Root Cause
create_artifact_tools() creates an artifact store bound to base_dir, but the
read tools do not use base_dir for containment.
For example, artifact_head() accepts artifact_path and immediately creates
an ArtifactRef with that path:
def artifact_head(artifact_path: str, lines: int = 50) -> str:
ref = ArtifactRef(path=artifact_path, summary="", size_bytes=0)
try:
return artifact_store.head(ref, lines=lines)
except FileNotFoundError:
return f"Error: Artifact not found: {artifact_path}"
artifact_tail(), artifact_grep(), and artifact_chunk() have the same
pattern. They trust the caller-supplied path rather than resolving it through
an artifact identifier, store lookup, manifest, or base-directory containment
check.
The store methods then read that path directly:
def head(self, ref: ArtifactRef, lines: int = 50) -> str:
file_path = Path(ref.path)
if not file_path.exists():
raise FileNotFoundError(f"Artifact not found: {ref.path}")
result_lines = []
with open(file_path, "r", encoding="utf-8", errors="replace") as f:
...
There is no check equivalent to:
resolved = Path(ref.path).resolve()
base = self.base_dir.resolve()
resolved.relative_to(base)
There is also no check that the file has a valid .meta sidecar or appears in
artifact_list().
Local PoV
Run against the latest PyPI package:
uv run --with 'praisonai==4.6.58' \
python poc/pov_prai_cand_026_artifact_tools_arbitrary_file_read.py --json
The PoV:
- Creates a temporary artifact base directory.
- Creates a separate
outside-secret.txtfile outside that base directory. - Stores one legitimate artifact through
FileSystemArtifactStore.store(). - Calls
artifact_head()on the legitimate artifact as a positive control. - Calls
artifact_head(),artifact_grep(), andartifact_chunk()on…
- Record
PYSEC-2026-3514- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
praisonaiPyPI |
3.8.1 to 4.6.58 | 4.6.59 |
praisonaiPyPI |
3.8.1 up to 4.6.59, plus listed versions 3.10.03.10.13.10.103.10.113.10.12 Show 45 moreShow less3.10.133.10.143.10.153.10.163.10.173.10.183.10.193.10.23.10.203.10.213.10.223.10.233.10.243.10.253.10.263.10.273.10.33.10.43.10.53.10.63.10.73.10.83.10.93.11.03.11.13.11.103.11.113.11.123.11.133.11.143.11.23.11.33.11.43.11.83.11.93.12.03.12.13.12.23.12.33.8.103.8.113.8.123.8.133.8.143.8.16 |
4.6.59 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-56834 is a high vulnerability (CVSS 7.5) in Mervinpraison Praisonai, published June 18, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.37%, the 31st percentile. Fixed in praisonai 4.6.59.
References
Left out here: 249 versions and the rest of 3 source descriptions. The JSON record has them.