mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-04-07 11:38:16 +00:00
* fix: add base_dir path containment to FileWriterTool os.path.join does not prevent traversal — joining "./" with "../../../etc/cron.d/pwned" resolves cleanly outside any intended scope. The tool also called os.makedirs on the unvalidated path, meaning it would create arbitrary directory structures. Adds a base_dir parameter that uses os.path.realpath() to resolve the final path (including symlinks) before checking containment. Any filename or directory argument that resolves outside base_dir is rejected before any filesystem operation occurs. When base_dir is not set the tool behaves as before — only use that in fully sandboxed environments. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: make directory relative to base_dir for better UX When base_dir is set, the directory arg is now treated as a subdirectory of base_dir rather than an absolute path. This means the LLM only needs to specify a filename (and optionally a relative subdirectory) — it does not need to repeat the base_dir path. FileWriterTool(base_dir="./output") → filename="report.txt" writes to ./output/report.txt → filename="f.txt", directory="sub" writes to ./output/sub/f.txt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: remove directory field from LLM schema when base_dir is set When a developer sets base_dir, they control where files are written. The LLM should only supply filename and content — not a directory path. Adds ScopedFileWriterToolInput (no directory field) which is used when base_dir is provided at construction, following the same pattern as FileReadTool/ScrapeWebsiteTool. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: prevent path traversal in FileWriterTool without interface changes Adds containment check inside _run() using os.path.realpath() to ensure the resolved file path stays within the resolved directory. Blocks ../ sequences, absolute filenames, and symlink escapes transparently — no schema or interface changes required. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: use Path.is_relative_to() for path containment check Replaces startswith(real_directory + os.sep) with Path.is_relative_to(), which does a proper path-component comparison. This avoids the edge case where real_directory == "/" produces a "//" prefix, and is safe on case-insensitive filesystems. Also explicitly rejects the case where the filepath resolves to the directory itself (not a valid file target). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: fix portability issues in path traversal tests - test_blocks_traversal_in_filename: use a sibling temp dir instead of asserting against a potentially pre-existing ../outside.txt - test_blocks_absolute_path_in_filename: use a temp-dir-derived absolute path instead of hardcoding /etc/passwd - test_blocks_symlink_escape: symlink to a temp "outside" dir instead of /etc, assert target file was not created Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Greyson LaLonde <greyson.r.lalonde@gmail.com>