@@ -385,6 +385,29 @@ process_phantom_symlink(const wchar_t *wtarget, const wchar_t *wlink)
385385 wchar_t relative [MAX_LONG_PATH ];
386386 const wchar_t * rel ;
387387
388+ /*
389+ * Do not follow symlinks to network shares, to avoid NTLM credential
390+ * leak from crafted repositories (e.g. \\attacker-server\share).
391+ * Since paths come in all kind of enterprising shapes and forms (in
392+ * addition to the canonical `\\host\share` form, there's also
393+ * `\??\UNC\host\share`, `\GLOBAL??\UNC\host\share` and also
394+ * `\Device\Mup\host\share`, just to name a few), we simply avoid
395+ * following every symlink target that starts with a slash.
396+ *
397+ * This also catches drive-less absolute paths, of course. These are
398+ * uncommon in practice (and also fragile because they are relative to
399+ * the current working directory's drive). The only "harm" this does
400+ * is that it now requires users to specify via the Git attributes if
401+ * they have such an uncommon symbolic link and need it to be a
402+ * directory type link.
403+ */
404+ if (is_wdir_sep (wtarget [0 ])) {
405+ warning ("created file symlink '%ls' pointing to '%ls';\n"
406+ "set the `symlink` gitattribute to `dir` if a "
407+ "directory symlink is required" , wlink , wtarget );
408+ return PHANTOM_SYMLINK_DONE ;
409+ }
410+
388411 /* check that wlink is still a file symlink */
389412 if ((GetFileAttributesW (wlink )
390413 & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY ))
0 commit comments