mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-07-08 11:56:59 +00:00
fix(security): match grep's rg sensitive-file exclusions case-insensitively (#5189)
The grep tool's ripgrep fast-path excluded deny-listed key files with `--glob "!*<pat>*"` for each entry in _SENSITIVE_FILE_PATTERNS. ripgrep's --glob is case-sensitive, so on a case-insensitive filesystem (Windows, default macOS) a key stored under a case variant of its name (ID_RSA, Known_Hosts, Authorized_Keys) is the same file on disk but slips past the lowercase exclusion, and ripgrep returns its contents. Those names are non-dotfiles, so ripgrep's default hidden-file skipping does not cover them either. The Python fallback already blocks them via the case-folded _is_sensitive_path (#5097), so the two paths disagreed. Switch the sensitive-pattern exclusions to --iglob so they match case-insensitively, mirroring _is_sensitive_path. Add a regression test that seeds ID_RSA and Known_Hosts and asserts grep returns ordinary matches but not the key contents.
This commit is contained in:
@@ -424,8 +424,12 @@ class GrepTool:
|
||||
cmd.append("--ignore-case")
|
||||
if glob_pat:
|
||||
cmd += ["--glob", glob_pat]
|
||||
# --iglob (not --glob) so the exclusion is case-insensitive:
|
||||
# on a case-insensitive filesystem "ID_RSA"/"Known_Hosts"
|
||||
# resolve to the same secret as their lowercase forms, and the
|
||||
# Python fallback below already folds case via _is_sensitive_path.
|
||||
for _pat in _SENSITIVE_FILE_PATTERNS:
|
||||
cmd += ["--glob", f"!*{_pat}*"]
|
||||
cmd += ["--iglob", f"!*{_pat}*"]
|
||||
for _d in _CODENAV_SKIP_DIRS:
|
||||
cmd += ["--glob", f"!**/{_d}/**"]
|
||||
cmd += ["--regexp", pattern, root]
|
||||
|
||||
@@ -91,6 +91,30 @@ def test_grep_python_fallback_when_no_rg(repo, monkeypatch):
|
||||
assert ".git/config" not in r["output"]
|
||||
|
||||
|
||||
@pytest.mark.skipif(shutil.which("rg") is None, reason="targets the ripgrep fast-path")
|
||||
def test_grep_skips_case_variant_sensitive_files_rg(repo):
|
||||
"""The rg fast-path must exclude deny-listed key files case-insensitively.
|
||||
|
||||
A file whose name is a case variant of a sensitive pattern (e.g. ID_RSA vs
|
||||
id_rsa, Known_Hosts vs known_hosts) points at the same secret on a
|
||||
case-insensitive filesystem, so grep must not return its contents. The
|
||||
Python fallback already folds case via _is_sensitive_path; a plain --glob
|
||||
exclusion is case-sensitive, so it would leak these — this pins the rg path.
|
||||
"""
|
||||
token = "GREPSECRET_TOKEN_ZZZ"
|
||||
with open(os.path.join(repo, "notes.txt"), "w") as f:
|
||||
f.write(f"see {token}\n")
|
||||
with open(os.path.join(repo, "ID_RSA"), "w") as f:
|
||||
f.write(f"PRIVATE {token}\n")
|
||||
with open(os.path.join(repo, "Known_Hosts"), "w") as f:
|
||||
f.write(f"host {token}\n")
|
||||
r = _run("grep", f'{{"pattern": "{token}", "path": "{repo}"}}')
|
||||
assert r["exit_code"] == 0
|
||||
assert "notes.txt" in r["output"] # ordinary matches still returned
|
||||
assert "ID_RSA" not in r["output"] # case-variant key excluded
|
||||
assert "Known_Hosts" not in r["output"]
|
||||
|
||||
|
||||
# ── glob ──────────────────────────────────────────────────────────────────
|
||||
|
||||
def test_glob_py(repo):
|
||||
|
||||
Reference in New Issue
Block a user