Skip to content

fix: prevent path traversal in FileSystemKnowledge.get_file (#8624) - #8726

Merged
harshsinha03 merged 5 commits into
agno-agi:mainfrom
SiAgentBuild:fix/8624-filesystem-knowledge-path-traversal
Jul 9, 2026
Merged

harshsinha03 merged 5 commits into
agno-agi:mainfrom
SiAgentBuild:fix/8624-filesystem-knowledge-path-traversal

Conversation

@SiAgentBuild

@SiAgentBuild SiAgentBuild commented Jul 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes the path-traversal vulnerability in FileSystemKnowledge._get_file fixes #8624.

FileSystemKnowledge(base_dir=...) exposes a get_file tool that the agent can call. Before this change, _get_file built the target path as Path(query) if isabs else base_path / query with no containment check, so a model-driven tool call (or a relative path like ../outside_secret.txt, or an absolute path such as /etc/passwd) could read any file the process had access to.

The fix builds the path with the shared safe_join_relative_path helper and rejects anything that escapes base_dir, mirroring the pattern already used by AirflowTools and agno/skills/agent_skills.py:

try:
    file_path = safe_join_relative_path(self.base_path, query)
except PathSecurityError:
    return []

safe_join_relative_path rejects absolute paths, .. traversal that escapes the base, control characters, and Windows drive/UNC prefixes, and it resolves the target before a containment check — so symlinks inside base_dir that point outside are blocked as well.

Error handling is also tightened: _get_file no longer swallows read errors into an empty list. Genuine read failures (e.g. a file that exists but is unreadable) propagate to the get_file tool wrapper, which surfaces the real cause to the agent — the same shape AirflowTools uses:

try:
    docs = self._get_file(path)
except Exception as e:
    log_warning(f"Error reading file {path}: {str(e)}")
    return f"Error reading file {path}: {e}"

Agent-facing behaviour: files inside base_dir return their content as before; missing / not-a-file / traversal / outside paths all return the safe File not found: {path} (an escape is indistinguishable from a missing file, so nothing is disclosed); a present-but-unreadable file returns the real error.

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Improvement
  • Model update
  • Other:

Checklist

  • Code complies with style guidelines
  • Ran format/validation scripts (./scripts/format.sh and ./scripts/validate.sh) — ruff format unchanged, ruff check clean, mypy reports no errors in knowledge/filesystem.py
  • Self-review completed
  • Documentation updated (comments, docstrings)
  • Examples and guides: Relevant cookbook examples have been included or updated (if applicable)
  • Tested in clean environment
  • Tests added/updated — four path-traversal regression tests in test_filesystem_knowledge.py

Duplicate and AI-Generated PR Check

  • I have searched existing open pull requests and confirmed that no other PR already addresses this issue

Notes for the maintainer

  • _list_files and _grep are not affected: they walk os.walk(self.base_path) and never join a user-supplied root, so no equivalent fix is required.
  • The fix is intentionally narrow: the _get_file signature, the tool contract, and all other class behaviour are unchanged. Files inside base_dir continue to work exactly as before.
  • The four regression tests cover relative .. traversal, an absolute path outside the base, a symlink inside the base that points outside, and the exposed get_file tool. They follow the existing test file's structure (nested base_dir under tmp_path, no manual cleanup).

agno-agi#8624)

FileSystemKnowledge._get_file accepted any absolute path or relative
path with '..' segments without checking that the resolved target
stayed under base_dir. An LLM-driven tool call to the exposed
`get_file` tool could therefore read any file the process had
access to (e.g. `../outside_secret.txt`, `/etc/passwd`).

Resolve the candidate path with strict=True before any I/O and reject
anything that does not satisfy is_relative_to(base_path). Symlinks
inside base_dir pointing outside are also rejected because the
containment check runs after canonical resolution.

The exposed `get_file` tool inherits the fix transparently because
it delegates to _get_file. Failures keep the existing return-empty-list
contract so callers do not need to handle a new exception.

Adds four regression tests covering relative traversal, absolute
path escape, symlink escape, and the exposed tool entrypoint.
@SiAgentBuild
SiAgentBuild requested a review from a team as a code owner July 3, 2026 03:37
@harshsinha03 harshsinha03 changed the title fix(knowledge): prevent path traversal in FileSystemKnowledge.get_file (#8624) fix: prevent path traversal in FileSystemKnowledge.get_file (#8624) Jul 8, 2026

@harshsinha03 harshsinha03 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for contributing

@harshsinha03
harshsinha03 merged commit 7698f64 into agno-agi:main Jul 9, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security] FileSystemKnowledge get_file can read outside base_dir

2 participants