fix(security): gate cp/mv/install into ~/.ssh, credential, and shell-rc files

tools/approval.py already denies tee/redirection writes to every
_SENSITIVE_WRITE_TARGET (~/.ssh/*, ~/.netrc/.pgpass/.npmrc/.pypirc, shell
rc files, ~/.hermes/config.yaml/.env) via the DANGEROUS_PATTERNS tee/`>`
rules, but cp/mv/install were only paired for _SYSTEM_CONFIG_PATH (/etc) and
the project-relative env/config target. So `cp evil ~/.ssh/authorized_keys`
(SSH-key implant / persistence), `cp creds ~/.netrc`, and `cp evil ~/.bashrc`
(login-time command injection) auto-approved while the equivalent tee/`>`
forms were denied — an unpaired write deny is theater (same rationale as
#14639 / commit 4e9d886d, which paired the terminal side for
~/.hermes/config.yaml writes but did not touch these cp/mv/install verbs on
the broader sensitive set).

Add one (cp|mv|install) DANGEROUS_PATTERNS entry reusing the existing
_SENSITIVE_WRITE_TARGET fragment, anchored via _COMMAND_TAIL so it fires on
the destination (last arg) only: reading OUT of a sensitive path
(`cp ~/.ssh/config /tmp/x`) stays auto-approved. Description differs from the
system-config cp entry so the two keep distinct approval keys (no silent
cross-approval). Additive — does not subsume the /etc or project-config rules.

Adds TestSensitiveCopyMovePattern: 5 positive cases (ssh authorized_keys,
ssh private key via mv, netrc via install, bashrc, ~/.hermes/config.yaml) +
2 negative guards (copy FROM ssh, unrelated copy). The ssh/netrc/bashrc
positives fail on main and pass on this branch; the negatives stay green
both ways.
This commit is contained in:
briandevans
2026-06-13 14:35:27 -07:00
committed by Teknium
parent 1fa761f8de
commit da28d5d113
2 changed files with 51 additions and 0 deletions
+37
View File
@@ -633,6 +633,43 @@ class TestProjectSensitiveCopyPattern:
assert desc is None
class TestSensitiveCopyMovePattern:
"""cp/mv/install OVERWRITING ~/.ssh/*, credential files (~/.netrc etc.),
shell rc files, or ~/.hermes/config.yaml/.env must require approval — the
tee/redirection forms were already gated (#14639 family / commit 4e9d886d),
but cp/mv/install on these targets was an unpaired half-door (key implant /
shell-rc command injection slipped through auto-approve)."""
def test_cp_to_ssh_authorized_keys(self):
dangerous, key, desc = detect_dangerous_command("cp /tmp/evil ~/.ssh/authorized_keys")
assert dangerous is True
assert key is not None
def test_mv_to_ssh_private_key(self):
dangerous, key, desc = detect_dangerous_command("mv /tmp/k ~/.ssh/id_rsa")
assert dangerous is True
def test_install_to_netrc(self):
dangerous, key, desc = detect_dangerous_command("install -m600 /tmp/c ~/.netrc")
assert dangerous is True
def test_cp_to_bashrc(self):
dangerous, key, desc = detect_dangerous_command("cp /tmp/e ~/.bashrc")
assert dangerous is True
def test_cp_to_hermes_config(self):
dangerous, key, desc = detect_dangerous_command("cp /tmp/evil.yaml ~/.hermes/config.yaml")
assert dangerous is True
def test_cp_from_ssh_is_safe(self):
dangerous, key, desc = detect_dangerous_command("cp ~/.ssh/config /tmp/x")
assert dangerous is False
def test_cp_unrelated_files_safe(self):
dangerous, key, desc = detect_dangerous_command("cp a.txt b.txt")
assert dangerous is False
class TestProjectSensitiveTeePattern:
def test_tee_to_local_dotenv_requires_approval(self):
dangerous, key, desc = detect_dangerous_command("printenv | tee .env.local")