Skip to content

feat(core): implement Windows sandbox dynamic expansion Phase 1 and 2.1#23691

Merged
scidomino merged 2 commits intomainfrom
tomm_win
Mar 25, 2026
Merged

feat(core): implement Windows sandbox dynamic expansion Phase 1 and 2.1#23691
scidomino merged 2 commits intomainfrom
tomm_win

Conversation

@scidomino
Copy link
Copy Markdown
Collaborator

@scidomino scidomino commented Mar 24, 2026

Summary

This PR implements Phase 1 and 2.1 of dynamic sandbox expansion for the Windows platform. It allows the CLI to dynamically grant network access and Low Integrity filesystem write permissions based on global settings, persistent approvals, and just-in-time requests.

Details

  • Phase 1: Added WindowsSandboxOptions interface, updating the constructor to accept modeConfig and policyManager.
  • Phase 1: Updated sandboxManagerFactory.ts to pass these new configurations to the WindowsSandboxManager.
  • Phase 2.1: Refactored prepareCommand to merge req.policy.additionalPermissions with persistent permissions from policyManager and modeConfig.
  • Added Plan Mode override restrictions.
  • Refactored shared shell parsing logic and introduced a dedicated Windows commandSafety.ts to decouple the implementation from macOS-specific utilities.

Related Issues

For google-gemini/maintainers-gemini-cli#1601 (Phase 1 & Phase 2.1)

How to Validate

Tests have been added to verify that the configurations merge correctly and trigger the expected icacls calls for Low Integrity access.

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 24, 2026

Size Change: +5.29 kB (+0.02%)

Total Size: 26.3 MB

Filename Size Change
./bundle/chunk-4L3MYAOH.js 0 B -14.6 MB (removed) 🏆
./bundle/chunk-BI2HCBTD.js 0 B -3.64 MB (removed) 🏆
./bundle/chunk-GWQRIYMB.js 0 B -1.96 MB (removed) 🏆
./bundle/chunk-K7UW2BKN.js 0 B -3.4 kB (removed) 🏆
./bundle/core-TF5IFBKD.js 0 B -43.5 kB (removed) 🏆
./bundle/devtoolsService-FOGO3YHI.js 0 B -27.7 kB (removed) 🏆
./bundle/gemini-6OJBBZVL.js 0 B -528 kB (removed) 🏆
./bundle/interactiveCli-JNWWP6FX.js 0 B -1.62 MB (removed) 🏆
./bundle/oauth2-provider-HBPGFC34.js 0 B -9.16 kB (removed) 🏆
./bundle/chunk-GPNQKRAG.js 3.4 kB +3.4 kB (new file) 🆕
./bundle/chunk-QFKNA2LI.js 3.64 MB +3.64 MB (new file) 🆕
./bundle/chunk-QWZ2ZTVN.js 1.96 MB +1.96 MB (new file) 🆕
./bundle/chunk-S773C4HU.js 14.7 MB +14.7 MB (new file) 🆕
./bundle/core-IHA3WDT7.js 43.6 kB +43.6 kB (new file) 🆕
./bundle/devtoolsService-U6KRYLLT.js 27.7 kB +27.7 kB (new file) 🆕
./bundle/gemini-I4YADZIF.js 528 kB +528 kB (new file) 🆕
./bundle/interactiveCli-RLUU5A3F.js 1.62 MB +1.62 MB (new file) 🆕
./bundle/oauth2-provider-O2T6WF5L.js 9.16 kB +9.16 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size Change
./bundle/chunk-34MYV7JD.js 2.45 kB 0 B
./bundle/chunk-5AUYMPVF.js 858 B 0 B
./bundle/chunk-664ZODQF.js 124 kB 0 B
./bundle/chunk-DAHVX5MI.js 206 kB 0 B
./bundle/chunk-IUUIT4SU.js 56.5 kB 0 B
./bundle/chunk-RJTRUG2J.js 39.8 kB 0 B
./bundle/cleanup-BY7VIV6H.js 0 B -856 B (removed) 🏆
./bundle/devtools-36NN55EP.js 696 kB 0 B
./bundle/dist-T73EYRDX.js 356 B 0 B
./bundle/gemini.js 2.06 kB 0 B
./bundle/getMachineId-bsd-TXG52NKR.js 1.55 kB 0 B
./bundle/getMachineId-darwin-7OE4DDZ6.js 1.55 kB 0 B
./bundle/getMachineId-linux-SHIFKOOX.js 1.34 kB 0 B
./bundle/getMachineId-unsupported-5U5DOEYY.js 1.06 kB 0 B
./bundle/getMachineId-win-6KLLGOI4.js 1.72 kB 0 B
./bundle/memoryDiscovery-GX6HE5X5.js 0 B -922 B (removed) 🏆
./bundle/multipart-parser-KPBZEGQU.js 11.7 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/client/main.js 221 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/_client-assets.js 227 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/index.js 11.5 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/types.js 132 B 0 B
./bundle/sandbox-macos-permissive-open.sb 890 B 0 B
./bundle/sandbox-macos-permissive-proxied.sb 1.31 kB 0 B
./bundle/sandbox-macos-restrictive-open.sb 3.36 kB 0 B
./bundle/sandbox-macos-restrictive-proxied.sb 3.56 kB 0 B
./bundle/sandbox-macos-strict-open.sb 4.82 kB 0 B
./bundle/sandbox-macos-strict-proxied.sb 5.02 kB 0 B
./bundle/src-QVCVGIUX.js 47 kB 0 B
./bundle/tree-sitter-7U6MW5PS.js 274 kB 0 B
./bundle/tree-sitter-bash-34ZGLXVX.js 1.84 MB 0 B
./bundle/cleanup-TBKHPZOY.js 856 B +856 B (new file) 🆕
./bundle/memoryDiscovery-HC34TZH7.js 922 B +922 B (new file) 🆕

compressed-size-action

@scidomino scidomino marked this pull request as ready for review March 24, 2026 20:26
@scidomino scidomino requested a review from a team as a code owner March 24, 2026 20:26
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the Windows sandbox capabilities by introducing dynamic permission management. It allows the system to intelligently grant network access and filesystem write permissions at a low integrity level, adapting to specific command requirements and predefined policies. This improves both security and flexibility by enabling fine-grained control over sandbox behavior, preventing unauthorized operations while facilitating legitimate ones.

Highlights

  • Dynamic Sandbox Expansion (Phase 1 & 2.1): Implemented dynamic network access and Low Integrity filesystem write permissions for the Windows platform, based on global settings, persistent approvals, and just-in-time requests.
  • WindowsSandboxOptions Interface: Introduced a new interface to configure Windows sandbox behavior, including mode configuration and a policy manager for persistent approvals.
  • Permission Merging and Enforcement: Refactored the prepareCommand method to merge additional permissions from the request with persistent permissions from the policy manager and enforce restrictions for Plan Mode overrides.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request enhances the Windows sandbox manager by introducing new configuration options for sandbox mode and policy management. It implements logic for command approval and merges various permission sources for network and file system access. New tests cover these functionalities, including network access, plan mode restrictions, and additional write paths. However, there are critical security concerns regarding the additionalPermissions allowing arbitrary write access outside the workspace and potential UNC path vulnerabilities. Additionally, there are high-severity logical flaws in the isStrictlyApproved method that can lead to incorrect command rejections, and a bug in the network permission evaluation where the nullish coalescing operator ?? incorrectly short-circuits, preventing proper consideration of all permission sources.

Comment thread packages/core/src/sandbox/windows/WindowsSandboxManager.ts
Comment thread packages/core/src/sandbox/windows/WindowsSandboxManager.ts Outdated
Comment thread packages/core/src/sandbox/windows/WindowsSandboxManager.ts Outdated
@gemini-cli gemini-cli Bot added the status/need-issue Pull requests that need to have an associated issue. label Mar 24, 2026
Copy link
Copy Markdown
Collaborator

@galz10 galz10 left a comment

Choose a reason for hiding this comment

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

Code Review

Scope: Pull Request #23691

This PR introduces dynamic sandbox expansion for Windows (Phase 1 and 2.1) by updating WindowsSandboxManager to support explicit and persistent overrides for network access and filesystem write permissions. The changes align well with the overall architecture, but there are several critical bugs affecting network access resolution, path handling, and shell parsing that need to be addressed before merging.

Metadata Review

The PR Title (feat(core): implement Windows sandbox dynamic expansion Phase 1 and 2.1) perfectly follows the Conventional Commits format. The PR Body is detailed, provides clear context, references the related issue, and has a completed pre-merge checklist for the relevant platforms.

Concerns (Action Required)

  • packages/core/src/sandbox/windows/WindowsSandboxManager.ts (Network Access Resolution): The resolution of networkAccess completely ignores overrides if the default mode explicitly disables network access.

    const networkAccess =
      this.options.modeConfig?.network ??
      req.policy?.networkAccess ??
      mergedAdditional.network;

    Because it uses the nullish coalescing operator (??), if this.options.modeConfig?.network is false (e.g., in a restrictive mode where allowOverrides is true), the expression evaluates to false. This completely ignores mergedAdditional.network, breaking the ability to dynamically grant network access on Windows.
    Suggestion: Update the logic to use a boolean OR to allow the override to take precedence over a false default, similar to the MacOS sandbox implementation:

    const defaultNetwork = this.options.modeConfig?.network ?? req.policy?.networkAccess ?? false;
    const networkAccess = defaultNetwork || mergedAdditional.network;
  • packages/core/src/sandbox/windows/WindowsSandboxManager.test.ts (Test Coverage Gap): The test case should handle persistent permissions from policyManager creates modeConfig: { allowOverrides: true } without explicitly setting network: false. Because network is left undefined, the nullish coalescing bug mentioned above is not triggered, allowing the test to incorrectly pass.
    Suggestion: Update the test's modeConfig to explicitly include network: false. This will ensure it properly asserts that an override can bypass a restrictive default.

  • packages/core/src/sandbox/windows/WindowsSandboxManager.ts (UNC Path Rejection Bug): The attempt to prevent SMB credential theft and SSRF by blocking UNC paths is overly broad:

    if (resolvedPath.startsWith('\\\\')) {
       debugLogger.log('WindowsSandboxManager: Rejecting UNC path...');
       return;
    }

    While this successfully blocks \\attacker\share\malicious, it also blocks legitimate Windows extended-length paths (\\?\C:\long\path\to\workspace) and local device paths (\\.\PhysicalDrive0). If a user's project is deeply nested and Node falls back to the \\?\ prefix to bypass MAX_PATH limitations, the sandbox will silently fail to grant Low Integrity write access, breaking builds entirely.
    Suggestion: Refine the check to explicitly exclude the local extended-length and device path prefixes:

    if (resolvedPath.startsWith('\\\\') && 
        !resolvedPath.startsWith('\\\\?\\') && 
        !resolvedPath.startsWith('\\\\.\\')) {
      debugLogger.log('WindowsSandboxManager: Rejecting UNC path...');
      return;
    }
  • packages/core/src/sandbox/windows/WindowsSandboxManager.ts (Incorrect Casting of Shell Parsing Objects): Inside isStrictlyApproved, the pipeline command parsing uses shellParse followed by a direct map to String:

    const parsedArgs = shellParse(cmdString).map(String);
    if (!isKnownSafeCommand(parsedArgs)) { ... }

    The shellParse method from shell-quote returns an array of entries, which can be standard strings but can also be objects for globs or operators (e.g., parsing ls *.js returns ['ls', { op: 'glob', pattern: '*' }]). Using .map(String) on these objects coerces them into the literal string "[object Object]". While this currently just safely fails the isKnownSafeCommand check, it's brittle and obfuscates what the command actually was.
    Suggestion: Update the map function to properly extract the underlying string representation from operator/glob objects. (Note: Since isStrictlyApproved seems to be copied directly from MacOSSandboxManager.ts, this bug exists there as well and should ideally be fixed in both places or moved to a shared utility).

    const parsedArgs = shellParse(cmdString).map(entry => 
      typeof entry === 'string' ? entry : String(entry.pattern || entry.op || '')
    );

Nits (Low Priority/Suggestions)

  • packages/core/src/sandbox/windows/WindowsSandboxManager.ts: The isStrictlyApproved method appears to be a direct duplicate of the method found in MacOSSandboxManager.ts. Consider extracting this logic into a shared utility function (e.g., in sandbox/utils/) to prevent code duplication.
  • packages/core/src/sandbox/windows/WindowsSandboxManager.ts: Importing isKnownSafeCommand directly from ../macos/commandSafety.js inside the Windows sandbox manager is an architectural smell. It would be better to move commandSafety.ts to a shared location since it is now used by multiple platforms.

@scidomino scidomino force-pushed the tomm_win branch 4 times, most recently from 1045ea2 to 885d4a2 Compare March 25, 2026 02:27
@scidomino
Copy link
Copy Markdown
Collaborator Author

Addressed all comments.

Comment thread packages/core/src/services/sandboxManager.ts Outdated
return false;
}

isDangerousCommand(_args: string[]): boolean {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as above

Comment thread packages/core/src/sandbox/windows/commandSafety.ts Outdated
Comment thread packages/core/src/sandbox/windows/commandSafety.ts
This commit introduces the WindowsSandboxOptions interface to WindowsSandboxManager, passing down modeConfig and policyManager from the sandbox manager factory (Phase 1). It also evaluates and merges additionalPermissions with persistent policyManager approvals and global mode configurations, allowing for dynamic network access and Low Integrity file writes on Windows (Phase 2.1). Fixes #1601.
@scidomino scidomino added this pull request to the merge queue Mar 25, 2026
Merged via the queue into main with commit 1b052df Mar 25, 2026
28 checks passed
@scidomino scidomino deleted the tomm_win branch March 25, 2026 18:08
ProthamD pushed a commit to ProthamD/gemini-cli that referenced this pull request Mar 29, 2026
afanty2021 pushed a commit to afanty2021/gemini-cli that referenced this pull request Apr 4, 2026
warrenzhu25 pushed a commit to warrenzhu25/gemini-cli that referenced this pull request Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status/need-issue Pull requests that need to have an associated issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants