Git 'detected dubious ownership' Error: A 5-Minute Fix Guide by Scenario
Why did git, which worked fine yesterday, suddenly stop?
Your build was working fine yesterday, but today a single git status throws a red error.
fatal: detected dubious ownership in repository at '/workspace'
To add an exception for this directory, call:
git config --global --add safe.directory /workspaceIf you just rebuilt a Docker image, upgraded a CI runner, or installed a newer Git on a shared server, you will almost certainly hit this message. First, don't panic. This is not a code problem, and your repository is not corrupted. Git simply stopped for safety because the directory owner and the user running the command don't match.
This error exploded after the security patch (CVE-2022-24765) was backported to Git 2.35.2 / 2.30.3 and similar versions. Container-based CI/CD became the norm, GitHub Actions self-hosted and container jobs multiplied, and WSL2, NFS shared workspaces, and monorepos became everyday tools — so UID mismatches turned into a normal landscape. If you're in a hurry, copy-paste from the 5-minute fixes by scenario below and read the why later.
Why this error happens: owner ≠ running user
Git compares the owner UID of the repository directory with the UID of the current user running the command. If they differ, Git suspects that someone else may have planted a malicious .git/config (for example, using core.fsmonitor to run arbitrary commands) and refuses to proceed. That is the core of CVE-2022-24765. It is an intentional defense against a scenario where, on a shared path like /tmp that anyone can write to, an attacker pre-creates a Git config that then runs with the victim's privileges. In other words, this is a feature, not a bug. What we need to do is either explicitly tell Git "I trust this directory" or make the owner match the running user in the first place.
5-Minute Fixes by Scenario (Copy-Paste Commands)
① Local / general environment
The most common case. Add a single path to the trust list. Replace <path> with the actual absolute path.
# <path>를 실제 리포지토리 절대경로로 교체 (예: /home/dev/myrepo)
git config --global --add safe.directory <path>This command adds the following entry to ~/.gitconfig. You can open the file to verify or write it by hand.
[safe]
directory = /home/dev/myrepo② Docker container builds
You use Git inside a container, but the owner of the build context or a mounted volume is the host UID, which doesn't match the container's running user. The cleanest fix is to add one line in the Dockerfile build stage.
# 작업 경로를 신뢰 디렉터리로 등록 (/workspace 등 실제 경로로 교체)
RUN git config --global --add safe.directory /workspace
# 비root 사용자로 전환해 빌드한다면, 그 사용자 컨텍스트에서 실행되도록 순서 주의
# root로 빌드하면서 마운트 소유자가 다를 때 가장 자주 재발합니다③ Repos cloned with sudo / by another user
You ran sudo git clone, or you're working on a repo that was cloned under a different account. In this case, fixing ownership is the real solution, not just adding a trust exception.
# <path>를 실제 경로로 교체. 디렉터리 전체 소유자를 현재 사용자로 정렬
sudo chown -R $(whoami):$(whoami) <path>④ CI/CD (Jenkins, GitHub Actions, GitLab) and NFS / WSL
This often blows up in CI runner containers, self-hosted runners, NFS mounts, and WSL2 Windows mount paths (/mnt/c/...). Add one step near the start of the job.
# GitHub Actions 예시 — checkout 직후 한 스텝
- name: Mark workspace as safe
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"# Jenkins / GitLab 셸 스텝 또는 entrypoint
git config --global --add safe.directory "$CI_PROJECT_DIR" # GitLab
git config --global --add safe.directory "$WORKSPACE" # JenkinsNote: GitHub Actions'
actions/checkouthandles this setting automatically on the default runner. If it still shows up on container jobs or self-hosted runners, the config created by checkout doesn't match the user actually running Git — add the step above explicitly.
safe.directory '*' — convenient but a dangerous master key
If you're thinking "I don't want to register every path — can't I do it all at once?", you'll find this command.
# 모든 디렉터리를 무조건 신뢰 (강력하지만 위험)
git config --global --add safe.directory '*'⚠️ Security warning
safe.directory '*'turns off owner checks for every directory. That is effectively the same as disabling the CVE-2022-24765 defense. Never overuse this on shared servers, multi-user build servers, or production environments. You are reopening a path for someone else's planted.git/configto run under your privileges.
That said, keep a balanced view. In an isolated, single-user, throwaway CI container with no external attack path and a short lifetime, '*' can be a reasonable choice. The key question is: "Can anyone else's hands reach this environment besides mine?"
In practice, the most common accident is someone baking '*' into a shared build server and forgetting about it. Everyone is comfortable for a while, then the moment that server builds untrusted PR code, the defense is gone. That's why I set the team standard to "register paths individually + bake it into the Docker image," and put '*' on the PR review checklist as allowed only in throwaway containers.
Wrap-up: diagnosis table + FAQ + the real fix
A table so you can go straight from symptom to fix.
| Error / symptom | Root cause | Recommended fix |
|---|---|---|
dubious ownership inside a Docker container | Mounted volume owner (host UID) ≠ container running user | Add RUN git config --global --add safe.directory <path> to the Dockerfile |
Happens on a normal account after sudo git clone | Directory owner is root | sudo chown -R $(whoami):$(whoami) <path> (the real fix) |
| Happens every time on a CI runner (container job / self-hosted) | Workspace owner / running user mismatch per job | After checkout, add a safe.directory "$WORKSPACE" step |
| Happens on NFS / WSL mount paths | Owner mapping on the network / Windows filesystem doesn't match Git's UID | Register that absolute path in safe.directory |
FAQ
Q. Can't I just run as root and be done?
A. It often works — root frequently bypasses the owner check. But I don't recommend it. Privilege escalation maximizes the blast radius if a malicious .git/config runs, and it also makes build artifacts owned by root, which creates more permission problems. It's a workaround that hides the cause (owner mismatch).
Q. I clearly fixed it, but it keeps coming back. Why?
A. Check three things. ① You set --global, but the HOME of the user running Git changes every time (for example, in CI HOME is empty and becomes /), so ~/.gitconfig is never read. ② You need --system to apply it for all users, but you only registered --global. ③ The path is not an absolute path, or a symlink / mount path changes every time. In CI, pin HOME or consider --system.
Q. How do I apply this permanently in CI?
A. Two paths. (1) Bake it into the image — when building the CI base Docker image, add RUN git config --system --add safe.directory <path> so every job inherits it. (2) Add a step in every job — right after checkout, add a safe.directory step. If you control the image, (1) is cleaner; if the workspace path changes per job, (2) is safer.
One-line action guide to close: the temporary fix is safe.directory; the real fix is aligning ownership (chown / matching UIDs). When you're in a hurry, add the path to the trust list and get back to work in 5 minutes. When you have time, match UIDs on containers and mounts so the error never comes back.
Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.
Comments
Be the first to comment.