1

Consider this scenario:

  1. You have a central Git repository online (e.g. on Github, GitLab, etc.)
  2. User1 and User2 have access to that repository
  3. User1 is malicious and changes some files in a past commit (he does not add a new, normal commit)
  4. User1 pushes the changes to the central Git repository

Will anyone notice this change? Or you can compromise a Git repository without anyone noticing that?

1 Answer 1

4

User1 is malicious and changes some files in a past commit (he does not add a new, normal commit)

Git commits are uniquely identified by a SHA1 hash and that SHA1 hash includes the hashes of all parent commits.

You can't alter a commit without changing its hash (except possibly in the case of hash collisions, but I'll discuss those separately later). If you change its hash, it becomes a new commit. So to change one commit you have to change all its child commits.

Now this is perfectly possible to do. Git even provides you with tools to do it (git rebase -i).

User1 pushes the changes to the central Git repository

Git will refuse to do this by default, but it can be forced to do so with git push -f. In some cases the remote Git repository may be configured to refuse force pushes, but often it won't be.

Will anyone notice this change?

Maybe; it depends how much attention they are paying and how careful the malicious user was in preparing the commits.

When people try to pull from the modified Git repository, Git will regard the altered commits as being distinct commits from the original commits. It will then try to merge the altered commits on the server with the original commits on the client. It's possible there will be a merge conflict, but it's far from a certainty.

Someone paying attention may wonder about the unexpected merge, but if they were expecting a merge anyway they may not notice that the split point is much further back in history than they were expecting.

Hash collisions and preimages

If two commits (or more likely: two files) included in a commit have the same hash, Git will regard them as being the same. The hash used by Git isn't quite a plain SHA1, but it's close enough that the same attacks applied.

Since Git regards them as being the same, a push or pull will be a no-op. So you can't push one commit and then push another with the same hash. You could, however, privately send someone the "good" commit for review and then later push the "bad" commit to the central repository before the reviewer pushes it. Or if you have admin access to the central repository you could replace the good commit with the bad one in the central repository's commit store, leaving existing clones with the "good" commit while new clones get the "bad" commit.

Recent versions of Git have implemented mitigations against the known collision attacks on SHA1. There are long term plans to move away from SHA1 but it isn't simple.

3
  • Thanks for the explanation! So a git pull, in case of altered past history, will attempt a normal merge and not complain??
    – collimarco
    Apr 14, 2022 at 10:41
  • I'm pretty sure it will attempt a normal merge, i'm not so sure if the "fetch" part of the pull will produce a warning or not. Apr 14, 2022 at 10:47
  • Ok, so in this case it's not a fast-forward and you need to take manual action to merge (?). In that case if you look at what you are merging you will notice something strange, but if you expected a merge and you don't look at it in detail, the alteration can go unnoticed.
    – collimarco
    Apr 14, 2022 at 10:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .