Compare commits

...

1 Commits

Author SHA1 Message Date
HAL9000 cd671bc33b fix(security): fix git_tools.py _handle_git_log injection #7482
Add strict validation for git log author and date filters to prevent git option injection.\n\nISSUES CLOSED: #7482
2026-04-12 04:18:08 +00:00
2 changed files with 64 additions and 3 deletions
+18
View File
@@ -135,6 +135,24 @@ Feature: Built-in Git Tools
Then the tool result should be successful
And the git output should contain "Initial commit"
Scenario: Git log rejects author values that look like options
Given a temporary git repository
When I execute the "builtin/git-log" tool with author "-c core.fsmonitor=malicious"
Then the tool result should not be successful
And the tool result error should mention "Invalid author value"
Scenario: Git log rejects since values that look like options
Given a temporary git repository
When I execute the "builtin/git-log" tool with since "-c core.fsmonitor=malicious"
Then the tool result should not be successful
And the tool result error should mention "Invalid since value"
Scenario: Git log rejects dates with unsupported characters
Given a temporary git repository
When I execute the "builtin/git-log" tool with until "2024-01-01; rm -rf"
Then the tool result should not be successful
And the tool result error should mention "Invalid until value"
Scenario: Git log filtered by path
Given a temporary git repository
And a tracked file "log-path-test.txt" with content "logged"
+46 -3
View File
@@ -36,6 +36,7 @@ register_git_tools(registry)
from __future__ import annotations
import os
import re
import subprocess
from pathlib import Path
from typing import Any
@@ -204,6 +205,48 @@ def _validate_ref(ref: str) -> str:
return ref
_SAFE_LOG_DATE_PATTERN = re.compile(r"^[\w: .,+\-]+$")
def _validate_author(author: str) -> str:
"""Validate a git log author filter value.
Author filters are passed to ``git log`` and must be treated as data,
not additional CLI options. Reject values that begin with ``-`` (which
git would interpret as a new option), contain line breaks, or include
NUL characters that could truncate arguments.
"""
if author.startswith("-"):
raise ValueError("Invalid author value: must not start with '-'")
if "\n" in author or "\r" in author:
raise ValueError("Invalid author value: must not contain newlines")
if "\x00" in author:
raise ValueError("Invalid author value: contains NUL byte")
return author
def _validate_log_date(value: str, field: str) -> str:
"""Validate ``since``/``until`` inputs passed to ``git log``.
Git accepts a broad range of human readable date formats. To prevent
option injection we disallow leading ``-`` (which would create a new
option) and restrict the value to a conservative character set that
covers the formats we support (ISO timestamps, relative expressions
like ``1 week ago``, etc.). Newlines and NUL bytes are also rejected.
"""
if value.startswith("-"):
raise ValueError(f"Invalid {field} value: must not start with '-'")
if "\n" in value or "\r" in value:
raise ValueError(f"Invalid {field} value: must not contain newlines")
if "\x00" in value:
raise ValueError(f"Invalid {field} value: contains NUL byte")
if not _SAFE_LOG_DATE_PATTERN.fullmatch(value):
raise ValueError(f"Invalid {field} value: contains unsupported characters")
return value
# ---------------------------------------------------------------------------
# Git subprocess helper
# ---------------------------------------------------------------------------
@@ -329,11 +372,11 @@ def _handle_git_log(inputs: dict[str, Any]) -> dict[str, Any]:
if oneline:
args.append("--oneline")
if author:
args.append(f"--author={author}")
args.append(f"--author={_validate_author(author)}")
if since:
args.append(f"--since={since}")
args.append(f"--since={_validate_log_date(since, 'since')}")
if until:
args.append(f"--until={until}")
args.append(f"--until={_validate_log_date(until, 'until')}")
if path:
_validate_sub_path(path, repo)
args.extend(["--", path])