Skip to content

Commit

Permalink
fix(hg): URL vulnerability via hg
Browse files Browse the repository at this point in the history
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 <[email protected]> via Snyk
  • Loading branch information
tony authored Mar 12, 2022
2 parents 96d2ada + 66640ae commit 7179656
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 2 deletions.
6 changes: 6 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

- _Add your latest changes from PRs here_

### Potential command injection via mercurial URLs

- By setting a mercurial URL with an alias it is possible to execute arbitrary shell commands via
`.obtain()` or in the case of uncloned destinations, `.update_repo()`. (#306, credit: Alessio
Della Libera)

### Development

- Run pyupgrade formatting (#305)
Expand Down
4 changes: 3 additions & 1 deletion libvcs/hg.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ def __init__(self, url, repo_dir, **kwargs):
def obtain(self):
self.ensure_dir()

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

def get_revision(self):
Expand Down
27 changes: 26 additions & 1 deletion tests/test_hg.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import pytest

from libvcs.shortcuts import create_repo_from_pip_url
from libvcs.shortcuts import create_repo, create_repo_from_pip_url
from libvcs.util import run, which

if not which("hg"):
Expand Down Expand Up @@ -72,3 +72,28 @@ def test_repo_mercurial(tmp_path: pathlib.Path, repos_path, hg_remote):
)

assert mercurial_repo.get_revision() == test_repo_revision


def test_vulnerability_2022_03_12_command_injection(
monkeypatch: pytest.MonkeyPatch,
user_path: pathlib.Path,
tmp_path: pathlib.Path,
hg_remote,
):
"""Prevent hg aliases from executed arbitrary commands via URLs.
As of 0.11 this code path is/was only executed via .obtain(), so this only would
effect explicit invocation of .object() or update_repo() of uncloned destination.
"""
random_dir = tmp_path / "random"
random_dir.mkdir()
monkeypatch.chdir(str(random_dir))
mercurial_repo = create_repo(
url="--config=alias.clone=!touch ./HELLO", vcs="hg", repo_dir="./"
)
with pytest.raises(Exception):
mercurial_repo.update_repo()

assert not pathlib.Path(
random_dir / "HELLO"
).exists(), "Prevent command injection in hg aliases"

0 comments on commit 7179656

Please sign in to comment.