Skip to content

Commit da779e6

Browse files
EliahKaganclaude
andcommitted
Clarify Git.execute() string semantics and shell/shlex risks
Update the rewritten :param command: block from gitpython-developers#2144 in two ways: * Add a Windows bullet. gitpython-developers#2144 said the string is "passed as a single executable name to subprocess.Popen" with shell=False. That is accurate on POSIX, but on Windows subprocess.Popen forwards the string to CreateProcessW and Windows command-line parsing produces the program's argv. So e.g. "git version" actually runs. * Name the tokenization risks specifically. gitpython-developers#2144 hedged with "possible security implications" for shlex.split and pointed at the existing shell-parameter warning for shell=True. Be concrete: under shell=True the shell interprets ;, |, &, $(...), etc. as syntax, so metacharacters in interpolated values can execute arbitrary commands; shlex.split is preferable on POSIX but follows POSIX rules on Windows that may diverge from Windows command-line conventions; and embedded whitespace or quotes can shift tokenization either way. Neither is safe with untrusted input (branch names, URLs, filenames, etc.); the sequence form is, because each interpolated value occupies a single argv slot. Documentation only; behavior is unchanged. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7b83f7a commit da779e6

1 file changed

Lines changed: 28 additions & 10 deletions

File tree

git/cmd.py

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,16 +1131,34 @@ def execute(
11311131
information (stdout).
11321132
11331133
:param command:
1134-
The command to execute. A sequence of program arguments is the
1135-
recommended form when `shell` is ``False`` (the default), e.g.
1136-
``["git", "log", "-n", "1"]``.
1137-
1138-
A string is accepted, but with `shell` set to ``False`` it is passed
1139-
as a single executable name to :class:`subprocess.Popen`. For example,
1140-
``"git log -n 1"`` looks for an executable literally named
1141-
``git log -n 1`` and will fail with :class:`GitCommandNotFound`. To
1142-
split a command string into argv tokens, pass ``shlex.split(...)`` as
1143-
a sequence or set `shell` to ``True`` (see the warning below).
1134+
The command to execute. A sequence of program arguments, e.g.
1135+
``["git", "log", "-n", "1"]``, is the recommended form: the tokens
1136+
are passed to the program unchanged on every platform.
1137+
1138+
A string is also accepted, but how it is interpreted depends on
1139+
the platform when `shell` is ``False`` (the default), because
1140+
:meth:`Git.execute` delegates to :class:`subprocess.Popen`:
1141+
1142+
* On POSIX, the entire string is taken as the executable name; no
1143+
tokenization is performed. ``"git log -n 1"`` therefore looks
1144+
for an executable literally named ``git log -n 1`` and fails
1145+
with :class:`GitCommandNotFound`.
1146+
* On Windows, the string is passed unchanged to the underlying
1147+
``CreateProcessW`` API, and Windows command-line parsing rules
1148+
determine the tokens the called program receives in its argv.
1149+
``"git log -n 1"`` therefore runs ``git`` with arguments
1150+
``log``, ``-n``, and ``1``.
1151+
1152+
``shell=True`` is rarely safe because the platform shell
1153+
interprets metacharacters such as ``;``, ``|``, ``&``, and
1154+
``$(...)`` as syntax. Use :func:`shlex.split` instead on
1155+
POSIX; on Windows it follows POSIX rules that may diverge
1156+
from Windows command-line conventions. Neither is safe
1157+
with untrusted input (branch names, URLs, filenames, etc.):
1158+
whitespace or quotes can shift tokenization, and under
1159+
``shell=True`` metacharacters can run arbitrary commands.
1160+
Build the sequence form when interpolating such values,
1161+
keeping each in a single argv slot.
11441162
11451163
:param istream:
11461164
Standard input filehandle passed to :class:`subprocess.Popen`.

0 commit comments

Comments
 (0)