Skip to content

Commit 7179656

Browse files
authored
fix(hg): URL vulnerability via hg
mercurial's aliases make it possible to inject arbitrary commands. Use `--` to escape them. > create_repo( > url="--config=alias.clone=!touch ./HELLO", vcs="hg", repo_dir="./" > ) Credit: Alessio Della Libera <alessio.dellalibera@snyk.io> via Snyk
2 parents 96d2ada + 66640ae commit 7179656

File tree

3 files changed

+35
-2
lines changed

3 files changed

+35
-2
lines changed

CHANGES

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
- _Add your latest changes from PRs here_
66

7+
### Potential command injection via mercurial URLs
8+
9+
- By setting a mercurial URL with an alias it is possible to execute arbitrary shell commands via
10+
`.obtain()` or in the case of uncloned destinations, `.update_repo()`. (#306, credit: Alessio
11+
Della Libera)
12+
713
### Development
814

915
- Run pyupgrade formatting (#305)

libvcs/hg.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ def __init__(self, url, repo_dir, **kwargs):
2626
def obtain(self):
2727
self.ensure_dir()
2828

29-
self.run(["clone", "--noupdate", "-q", self.url, self.path])
29+
# Double hyphens between [OPTION]... -- SOURCE [DEST] prevent command injections
30+
# via aliases
31+
self.run(["clone", "--noupdate", "-q", "--", self.url, self.path])
3032
self.run(["update", "-q"])
3133

3234
def get_revision(self):

tests/test_hg.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import pytest
77

8-
from libvcs.shortcuts import create_repo_from_pip_url
8+
from libvcs.shortcuts import create_repo, create_repo_from_pip_url
99
from libvcs.util import run, which
1010

1111
if not which("hg"):
@@ -72,3 +72,28 @@ def test_repo_mercurial(tmp_path: pathlib.Path, repos_path, hg_remote):
7272
)
7373

7474
assert mercurial_repo.get_revision() == test_repo_revision
75+
76+
77+
def test_vulnerability_2022_03_12_command_injection(
78+
monkeypatch: pytest.MonkeyPatch,
79+
user_path: pathlib.Path,
80+
tmp_path: pathlib.Path,
81+
hg_remote,
82+
):
83+
"""Prevent hg aliases from executed arbitrary commands via URLs.
84+
85+
As of 0.11 this code path is/was only executed via .obtain(), so this only would
86+
effect explicit invocation of .object() or update_repo() of uncloned destination.
87+
"""
88+
random_dir = tmp_path / "random"
89+
random_dir.mkdir()
90+
monkeypatch.chdir(str(random_dir))
91+
mercurial_repo = create_repo(
92+
url="--config=alias.clone=!touch ./HELLO", vcs="hg", repo_dir="./"
93+
)
94+
with pytest.raises(Exception):
95+
mercurial_repo.update_repo()
96+
97+
assert not pathlib.Path(
98+
random_dir / "HELLO"
99+
).exists(), "Prevent command injection in hg aliases"

0 commit comments

Comments
 (0)