Skip to content

Python: block reparse points in Monty file capture - #9364

Merged
Eduard van Valkenburg (eavanvalkenburg) merged 3 commits into
microsoft:mainfrom
eavanvalkenburg:fix-monty-junction-capture
Oct 14, 2026
Merged

Eduard van Valkenburg (eavanvalkenburg) merged 3 commits into
microsoft:mainfrom
eavanvalkenburg:fix-monty-junction-capture

Conversation

@eavanvalkenburg

@eavanvalkenburg Eduard van Valkenburg (eavanvalkenburg) commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Motivation & Context

Monty's post-execution file capture scans read-write mounts for new or modified files to return as attachments. On Windows, directory junctions and other reparse points are not always reported by Path.is_symlink(), so the host-side capture walker could traverse beyond the configured mount. This change keeps attachment capture limited to real regular files under the mount root.

Description & Review Guide

  • What are the major changes? Reuse the core link/reparse-point predicate while walking Monty mounts, and read each captured file through one descriptor that is checked against the validated file (opened with O_NOFOLLOW where available) with every path component revalidated after opening. Add regression tests: real NTFS junctions on Windows, a portable junction model elsewhere, and swap-after-validation cases.
  • What is the impact of these changes? Symlinks, junctions, and other reparse points are skipped during snapshots and post-run capture, and a file or ancestor swapped for a link after validation is skipped instead of read. Regular nested files, unchanged-file filtering, large-file omission, and virtual attachment paths retain their existing behavior.
  • What do you want reviewers to focus on? The fail-closed path inspection and _read_validated_file. Windows has no no-follow open, so the read-time check narrows the replacement window rather than being kernel-atomic there.

Related Issue

N/A - no public issue. This is a narrowly scoped correction to host-side file capture, and no competing open pull request was found.

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: Implementation, tests, design review, and this PR description.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Copilot AI balanced review requested due to automatic review settings October 14, 2026 09:15
@agent-framework-automation agent-framework-automation Bot added the python Usage: [Issues, PRs], Target: Python label Oct 14, 2026

Copilot AI 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.

🟡 Changes recommended

Path validation remains vulnerable to a swap before read_bytes() reopens the file.

1 open finding
What changed in this PR

Hardens Monty’s attachment capture against Windows reparse-point traversal.

Changes:

  • Detects symlinks, junctions, and reparse points during capture.
  • Adds fail-closed and Windows junction regression tests.
File Description
_execute_code_tool.py Adds secure-path validation during capture.
test_monty_codeact.py Covers junctions, failures, and unchanged files.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread python/packages/monty/agent_framework_monty/_execute_code_tool.py Outdated

@github-actions github-actions Bot 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.

MAF Automated Review — Iteration 1

Result: No findings
Scope: full PR (1 commit(s)): ad29dce3dd2d
Model: gpt-5.6-sol

Overview

This change strengthens Monty attachment capture by replacing symlink-only checks with the shared link/reparse-point predicate, classifying entries with lstat, and revalidating each path component before reading. The new tests cover Windows junctions created before and after the snapshot, fail-closed probe errors, unchanged files, and replacement detected by the second validation. The panel found residual path-open and aggregate-capture risks, but base-source comparison established that both predate this PR, so there is no publishable PR-introduced finding.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.

@jpalvarezl Jose Alvarez (jpalvarezl) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed the complete change and surrounding mount/capture code. I found no additional issues beyond the existing unresolved atomic path-swap thread, which remains the blocker to approval.

Open each captured file once, require the descriptor to match the validated lstat identity, and revalidate the path after opening so a file or ancestor swapped for a link after validation is skipped. Add portable junction-model and swap-after-validation tests.
@eavanvalkenburg

Copy link
Copy Markdown
Member Author

Jose Alvarez (@jpalvarezl) the atomic path-swap thread is addressed in 01911a7 (details and the remaining Windows limitation are in the thread), and all checks are green on the new commit. Thanks for the review.

Merged via the queue into microsoft:main with commit 245ded2 Oct 14, 2026
48 checks passed
@eavanvalkenburg
Eduard van Valkenburg (eavanvalkenburg) deleted the fix-monty-junction-capture branch October 14, 2026 17:16

This branch was successfully deployed

1 active deployment
github-app-auth — 93475c74 Deployed Oct 14, 2026 by eavanvalkenburg via add_label #25313
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants