DEV Community

Libme
Libme

Posted on

Git "detected dubious ownership in repository": Fix It in Docker and CI Without Trusting Everything

The error means the user running Git does not own the repository directory, and since Git 2.35.2 Git refuses to run there as a security measure. The quick fix is git config --global --add safe.directory <path>, but in containers and CI the better fix is usually to make the UIDs match, and a blanket safe.directory '*' is only acceptable on throwaway machines.

What does the error actually look like?

fatal: detected dubious ownership in repository at '/workspace'
To add an exception for this directory, call:

    git config --global --add safe.directory /workspace
Enter fullscreen mode Exit fullscreen mode

You tend to meet it in four places: a bind-mounted source directory inside Docker, a CI job that runs inside a container image, a repo checked out by one user and used by another (a deploy user versus root, say), and network or Windows-shared drives. In every case the cause is identical: the owner of the .git directory's parent differs from the effective user running git.

The check exists because of CVE-2022-24765. A malicious repo placed in a shared location such as C:\ or /tmp could carry a config that executes code when someone else ran a harmless-looking git status there. Git now refuses unless you say that directory is trusted. Takeaway: the error is a security check working as designed, not a corrupted repository.

Why does git config --global seem to do nothing in my container?

This is the dead end that cost me the most time. Three things commonly go wrong:

  1. The setting is read only from trusted scopes. safe.directory is honored in system, global and command-line config. A safe.directory line inside the repository's own .git/config is ignored on purpose, otherwise the untrusted repo could vouch for itself.
  2. --global writes to $HOME/.gitconfig. If your container runs as an arbitrary UID with no home directory, or with a read-only filesystem, the write fails or lands somewhere Git never reads.
  3. The path must match what Git sees. Trusting /app does not help if the process runs in /app/ through a symlink, or if the mount point differs between build and run steps.

Takeaway: when safe.directory "doesn't work", check which config file you actually wrote to with git config --show-origin --get-all safe.directory.

Which fix should I use?

Situation Fix Trade-off
Local Docker bind mount Run the container as your host UID/GID Cleanest; no Git config needed
CI container job, ephemeral runner Trust the one workspace path Fine, the runner is disposable
Shared build box or long-lived server Trust specific paths in system config Wildcards widen the attack surface
Read-only or random-UID container Pass config via environment variables No file write required
Quick throwaway debugging safe.directory '*' Trusts every repo this user will ever touch

Match the UID instead of trusting the directory

For a bind mount, the root cause is ownership, so fix ownership:

docker run --rm \
  --user "$(id -u):$(id -g)" \
  -v "$PWD":/workspace -w /workspace \
  -e HOME=/tmp \
  alpine/git status
Enter fullscreen mode Exit fullscreen mode

Setting HOME matters: an arbitrary UID usually has no home, and Git will complain about a missing $HOME/.gitconfig location or about tools that cache there. On Linux hosts this is the standard answer. On Docker Desktop for Mac, file ownership is translated by the file-sharing layer, so you may never see this error locally and then hit it for the first time in Linux CI. That mismatch is why the failure feels random.

Trust one explicit path in a throwaway job

In a CI container where the workspace is mounted by the runner as a different user than the job runs as, trust that single path:

jobs:
  build:
    runs-on: ubuntu-latest
    container: node:22
    steps:
      - uses: actions/checkout@v4
      - name: Allow Git in the workspace
        run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
      - run: git describe --tags --always
Enter fullscreen mode Exit fullscreen mode

As of late 2026, actions/checkout registers the workspace as safe for its own operations, but later steps that run git as a different user, or in a different path, can still hit the error. Trusting $GITHUB_WORKSPACE explicitly is a one-line, auditable fix. Takeaway: in disposable CI, trusting exactly one named path costs nothing and tells the next reader why it is there.

Pass the setting through the environment

When you cannot write a config file at all, Git 2.31 and later reads config from environment variables:

export GIT_CONFIG_COUNT=1
export GIT_CONFIG_KEY_0=safe.directory
export GIT_CONFIG_VALUE_0=/workspace
git status
Enter fullscreen mode Exit fullscreen mode

This is the approach I use for containers running under platforms that assign a random UID. Nothing is persisted, so nothing leaks into the next job that reuses the image. The same effect works per command with git -c safe.directory=/workspace status.

Is safe.directory '*' ever okay?

Newer Git versions accept * to mean "trust every directory". On a single-purpose CI runner that is destroyed after each job, the risk is small because there is no second user whose repos you could be tricked into running hooks from. On a developer laptop or a shared build server it removes the very protection the check provides, since any repo that lands in a world-writable location becomes trusted. I would not bake '*' into a base image that people also use interactively. Takeaway: '*' is a property of the machine's lifetime, not of how annoying the error is.

What about sudo and root?

If you run sudo git ... in a repo owned by your normal user, recent Git versions consult SUDO_UID and let it through when it matches the owner, so the common "sudo deploy" case often works. Plain su or a service running as root against a repo owned by a deploy user does not set that variable, and you will see the error. For deployment scripts, run Git as the owning user (sudo -u deploy git pull) rather than widening trust for root.

FAQ

How do I fix "fatal: detected dubious ownership in repository" in Docker?

Run the container with --user "$(id -u):$(id -g)" so the process owns the mounted files. If that is not possible, add the exact mount path with git config --global --add safe.directory /path, or pass it through GIT_CONFIG_COUNT, GIT_CONFIG_KEY_0 and GIT_CONFIG_VALUE_0.

Why does safe.directory in .git/config not work?

Git deliberately ignores safe.directory in repository-local config, because an untrusted repo could otherwise mark itself as safe. Put it in the global, system or command-line config instead.

Is it safe to set safe.directory to *?

Only on short-lived machines where you are the only user. Elsewhere it makes Git trust every repository on the system, which defeats the check added for CVE-2022-24765.

Bottom line

If the cause is a bind mount, fix ownership with a matching UID and skip Git config entirely. In disposable CI, trust the one workspace path and leave a comment explaining why. For random-UID platforms with read-only filesystems, use the GIT_CONFIG_* environment variables, and keep '*' for machines you will delete in ten minutes.

Related reading

Top comments (0)