fix(approvals): match denied executable paths behind shell prefixes
Adapt the command-position, bounded-candidate and launcher-option work from embwl0x's #76063 to the current detection owner, then add executable basename projection from Rohith Pariki's #104338. Parse raw quote state before applying existing text normalization so quoted arguments do not become commands. Cover shell payloads and literal env split-string carriers, retain path-specific rules and whole-command globs, and document the supported normalization rather than claiming an OS capability sandbox. Related: #104308, #76037, #76063, #104338, #78521, #86711. No automatic closing directives: the older carriers also contain broader case syntax and git-option work not included here. Co-authored-by: embwl0x <embwl0x@users.noreply.github.com> Co-authored-by: Rohith Pariki <rohithpariki@gmail.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
"""Offline production-dispatch receipt; never invokes a privileged binary.
|
||||
|
||||
Run with the shared Python environment and a source tree argument to compare
|
||||
base/head. The executable named sudo is an owned temporary marker script.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shlex
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
source = Path(sys.argv[1]).resolve()
|
||||
with tempfile.TemporaryDirectory(prefix="hermes-deny-dispatch-") as directory:
|
||||
home = Path(directory)
|
||||
os.environ.clear()
|
||||
# The terminal's own NOPASSWD probe must also resolve to our inert fixture.
|
||||
os.environ.update(PATH=directory + ":/usr/bin:/bin", HOME=directory, HERMES_HOME=directory,
|
||||
HERMES_INTERACTIVE="1", TERMINAL_ENV="local")
|
||||
(home / "config.yaml").write_text(
|
||||
'approvals:\n mode: "off"\n deny: ["sudo *"]\n'
|
||||
'security:\n tirith_enabled: false\n', encoding="utf-8")
|
||||
executable = home / "sudo"
|
||||
executable.write_text('#!/bin/sh\nprintf "OWNED_EXECUTABLE_REACHED\\n"\n', encoding="utf-8")
|
||||
executable.chmod(0o700)
|
||||
sys.path.insert(0, str(source))
|
||||
from tools import terminal_tool # noqa: F401
|
||||
from tools.registry import registry
|
||||
from tools import approval_context
|
||||
|
||||
binary = shlex.quote(str(executable))
|
||||
cases = [binary + " -n id -u", "env -i " + binary + " -n id -u",
|
||||
"command " + binary + " -n id -u",
|
||||
"true && " + binary + " -n id -u",
|
||||
"bash -c " + shlex.quote(binary + " -n id -u"),
|
||||
"printf '%s\\n' 'sudo -n id -u'"]
|
||||
rows = []
|
||||
for command in cases:
|
||||
result = registry.dispatch("terminal", {"command": command, "workdir": directory, "timeout": 10})
|
||||
if isinstance(result, str):
|
||||
result = json.loads(result)
|
||||
rows.append({"command": command, "result": result})
|
||||
print(json.dumps({"source": str(source), "config": approval_context._get_approval_config(),
|
||||
"rows": rows}, indent=2))
|
||||
Reference in New Issue
Block a user