mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-29 06:31:32 +00:00
fix(security): block /proc/*/environ, cmdline, maps from file read (#4609)
The read_file tool and terminal cat can access /proc/self/environ to recover all process env vars including secrets stripped by the subprocess blocklist. Output redaction partially mitigates (catches known-format tokens) but misses custom/proprietary key formats, especially when values are printed without their key names. Add /proc/*/environ, /proc/*/cmdline, and /proc/*/maps to the blocked device paths in _is_blocked_device(): - /proc/*/environ: leaks full process env (API keys, tokens) - /proc/*/cmdline: leaks command-line args (may contain passwords) - /proc/*/maps: leaks memory layout (ASLR bypass for exploitation) Legitimate /proc reads (cpuinfo, meminfo, uptime, version) remain accessible — the check only blocks per-pid pseudo-files with known sensitive suffixes. Complements PR #4432 (PID namespace isolation for child processes) which prevents children from reading the parent's /proc, but does not prevent the parent process itself from being read via file tools. Partially addresses #4427 Changes: tools/file_tools.py | +6 tests/tools/test_file_read_guards.py | +18 -1 Co-authored-by: dsr-restyn <dsr-restyn@users.noreply.github.com>
This commit is contained in:
parent
4909dd84c1
commit
b7b8bec800
2 changed files with 23 additions and 1 deletions
|
|
@ -78,7 +78,23 @@ class TestDevicePathBlocking(unittest.TestCase):
|
|||
|
||||
def test_proc_fd_other_not_blocked(self):
|
||||
self.assertFalse(_is_blocked_device("/proc/self/fd/3"))
|
||||
self.assertFalse(_is_blocked_device("/proc/self/maps"))
|
||||
|
||||
def test_proc_sensitive_pseudo_files_blocked(self):
|
||||
"""environ/cmdline/maps under /proc/<pid> must be blocked (issue #4427)."""
|
||||
for path in (
|
||||
"/proc/self/environ",
|
||||
"/proc/12345/environ",
|
||||
"/proc/self/cmdline",
|
||||
"/proc/99/cmdline",
|
||||
"/proc/self/maps",
|
||||
"/proc/1/maps",
|
||||
):
|
||||
self.assertTrue(_is_blocked_device(path), f"{path} should be blocked")
|
||||
|
||||
def test_proc_legitimate_files_not_blocked(self):
|
||||
"""Top-level /proc files like cpuinfo and meminfo must remain accessible."""
|
||||
for path in ("/proc/cpuinfo", "/proc/meminfo", "/proc/uptime", "/proc/version"):
|
||||
self.assertFalse(_is_blocked_device(path), f"{path} should not be blocked")
|
||||
|
||||
def test_normal_files_not_blocked(self):
|
||||
self.assertFalse(_is_blocked_device("/tmp/test.py"))
|
||||
|
|
|
|||
|
|
@ -143,6 +143,12 @@ def _is_blocked_device(filepath: str) -> bool:
|
|||
("/fd/0", "/fd/1", "/fd/2")
|
||||
):
|
||||
return True
|
||||
# /proc/*/environ, /proc/*/cmdline, /proc/*/maps can leak secrets,
|
||||
# command-line args, and memory layout from the host process (issue #4427)
|
||||
if normalized.startswith("/proc/") and normalized.endswith(
|
||||
("/environ", "/cmdline", "/maps")
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue