-
-
Notifications
You must be signed in to change notification settings - Fork 911
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Quote URLs in Repo.clone_from() #1516
Quote URLs in Repo.clone_from() #1516
Conversation
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.
Thanks a lot, much appreciated. I don't know why quoting the URL prevents it from being effective when the ext
protocol is allowed. There seem to be no internal quotes in the 'ext:…' url that would be quoted then.
In any case, I think it would be useful to have a test for the unsafe_protocols
feature. My intuition here is also to document it to allow folks to bypass the quoting in case they relied on using the ext
protocol.
Regrading CI, I have a feeling that the python action doesn't support older versions anymore - please feel free to remove them from the test suite so there is a chance for the tests to succeed.
Quoting removes URL unsafe characters, such as spaces, so we end up with:
which will not execute. Successfully, anyway -- and should also leave most of the usual suspects https:// and git:// alone, but I will confirm when I fix up GitHub Actions. |
I may have to parse it and then quote the host portion, depending on if it's overzealous, but I have it in hand. I will also add a test for |
a3bc689
to
0cd4e4d
Compare
@Byron Sadly, I've had to change this around to not quote, but this is ready for another look. |
In #1515 (comment) there is this case that should be fixed too from git import Repo
r = Repo.init('', bare=True)
r.clone('foo', '/tmp/foo', multi_options=['--upload-pack="touch /tmp/pwn"']) Here the URL can be anything. We could check/ban the unsafe options (--upload-pack/-c protocol.*) instead of (or in addition of) checking the protocol. EDIT: This also works r.clone('--upload-pack=touch /tmp/pwn') |
This is sort of the problem -- git is designed to run arbitrary commands. However, I'll see if I can refactor the checks out to a function. |
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.
Thanks a lot for your help with CI!
I have a few comments and questions that I hope we can sort out quickly so we can get this PR merged and cut a new release right after that.
Thank you for your continued help.
git/repo/base.py
Outdated
:param kwargs: see the ``clone`` method | ||
:return: Repo instance pointing to the cloned directory""" | ||
git = cls.GitCommandWrapperType(os.getcwd()) | ||
if env is not None: | ||
git.update_environment(**env) | ||
if not unsafe_protocols and "::" in url: |
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.
Could we factor "::" in url
out into its own publicly available and documented function to allow it to be used before trying to clone as well? Furthermore, this would allow to run unit-tests against it which I'd love to see. Particularly, are there ways to get false positives for legitimate cases, or false negatives in case the url is obfuscated somehow? My intuition here is that url.startswith('ext::')
might reduce false positives, but specific tests should help find the sweet spot.
It would be interesting to find out if a url like ext::…
(note the leading whitespace) also works. I'd guess it won't work as the command invocation doesn't use a shell by default. If that's indeed the case, one could make the url check more specific.
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.
Indeed, and we probably should -- if other cases come up, we can add them there.
git/repo/base.py
Outdated
:param kwargs: see the ``clone`` method | ||
:return: Repo instance pointing to the cloned directory""" | ||
git = cls.GitCommandWrapperType(os.getcwd()) | ||
if env is not None: | ||
git.update_environment(**env) | ||
if not unsafe_protocols and "::" in url: | ||
raise ValueError(f"{url} requires unsafe_protocols flag") |
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.
Is there a more specific error type that could be used to better classify the issue? Maybe ValueError
is already specific enough compared to the errors that are usually thrown from this function (but I don't know).
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.
I'm happy to add a UnsafeOptionsException or something similar, but ValueError is described as when a function receives an argument that has the right type but an inappropriate value, which feels right too?
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.
In this particular case, having something uniquely identifiable as this particular error is probably helpful for folks who would use it to learn about the kind of URLs thrown at them. ValueError might be unique enough, but it's hard to prove it can't be raised elsewhere either.
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.
random 2 cents from a random guy: If I was using a library and it found some dangerous input, I would prefer to have an exception that clearly says so
While ValueError fits the description, adding the "this is can be dangerous" bit would help I think
0cd4e4d
to
e526cbb
Compare
Since the URL is passed directly to git clone, and the remote-ext helper will happily execute shell commands, so by default disallow URLs that contain a "::" unless a new unsafe_protocols kwarg is passed. (CVE-2022-24439) Fixes gitpython-developers#1515
With a large number of the versions of Python specified not being supported with GitHub Actions, trim it down to the major versions, and add in 3.11 for good measure.
e526cbb
to
ce529b9
Compare
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.
Thanks a lot for taking it to the next level, I love the additional tests for what constitutes unsafe options.
I think the CI failure is legit as the sanity check is done in a way that assumes a string even though PosixPath
isn't particularly string like.
Something I am not so sure about is if this PR should try to address #1517, and I'd clearly prefer that to happen in another PR. Probably @stsewd could provide valuable feedback here as well.
Thanks for taking another look.
Add `--` in some commands that receive user input and if interpreted as options could lead to remote code execution (RCE). There may be more commands that could benefit from `--` so the input is never interpreted as an option, but most of those aren't dangerous. For anyone using GitPython and exposing any of the GitPython methods to users, make sure to always validate the input (like if starts with `--`). And for anyone allowing users to pass arbitrary options, be aware that some options may lead fo RCE, like `--exc`, `--upload-pack`, `--receive-pack`, `--config` (gitpython-developers#1516). Ref gitpython-developers#1517
Add `--` in some commands that receive user input and if interpreted as options could lead to remote code execution (RCE). There may be more commands that could benefit from `--` so the input is never interpreted as an option, but most of those aren't dangerous. Fixed commands: - push - pull - fetch - clone/clone_from and friends - archive (not sure if this one can be exploited, but it doesn't hurt adding `--` :)) For anyone using GitPython and exposing any of the GitPython methods to users, make sure to always validate the input (like if starts with `--`). And for anyone allowing users to pass arbitrary options, be aware that some options may lead fo RCE, like `--exc`, `--upload-pack`, `--receive-pack`, `--config` (gitpython-developers#1516). Ref gitpython-developers#1517
Taken from gitpython-developers#1516
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.
Taking a look at this, if gitpython is going to disallow passing the --upload-pack/--receive-pack
and friends as options, the check should probably be in all other commands where those options are allowed (and should also check for their short form -u
).
And reading from https://git-scm.com/docs/gitremote-helpers
A URL of the form
<transport>::<address>
explicitly instructs Git to invokegit remote-<transport>
with<address>
as the second argument. If such a URL is encountered directly on the command line, the first argument is<address>
, and if it is encountered in a configured remote, the first argument is the name of that remote.
Maybe is safer to disallow foo::bar
like URLs,
if not unsafe_protocols and cls.unsafe_options(url, multi_options): | ||
raise UnsafeOptionsUsedError(f"{url} requires unsafe_protocols flag") |
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.
these checks could probably be moved to the _clone()
method, so you don't need to add them everywhere where that is called.
Thanks for your help! Due to the time-sensitive nature, #1521 was merged first and includes the changes from this PR. |
Since the URL is passed directly to git clone, and the remote-ext helper will happily execute shell commands, so by default qoute URLs unless a (undocumented, on purpose) kwarg is passed. (CVE-2022-24439)
Fixes #1515