Skip to content

fix(cron): catch ValueError on NUL paths in lifecycle_guard os.open - #79404

Closed
rainbowgore wants to merge 0 commit into
NousResearch:mainfrom
rainbowgore:fix/lifecycle-guard-nul-os-open
Closed

fix(cron): catch ValueError on NUL paths in lifecycle_guard os.open#79404
rainbowgore wants to merge 0 commit into
NousResearch:mainfrom
rainbowgore:fix/lifecycle-guard-nul-os-open

Conversation

@rainbowgore

Copy link
Copy Markdown
Contributor

What does this PR do?

Follow-up to #76762: _read_referenced_script() in cron/lifecycle_guard.py only caught OSError around os.open(path). Paths with an embedded NUL raise ValueError: embedded null byte (CPython), which escaped the guard, crashed the terminal tool, and surfaced as Failed to execute command: embedded null byte.

Widen the handler to except (OSError, ValueError) so the guard fails open (None, False) instead of crashing — same pattern already used at the Path.resolve() site from #76762.

Note: open PRs #78572 and #78013 also touch this area (broader NUL hardening). This change is the minimal #79398 fix only.

Related Issue

Fixes #79398

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • cron/lifecycle_guard.py — catch (OSError, ValueError) on os.open in _read_referenced_script
  • tests/hermes_cli/test_gateway_restart_loop.py — add test_nul_bearing_script_path_does_not_crash_guard (issue repro)

How to Test

  1. On unfixed main, run:
    from cron.lifecycle_guard import contains_gateway_lifecycle_command_or_referenced_script
    cmd = "source /tmp/hermes-snap-\x00x.sh >/dev/null 2>&1"
    contains_gateway_lifecycle_command_or_referenced_script(cmd, cwd="/Users/agents")
    Observe: ValueError: embedded null byte
  2. On this branch, run the same snippet — expect False with no exception.
  3. scripts/run_tests.sh tests/hermes_cli/test_gateway_restart_loop.py -q — all tests pass (including the new regression). Confirm hermes gateway restart is still detected as unsafe.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 26.5.1 (arm64)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Screenshots / Logs

Before (on main):

UNCAUGHT CRASH -> ValueError embedded null byte
  File "cron/lifecycle_guard.py", line 260, in _read_referenced_script
    descriptor = os.open(path, flags)
ValueError: embedded null byte

After:

RESULT: False

Made with Cursor

@alt-glitch alt-glitch added type/bug Something isn't working comp/cron Cron scheduler and job management tool/terminal Terminal execution and process management P2 Medium — degraded but workaround exists duplicate This issue or pull request already exists labels Aug 5, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #77898 — both catch os.open ValueError for the same embedded-NUL lifecycle-guard path and preserve the existing fail-open result.

@CN-42

CN-42 commented Aug 5, 2026

Copy link
Copy Markdown

补充一个真实生产环境复现案例(Linux / Ubuntu 26.04 LTS),确认此修复对实际触发场景有效:

真实触发场景

Hermes gateway 运行中(_HERMES_GATEWAY=1),agent 执行一条含二进制可执行文件路径的命令:

ls ~/.local/bin/cua-driver 2>/dev/null && ~/.local/bin/cua-driver --version 2>/dev/null | head -1

cua-driver 是 42MB 的 ELF 二进制(cua-driver 0.17.0)。_iter_referenced_shell_scripts() 把它当作"引用的脚本"(因为 token 含 /),_read_referenced_script() 调用 os.open(path) 直接崩溃。

完整 traceback(生产网关实测)

File "tools/terminal_tool.py", line 2560, in terminal_tool
    if contains_gateway_lifecycle_command_or_referenced_script(
File "cron/lifecycle_guard.py", line 353, in contains_gateway_lifecycle_command_or_referenced_script
    return _contains_unsafe_gateway_action(
File "cron/lifecycle_guard.py", line 335, in _contains_unsafe_gateway_action
    if script_text and _contains_unsafe_gateway_action(
File "cron/lifecycle_guard.py", line 324, in _contains_unsafe_gateway_action
    script_text, unsafe = _read_referenced_script(script_path)
File "cron/lifecycle_guard.py", line 260, in _read_referenced_script
    descriptor = os.open(path, flags)
ValueError: embedded null byte

表面现象:terminal 工具报 Failed to execute command: embedded null byte,整个命令未执行,会话表现为"卡住"。

#79398 / #79444 的差异

修复验证

应用本 PR 的 except (OSError, ValueError) 后(本地 patch 相同改动),原命令正常通过守卫(返回 False),不再崩溃。与 #79398 的 suggested fix 完全一致。

补充建议:_read_referenced_script() 的 NUL 防护已覆盖"文件内容含 NUL"(037825c1f)和"路径含 NUL"(本 PR),但 read_remote_scriptcat 兜底路径对超大二进制(>1MB 被本地跳过后走 cat)仍会把整个二进制读进递归扫描——如果后续想更彻底,可在 _read_script_in_env 对二进制内容也做 NUL 检测。

@MattBetancourt

Copy link
Copy Markdown

Independent reproduction on Linux (Ubuntu 24.04, GCP e2-standard-2, Hermes v0.20.0/v2026.8.3).

Trigger: Any command referencing a path-like token that reaches _read_referenced_script with an embedded NUL — we hit it via the ELF-binary-content path (same traceback shape as the cua-driver report above: os.open on a path tokenized from binary data decoded as text).

Fix verified locally: Applied the identical except (OSError, ValueError) change at line 260-261. Added a regression test (test_null_byte_path_does_not_crash_guard) alongside the existing test_absolute_path_binary_does_not_crash_guard. All 83 tests in tests/hermes_cli/test_gateway_restart_loop.py pass.

# Repro (crashes on main, passes after fix):
from cron.lifecycle_guard import contains_gateway_lifecycle_command_or_referenced_script
contains_gateway_lifecycle_command_or_referenced_script(
    ".venv/bin/python\x00 -m pip install --quiet polymarket-us",
    cwd="/tmp",
)  # main: ValueError: embedded null byte → fix: False (no crash)

This is the minimal fix consistent with the Path.resolve() pattern already in place from #76762. PR has merge conflicts against current main — happy to help resolve if useful.

@rainbowgore rainbowgore closed this Aug 6, 2026
@rainbowgore
rainbowgore force-pushed the fix/lifecycle-guard-nul-os-open branch from e0a820a to 8f27127 Compare August 6, 2026 09:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cron Cron scheduler and job management duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists tool/terminal Terminal execution and process management type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] lifecycle_guard: os.open(path) crashes with ValueError: embedded null byte — incomplete fix for #76762

4 participants