mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-11 13:41:53 +00:00
fix(security): strip shell escapes in denylist normalizer; fail-closed on missing approval module
DANGEROUS_PATTERNS and HARDLINE_PATTERNS are matched on the raw command string, so backslash-escape (r\m) and empty-quote split (r''m) bypass both lists. _normalize_command_for_detection now strips these before pattern matching. tui_gateway shell.exec had a bare 'except ImportError: pass' that silently disabled the entire safety gate if tools.approval wasn't importable. Changed to fail-closed (return 5001 error). Added detect_hardline_command check. Fixes #36846, #36847.
This commit is contained in:
parent
1fb99b1f22
commit
621bf3a873
2 changed files with 11 additions and 2 deletions
|
|
@ -537,6 +537,10 @@ def _normalize_command_for_detection(command: str) -> str:
|
||||||
command = command.replace('\x00', '')
|
command = command.replace('\x00', '')
|
||||||
# Normalize Unicode (fullwidth Latin, halfwidth Katakana, etc.)
|
# Normalize Unicode (fullwidth Latin, halfwidth Katakana, etc.)
|
||||||
command = unicodedata.normalize('NFKC', command)
|
command = unicodedata.normalize('NFKC', command)
|
||||||
|
# Strip shell backslash-escapes: r\m → rm. Prevents \-injection bypass.
|
||||||
|
command = re.sub(r'\\([^\n])', r'\1', command)
|
||||||
|
# Strip empty-string literals that split tokens: r''m → rm, r""m → rm.
|
||||||
|
command = re.sub(r"''|\"\"", '', command)
|
||||||
return command
|
return command
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8490,15 +8490,20 @@ def _(rid, params: dict) -> dict:
|
||||||
if not cmd:
|
if not cmd:
|
||||||
return _err(rid, 4004, "empty command")
|
return _err(rid, 4004, "empty command")
|
||||||
try:
|
try:
|
||||||
from tools.approval import detect_dangerous_command
|
from tools.approval import detect_dangerous_command, detect_hardline_command
|
||||||
|
|
||||||
|
is_hardline, hardline_desc = detect_hardline_command(cmd)
|
||||||
|
if is_hardline:
|
||||||
|
return _err(
|
||||||
|
rid, 4005, f"blocked (hardline): {hardline_desc}. Use the agent for dangerous commands."
|
||||||
|
)
|
||||||
is_dangerous, _, desc = detect_dangerous_command(cmd)
|
is_dangerous, _, desc = detect_dangerous_command(cmd)
|
||||||
if is_dangerous:
|
if is_dangerous:
|
||||||
return _err(
|
return _err(
|
||||||
rid, 4005, f"blocked: {desc}. Use the agent for dangerous commands."
|
rid, 4005, f"blocked: {desc}. Use the agent for dangerous commands."
|
||||||
)
|
)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
return _err(rid, 5001, "shell.exec unavailable: approval safety module not importable")
|
||||||
try:
|
try:
|
||||||
r = subprocess.run(
|
r = subprocess.run(
|
||||||
cmd, shell=True, capture_output=True, text=True, timeout=30, cwd=os.getcwd()
|
cmd, shell=True, capture_output=True, text=True, timeout=30, cwd=os.getcwd()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue