GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Harden config and Git option validation by Byron · Pull Request #2204 · gitpython-developers/GitPython

Conversation

@Byron

@Byron Byron commented Aug 2, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Tasks

This section is for Byron only. Models continuing this PR must not add, remove, check, uncheck, rename, or reorder checkboxes here.

  • refackiew

Everything below this line was generated by Codex GPT-5.

Created by Codex on behalf of Byron. Byron will review before this is ready to merge.

Security advisories

  • GHSA-jm78-9fvv-mhgr — High. GitPython (pip), affected range <= 3.1.57. Rejects syntax-bearing config option names before serialization. Patched versions and CVE are not yet assigned.
  • GHSA-wvpp-8hx9-p66j — High. GitPython (pip), affected range <= 3.1.57. Ensures unsafe-option validation sees joined short-option tokens. Patched versions and CVE are not yet assigned.
  • GHSA-4gmw-gg2m-w46p — High. GitPython (pip), affected range <= 3.1.57. Guards read-tree output redirection across IndexFile entry points. Patched versions and CVE are not yet assigned.
  • GHSA-9rj7-rf2p-w77r — High. GitPython (pip), affected range <= 3.1.57. Guards repository-template installation and repository-directory redirection during Repo.init. Patched versions and CVE are not yet assigned.
  • GHSA-hh9p-6wh2-4mfc — Medium. GitPython (pip), affected range <= 3.1.57. Prevents high-level pathspec commands from reading caller-selected files through forwarded options. Patched versions and CVE are not yet assigned.

Exploit payloads and unnecessary reproduction detail are intentionally omitted from this public summary.

Behavior

Config writers reject option-name characters that can alter config syntax while retaining GitPython's established safe character set. Unsafe Git option checks now inspect the exact joined short-option form emitted when splitting is disabled. IndexFile.from_tree, reset, and merge_tree reject caller-controlled --index-output forms unless explicitly opted out. Repo.init rejects unsafe template and separate-Git-directory options before creating or changing filesystem paths. IndexFile.remove, Head.checkout, and HEAD.reset reject caller-controlled pathspec-file input, including abbreviated and option-shaped positional forms. Trusted callers retain an explicit allow_unsafe_options=True escape hatch.

Implementation

The config mutation APIs share a syntax-safe option-name validator. _option_candidates constructs joined candidates for unsplit one-character kwargs, covering every existing guarded caller. Both read-tree sinks use a shared unsafe-option list, with IndexFile.reset delegating to the guarded from_tree path. Repo.init applies a dedicated unsafe-option list through the same normalized checker. The pathspec-file fix defines one shared denylist and applies it before rm, checkout, or reset; reset validates both kwargs and its pre-separator commit argument.

Each change includes a regression test and a broader class audit. The audits covered all config option-creating APIs, all unsafe-option guard call sites, all read-tree invocations, every repository-template consumer exposed by GitPython's high-level APIs, and all native Git commands supporting pathspec-file input. Native Git supports the latter in add, checkout/restore, commit, reset, rm, and stash; only rm, checkout, and reset have GitPython high-level arbitrary-option forwarding, and all three are guarded. GitPython implements high-level add/commit without such forwarding and has no high-level restore/stash wrapper; git mv does not accept this option. The intentionally raw Git interface remains caller-controlled by design.

For repository templates, Native Git's built-in consumers are init and clone; clone, clone-from, and submodule clone paths converge on the guarded clone helper. git svn init is exposed only through the raw Git interface. The commit --template option is a commit-message input and is not the same hook-installation class.

Git baseline

Behavior was checked against the local Git reference checkout at commit cf5497b14c5a24f10c13f7e0ee85cb95af13ea6a (v2.55.0.windows.3-16-gcf5497b14c). Its config parser, clustered short-option loop, read-tree --index-output parsing, repository-template definitions, and pathspec-file implementations informed the GitPython-specific changes.

Validation

  • Expanded affected-module suite: 214 passed, 3 skipped, 2 local master-fixture tests deselected, 5 expected xfailed
  • Focused pathspec rejection, positional-bypass, opt-in, and candidate-transformation regressions: 6 passed
  • Ruff lint: passed
  • Ruff format check: passed
  • basedpyright on all touched production modules: 0 errors; one environment-only missing-source warning for typing_extensions
  • git diff --check: passed

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

chatgpt-codex-connector[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@Byron
Byron force-pushed the security-fixes branch from bae35f9 to 8ff1b66 Compare August 2, 2026 09:26
Byron and others added 5 commits August 4, 2026 15:16
@Byron @codex
Reject syntax-bearing git config option names
a495ccd
<!-- agent -->
GHSA-jm78-9fvv-mhgr reports that config option names containing Git
syntax can be serialized as unintended directives. A regression test showed
that set, set_value, and add_value accepted delimiter, comment, bracket, and
whitespace characters in option names.

Restrict written option names to GitPython's established safe character set of
letters, digits, hyphens, underscores, and dots. This blocks characters that
can change config syntax while preserving option names historically supported
by the writer and SectionConstraint.

A broader audit confirmed that every public option-creating config API and
SectionConstraint delegate reaches this validator; no separate config writer
sink was found. The behavior was checked against Git cf5497b14, and the full
config test module plus dotted-option regression pass.

Assisted-by: GPT 5.6
Co-authored-by: GPT 5.6 <[email protected]>
@Byron @codex
Check joined short-option values before Git execution
96a888f
<!-- agent -->
GHSA-wvpp-8hx9-p66j reports that unsafe-option checks omitted the value
joined to a one-character option when split_single_char_options was false. A
regression test reproduced the mismatch: GitPython checked only -n even though
it emitted a joined -nVALUE token that Git parses as clustered short options.

Collect the exact joined token for unsplit one-character keyword arguments so
the existing clustered-short-option validation sees every option character.
The split form and long-option behavior remain unchanged.

A broader audit confirmed that all guarded keyword-forwarding APIs use
_option_candidates, including clone, ls-remote, fetch, pull, push, archive,
revision, diff, checkout-index, and tag paths. Git cf5497b14 confirms repeated
short-option parsing within a joined token. Focused candidate and unsafe-option
tests pass.

Assisted-by: GPT 5.6
Co-authored-by: GPT 5.6 <[email protected]>
@Byron @codex
Guard read-tree index output paths
9b5dcaf
<!-- agent -->
GHSA-4gmw-gg2m-w46p reports that caller-controlled treeish arguments could
be parsed by git read-tree as --index-output and select an arbitrary output
path. A regression test showed that from_tree reached Git instead of raising
UnsafeOptionError; the same unchecked path was reachable through reset and
both merge_tree treeish positions.

Add the project-standard unsafe-option guard and explicit opt-out to
from_tree, merge_tree, and reset. Check positional and keyword candidates so
abbreviations and alternate forwarding forms are covered before read-tree
runs.

A broader audit found only two read-tree sinks in the codebase; both are now
guarded, and reset delegates to the guarded from_tree path. The only remaining
index-output use is GitPython's controlled temporary index. Git cf5497b14
confirms read-tree parses this path-taking option before tree arguments.
Focused index tests and Ruff checks pass.

Assisted-by: GPT 5.6
Co-authored-by: GPT 5.6 <[email protected]>
@Byron @codex
Guard unsafe git init options
d9ddb55
<!-- agent -->
GHSA-9rj7-rf2p-w77r reports that Repo.init forwarded git-init
options without applying GitPython's unsafe-option policy. A regression
showed template and abbreviated option spellings reached Git without an
UnsafeOptionError and could create the destination before validation.

Add a git-init denylist for template installation and separate Git
directory redirection, check keyword options before any path or directory
mutation, and provide the standard explicit allow_unsafe_options escape
hatch. This preserves trusted uses while rejecting untrusted forwarding by
default.

An audit against Git cf5497b14c5a24f10c13f7e0ee85cb95af13ea6a
(v2.55.0.windows.3-16-gcf5497b14c) confirmed that init and clone are the
built-in commands that consume repository template directories. Clone,
clone_from, and submodule cloning already share the guarded clone helper;
the similarly named commit option only reads a commit-message template.

Validated with the focused init regression, the clone/init unsafe-option
suite, 185 config/Git/index/clone tests, Ruff, and basedpyright.

Assisted-by: GPT 5.6
Co-authored-by: GPT 5.6 <[email protected]>
@Byron @codex
Guard pathspec file inputs in high-level commands
f2550b6
<!-- agent -->
GHSA-hh9p-6wh2-4mfc reports that high-level rm and checkout wrappers
forwarded pathspec file options without GitPython's unsafe-option policy.
A regression showed that both commands surfaced multi-line pathspec data in
Git errors, while reset consumed the same caller-selected file without a
validation error. The audit also found that reset's positional commit could
carry the option before its argument separator.

Define one shared unsafe pathspec-file option list and apply it to
IndexFile.remove, Head.checkout, and HEAD.reset before invoking Git. Check
reset's positional commit as well as keyword options, retain the standard
allow_unsafe_options escape hatch for trusted callers, and cover abbreviated
long-option spellings.

An audit against Git cf5497b14c5a24f10c13f7e0ee85cb95af13ea6a
(v2.55.0.windows.3-16-gcf5497b14c) found pathspec-file support in add,
checkout/restore, commit, reset, rm, and stash. GitPython has no arbitrary
high-level option forwarding to the other commands, and git mv does not
support this option.

Validated with focused rejection and opt-in tests, 214 affected-module
regressions, Ruff, basedpyright, and git diff --check.

Assisted-by: GPT 5.6
Co-authored-by: GPT 5.6 <[email protected]>
@Byron
Byron force-pushed the security-fixes branch from 1ef1a9a to f2550b6 Compare August 4, 2026 13:39
@Byron
Byron marked this pull request as ready for review August 4, 2026 13:39
Copilot AI lite review requested due to automatic review settings August 4, 2026 13:39
Copilot started reviewing on behalf of Byron August 4, 2026 13:40
View session
Copilot AI reviewed Aug 4, 2026
View reviewed changes

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request hardens GitPython’s higher-level APIs against option-based injection and unsafe filesystem/code-execution vectors by adding targeted unsafe-option validation, stricter config key validation, and regression tests to cover these cases.

Changes:

  • Add unsafe-option guarding (with allow_unsafe_options=True escape hatch) for Repo.init, Head.checkout/HEAD.reset, and IndexFile entry points (from_tree, merge_tree, remove, reset).
  • Reject syntax-bearing Git config option names via a shared validator in GitConfigParser.
  • Extend option-candidate generation and add tests to ensure unsafe-option detection considers additional spellings/encodings (including abbreviations and unsplit short-option forms).

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
git/cmd.py Adds pathspec-from-file unsafe option list and adjusts _option_candidates for improved unsafe-option detection.
git/config.py Enforces a stricter allowed character set for config option names to prevent syntax-altering keys.
git/index/base.py Adds unsafe-option checks and allow_unsafe_options to read-tree-based and pathspec-related index operations.
git/repo/base.py Adds unsafe-option checks and allow_unsafe_options to Repo.init for template / separate git-dir options.
git/refs/head.py Adds unsafe-option checks and allow_unsafe_options to checkout and reset to block pathspec-from-file.
test/test_config.py Adds regression tests for invalid config option names.
test/test_git.py Adds regression tests for _option_candidates behavior and unsafe-option validation coverage.
test/test_index.py Adds regression tests for --index-output and pathspec-from-file blocking/opt-in.
test/test_refs.py Adds regression tests for Head.checkout / HEAD.reset pathspec-from-file blocking/opt-in.
test/test_repo.py Adds regression tests for Repo.init unsafe options blocking/opt-in.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread git/cmd.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@Byron
Byron merged commit 9a8f6fe into main Aug 4, 2026
54 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@bindsi bindsi mentioned this pull request Aug 6, 2026
security(deps): bump gitpython from 3.1.57 to 3.1.58 in /training/rl microsoft/physical-ai-toolchain#1343
Closed
This was referenced Aug 18, 2026
🟠 [High] GitPython: Unguarded Git Read-Tree Option Forwarding in IndexFile.from_tree/reset/merge_tree Enables Arbitrary File Overwrite Latch/connectedhomeip#46
Open
🟠 [High] GitPython: Unguarded Git Option Forwarding in Repo.init Enables Arbitrary Command Execution via --Template Clone Hooks Latch/connectedhomeip#47
Open
Copilot AI mentioned this pull request Aug 24, 2026
[WIP] Fix GitPython vulnerability for config-name injection DeltaE/PyPSA_BC#18
Merged
1 task done
This was referenced Sep 9, 2026
🟠 [High] GitPython: Git-Config OPTION-name Injection via =/#/Whitespace Bypasses Name Validator, Enabling Forged core.sshCommand/hooksPath (RCE) Latch/connectedhomeip#52
Open
🟠 [High] GitPython: Unsafe Git Option Guard Bypass via Split_single_char_options=False Short-Option Token Smuggling Enables Command Execution Latch/connectedhomeip#51
Open
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

Copilot code review Copilot
Copilot review effort
Applies to this pull request for everyone.Learn more about Copilot code review.
Copilot left review comments

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@Byron
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.