Skip to content

sandbox: a junction at .git sends the fallback carveouts outside the workspace on Windows #1024

Description

@Vasanthdev2004

On main at f30f550, gitMetadataWriteCarveouts in internal/sandbox/profile.go emits <root>/.git/hooks and <root>/.git/config as write-denied carveouts. The Windows ACL apply then opens those paths with FILE_FLAG_OPEN_REPARSE_POINT, which guards only the final path component. A junction at <root>/.git is traversed as an intermediate, so the deny-write ACEs land on <junction-target>/hooks and <junction-target>/config, outside the workspace.

mklink /J needs no privilege, so any local user with write access to a workspace that has no .git yet can plant one.

Evidence, with provenance. I confirmed the carveout shape by reading the code on main: the two children are emitted unconditionally, with no lstat of .git at all. The traversal itself was probed during the review of #805: a junction created unelevated with mklink /J, then both <root>\.git\hooks through the junction and <junction-target>\hooks directly opened with the apply's exact CreateFile flags, and both resolved to the same volume serial and file index. Opening <root>\.git itself reports reparse=true and is refused, but with these carveouts that path is never opened.

Consequences differ by path. On the unelevated per-command path this only touches objects the user could already re-ACL, and it is rolled back after the command. On zero sandbox setup, which requires Administrator, the same redirect happens with an elevated token: the same TOCTOU class as #728, one component further up.

#805 does not introduce or widen this; it improves the regular-file case and leaves the junction case exactly as main has it. It also does not close it, which is why this is its own issue against the ACL apply rather than against that PR. The fix belongs in the apply: refuse to write an ACE through any owned intermediate that is a reparse point, which is the rule the rooted descent in #901 already follows for the runtime tree.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions