Summary
find-replace calls os.Stat (via File.Info()) when deciding whether a directory entry is a directory. os.Stat follows symbolic links, so any symlink encountered during traversal will be transparently resolved and traversed.
Impact (Security: High)
If find-replace is run in a directory that contains a symlink to a path outside the current working directory (for example a symlink tmp -> /etc, log -> /var/log, or home -> /home/victim), the tool will:
- Recurse into the linked-to directory.
- Rewrite the contents of any text files it finds there (using the supplied
find/replace strings).
- Rename files inside the symlink target.
This is contrary to the documented contract ("Searches are performed recursively from the current working directory") and can lead to:
- Privilege-escalation primitives if the user running
find-replace has write access to the target (e.g., a setup script that tweaks files in a checked-out source tree, but a malicious dependency drops a node_modules/something/etc -> /etc symlink).
- Silent corruption of unrelated files when running the tool inside a directory that contains symlinks to system or user directories.
Reproduction
mkdir /tmp/repro && cd /tmp/repro
mkdir -p victim
echo "secret data" > victim/file.txt
mkdir -p attacker
ln -s ../victim attacker/escape
cd attacker
find-replace secret PWNED # rewrites /tmp/repro/victim/file.txt
Suggested Fix
In HandleFile and WalkDir, use os.Lstat (or the fs.DirEntry returned by os.ReadDir) and explicitly skip symbolic links by default. Optionally, add a flag to follow them when explicitly requested.
Files
find_replace.go:79-94 (HandleFile)
file_handling.go:34-43 (Info() uses os.Stat)
Summary
find-replacecallsos.Stat(viaFile.Info()) when deciding whether a directory entry is a directory.os.Statfollows symbolic links, so any symlink encountered during traversal will be transparently resolved and traversed.Impact (Security: High)
If
find-replaceis run in a directory that contains a symlink to a path outside the current working directory (for example a symlinktmp -> /etc,log -> /var/log, orhome -> /home/victim), the tool will:find/replacestrings).This is contrary to the documented contract ("Searches are performed recursively from the current working directory") and can lead to:
find-replacehas write access to the target (e.g., a setup script that tweaks files in a checked-out source tree, but a malicious dependency drops anode_modules/something/etc -> /etcsymlink).Reproduction
Suggested Fix
In
HandleFileandWalkDir, useos.Lstat(or thefs.DirEntryreturned byos.ReadDir) and explicitly skip symbolic links by default. Optionally, add a flag to follow them when explicitly requested.Files
find_replace.go:79-94(HandleFile)file_handling.go:34-43(Info()usesos.Stat)