VYPR
Critical severity9.3NVD Advisory· Published Mar 31, 2015· Updated May 6, 2026

CVE-2014-9706

CVE-2014-9706

Description

The build_index_from_tree function in index.py in Dulwich before 0.9.9 allows remote attackers to execute arbitrary code via a commit with a directory path starting with .git/, which is not properly handled when checking out a working tree.

Affected products

2

Patches

1
091638be3c89

By default refuse to create index entries with a path starting with .git/.

https://github.com/jelmer/dulwichJelmer VernooijJan 15, 2015via ghsa
3 files changed · +53 2
  • dulwich/index.py+11 1 modified
    @@ -431,8 +431,14 @@ def build_file_from_blob(blob, mode, target_path, honor_filemode=True):
                 os.chmod(target_path, mode)
     
     
    +def validate_path_default(path):
    +    """Default path validator that just checks for .git/."""
    +    return not path.startswith(".git/")
    +
    +
     def build_index_from_tree(prefix, index_path, object_store, tree_id,
    -                          honor_filemode=True):
    +                          honor_filemode=True,
    +                          validate_path=validate_path_default):
         """Generate and materialize index from a tree
     
         :param tree_id: Tree to materialize
    @@ -441,6 +447,8 @@ def build_index_from_tree(prefix, index_path, object_store, tree_id,
         :param object_store: Non-empty object store holding tree contents
         :param honor_filemode: An optional flag to honor core.filemode setting in
             config file, default is core.filemode=True, change executable bit
    +    :param validate_path: Function to validate paths to check out;
    +        default just refuses filenames starting with .git/.
     
         :note:: existing index is wiped and contents are not merged
             in a working dir. Suiteable only for fresh clones.
    @@ -449,6 +457,8 @@ def build_index_from_tree(prefix, index_path, object_store, tree_id,
         index = Index(index_path)
     
         for entry in object_store.iter_tree_contents(tree_id):
    +        if not validate_path(entry.path):
    +            continue
             full_path = os.path.join(prefix, entry.path)
     
             if not os.path.exists(os.path.dirname(full_path)):
    
  • dulwich/tests/test_index.py+37 1 modified
    @@ -50,7 +50,6 @@
     from dulwich.tests import TestCase
     from dulwich.tests.utils import skipIfPY3
     
    -
     @skipIfPY3
     class IndexTestCase(TestCase):
     
    @@ -281,6 +280,43 @@ def test_empty(self):
             # Verify no files
             self.assertEqual(['.git'], os.listdir(repo.path))
     
    +    def test_git_dir(self):
    +        if os.name != 'posix':
    +            self.skipTest("test depends on POSIX shell")
    +
    +        repo_dir = tempfile.mkdtemp()
    +        repo = Repo.init(repo_dir)
    +        self.addCleanup(shutil.rmtree, repo_dir)
    +
    +        # Populate repo
    +        filea = Blob.from_string('file a')
    +        filee = Blob.from_string('d')
    +
    +        tree = Tree()
    +        tree['.git/a'] = (stat.S_IFREG | 0o644, filea.id)
    +        tree['c/e'] = (stat.S_IFREG | 0o644, filee.id)
    +
    +        repo.object_store.add_objects([(o, None)
    +            for o in [filea, filee, tree]])
    +
    +        build_index_from_tree(repo.path, repo.index_path(),
    +                repo.object_store, tree.id)
    +
    +        # Verify index entries
    +        index = repo.open_index()
    +        self.assertEqual(len(index), 1)
    +
    +        # filea
    +        apath = os.path.join(repo.path, '.git', 'a')
    +        self.assertFalse(os.path.exists(apath))
    +
    +        # filee
    +        epath = os.path.join(repo.path, 'c', 'e')
    +        self.assertTrue(os.path.exists(epath))
    +        self.assertReasonableIndexEntry(index['c/e'],
    +            stat.S_IFREG | 0o644, 1, filee.id)
    +        self.assertFileContents(epath, 'd')
    +
         def test_nonempty(self):
             if os.name != 'posix':
                 self.skipTest("test depends on POSIX shell")
    
  • NEWS+5 0 modified
    @@ -1,5 +1,10 @@
     0.9.9	UNRELEASED
     
    + BUG FIXES
    +
    +  * In dulwich.index.build_index_from_tree, by default
    +    refuse to create entries that start with .git/.
    +
     0.9.8	2014-11-30
     
      BUG FIXES
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

10

News mentions

0

No linked articles in our index yet.