Subject: Possible vulnerability to SHA-1 collisions

From: Michael Hirshleifer <[email-masked]>
Date: Sat, 24 Nov 2012 11:12:28 +0000

Evil Guy creates 2 files, 1 evil and 1 innocuous, with the same SHA-1 
checksum (including Git header). Mr. Evil creates a local branch with an 
innocuous name like “test-bugfix”, and adds a commit containing a 
reference to the evil file. Separately, using a sockpuppet, Evil Guy 
creates an innocuous bugfix (very likely to be accepted) containing the 
innocuous file, and submits it to Good Guy. Before Good Guy can commit 
the bugfix, Evil Guy pushes the evil branch to Github, and then 
immediately deletes it; or equivalently --force pushes any innocuous 
commit on top of it. (This is unlikely to arouse suspicion, and he can 
always say he deleted it because it didn’t work.)

Git keeps unreferenced objects around for a few weeks, so when Good Guy 
commits the patch and pushes to Github, an object with an sha1sum that 
matches the good file will already exist in the main repository. Since 
Git keeps the local copy of files when sha1sums match, the main Github 
repository will then contain the evil file associated with Good Guy’s 
commit. Any users cloning from Github will get the evil version. This is 
an exploit.

And Good Guy’s local repository will contain the good file; he will not 
notice anything amiss unless he nukes his local repository and clones 
from Github again. Even when the compromise is discovered, there will be 
no reason to suspect Evil Guy; the evil file seems to have been 
committed by Good Guy.

Previous discussion about hash collisions in Git seems to conclude that 
they aren’t a security threat. See 
http://stackoverflow.com/questions/9392365/how-would-git-handle-a-sha-1-collision-on-a-blob/9392525#9392525, 
Linus Torvalds arguing that Git’s security doesn’t depend on SHA-1 
collision resistance.

This proposed exploit does not involve social engineering, or any good 
guys failing to spot or accepting patches containing evil data (what 
Good Guy accepts is a genuine bugfix). It contaminates the main public 
repository in a way that Good Guy won’t immediately notice. It does not 
require a second-preimage attack; Bad Guy creates both versions of the 
file. While this does require the bad guy to have commit access, the bad 
guy can avoid suspicion after the attack.