CVE-2026-76832: Agno PythonTools Path Traversal Escapes base_dir

CVE-2026-76832: Agno PythonTools Path Traversal Escapes base_dir

CVE-2026-76832 is a CWE-22 path traversal in Agno PythonTools. file_name was joined onto base_dir with no resolved-path check. Upgrade agno to 2.3.24 or later. restrict_to_base_dir=False reopens the hole.

4 min read876 words
Contents

TL;DR: Agno's PythonTools built filesystem paths with self.base_dir.joinpath(file_name) and never checked that the resolved path stayed inside base_dir. read_file, save_to_file_and_run, and run_python_file_return_variable all take file_name. If an attacker can set that argument, through a direct tool call or through prompt injection into agent-processed content, the agent process can read, write, or run Python files outside the intended directory as the process user. The bug is CWE-22. It applies when PythonTools is enabled on an agent. VulnCheck scores it 8.5 High under CVSS 4.0 (AV:A, UI:A) and 8.8 High under CVSS 3.1. Agno patched it in v2.3.24 on 2026-01-08. Current PyPI is 2.9.0. Upgrade and confirm >= 2.3.24. Setting restrict_to_base_dir=False turns the check off and reopens the hole.

What happened

Agno (PyPI package agno) is an agent framework. PythonTools lets an agent save, read, and run Python files under a configured base_dir. If base_dir is omitted, the toolkit uses the process current working directory.

Before the patch, those file tools treated file_name as a relative path and concatenated it with base_dir. pathlib.Path.joinpath does not reject parent-directory segments. The resulting path was passed to read_text, write_text, or runpy.run_path with no resolve() plus containment check. The advertised base directory was a prefix, not a boundary. That is CWE-22.

The reporter, Ali Raza (locus-x64), disclosed it to Agno support on 2026-01-07. Maintainer Yuvaraj Shanmugam acknowledged the report on 2026-01-08, the day the fix shipped. oss-security carried the write-up on 2026-01-27 while a CVE was still pending. VulnCheck assigned CVE-2026-76832 on 2026-08-19. The code fix is seven months old. Installs that never upgraded, and installs that opted out of the new default, remain in scope.

Affected versions

  • Package: PyPI agno (vendor Agno AGI)
  • Affected: versions before 2.3.24. The vulnerable joinpath construction is present in the v2.3.23 tree at libs/agno/agno/tools/python.py. The VulnCheck CNA record versions the product against git commit 710d7e7 rather than a PyPI range. That hash is the fix commit, not a release number.
  • Fixed: 2.3.24, GitHub release and PyPI upload on 2026-01-08. PR 5940, commit 710d7e7f846f93b7a3eadfd3e77075428c39e803.
  • Current PyPI latest: 2.9.0. The restrict_to_base_dir=True default and _check_path call sites are still present on the v2.9.0 tag.
  • CWE: CWE-22 (Improper Limitation of a Pathname to a Restricted Directory)
  • CVSS: VulnCheck CNA, CVSS 4.0 8.5 High (CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N). CVSS 3.1 8.8 High (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H). NVD status is Received as of 2026-08-19. There is no NVD analysis score yet. Not listed in CISA KEV. No GitHub Security Advisory for CVE-2026-76832. Other Agno GHSAs exist for different bugs, including CVE-2026-35002 (eval injection), which was also fixed in 2.3.24.
  • Preconditions: PythonTools enabled on an agent. The attacker must influence file_name.

What to do

Upgrade the PyPI package:

pip install --upgrade agno

Confirm the installed version:

pip show agno

The Version field must be 2.3.24 or newer. 2.9.0 is the current PyPI release.

After upgrading, do not set restrict_to_base_dir=False on PythonTools unless you have a documented reason and a separate containment boundary. That flag is the vendor opt-out. It restores unconstrained path joining and reopens this CVE.

Inventory agents that construct Agent(tools=[PythonTools(...)]) or the equivalent. If the agent does not need file save, read, or run, drop PythonTools, or use exclude_tools to remove read_file, save_to_file_and_run, and run_python_file_return_variable.

The path check is not a sandbox. run_python_code, pip_install_package, and uv_pip_install_package still execute or install with the process user's privileges. Agno's docs still say to keep human supervision and to run untrusted execution in a container, VM, or Daytona.

Technical details

Vulnerable construction in v2.3.23 libs/agno/agno/tools/python.py:

file_path = self.base_dir.joinpath(file_name)

That line appeared in save_to_file_and_run, run_python_file_return_variable, and read_file. The CVE text names the tool actions save_to_file and run_python_file. The Python methods are the names above.

Commit 710d7e7 (PR 5940, "feat: add restrict_to_base_dir param to PythonTools and MLXTranscribeTools") does three things:

1. Resolves base_dir at toolkit init. 2. Adds restrict_to_base_dir: bool = True. 3. Routes file operations through Toolkit._check_path, which resolve()s the joined path and calls Path.relative_to(base_dir). A path that is not inside base_dir returns (False, base_dir) and the tool returns an error string instead of touching the file.

If restrict_to_base_dir is False, _check_path returns (True, file_path) with no containment test. That is an intentional opt-out, and it reopens CVE-2026-76832.

The same PR applied the helper to FileTools and MLXTranscribeTools. CVE-2026-76832 is scoped to PythonTools.

The v2.3.24 GitHub notes describe the change as "Forbid tools to operate out of base directory." Agno's product changelog calls it "Safer defaults: tools are restricted to their base directory by default" and flags it as a breaking change for workloads that previously wrote outside base_dir.

No GitHub Security Advisory exists for CVE-2026-76832 as of this writing. HOL Guard's evidence pack still has cvssScore: null because NVD analysis has not landed. The scores above come from the published VulnCheck CNA CVE document.

Track the CVE on HOL Guard as more sources land.

References

Continue reading

All posts