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