Skip to content

Replace password in URI by stars if present to avoid leaking secrets in logs #1198

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

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add more test and remove password also from error logs
  • Loading branch information
mickours committed Mar 15, 2021
commit 50cbafc690e5692a16148dbde9de680be70ddbd1
4 changes: 2 additions & 2 deletions git/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ def pump_stream(cmdline, name, stream, is_decode, handler):
line = line.decode(defenc)
handler(line)
except Exception as ex:
log.error("Pumping %r of cmd(%s) failed due to: %r", name, cmdline, ex)
raise CommandError(['<%s-pump>' % name] + cmdline, ex) from ex
log.error("Pumping %r of cmd(%s) failed due to: %r", name, remove_password_if_present(cmdline), ex)
raise CommandError(['<%s-pump>' % name] + remove_password_if_present(cmdline), ex) from ex
finally:
stream.close()

Expand Down
13 changes: 6 additions & 7 deletions git/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,13 +343,13 @@ def expand_path(p, expand_vars=True):
def remove_password_if_present(cmdline):
"""
Parse any command line argument and if on of the element is an URL with a
password, replace it by stars. If nothing found just returns a copy of the
command line as-is.
password, replace it by stars (in-place).

If nothing found just returns the command line as-is.

This should be used for every log line that print a command line.
"""
redacted_cmdline = []
for to_parse in cmdline:
for index, to_parse in enumerate(cmdline):
try:
url = urlsplit(to_parse)
# Remove password from the URL if present
Expand All @@ -358,12 +358,11 @@ def remove_password_if_present(cmdline):

edited_url = url._replace(
netloc=url.netloc.replace(url.password, "*****"))
redacted_cmdline.append(urlunsplit(edited_url))
cmdline[index] = urlunsplit(edited_url)
except ValueError:
redacted_cmdline.append(to_parse)
# This is not a valid URL
pass
return redacted_cmdline
return cmdline


#} END utilities
Expand Down
17 changes: 16 additions & 1 deletion test/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
Actor,
IterableList,
cygpath,
decygpath
decygpath,
remove_password_if_present,
)


Expand Down Expand Up @@ -322,3 +323,17 @@ def test_pickle_tzoffset(self):
t2 = pickle.loads(pickle.dumps(t1))
self.assertEqual(t1._offset, t2._offset)
self.assertEqual(t1._name, t2._name)

def test_remove_password_from_command_line(self):
"""Check that the password is not printed on the logs"""
password = "fakepassword1234"
url_with_pass = "https://fakeuser:{}@fakerepo.example.com/testrepo".format(password)
url_without_pass = "https://fakerepo.example.com/testrepo"

cmd_1 = ["git", "clone", "-v", url_with_pass]
cmd_2 = ["git", "clone", "-v", url_without_pass]
cmd_3 = ["no", "url", "in", "this", "one"]

assert password not in remove_password_if_present(cmd_1)
assert cmd_2 == remove_password_if_present(cmd_2)
assert cmd_3 == remove_password_if_present(cmd_3)