| … | … | @@ -198,6 +200,15 @@ export const make = Effect.gen(function* () { | |
| 204 | + | const entryType = Effect.fnUntraced(function* (parent: string, entry: NodeFS.Dirent) { | |
| 205 | + | if (!entry.isSymbolicLink()) return entry; | |
| 206 | + | return yield* Effect.tryPromise({ | |
| 207 | + | try: () => NodeFSP.stat(path.join(parent, entry.name)), | |
đźź High workspace/WorkspaceEntries.ts:207
Listing a directory follows every symlink with NodeFSP.stat before checking its target, so a UNC-target link on Windows with NTLM enabled triggers SMB authentication and exposes the user's NTLMv2 hash—even if the entry is later omitted. entryType is shared by browse and list, and list checks network paths only after this call; inspect and reject network targets before any operation that follows the link.
🤖 Copy this AI Prompt to have your agent fix this:
| 1 | In file @apps/server/src/workspace/WorkspaceEntries.ts around line 207: |
| 2 | |
| 3 | Listing a directory follows every symlink with `NodeFSP.stat` before checking its target, so a UNC-target link on Windows with NTLM enabled triggers SMB authentication and exposes the user's NTLMv2 hash—even if the entry is later omitted. `entryType` is shared by `browse` and `list`, and `list` checks network paths only after this call; inspect and reject network targets before any operation that follows the link. |
Confirmed and fixed in a01081dd. Classification no longer calls stat or realpath on a candidate symlink. It walks path components with lstat and reads each link with readlink, rejecting a UNC/device/network target before following it. Intermediate links are inspected too, so a local-looking target that leads through another link cannot bypass the check. Traversal is capped at 40 links, and the resolved local metadata/path is reused by the existing Git/cycle checks.
Added never follows network targets while classifying links: its direct, chained, and intermediate-component cases fail against the previous head. Both browse and list now exclude those targets, retain a normal local link, make no stat calls, and never pass a network path to lstat, readlink, or realpath. All 44 focused tests and vp run check:changed HEAD pass, including lint, both knip passes and affected typechecks. This is a simulated network-link regression on macOS; I have not run an SMB/NTLM capture on Windows. The separate maintainer decision on local read containment remains explicit in the PR.
Sorry, I'm unable to act on this request because you do not have permissions within this repository.