Skip to content

improve: add path validation for filesystem-writing tools#91

Open
cagataycali wants to merge 3 commits intostrands-labs:mainfrom
cagataycali:improve/path-validation-tools
Open

improve: add path validation for filesystem-writing tools#91
cagataycali wants to merge 3 commits intostrands-labs:mainfrom
cagataycali:improve/path-validation-tools

Conversation

@cagataycali
Copy link
Copy Markdown
Member

Summary

Adds a shared path validation module and applies it to all tools that accept user-supplied paths for file I/O operations (camera captures, calibration backups/restores, pose storage).

Changes

New module: strands_robots/tools/_path_validation.py

validate_save_path(path, label) performs three checks:

  1. Null bytes / malformed input — rejects \x00
  2. Path traversal — rejects .. components (e.g. ../../etc/cron.d/evil)
  3. Protected directories — after os.path.realpath() resolution, blocks writes into /etc/, /usr/, /bin/, /sbin/, /boot/, /dev/, /proc/, /sys/, /var/spool/cron, /var/spool/at

Returns the resolved absolute path on success, raises ValueError on failure.

Updated tools

Tool Where validated
lerobot_camera save_path in capture, batch capture, video recording, config save
lerobot_calibrate output_dir (backup), backup_dir (restore)
pose_tool storage_dir in PoseManager.__init__

Motivation

These tools are called by AI agents which construct file paths from conversation context. Without validation, a crafted path like ../../etc/cron.d/evil could write to arbitrary locations. The validation module provides consistent defense-in-depth across all file-writing tools.

Design decisions

  • Shared module (_path_validation.py) rather than inline checks — single source of truth, easy to extend the blocked-prefix list.
  • Underscore prefix — signals this is an internal helper, not a public tool.
  • os.path.realpath — resolves symlinks to catch symlink-based bypasses.
  • Allowlist-by-exclusion — we block known dangerous prefixes rather than requiring a specific allowed directory, keeping the tools flexible for different deployment environments.

Adds a shared _path_validation module and applies it to all tools that
accept user-supplied paths for file I/O:

New module: strands_robots/tools/_path_validation.py
- validate_save_path() rejects null bytes, '..' traversal components,
  and paths that resolve into protected system directories (/etc, /usr,
  /proc, /sys, /var/spool/cron, etc.).

Updated tools:
- lerobot_camera: validates save_path in capture, batch capture,
  video recording, and config save operations.
- lerobot_calibrate: validates output_dir (backup) and backup_dir
  (restore) before any filesystem writes.
- pose_tool: validates storage_dir in PoseManager initialization.
@cagataycali cagataycali requested a review from mrgh-test April 1, 2026 22:53
Copy link
Copy Markdown

@mrgh-test mrgh-test left a comment

Choose a reason for hiding this comment

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

Might want to add tests for the path validation as well.

Comment on lines +58 to +59
"/var/spool/cron",
"/var/spool/at",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

These two probably also need trailing slashes?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 6ad33de — added trailing slashes to both /var/spool/cron/ and /var/spool/at/.

Also improved the matching logic: the resolved path now gets a trailing / appended before startswith comparison, so the exact directory path itself (e.g. /var/spool/cron) is also caught. Moved BLOCKED_PREFIXES to a module-level constant and added an invariant test (test_all_blocked_prefixes_end_with_slash) to prevent this class of bug from recurring.

Added 37 tests covering path validation — see tests/test_path_validation.py.


🤖 AI agent response. Strands Agents. Feedback welcome!

Address review feedback from PR strands-labs#91:

1. Fix trailing slashes on /var/spool/cron/ and /var/spool/at/ blocked
   prefixes — without the slash, paths like /var/spool/crondata would
   incorrectly match while /var/spool/cron itself could slip through.

2. Move BLOCKED_PREFIXES to module-level constant (importable, not
   re-created on every call).

3. Add check_path normalization — append '/' to resolved path before
   prefix comparison so exact directory matches (e.g. /var/spool/cron)
   are also caught.

4. Add comprehensive test suite (37 tests):
   - Happy paths (tmp, home, tilde expansion)
   - Null byte rejection
   - Directory traversal (.., backslash variants)
   - All blocked prefixes parametrized
   - Trailing-slash precision (sibling dir false-positive prevention)
   - Custom label propagation
   - Symlink resolution (blocked and safe targets)
   - Invariant: all prefixes must end with '/'
@cagataycali
Copy link
Copy Markdown
Member Author

👋 Friendly nudge — the review feedback (trailing slashes on blocked prefixes) was addressed in commit 6ad33de along with 37 tests covering the path validation module. The unresolved thread should be good to resolve now.

Summary of changes since review:

  • ✅ Added trailing slashes to /var/spool/cron/ and /var/spool/at/
  • ✅ Moved BLOCKED_PREFIXES to module-level constant
  • ✅ Improved path normalization (append / before startswith comparison)
  • ✅ Added invariant test test_all_blocked_prefixes_end_with_slash
  • ✅ 37 comprehensive tests in tests/test_path_validation.py

CI is green. Ready for re-review when convenient. 🙏


🤖 AI agent response. Strands Agents. Feedback welcome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

2 participants