I have stumbled across some very unexpected behaviour in git related to remote.origin.url. I initially reported it to the security mailing list because of concern of possible exploits, but Glenn Choo and Taylor Blau deemed that the issue was outside Git's security boundary, and thus safe to discuss on the public list. In short, I found out that if a user for some reason, either intentionally/maliciously or unintentionally sets `remote.origin.url` to a repo URL in their *global* config, then a subsequent `git clone`operation will *silently* use this URL instead of the one provided as the command line argument to `git clone`. I believe this is unintentional behaviour, and not just a corner case I haven’t thought of, because of the following observations: * The folder name to clone to is still taken from the command-line specified URL * Git still prints “cloning into…” and the folder name that the user specified * Git sets sets the *local* `remote.origin.url` to the value provided * However, Git fetches the actual repo content, and subsequent workspace checkout, from the URL in the global config, without any notification to the user. Security implications: I believe that this behaviour could theoretically be mis-used for supply-chain attacks, especially on a build server, but Glenn and Taylor pointed out that if an attacker has access to modify a global git config, then there are much worse things they could do. Also, I realise that most build servers these days don’t actually use `git clone` under normal operations (rather they use git init, git remote add, git fetch) so the problem isn't that severe. If a team disables the regular build server fake cloning behaviour and does actual cloning in e.g. a shell step for more control, an attacker with access to pipelines running on the same build node, could potentially set the global url to a malicious fork of a repo used in other pipelines, and silently make the other pipelines clone this forked and patched repo, and potentially execute code within. What did you do before the bug happened? (Steps to reproduce your issue) What happened instead? (Actual behaviour) ------------------------------------------------------------------ I discovered the problem in the wild, reproduced it on my Mac (see later) and then went through the following controlled reproduction in a Docker environment. `docker run -it --entrypoint /bin/bash bitnami/git:2.19.2` ``` $ git config --global remote.origin.url https://github.com/JKrag/sc_demo.git $ git clone https://github.com/eficode-academy/git-katas.git Cloning into 'git-katas'... $ cd git-katas $ ls README.md (i.e. content from sc_demo, not git-katas) $ git remote show origin * remote origin Fetch URL: https://github.com/JKrag/sc_demo.git Push URL: https://github.com/JKrag/sc_demo.git Push URL: https://github.com/eficode-academy/git-katas.git $ cat .git/config ... [remote "origin"] url = https://github.com/eficode-academy/git-katas.git ... $ git config --list --show-origin |grep "remote\.origin" file:/root/.gitconfig remote.origin.url=https://github.com/JKrag/sc_demo.git file:.git/config remote.origin.url=https://github.com/eficode-academy/git-katas.git file:.git/config remote.origin.fetch=+refs/heads/*:refs/remotes/origin/* $ git fetch $ git status On branch master Your branch is up to date with 'origin/master'. nothing to commit, working tree clean $ git config --global --unset remote.origin.url $ git status On branch master Your branch is up to date with 'origin/master'. nothing to commit, working tree clean $ git fetch remote: Enumerating objects: 2443, done. remote: Counting objects: 100% (1109/1109), done. remote: Compressing objects: 100% (465/465), done. remote: Total 2443 (delta 699), reused 674 (delta 642), pack-reused 1334 Receiving objects: 100% (2443/2443), 2.46 MiB | 6.29 MiB/s, done. Resolving deltas: 100% (1052/1052), done. >From https://github.com/eficode-academy/git-katas + 398b171...8bc6cc8 master -> origin/master (forced update) * [new branch] brent-clark-SED-Sw-Mgr/improve-overview -> origin/brent-clark-SED-Sw-Mgr/improve-overview * [new branch] improve-rebase-powershell -> origin/improve-rebase-powershell * [new branch] pr-verify -> origin/pr-verify * [new branch] reorder-instructions-unclear -> origin/reorder-instructions-unclear * [new branch] sofusalbertsen-patch-1 -> origin/sofusalbertsen-patch-1 * [new branch] sofusalbertsen-patch-2 -> origin/sofusalbertsen-patch-2 * [new branch] test-script -> origin/test-script * [new branch] tree-vis -> origin/tree-vis * [new branch] uppercase -> origin/uppercase * [new tag] 0.1.1 -> 0.1.1 * [new tag] 0.2.0 -> 0.2.0 * [new tag] 0.3.0 -> 0.3.0 $ git rev-list --max-parents=0 --all 398b17173d150371977cc12d4406f927a4be32ea # Initial commit from sc-demo repo ad31d12363a181b998317d5f075d89b3fb990122 # Initial commit from git-katas repo ``` What did you expect to happen? (Expected behaviour) First off, I would expect that Git used the url specified on the command line, as it is normal that command-line arguments override both local and global configs. Alternatively, if there really is a good reason to use the global configured one, git should at least take the folder name from there and print out “Cloning into [global configured repo name]” In reality, I can’t see any reason why there would ever be a need to configure global remote.origin.url, and ideally doing so could lead to an error/warning message, but I also know that the philosophy behind Git config is to basically allow any settings, and there is no natural place to “stop” such entries, although I guess it might be reasonable to expect a warning at least when cloning a new repo. Anything else you want to add: -------------------------------------------- Yes, I am aware that this is a very obscure scenario, and as an experienced Git user, it had never crossed my mind that this could happen, but I saw it “in the wild” a few weeks ago, when delivering a 2-day Git training. I asked the participants to clone our “git-katas” repo (as in the reproduced scenario above), and then one participant was VERY confused because the folder then had “her own code”, and she couldn’t understand why. After going through her bash history and verifying that there was no other good explanation, I finally found the explanation by looking in the global config where I found the unexpected setting. The user had no real idea how it had gotten there, except some vague idea of having tried “some stuff” to fix “some issue” a long time ago. Since she only used a single repo on her computer, she would never really have noticed under normal conditions. Platform: ---------------- Problem originally seen “in the wild” on an Ubuntu laptop running Git 2.17 as I recall. Issue reproduced on OSX Git 2.39.2, and in docker containers running 2.19.2 and 2.40. [ Local Mac ] [System Info] git version: git version 2.39.2 cpu: x86_64 no commit associated with this build sizeof-long: 8 sizeof-size_t: 8 shell-path: /bin/sh feature: fsmonitor--daemon uname: Darwin 22.4.0 Darwin Kernel Version 22.4.0: Mon Mar 6 21:00:17 PST 2023; root:xnu-8796.101.5~3/RELEASE_X86_64 x86_64 compiler info: clang: 14.0.0 (clang-1400.0.29.202) libc info: no libc information available $SHELL (typically, interactive shell): /bin/zsh [ Bitnami/git:2:40 ] $ docker run -it --entrypoint /bin/bash bitnami/git:2.40.0 root@89543b59ce2c:/# git version --build-options git version 2.40.0 cpu: x86_64 $SHELL = /bin/bash [ Bitnami/git:2.19.2 ] $ docker run -it --entrypoint /bin/bash bitnami/git:2.19.2 root@6a86a5c92e58:/# git version --build-options git version 2.19.2 cpu: x86_64 $SHELL = /bin/bash $ uname -a Linux 6a86a5c92e58 5.15.49-linuxkit #1 SMP Tue Sep 13 07:51:46 UTC 2022 x86_64 GNU/Linux Regards Jan ----------------------- Jan Krag Git Trainer & DevOps Consultant jan.krag@xxxxxxxxxxx www.eficode.com Copenhagen, Denmark