Skip to content

fix(python_repl): restrict permissions on persisted state and error logs#517

Open
yonib05 wants to merge 3 commits into
strands-agents:mainfrom
yonib05:fix/python-repl-file-perms
Open

fix(python_repl): restrict permissions on persisted state and error logs#517
yonib05 wants to merge 3 commits into
strands-agents:mainfrom
yonib05:fix/python-repl-file-perms

Conversation

@yonib05

@yonib05 yonib05 commented Jun 27, 2026

Copy link
Copy Markdown
Member

Description

python_repl persists the REPL namespace to repl_state/repl_state.pkl and
appends executed code and tracebacks to errors/errors.txt. Both the
directories and files were created with default permissions, so on a shared
host they could be readable by other local users even though they may hold
sensitive values from the session.

This change creates those directories with mode 0o700 and writes the files
with mode 0o600 (via os.open), so they are owner-only.

Changes

  • Create the persistence directory and errors directory with mode=0o700 and
    os.chmod them to 0o700 (covering the already-exists case).
  • Write repl_state.pkl and errors.txt through os.open(..., 0o600).

Testing

  • Added TestStatePermissions asserting no group/other permission bits are set
    on the persistence directory and the state file.
  • pytest tests/test_python_repl.py passes.
  • ruff format --check and ruff check pass on the changed files.

The REPL state directory and pickle file hold the full REPL namespace, and
the errors directory and errors.txt echo executed code. These were created
with default permissions, leaving them readable by other users on a shared
host. Create the directories mode 0o700 and write the files mode 0o600 via
os.open so they are owner-only.
@JackYPCOnline

Copy link
Copy Markdown
Contributor

/strands-ts review

@github-actions

Copy link
Copy Markdown

Review

The permission-hardening approach is sound and the existing tests are well targeted. I found one gap worth closing:

O_CREAT only applies the mode when the file is created. A pre-existing repl_state.pkl or errors/errors.txt (e.g. left behind by an earlier version, or created by another process) keeps its original — potentially world-readable — permissions, even though os.open(..., 0o600) is used. I confirmed this empirically:

before: 0o644
after : 0o644   # after re-opening with O_CREAT|O_TRUNC, mode=0o600

This is exactly the upgrade scenario the change is meant to protect, and it's inconsistent with how the PR already handles the directories (explicit os.chmod for the already-exists case).

Change applied (commit c41967b)

  • Added os.fchmod(fd, 0o600) on the open descriptor in both save_state() and the error-logging path, enforcing owner-only access on new and pre-existing files. Using fchmod on the fd avoids a TOCTOU race.
  • Added two regression tests:
    • test_existing_state_file_permissions_are_tightened
    • test_error_log_is_owner_only

Validation

  • pytest tests/test_python_repl.py → 39 passed, 1 skipped
  • ruff format --check and ruff check pass

Note: this run has read-restricted GitHub access, so the commit/push and this comment are deferred and will be applied to fix/python-repl-file-perms after completion.

… files

os.open with O_CREAT only applies the mode on creation, so fchmod the open descriptor to also restrict a pre-existing repl_state.pkl or errors.txt. Add regression tests for both.
@yonib05

yonib05 commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

/strands-ts review

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review (pass 2)

Re-reviewed after the /strands-ts review re-trigger. The prior fix (fchmod-based tightening of pre-existing files) is in good shape, but I found a cross-platform regression introduced by using os.fchmod:

os.fchmod is POSIX-only and raises AttributeError on Windows. The CI matrix includes windows-latest and the package is classified Operating System :: OS Independent. Consequences on Windows:

  • Error-logging path: the os.fchmod call was not individually wrapped in try/except, so it could crash the tool when logging an error.
  • save_state: the AttributeError is caught, but state would silently fail to persist.

The original PR's os.open(..., 0o600) was already Windows-safe; the fchmod addition is what introduced the incompatibility. The test module is skipped on Windows (os.name == "nt"), so CI wouldn't have surfaced this.

Change applied (commit 2b7beee)

  • Guard both fchmod calls with hasattr(os, "fchmod"). POSIX keeps the owner-only hardening (including tightening pre-existing files); on Windows we rely on the O_CREAT mode, matching prior behavior.

Validation

  • pytest tests/test_python_repl.py → 39 passed, 1 skipped
  • ruff format --check and ruff check pass

Read-restricted GitHub access this run — commit/push and this comment are deferred and will be applied to fix/python-repl-file-perms.

os.fchmod is POSIX-only and raises AttributeError on Windows. Guard both calls with hasattr(os, 'fchmod'); on Windows the O_CREAT mode still applies, matching prior behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants