当EDR告警被AI Agent占满:从真实告警看Agent时代的检测规则重构

声明:本人还只是一介小实习生,以下都只是本人一些拙见,期待和各位大佬交流!!!

最近接手看了下公司内的EDR告警,我觉得相比之前在Agent爆发前实习时看的有一个明显变化,不是什么新的手法或者某些恶意软件突然增多,也不是什么攻击行为更加活跃,而是内部的告警列表反而先逐渐被各种AI Agent占满。

经常使用各个Agent的师傅们应该知道,Codex、Claude Code、Cursor 等工具频繁拉起 zsh、bash、PowerShell、Node.js 和 Python,自动读取代码、修改文件、安装依赖、执行测试、调用 Git、访问网络。放在传统 EDR 规则里,这些行为几乎每一项都具备“可疑特征”:

  • IDE 拉起 Shell;
  • 命令行中出现 eval、curl、chmod;
  • 解释器执行临时目录中的脚本;
  • 进程读取敏感文件;
  • 本地文件内容被发送至网络;
  • 自动更新组件替换程序文件。

但问题在于,这些行为中的相当一部分,并不是 Agent 偶然触发的副作用,而是产品本身的正常工作方式。

OpenAI 对 Codex CLI 的描述就是在终端中检查、修改并运行代码,可以读取本地仓库、编辑文件并调用机器上已有的工具;Anthropic 对 Claude Code 的定义更加直接:读取代码库、编辑文件、运行命令,并与开发工具集成。也就是说,过去检测规则重点关注的“代码编辑器调用 Shell”、“脚本解释器执行命令”等可能是恶意模式的行为,现在已经成为 Agent 编程工具的基础能力。

我觉得出现这种问题的根因是EDR还是按照传统的人类行为来建模的,agent的行为太不一样了,只看命令是否危险,已经不足以判断一次 Agent 行为是否危险。

1. 先看一些真实示例:告警失去了区分度

先看几个我实际遇到的案例。已经做了脱敏处理,只保留行为特征

1.1 Cursor 的 Shell 包装命令

一条告警的核心命令如下:

/bin/zsh -c '
snap=$(command cat <&3)
builtin unsetopt aliases 2>/dev/null
builtin unalias -m "*" 2>/dev/null || true
builtin eval "$snap" && {
    builtin eval "${__CURSOR_SANDBOX_ENV_RESTORE:-}"
    builtin export PWD="$(builtin pwd)"
    builtin eval "$1" < /dev/null
}
COMMAND_EXIT_CODE=$?
dump_zsh_state >&4
builtin exit $COMMAND_EXIT_CODE
' -- echo test

从规则视角看,它确实非常可疑。又是IDE直接启动zsh、多次执行了eval、修改了shell环境、从文件描述符读取内容、修改沙箱环境变量、动态执行参数中的命令等等。这些特征与很多Shell注入、内存加载和命令隐藏行为都高度重合。

但当我向上回溯系统的进程树后可以看到,这是一段 Cursor 为了恢复终端状态、执行用户命令并收集执行结果而生成的包装逻辑,最终执行的内容只有:

echo test

规则命中了真实行为,却没有回答最重要的问题:eval 最终执行了什么?

如果规则只匹配 “IDE → Shell → eval”,那么 echo test、npm test、读取 SSH 私钥、下载执行木马,最终会进入同一个告警队列。这种规则没有误识别技术动作,但失去了风险区分能力。

1.2 Codex 调用 curl 上传代码变更

另一条告警中,向上回溯可以看到 Codex,实际执行的是一个 HTTP POST 请求:

/usr/bin/curl \
  -X POST \
  -H 'Content-Type: application/json' \
  --data '{
    "projectName": "example-app",
    "filePath": ".../Info.plist",
    "diff": [
      "+ <key>NSAllowsArbitraryLoads</key>",
      "+ <true/>"
    ],
    "agentName": "codex",
    "sessionId": "<redacted>"
  }' \
  https://internal.example/record/upload

从终端行为看,这是一个非常典型的数据外发链路:

读取代码变更 -> 组织成JSON格式 -> 通过curl发起POST请求 -> 文件路径和diff被发送到远端

因此从 EDR 看到的事实是:本地代码内容发生了网络传输。

如果只依据 curl + POST + 文件内容,它很容易命中敏感数据外传规则。但结合上下文后可以发现,目标是企业内部记录平台,数据结构中还明确包含 Agent 名称、版本和 Session ID,其实是内部对 Agent 代码修改行为进行审计。

但是这个案例不能简单归为误报。

因为即使目标是内网,传输内容中仍可能包含源代码、凭证、配置和业务信息。更合理的结论应该是:

这是一次真实的代码内容传输,但是否违规,取决于目的地址、数据分类、项目策略和用户授权,而不是仅由 curl 决定。

传统规则通常只能给出“发生了 HTTP POST”,却难以区分,这个行为上传的内容是上传到内部审计平台?上传到代码托管平台?还是真的是上传到攻击者的服务器。

这也就是 Agent 场景下EDR的上下文缺口问题。

1.3 Codex 自动执行 yt-dlp

还有一类告警来自 Agent 自动调用用户本机已有工具:

/bin/zsh -lc '
.venv/bin/yt-dlp
  --retries 30
  --fragment-retries 30
  --merge-output-format mp4
  -o "downloads/%(title)s/%(title)s.%(ext)s"
  https://www.youtube.com/shorts/...
'

它包含外部网络访问、大文件下载、Python 虚拟环境和复杂命令行参数。

但它并不属于典型的入侵行为。这里真正需要关注的可能不是“攻击检测”,而是:

  • Agent 是否被允许访问外部视频网站
  • 下载内容是否符合企业网络策略
  • 文件最终写入了什么目录
  • 下载结果是否被执行
  • Agent 是否绕过了代理、审计或版权相关控制

也就是Agent行为把传统 EDR 中的“恶意检测”、“合规审计”和“数据治理”混在了同一条终端事件里。如果检测平台仍然只有“恶意”和“非恶意”两个出口,安全分析人员就只能不断手工解释这些灰色行为。

1.4 Claude Code 读取 Chrome Safe Storage

相比之下,下面这条命令就不应该因为父进程是 Claude 而被轻易降级,这也是我惊叹于Claude居然会干的事:

/usr/bin/security find-generic-password \
  -w \
  -s "Chrome Safe Storage" \
  -a "Chrome"

这条命令直接从 macOS Keychain 中读取名为 Chrome Safe Storage 的秘密值。

严格来说,它不是“直接获取浏览器里的所有密码”,但它访问的是浏览器本地凭证保护链路中的敏感材料。无论执行主体是人工终端、恶意脚本,还是 Claude Code,这都属于需要重点审核的凭证访问行为。

这也是 Agent 告警治理最容易走向错误的地方,因为我前面也思考过,那发现大量Agent误报后,为什么不直接给Codex、ClaudeCode、Cursor等加白名单。后面想了一下发现完全不可以,因为Agent并不是固定功能的软件,它们可以根据用户指令、外部内容和工具返回结果执行不同命令。父进程可信,只能说明执行载体是可信软件,不能说明这次具体行为符合用户意图,又或者可能是模型被投毒的skills或者提示词注入影响。

2. Agent 让“正常行为”和“攻击行为”共享了同一套原语

传统 EDR 的很多规则,本质上是在利用攻击行为与正常行为之间的统计差异。

比如:

Office → PowerShell
浏览器 → Shell
IDE → curl
脚本解释器 → chmod
未知程序 → Keychain

以上这些字父进程特征在曾经都会是高危的。记得之前在厦门的一家企业实习时,我可没少写过类似的规则,因为在过去,这些进程关系相对少见,因此具有较好的检测价值,但 Agent 正在系统性改变这种分布。

一个正常的编程任务,可能自然地产生下面这条行为链:

Cursor / Claude Code / Codex
        ↓
       zsh
        ↓
  python / node / git
        ↓
读取项目文件、修改配置
        ↓
npm install / pip install
        ↓
运行测试、访问网络
        ↓
提交代码或上传结果

