VYPR
Medium severity4.7GHSA Advisory· Published Oct 9, 2025· Updated Apr 15, 2026

CVE-2025-10281

CVE-2025-10281

Description

BBOT's git_clone module could be abused to disclose a GitHub API key to an attacker controlled server with a malicious formatted git URL.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
bbotPyPI
< 2.7.02.7.0

Affected products

1

Patches

1
0ede97fa887d

Merge commit from fork

https://github.com/blacklanternsecurity/bbotTheTechromancerSep 11, 2025via ghsa
4 files changed · +30 13
  • bbot/core/helpers/git.py+18 0 added
    @@ -0,0 +1,18 @@
    +import regex as re
    +from pathlib import Path
    +
    +
    +def sanitize_git_repo(repo_folder: Path):
    +    # sanitizing the git config is infeasible since there are too many different ways to do evil things
    +    # instead, we move it out of .git and into the repo folder, so we don't miss any secrets etc. inside
    +    config_file = repo_folder / ".git" / "config"
    +    if config_file.exists():
    +        config_file.rename(repo_folder / "git_config_original")
    +    # move the index file
    +    index_file = repo_folder / ".git" / "index"
    +    if index_file.exists():
    +        index_file.rename(repo_folder / "git_index_original")
    +    # move the hooks folder
    +    hooks_folder = repo_folder / ".git" / "hooks"
    +    if hooks_folder.exists():
    +        hooks_folder.rename(repo_folder / "git_hooks_original")
    
  • bbot/core/helpers/misc.py+1 0 modified
    @@ -17,6 +17,7 @@
     from asyncio import create_task, gather, sleep, wait_for  # noqa
     from urllib.parse import urlparse, quote, unquote, urlunparse, urljoin  # noqa F401
     
    +from .git import *  # noqa F401
     from .url import *  # noqa F401
     from ... import errors
     from . import regexes as bbot_regexes
    
  • bbot/modules/git_clone.py+8 1 modified
    @@ -82,4 +82,11 @@ async def clone_git_repository(self, repository_url):
                 return
     
             folder_name = output.stderr.split("Cloning into '")[1].split("'")[0]
    -        return folder / folder_name
    +        repo_folder = folder / folder_name
    +
    +        # sanitize the repo
    +        # this moves the git config, index file, and hooks folder out of the .git folder to prevent nasty things
    +        # Note: the index file can be regenerated by running "git checkout HEAD -- ."
    +        self.helpers.sanitize_git_repo(repo_folder)
    +
    +        return repo_folder
    
  • bbot/modules/gitdumper.py+3 12 modified
    @@ -35,7 +35,6 @@ async def setup(self):
             else:
                 self.output_dir = self.scan.temp_dir / "git_repos"
             self.helpers.mkdir(self.output_dir)
    -        self.unsafe_regex = self.helpers.re.compile(r"^\s*fsmonitor|sshcommand|askpass|editor|pager", re.IGNORECASE)
             self.ref_regex = self.helpers.re.compile(r"ref: refs/heads/([a-zA-Z\d_-]+)")
             self.obj_regex = self.helpers.re.compile(r"[a-f0-9]{40}")
             self.pack_regex = self.helpers.re.compile(r"pack-([a-f0-9]{40})\.pack")
    @@ -131,7 +130,6 @@ async def handle_event(self, event):
             else:
                 result = await self.git_fuzz(repo_url, repo_folder)
             if result:
    -            await self.sanitize_config(repo_folder)
                 await self.git_checkout(repo_folder)
                 codebase_event = self.make_event({"path": str(repo_folder)}, "FILESYSTEM", tags=["git"], parent=event)
                 await self.emit_event(
    @@ -251,15 +249,6 @@ async def download_files(self, urls, folder):
                 self.debug(f"Unable to download git files to {folder}")
                 return False
     
    -    async def sanitize_config(self, folder):
    -        config_file = folder / ".git/config"
    -        if config_file.exists():
    -            with config_file.open("r", encoding="utf-8", errors="ignore") as file:
    -                content = file.read()
    -                sanitized = await self.helpers.re.sub(self.unsafe_regex, r"# \g<0>", content)
    -            with config_file.open("w", encoding="utf-8") as file:
    -                file.write(sanitized)
    -
         async def git_catfile(self, hash, option="-t", folder=Path()):
             command = ["git", "cat-file", option, hash]
             try:
    @@ -270,8 +259,10 @@ async def git_catfile(self, hash, option="-t", folder=Path()):
             return output.stdout
     
         async def git_checkout(self, folder):
    +        self.helpers.sanitize_git_repo(folder)
             self.verbose(f"Running git checkout to reconstruct the git repository at {folder}")
    -        command = ["git", "checkout", "."]
    +        # we do "checkout head -- ." because the sanitization deletes the index file, and it needs to be reconstructed
    +        command = ["git", "checkout", "HEAD", "--", "."]
             try:
                 await self.run_process(command, env={"GIT_TERMINAL_PROMPT": "0"}, cwd=folder, check=True)
             except CalledProcessError as e:
    

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

5

News mentions

0

No linked articles in our index yet.