DeepAI Paper Hermes Agent 教程,Hermes 安全、网络与代理,Hermes 终端、Docker 与安装 安全过滤器把注释也当命令了:Hermes 终端误杀 setsid / nohup 的坑

安全过滤器把注释也当命令了:Hermes 终端误杀 setsid / nohup 的坑

有时候不是命令危险,而是过滤器太敏感。

NousResearch/hermes-agent issue #20064 讲的是一个很典型的终端工具误判:Hermes 的 terminal safety filter 会用一个简单正则去找 shell-level background wrapper 关键词:

\b(?:nohup|disown|setsid)\b

问题是,这个规则太粗了。

它只要在整段命令字符串里看到这些词,不管它们是在:

  • 单引号里;
  • 双引号里;
  • Python -c 代码里;
  • git commit message 里;
  • gh pr create --body 里;
  • echo / grep 的普通文本里;

都会误杀。

于是你可能只是写了一句说明文字,Hermes 却把它当成了真的后台包裹命令。


这不是“后台命令危险”,而是“字符串里出现了关键词”

issue 里的复现非常直接。

这些本来应该允许的命令,都会被拦:

python3 -c "x = 'preexec_fn=os.setsid'"

git commit -m "fix: replace preexec_fn=os.setsid with process_group=0"

gh pr create --body "We removed preexec_fn=os.setsid..."

echo "The function os.setsid() creates a new session"

你会得到类似提示:

Foreground command uses shell-level background wrappers (nohup/disown/setsid).
Use terminal(background=true) so Hermes can track the process...

这提示本身没错,错的是触发条件。


真正应该拦的是什么?

正确的拦截对象应该是这种 真正在 shell 层执行的命令

setsid my_server
nohup ./script.sh &

也就是关键词作为命令本身出现,而不是只作为字符串内容出现。

这两类内容差别很大:

  • setsid my_server:危险/需要特殊处理
  • "the word setsid appears in this sentence":普通文本

但旧正则没做语义分层,看到词就亮红灯。


根因:单纯的全局正则匹配

issue 指出的核心逻辑是:

_SHELL_LEVEL_BACKGROUND_RE = re.compile(r"\b(?:nohup|disown|setsid)\b", re.IGNORECASE)

这个模式的问题是:

1. 没有判断关键词是不是命令开头; 2. 没有判断它是不是在引号内部; 3. 没有判断它是不是 ;&&|| 之后的真正 shell 子命令; 4. 没有考虑 Python / shell / PR body / commit message 这些不同语义层。

所以它是“文本扫描器”,不是“命令解析器”。


为什么这种 bug 会严重影响日常使用?

因为 Hermes 的 terminal 工具不只是跑命令,它还经常用于:

  • review PR 内容;
  • 写 commit message;
  • 调试 subprocess;
  • 生成说明文本;
  • 复制粘贴脚本片段;
  • -c 参数里临时写小段代码。

这些场景里,setsid / nohup / disown 之类词很常见,但很多时候只是被“提到”,不是被“执行”。

一旦误杀,用户就会被迫:

  • 把内容写进临时文件;
  • 先 echo 到文件再执行;
  • 绕开 inline 命令;
  • 反复改写文本避免触发关键词。

这对一个终端代理来说很烦。


更合理的拦截方式

issue 提出的方向是:

只在关键词作为命令时匹配,而不是在字符串或参数里匹配。

一个保守修复是把正则改成只匹配命令位置,比如:

_SHELL_LEVEL_BACKGROUND_RE = re.compile(
    r"(?:^|[;&|]\s*|&&\s*|\|\|\s*|\(\s*)(?:nohup|disown|setsid)\b",
    re.IGNORECASE | re.MULTILINE,
)

这样至少能避免很多“引号里有关键词”的误报。

更稳一点的做法是:

1. 先剥离 quoted strings; 2. 再检测 shell-level command token; 3. 或者直接做简单 shell tokenization,而不是裸 regex。


从安全角度看,这个问题为什么值得修?

