@@ -352,6 +352,29 @@ process_phantom_symlink(const wchar_t *wtarget, const wchar_t *wlink)
352352 wchar_t relative [MAX_PATH ];
353353 const wchar_t * rel ;
354354
355+ /*
356+ * Do not follow symlinks to network shares, to avoid NTLM credential
357+ * leak from crafted repositories (e.g. \\attacker-server\share).
358+ * Since paths come in all kind of enterprising shapes and forms (in
359+ * addition to the canonical `\\host\share` form, there's also
360+ * `\??\UNC\host\share`, `\GLOBAL??\UNC\host\share` and also
361+ * `\Device\Mup\host\share`, just to name a few), we simply avoid
362+ * following every symlink target that starts with a slash.
363+ *
364+ * This also catches drive-less absolute paths, of course. These are
365+ * uncommon in practice (and also fragile because they are relative to
366+ * the current working directory's drive). The only "harm" this does
367+ * is that it now requires users to specify via the Git attributes if
368+ * they have such an uncommon symbolic link and need it to be a
369+ * directory type link.
370+ */
371+ if (is_wdir_sep (wtarget [0 ])) {
372+ warning ("created file symlink '%ls' pointing to '%ls';\n"
373+ "set the `symlink` gitattribute to `dir` if a "
374+ "directory symlink is required" , wlink , wtarget );
375+ return PHANTOM_SYMLINK_DONE ;
376+ }
377+
355378 /* check that wlink is still a file symlink */
356379 if ((GetFileAttributesW (wlink )
357380 & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY ))
0 commit comments