从单个节点看,这条链与攻击者在失陷主机上的操作没有明显差异。攻击者同样会使用 shell、curl、python等等这些指令。因此Agent 带来的并不是一批全新的系统调用,而是让攻击者长期使用的系统能力,开始大规模出现在正常的借助Agent来开发的工作流中。

过去能够形成检测信号的“稀有性”,正在迅速下降。

我在和AI讨论这个问题的时候,GPT给了我一个我觉得很好的表:

终端行为

传统规则中的常见解释

Agent 场景中的正常用途

仍需重点关注的边界

IDE 启动 Shell

插件命令执行

运行测试、构建项目

未授权命令、跨目录执行

curl POST 文件内容

数据外传

上传构建结果、代码审计

外部目的地、敏感内容

chmod +x

恶意载荷准备

编译产物、脚本安装

临时目录下载后执行

读取 Keychain

凭证窃取

工具认证、获取开发凭证

浏览器、云密钥、SSH 凭证

修改配置文件

持久化或防护绕过

自动修复项目配置

系统级配置、安全策略

eval 执行字符串

命令注入

Shell 状态恢复和包装

动态内容来源及最终命令

自动更新程序

可执行文件替换

Sparkle 等正常更新

签名异常、非官方更新源

但其实,这些曾经的特征也不是说以后就完全失效了,而是它们变得更适合作为行为链中的一个证据,而不是最终的结论了。

3. ADR论文真正指出的,是EDR的可观测性缺口

在我那天看完EDR上那些大批量由Agent产生的告警时,我去找了找网上有没有关于类似的讨论,找到了一篇提出了ADR这个概念的论文。ADR: An Agentic Detection System for Enterprise Agentic AI Security

看完《ADR: An Agentic Detection System for Enterprise Agentic AI Security》后,我认为这篇论文也不是想用 ADR 替代 EDR,它指出了一个比较具体的问题:EDR 能看到 Agent 写了文件、启动了进程、发起了网络请求,却看不到 Agent 为什么要这样做。

论文将其称为 Agent 场景下的可观测性缺口(limited observability)。

一次 Agent 操作至少存在四层信息:用户原始任务;Agent 对任务的理解与计划;工具调用及参数;进程、文件、网络等终端行为

从以上四层来看,传统的EDR说到底只从最后一层才开始观测,用一些特征就把一个行为打上恶意或非恶意的标签。

因此,当 EDR 看到 Agent 读取 SSH Key 并发起 HTTP 请求时,它不知道用户原本要求的是“部署服务器”,还是仅仅“总结一个工单”。在第二种情况下,这条行为链显然严重偏离了用户意图。论文提出的 ADR Sensor,正是尝试关联用户 Prompt、Agent 计划、工具调用、执行结果和环境信息,重新构建完整会话。

ADR 的整体架构,下图来自论文:

ADR 的整体架构可以理解为“在线检测 + 离线增强”两条链路:ADR Sensor 先采集用户 Prompt、Agent 计划、工具调用和执行结果等会话数据,在线检测器再通过低成本、高召回的 Triage LLM 完成初筛,并由 Reasoning Agents 结合企业策略、源码和威胁情报进行进一步研判,最终将高置信风险提交给人工分析。与此同时,离线 Explorer 会通过红队 Agent、沙箱仿真和威胁情报持续生成新的攻击样例与检测指导,再反哺在线检测能力,形成“检测、分析、调整、再验证”的闭环。

论文结果

我原本是带着问题找答案,进而找到这篇论文的,但是当我看到这个论文的结果,发现还是任重道远。

ADR-Bench 包含 302 个任务,其中 42 个恶意任务、260 个良性任务,覆盖 133 个 MCP Server 和 17 种攻击技术。在这个数据集上,ADR 的 Precision 为 1.000,Recall 为 0.667。也就是说,它检测出了 42 个攻击任务中的 28 个,没有产生误报,但仍漏掉了约三分之一的攻击。

也就是说这并不是一个“彻底解决 Agent 安全”的结果。但是反而让我更加相信了这篇论文的真实性,因为它很贴近生产中的模式:面对真实企业中严重不均衡的数据分布,优先控制误报,避免告警队列被无法运营的噪声淹没,然后再从过滤后的数据中进行人工运营。

