You run git status on a repo that's been sitting on your NAS, WSL mount, or SMB share for months, and Git suddenly refuses to work: fatal: detected dubious ownership in repository at '/mnt/data/projects/api'. Nothing changed on your end. Git just decided your repo belongs to someone else. I've hit this on a QNAP share, on WSL2 with a Windows-mounted project, and inside a Docker container that mounted a host directory. Same error, three different setups.
Why Git started doing this
Git 2.35.2 (April 2022) shipped a security fix for CVE-2022-24765. Before that, if you ran Git inside a directory you didn't own, a malicious repo could plant a .git/config file that executed arbitrary commands on your machine. The patch made Git check the owner of the .git directory against the user running the command. If they don't match, Git bails out with the dubious ownership error.
On a normal local repo this never triggers. It triggers when:
- You're on WSL2 and the repo lives under
/mnt/c/...— Windows owns the files as a different UID than your Linux user. - The repo is on a network share (SMB, NFS) where ownership maps to something like
nobodyor the server's UID. - You mounted a USB drive formatted on another machine.
- A Docker container mounts a host folder with mismatched UIDs.
- Someone else created the repo and you're a collaborator on a shared box.
The files are fine. Git just doesn't trust where they came from.
The fix
Git has a config called safe.directory that whitelists specific paths. You set it once per path and you're done. Do not use the wildcard * unless you fully understand what you're disabling — more on that below.
Step 1: Copy the exact path from the error
The error message gives you the path Git is complaining about. Grab it verbatim. Case matters on Linux and macOS. Don't guess.
Step 2: Add it as a safe directory
Run this, swapping in your path:
git config --global --add safe.directory /mnt/data/projects/api
Verify it stuck:
git config --global --get-all safe.directory
You should see the path in the output. If you add multiple repos, use --add each time — otherwise you'll overwrite the previous entry.
Step 3: Re-run the Git command
git status should now work. If you've got submodules, each submodule is its own repo and needs its own entry. Same for worktrees if the worktree lives on a different mount.
Step 4: For system-wide management, use the system config
On a shared build server or CI box, add it at the system level so every user gets it:
sudo git config --system --add safe.directory /var/lib/jenkins/workspace/repo
On Windows the file is at C:\Program Files\Git\etc\gitconfig. On Linux it's /etc/gitconfig. Don't hand-edit unless you have to — --system handles it.
Step 5: If you're inside Docker, fix the UID instead
Whitelisting inside a container is a band-aid. The real fix is making the container user match the host user. In your Dockerfile or compose file:
docker run --user $(id -u):$(id -g) -v /host/repo:/repo -w /repo git-image git status
That way the container runs as your host UID and Git sees matching ownership. If you must run as root inside the container, whitelist /repo inside the image's config.
Why the wildcard * is a trap
Half the Stack Overflow answers tell you to run git config --global --add safe.directory '*'. It works. It also completely disables the CVE-2022-24765 protection. If you ever cd into a malicious repo — a cloned one from a sketchy source, or a tarball someone sent you — its .git/config can execute code. I had a client last month whose entire print queue died because a dev ran that wildcard, then cloned an internal repo from a compromised mirror. The payload wasn't a print queue problem directly — it was a persistence script that hijacked a scheduled task. Point is: don't wildcard.
Still failing?
Check the actual owner
On Linux/macOS:
ls -ld /path/to/repo/.git
id
The UID shown should match the UID from id. If it doesn't, and you have write access, the cleanest fix is to chown it:
sudo chown -R $(id -u):$(id -g) /path/to/repo
Only do this if it's your drive. On an SMB share, chown usually won't work because the server dictates ownership. Whitelisting is the right call there.
Check which config file is winning
Git reads configs in a specific order: system, global, local. If your local repo has a conflicting safe.directory entry or a [safe] section that overrides things, that's your problem. Run:
git config --show-origin --get-all safe.directory
That tells you exactly which file each entry came from.
Check the filesystem case sensitivity
On macOS with a case-insensitive volume, the path in your config must match the path Git resolves. /Users/me/Repo and /users/me/repo are the same directory on disk but different strings to Git on some setups. Copy the path straight from the error message.
Check for NFS root squashing
If you're on an NFS mount, the server likely squashes remote root to nobody. That UID will never match yours. Whitelist the mount point. Don't try to chown NFS files — you'll either fail or corrupt permissions.
Check Git version
If safe.directory isn't recognized, your Git is too old. Run git --version. Anything below 2.35.2 predates the safety check entirely, which means you're either running something weird or you upgraded through a distro that backported the fix. Update Git, then retry.
What I actually do on my own machines
One safe.directory entry per mount point. Not per repo. On WSL, I whitelist /mnt/c/dev once and every repo under it just works. On the NAS, one entry for the share root. That keeps the config short and readable, and it never accidentally covers a temp directory or download folder where a malicious clone could land.