因为安全过滤器如果误报太多,用户会开始不信它。

一旦误报频率高,后果通常是:

  • 用户无视警告;
  • 用户绕过工具;
  • 真正危险命令也被当成“又一次误报”;
  • 安全层失去威慑力。

所以安全过滤最怕两件事:

  • 漏报;
  • 乱报。

#20064 这种就是典型的 乱报


排查时怎么判断是不是这个问题?

如果你看到类似下面的情况,就很像这个 bug:

  • 命令本身不是 nohup/disown/setsid
  • 只是字符串、说明文字、commit message 里提到了这些词;
  • Hermes 仍然提示要用 terminal(background=true)
  • 你改成写到文件后就能过。

举例:

git commit -m "refactor: remove preexec_fn=os.setsid"

这不是在启动后台进程,但旧过滤器会误判。


对 DeepAI API 中转站用户的边界说明

这篇问题发生在 Hermes 的 terminal tool,不在模型 API 层。

所以不要把它理解成 DeepAI API 中转站的问题。

DeepAI 适合解决的是:

  • OpenAI-compatible Base URL;
  • API Key 统一;
  • 模型调用入口统一;
  • 某些支持 OpenAI 兼容协议的客户端接入。

但它不能修复:

  • Hermes terminal safety regex;
  • 本地命令判断逻辑;
  • 误把文本当 shell 命令的安全规则。

所以文中最好把 DeepAI 作为“上游 API 层”对比,而不是“修复这个 bug 的工具”。


FAQ

这是安全功能坏了吗?

不是坏了,是规则太粗,误伤太多。

为什么引号里的 setsid 也会触发?

因为旧规则扫描的是整段字符串,不区分语义位置。

只拦真正的 shell 命令该怎么做?

至少要限制关键词出现在命令位置,或者先剥离 quoted strings,再做 token 级判断。

这个问题会影响什么场景?

PR review、commit message、python -c、echo 文本、脚本注释、甚至普通说明字符串都可能被误杀。

DeepAI 能修复吗?

不能。这是 Hermes 本地 terminal 工具的过滤逻辑问题,不是模型 API 问题。


总结

#20064 的教训很简单:

安全过滤不能只靠关键词扫描。

nohupdisownsetsid 这些词只有在 shell-level command 里才危险;一旦出现在引号、参数或说明文字里,它们只是文本。

如果过滤器不分语境,就会把“提醒用户注意”误判成“用户真的要后台跑进程”,最后把正常工作流卡死。

Related Post

只有思考没有正文,Hermes 流式输出也会崩:Gemini reasoning-only delta 的 .content 空洞只有思考没有正文,Hermes 流式输出也会崩:Gemini reasoning-only delta 的 .content 空洞

Gemini Code Assist streaming 中 reasoning-only delta 先于正文到达,Hermes 旧版 _make_stream_chunk 没有补 content=None,导致 downstream 访问 delta.content 时报 AttributeError。本文复盘 #24974:为什么流式 chunk schema 必须稳定。

Hermes Agent Issue 观察:Discord 重复回复、Cloudflare 403 和长任务心跳为什么容易误判Hermes Agent Issue 观察:Discord 重复回复、Cloudflare 403 和长任务心跳为什么容易误判

从 Hermes Agent GitHub Issues 看三类高频误判:Discord 重复回复、Custom Provider Cloudflare 403、长任务 heartbeat 异常。本文按链路分层排错,帮助判断问题在平台、Gateway、Agent 还是上游模型。

Mattermost 里点不了按钮就只能超时?Hermes clarify 多选题文字兜底为什么没接住回复Mattermost 里点不了按钮就只能超时?Hermes clarify 多选题文字兜底为什么没接住回复

Hermes clarify 多选题在 Telegram 按钮正常,但 Mattermost 只能显示编号文本列表时,用户回复 2 却仍然 10 分钟超时?本文复盘 #25567:awaiting_text 与 choices 绑定导致文本兜底永远接不到回复。