论文称 ADR 在 Uber 内部部署超过十个月,覆盖超过 7200 台主机,每日处理超过一万次 Agent 会话。但在进入人工审核队列的会话中:34% 被标记为真实风险,17% 属于非恶意的真实高风险行为,例如内部红队活动,49% 最终属于误报或复杂良性会话。

很多误报来自大型、多文件代码库分析等上下文复杂的正常任务。也就是说,即使已经采集了 Prompt、工具调用和 Agent 上下文,复杂良性行为仍然很难判断。

但是至少ADR证明了像从前那样单靠终端事件、静态规则都无法适配现在的时代了,并且把所有数据直接交给大模型,同样无法在成本和运营上成立。

4. EDR还不能被替代,但检测单位需要改变

但是针对企业内实际落地时,EDR 仍然有不可替代的价值。Agent 日志可能被关闭、删除或伪造,Prompt 可能缺失,部分产品不会公开完整计划和工具调用,所谓“推理过程”也未必稳定可得。最终,进程到底执行了什么、文件是否真的被读取、数据是否真的发送出去,仍然需要终端遥测确认。

因此现在看来不可能使用ADR来替换EDR,而应该是:Agent 上下文说明 “为什么” + EDR 遥测证明 “实际发生了什么”

传统规则通常以单个 Event 为中心,比如某某进程执行了某某命令。但是在Agent场景下,适合一一个session为中心,从某个用户提出了什么任务、Agent实际调用了哪些工具,搭配最终访问了哪些数据,数据被传到了哪里,行为是否偏离原始任务等。

这意味着告警去重也不能再只按命令行、主机或规则 ID 进行。同一个 Agent 会话可能连续产生几十条甚至上百条 EDR 事件。逐条告警会让分析人员反复处理同一件事,而会话级关联可以将其合并为:

Agent 会话 #A1024

用户任务:
修复项目构建错误

执行链:
读取 package.json
→ npm install
→ 修改 webpack 配置
→ 执行 npm test
→ curl 上传测试结果

风险点:
上传内容包含代码 diff

目的地址:
企业内部审计平台

最终结论:
合法开发行为,存在低等级数据治理风险

这比五条互相独立的“Shell 执行”、“文件修改”、“依赖安装”、“测试命令”、“数据外发”告警更接近安全运营真正需要的对象。

5. 从危险命令到危险边界

传统的EDR,因为基本都是通过规则来匹配一些敏感操作,但Agent会执行大量具备攻击能力的命令,因此,仅维护一份危险命令表很难长期工作。

这么一想,更稳定的检测对象应该是检测它跨越了什么安全边界。这里说的安全边界,比如就是一些对敏感数据的读取、执行能力的范围、系统配置的修改边界、网络边界等。

以下是我个人理解的一些可以当作安全边界的项,当然不完善,也期待各位师傅的补充:

5.1 敏感数据边界

比如一些较为敏感的路径,agent也是不应能够读取的,近期我做的一个插件安全分析平台也有使用类似的检测方法:

SSH 私钥
云服务凭证
浏览器凭证保护材料
Keychain / Credential Manager
.env 和密钥配置
AI Agent 自身会话及认证文件
企业内部 Token
生产数据库连接信息

访问这些数据不一定恶意,但一旦出现读取敏感数据且网络外联发送,那么风险就应显著提高。

也就是有危害的不应该只是单一的cat /etc/passwdd这样的指令,而是Agent读取敏感数据 -> 向外发送至非预期地址。

5.2 执行能力边界

这块重点也不是 Agent 是否运行了 Shell,而是是否获得了超出任务需要的执行能力:

关闭权限确认
主动使用--dangerously-skip-permissions来跳过确认
执行 sudo
修改系统安全配置
进入项目目录之外执行
调用系统级管理工具

5.3 持久化与系统修改边界

正常编程 Agent 经常修改项目内的文件,但一些系统级别的文件还是不应修改,比如:

系统启动项
Shell Profile
计划任务
安全软件配置
系统代理
证书信任配置
浏览器策略

5.4 网络信任边界

Agent很喜欢使用curl命令,但是同样的curl,目标不同风险可能也完全不同

企业内网API         低至中风险
代码仓库和包管理源    根据策略判断
已批准SaaS          中风险
个人网盘            高风险
新注册域名          高风险
裸IP或异常端口      高风险
已知恶意域名或IP			高风险

Agent 产生的网络连接应该同时结合目的地址的信任级别、上传数据内容和类型、是否包含文件内容、是否在用户任务范围之内、是否由外部内容间接触发。

6. 新的规则应该怎么改写

以前面说看到的Cursor的 zsh + eval 告警为例,旧规则可能类似:

父进程属于 IDE
AND 子进程属于 Shell
AND 命令行包含 eval
→ 告警

有没有可能逻辑可以写成:

识别为已知 Cursor Shell 包装模板
AND 主程序签名、路径、版本可信
AND 最终执行命令属于低风险开发行为
AND 未访问敏感路径
AND 未产生异常外联
AND 未执行持久化、提权或防护绕过
-> 记录但不告警
-> 否则告警

7 论文中的两层检测结构

ADR 论文中的两层检测结构,很适合迁移到 EDR 告警治理中。

ADR 论文采用两级在线检测:先由低成本的 Triage LLM 快速筛选可疑会话,再由 Reasoning Agents 结合企业策略、工具源码和威胁情报做深度分析。迁移到 EDR 场景时,不用完全照搬这套实现,但可以保留先过滤再研判的思路。

第一层是快速筛选,主要依靠确定性规则和已有终端数据,对高频 Agent 行为进行规范化处理。例如识别 Codex、Claude Code、Cursor 的进程来源,解析固定的 Shell 包装命令,将同一进程树和工作目录下的事件聚合成一个会话,并标记敏感路径、外部网络连接、权限绕过等风险信号。对于已知包装模板、普通开发命令、可信内部地址等行为,可以合并记录或降低优先级,而不是逐条产生告警。

第二层只处理第一层筛出的可疑会话,并补充更多上下文进行判断,包括用户原始任务、Agent 工具调用、实际执行命令、文件访问对象、网络目的地址以及企业策略。例如,curl 向内部平台上传普通构建结果,可以直接在第一层完成降噪;但如果同一会话中先读取了 Chrome Safe Storage,随后又向外部域名发起 POST 请求,就需要进入第二层,判断是否存在凭证访问和数据外传。

此处我让GPT总结论文里的思路,绘了个图:

例如,如果Agent执行:curl https://internal.example/upload

如果目标是可信内部平台,上传内容只是构建结果,可以在第一层完成降噪。

但如果同一会话中出现:读取 Chrome Safe Storage、获取敏感凭证材料、向外部未知域名发起 POST 请求,就需要进入第二层,结合用户原始任务、目标域名和数据内容判断是否存在凭证窃取或数据外传。

8. 总结

其实到最后,Agent时代确实让EDR过去依赖的一些检测设计开始失效了,前面也有提到,因为以前的一些在正常环境中比较少见的行为被Agent变得正常了。Codex、Claude Code、Cursor这类Agent本身就需要读文件、改代码、执行命令和访问网络,过去相对稀有的行为开始大量出现在正常开发流程里。如果规则还是简单匹配父子进程、命令关键字和单个事件,告警自然会被Agent行为占满。

但这也不代表以后就不需要检测这些行为了,更不代表可以直接给Agent进程加白名单。Agent只是执行载体,最终执行什么仍然可能受到用户指令、提示词注入、恶意Skill、MCP工具返回内容等多种因素影响。父进程可信,只能说明命令来自可信软件,不能说明这次命令一定符合用户意图。

在检测规则上,也需要逐渐从“某条命令是否危险”,转向判断一次Agent会话是否跨越了敏感数据、执行权限、系统配置和网络信任等安全边界。像eval、curl、chmod这些特征以后仍然有价值,但更适合作为一条行为链中的证据,而不是直接作为最终结论。

以上都只是我作为一个小菜鸡,在看了一些真实告警和论文之后产生的一些个人思考。很多想法目前也还停留在思路,难免有很多理想化的部分,也肯定还有不少不完善的地方,也期待各位师傅交流和补充。