Sushanth2624/browser-ai-sentinel

GitHub: Sushanth2624/browser-ai-sentinel

该系统通过Chrome扩展、Go服务和网络传感器协同检测浏览器与AI交互中的间接提示词注入和未授权数据外发。

Stars: 0 | Forks: 0

# Browser AI Sentinel 使用多指标内容分析,进行客户端检测,以防范浏览器与 AI 交互中的间接提示词注入和未经授权的数据外发。这是第二个毕业设计项目(MTech Cyber Security,RACE/REVA),独立于第一个项目(`dns-https-c2-ueba-detection`)——没有共享代码,拥有独立的代码库和基础设施。 完整的设计原理、威胁模型和阶段划分详见 [`/root/.claude/plans/nifty-crafting-acorn.md`](../../.claude/plans/nifty-crafting-acorn.md) (本代码库实现了该已批准的构建计划)。 ## 功能说明 1. **提示词注入检测** — content script 会扫描*任何*页面的实时 DOM(不仅仅是 AI 平台 —— 注入载荷会被植入在 AI Agent 稍后可能读取的任意页面上),寻找对人类隐藏但存在于文档中的内容:屏幕外 CSS、零宽度 Unicode 字符、可疑的 HTML 注释、alt/ARIA 文本、JSON-LD 元数据。多指标评分(noisy-OR 组合)会对可能包含针对 AI Agent 指令的页面进行标记。 2. **出站 DLP/外发网关** — 在已知的 AI 域名上,MAIN-world 脚本会在发送前拦截 `fetch`/`XHR` 请求体,对它们进行 PII/机密信息分类,并在标记后暂停请求,等待用户批准(通过带有允许/阻止按钮的 Chrome 通知)。 3. **AI 平台 / 影子 AI 发现** — 一对独立的 Zeek + Suricata 传感器(拥有独立的配置、独立的 systemd 服务,监控本机的真实 NIC —— 见下文第 2 阶段)提取每个 TLS 连接的真实 SNI/JA3/JA4。已知 AI 域名会被直接标记;在 ≥2 个不同的*未列出*域名中复用的 TLS 指纹会被标记为影子 AI 候选者 —— 其基本原理是,一个共享的客户端指纹命中多个 LLM 形态的 endpoint,看起来像是程序化的 API 流量,而不是有机的浏览行为。扩展程序自身声明的客户端域名检查(第 1 阶段)将作为一个额外的、更快的信号予以保留 —— 两者都写入同一个表,并按来源进行标记。 **明确为 IDS,而非 IPS**:扩展程序可以警告人类,但如果 AI Agent 是通过其自身的特权通道(例如 CDP/无障碍树)而不是可见 DOM 读取页面,则扩展程序无法进行阻止。 ## 架构(第 1 + 2 阶段) ``` Chrome extension (TypeScript, MV3) ├─ content-isolated/injection-scan.js — DOM indicator scan ├─ content-isolated/relay.js known AI domains — MAIN<->background bridge ├─ content-isolated/platform-adapters/ known AI domains — best-effort account-identity scrape ├─ content-main/fetch-patch.js known AI domains, MAIN world — body interception ├─ background/service-worker.js native messaging + approval-gate orchestration └─ popup/ Phase 1 read-only view (superseded by dashboard later) │ chrome.runtime.connectNative ▼ agent/cmd/nmhost (ephemeral, Chrome-spawned, stdio<->HTTP shim, no logic of its own) │ HTTP :8090 ▼ agent/cmd/daemon ◄──── agent/internal/sensor tailers (byte-offset persisted, resume-safe) │ ▲ ▲ │ │ ssl.log (JSON) eve.json (JSON, tls events) │ │ │ │ │ │ bas-zeek.service bas-suricata.service │ │ (Zeek + ja3/ja4 zkg) (Suricata, JA3/JA4 native) │ │ └──────────── both watch ens18 (real NIC) ────────┘ │ │ │ HTTP :8100 │ Postgres :5433 ▼ │ ▼ ai-engine (Python/FastAPI) db/ (schema.sql, docker-compose.yml) injection_scoring, pii_detection, atlas_mapping platform_events, shadow_ai_clusters, ... ``` 端口(选择这些端口是为了避免与已在此 VM 上运行的无关的毕业设计项目 1 的服务发生冲突 —— 有关通过 `ss -tlnp` 检查的完整列表,请参阅计划):Postgres `5433`,Go daemon `8090`,ai-engine `8100`,dashboard(第 4 阶段)`3000`。这两个传感器服务不监听任何端口 —— 它们只将日志写入到 `sensor/logs/` 下各自的日志文件中。 ## 第 1 阶段设置 ``` make setup # brings up Postgres, ai-engine venv, builds Go binaries, builds extension make ai-engine-run # terminal 1 — leave running make daemon-run # terminal 2 — leave running make health # confirms both are up ``` 原生消息宿主已在此机器上完成注册,位于 `~/.config/google-chrome/NativeMessagingHosts/com.browseraisentinel.nmhost.json`(用户级)和 `/etc/opt/chrome/native-messaging-hosts/com.browseraisentinel.nmhost.json`(系统级),指向 `agent/bin/nmhost`,并限定为本扩展程序的真实 ID,即 `extension/extension_id.txt` (`infjoghmhbkbhohajodjccgphpgejkip`)。 **在端到端实现过程中发现的两个真实问题,值得保留在报告/答辩中 —— 它们耗费了大量调试时间,正是专家组可能会深入探究的那类问题:** 1. **`--load-extension`(命令行标志)在此机器的 Chrome 版本 (150.0.7871.46) 上并不是安装未打包扩展程序的可靠方法。** 它会启动*一个* service worker,但 content script 实际上从未注入(通过 CDP 确认:从未出现过零个隔离世界的执行上下文),并且该扩展程序从未显示在 `chrome://extensions` 的 UI 中。正确且经过验证有效的安装路径是 **`Extensions.loadUnpacked` CDP 命令**(即 `chrome://extensions` 的“加载已解压的扩展程序”按钮在内部调用的方法)—— `scripts/register-native-host.sh` 和 `test-pages/cdp_test.py` 都使用了此方法,它能正确遵循 `manifest.json` 中固定的 `"key"` 字段,从而确定性地生成稳定的 ID `infjoghmhbkbhohajodjccgphpgejkip`。(过程中的一个小插曲:一个 Chrome 内置的默认组件扩展恰好在每个*全新*配置文件中暴露了一个字面名为 `service_worker.js` 的目标,其 ID 为 `fignfifoniblkonapihmkfakmlgkbkcf` —— 如果你不检查 service worker URL 中的脚本路径,很容易将其误认为“我们的扩展程序获得了不同的 ID”。) 2. **使用自定义 `--user-data-dir` 启动的 Chrome 配置文件无法发现用户级(`~/.config/google-chrome/NativeMessagingHosts`)原生消息宿主注册** —— 在测试中,只有系统级路径 (`/etc/opt/chrome/native-messaging-hosts/`) 能被可靠找到,无论启动 Chrome 的是哪个配置文件。日常使用默认配置文件可能不会遇到此问题,但同时注册两者(脚本现在就是这么做的)消除了整类“在我的机器上能运行”的故障,这也正是让 `test-pages/cdp_test.py` 从报错 `Specified native messaging host not found` 变为成功通过的原因。 ### 在真实的 Chrome 中加载扩展程序 1. `chrome://extensions` → 启用 **开发者模式** → **加载已解压的扩展程序** → 选择 `extension/dist/`。(这与上面验证过的安装路径相同 —— 如果你正在编写脚本进行此操作,请勿通过任何命令行 `--load-extension` 标志来加载它;那实际上是不起作用的。) 2. 确认加载的扩展程序 ID 与 `extension/extension_id.txt` (`infjoghmhbkbhohajodjccgphpgejkip`) 匹配 —— 如果不匹配(例如,代码库被移动到了不同的绝对路径,尽管通过这种安装方法,路径不应有影响,因为 ID 是由 key 派生的,而不是由路径派生的),请再次运行 `scripts/register-native-host.sh` 并重启 Chrome。ID 不匹配意味着原生消息将默默地无法连接。 3. 加载后重启一次 Chrome,以便它重新读取 `NativeMessagingHosts/`。 ### 自动化验证 `test-pages/cdp_test.py`(需要 `websocket-client` 和 `requests` Python 包)已经在真实的(无头)Chrome 实例中针对注入检测路径进行了端到端的验证:它通过 `Extensions.loadUnpacked` 安装 `extension/dist/`,导航到 `test-pages/injection-test.html`(由该目录下的 `python3 -m http.server 8877` 提供服务 —— 请先启动它),并断言警告横幅已被渲染。**截至撰写本文时已通过测试**,使用真实的预置页面(六个植入的指标 —— 屏幕外 CSS、零宽度 Unicode、可疑的 HTML 注释、隐藏的 alt/ARIA 文本、JSON-LD 元数据以及可见的命令式语言)评分为 1.00,并正确落入 `injection_alerts` 中。一旦 `ai-engine` 和 `daemon` 启动,运行 `python3 test-pages/cdp_test.py` 即可。 ### 手动验证(计划中第 1 阶段的“完成”标准) **注入检测**:由上述自动化测试覆盖;要尝试你自己的页面,请打开一个包含隐藏元素(例如 `display:none` 或屏幕外定位)的本地测试 HTML 文件,其文本需匹配 `extension/src/shared/patterns.ts` 中的模式之一(例如“ignore all previous instructions”),并带有足够的周边指标以越过标记阈值(单一弱指标不会触发标记 —— 参见评分器的 noisy-OR 设计)。预期:页面顶部注入一条红色警告横幅,并在 `injection_alerts` 中出现新的一行 —— 通过 `curl http://127.0.0.1:8090/api/injection_alerts` 或扩展程序弹窗进行检查。 **DLP/外发网关**:在其中一个已知的 AI 域名(`claude.ai`、`chatgpt.com` 等)上,打开开发者工具并运行 `fetch('/test-endpoint', {method:'POST', body:'contact me at test@example.com, card 4111 1111 1111 1111'})`。 预期:弹出 Chrome 通知询问允许/阻止;选择阻止时,fetch 调用会以 `AbortError` 拒绝;无论哪种情况,`dlp_events` 中都会出现新的一行,并且 `matched_entities` 已被填充。未确认的提示将在 30 秒后自动拒绝(默认拒绝)。 ## 第 2 阶段设置 — 真实网络传感器 ``` sudo bash deploy/install-sensors.sh # or: make sensor-up (also needs sudo) make health # now also reports bas-zeek / bas-suricata status ``` 这将安装并启动 `bas-zeek.service`、`bas-zeek-lo.service` 和 `bas-suricata.service` —— 这是与毕业设计 1 自身(已禁用/失败)的 `suricata.service` 完全不同的、独立的 systemd 单元,拥有自己的配置(`sensor/zeek/bas.zeek`、`sensor/suricata/suricata.yaml`),自己的日志目录(`sensor/logs/{zeek,zeek-lo,suricata}/`),监控此机器的真实主接口(`ens18`,通过 `ip route get 8.8.8.8` 确认)**以及 loopback**。Go daemon 会持续追踪所有三个日志(添加传感器后需重新构建它:`make agent-build`,然后重启 `daemon-run`)。 **为什么还要加上 loopback,这是在第 3 阶段添加的**:第 3 阶段的模拟“未知 AI”endpoint(`sensor/mock-ai/`)运行在同一台主机上。发往本地地址的同主机流量永远不会经过物理 NIC —— 经验证实,仅限 ens18 的捕获未看到任何相关流量,而 `-i lo` 捕获到了。Zeek 每个进程只接受一个 `-i`(因此有了复用相同脚本的独立 `bas-zeek-lo` 服务),而 Suricata 的 `af-packet` 配置原生支持在一个进程中监控多个接口(只是不要在其命令行中传递 `-i` —— 那会悄悄地将配置的接口列表覆盖为一个,这正是第一次破坏此功能的原因)。 **一个值得保留在报告中的真实 Bug**:`shadow_ai_clusters.confidence` 的列默认值最初(错误地)被设为 `'candidate'` 而不是 `'observed'` —— 每一个单域名的指纹目击都立即显示为“candidate”,这完全违背了 ≥2 个不同域名规则的初衷。这是通过测试真实的环境流量(这台机器自身的后台服务 —— `mail.google.com`、`telemetry.elastic.co` —— 每个都在一次目击中显示为错误的候选者)而不是仅测试理想路径发现的。已在 `db/schema.sql` 中修复,并通过对已运行的数据库执行一次性 `UPDATE` 解决。 **针对真实流量验证**:一个 curl 客户端命中两个不同的非已知 AI 域名(`api.github.com`,然后是 `httpbin.org`),在第二次目击时正确触发了 `confidence: "candidate"` —— 由于是同一个客户端,两次的 JA3/JA4 相同 —— 而其他域名单次目击则正确地保持为 `"observed"`。数据流传输期间的 daemon 重启从持久化的字节偏移量恢复,没有重新处理,也没有产生间隙。 ## 第 3 阶段设置 — 带标签的数据集、模拟 AI、测试集群、A/B/C 评估 ``` make dataset-gen # 70 labeled synthetic pages -> eval/dataset/ make dataset-serve # separate terminal, leave running — serves them on :8877 make mock-ai-up # two local TLS "unknown AI" endpoints for shadow-AI testing make endpoints-build # builds the one shared endpoint image (Chrome + Go agent + extension) make endpoints-up # brings up 4 containers, each its own OS user/hostname make endpoints-test # runs driver.py inside each, one at a time make eval-run # A/B/C precision/recall/F1 against the labeled dataset ``` **范围说明,这是经过明确决定的,而不是照搬最初的草案**:测试集群不会登录真实的 claude.ai/chatgpt.com 账户 —— 仅仅为了生成测试流量而在生产环境的第三方服务上创建多个账户会违反其 ToS,并且通常是无法自动化的(电子邮件/电话验证)。因此采用:真实 AI 域名的公开页面(真实的 SNI/JA3/JA4,无需登录),用于影子 AI 聚类的本地自签名模拟 endpoint,用于注入检测的全合成带标签数据集,以及已在第 1 阶段手动验证过的相同安全 DLP 测试模式。 **四个 endpoint,行为各异**(比四次相同的运行有更好的面板展示效果,且每个在 `endpoints` 中代表不同的 OS 用户 + 主机名):`priya.sharma` 和 `arjun.mehta` 是基线/正常状态(仅包含数据集页面 + 已知 AI 域名);`karan.iyer` 额外访问了两个模拟 AI endpoint,这实际上正是触发影子 AI 聚类的原因 —— 该规则在**一个指纹命中 ≥2 个不同的未列出域名**时触发,因此一个 endpoint 同时两个模拟域名本身就足够了,不需要跨 endpoint 协调(此计划的一份早期草案暗示了其他情况,在实际实现后予以更正);`divya.rao` 额外运行了 DLP 批准网关测试。这四个 endpoint 都会访问完整的 70 页数据集,因此 A/B/C 评估具有高达 4 倍的每页覆盖率 —— 这同时兼作确定性检查(`eval/evaluate.py` 会标记同一静态页面在不同访问中得出不同判定的情况,因为检测应该是确定性的)。 **容器网络**:`network_mode: host`,而不是自定义 bridge —— 允许每个容器直接访问宿主机上已绑定到 loopback 的 Postgres (`:5433`) 和 ai-engine (`:8100`),而无需将它们绑定到 `0.0.0.0`,否则对本项目自身的数据库来说将是真实的暴露倒退。权衡:每个容器自己的 Go daemon 监听不同的端口(`8091`-`8094`),因为它们共享宿主机的网络命名空间;但每个容器仍然有各自的主机名(UTS 命名空间独立于网络命名空间)和用于 endpoint 身份的 OS 用户。 **Chrome 安装说明**:Ubuntu 24.04 的 apt 中的 `chromium-browser` 是一个 snap 包装器,无法在容器内运行 —— 在编写 Dockerfile 之前已通过 `apt-cache policy` 确认。`endpoints/Dockerfile` 改为从 Google 自己的 apt 仓库安装 `google-chrome-stable`,而 `endpoints/driver.py` 以与 `test-pages/cdp_test.py` 相同的经过验证的方法(`Extensions.loadUnpacked`,绝不是 `--load-extension`)安装扩展程序。 ### A/B/C 结果 — 来自集群运行的真实数据 | 检测器 | Precision | Recall | F1 | TP | FP | TN | FN | |---|---|---|---|---|---|---|---| | A — 仅关键词 | 0.754 | 0.817 | 0.784 | 98 | 32 | 128 | 22 | | B — 仅可见性 | 0.854 | 0.975 | 0.911 | 117 | 20 | 140 | 3 | | **C — 多指标** | **0.983** | **0.975** | **0.979** | 117 | **2** | 158 | 3 | 280 行匹配的告警(70 页数据集 × 4 个 endpoint,减去几个不匹配数据集清单的已知 AI/模拟域名访问)。C 在各项指标上均胜出 —— 与毕业设计 1 的 A/B/C 结果呈现相同的 C > B > A 趋势。真正验证了整个模块设计论点的数字是:**在 40 次强阴性访问行(10 个页面 × 4 个 endpoint,每次都恰好带有一个弱指标)中,A 误报 32 次,B 误报 20 次,C 仅为 2 次。** 完整数据见 `eval/results/phase3-injection-eval.json`。可通过 `make dataset-gen`、`make dataset-serve`、`make mock-ai-up`、`make endpoints-build`、`make endpoints-up`、`make endpoints-test`、`make eval-run` 进行重现。 **在让这次运行真正生效期间发现并修复的三个真实 Bug —— 值得保留在报告中,它们比一次干净利落的首次尝试更能证明严谨性:** 1. **第一次完整的集群运行默默地产生了零行数据。** 驱动程序报告每个页面都已“访问”,但没有任何数据到达 daemon。根本原因:容器的原生消息注册遇到了在第 1 阶段于宿主机上发现并修复的完全相同的仅用户级缺口(带有自定义 `--user-data-dir` 的 Chrome 配置文件无法发现 `~/.config/google-chrome/NativeMessagingHosts`,只能发现系统级路径)—— 但此修复从未被移植到 `endpoints/entrypoint.sh` 中。使问题复杂化的是:每个容器的 daemon 都监听自己的端口 (8091-8094),但 `nmhost` 默认为 8090,并且针对每个容器没有任何设置来覆盖它。通过在 `entrypoint.sh` 中注册系统级路径,并在启动前让 `driver.py` 将 `DAEMON_NM_URL` 传入 Chrome 的环境变量中而得到修复。 2. **影子 AI 聚类默默地从未为真实浏览器流量累积多域名证据。** 最初的 schema 将 `shadow_ai_clusters` 的键设置为 `(ja3, ja4)` 组合。Chrome 的 GREASE 机制会在每个 ClientHello 中随机化保留的密码/扩展值,而 JA3 朴素的哈希处理会将其视为信号 —— 经验证实,到相同两个模拟 endpoint 的 12 个真实 Chrome 连接中有 10 个各获得了不同的 JA3。JA4 专门设计用于在哈希前剥离 GREASE,并在所有连接中保持一致。这在早期的手动测试中之所以看起来有效,仅仅是因为该测试使用了 `curl`,它不实现 GREASE。重新以单独的 JA4 作为键(`sample_ja3` 保留为信息性的非匹配列)。 3. **扩展程序自身的 DOM 扫描器完全跳过了良性页面。** `injection-scan.ts` 仅在本地找到至少一个指标时才向 daemon 发送消息 —— 这意味着 30 个纯良性的数据集页面根本没有被评分或记录,尽管在 daemon 端进行了“记录每个分数”的更改,评估仍缺乏真阴性数据。通过移除提前返回 (early return) 修复,以便每次扫描无论干净与否都会报告。 **根据实际针对真实流量运行影子 AI 聚类发现的一个问题,这虽然不是 Bug,但值得坦诚说明**:一旦修复,包含这两个模拟域名的以 JA4 为键的集群也引入了另外 16 个域名 —— 常规的 Chrome 后台流量(Google 服务检查、安全浏览、更新 ping、Cloudflare 挑战)它们都共享相同的 JA4,因为它实际上就是“通用的无头 Chrome”,而不是因为其中任何一个是与 AI 相关的。这正是下面作为已知限制指出的误报模式,现在已经用真实数据进行了展示,而不仅仅是停留在理论论证。 ## 第 4 阶段 — EDR 风格的 dashboard ``` make dashboard-setup # once make dashboard-dev # separate terminal — http://127.0.0.1:3000 ``` React + TypeScript + Vite,**不是** Grafana/Kibana(刻意为之 —— 见计划)。开发服务器将 `/api/*` 代理给 daemon (`vite.config.ts`),因此 daemon 不需要任何 CORS 更改,并保持与第 1-3 阶段的任何其他服务完全一样的 loopback 范围限制。 五个新的 daemon endpoint 为其提供支持(`agent/cmd/daemon/dashboard.go`,`agent/internal/store/dashboard.go`)—— 这些是服务器端的聚合数据,而不是将原始行数据导出到前端:KPI 摘要、按 endpoint 的汇总、已知与影子 AI 的资产可见性、真实的 ATLAS 技术覆盖,以及按 endpoint 的活动(支持点击展开行,作为单独的常驻时间轴视图的替代)。 **一个故意的范围修正**:“MITRE ATLAS 技术热图”最初被设想为一个完整的 ATT&CK 风格网格。但真实数据仅填充了该项目实际映射的两种技术 —— 渲染一个大部分为空的 16 战术网格会夸大覆盖范围。取而代之的是构建了一个紧凑的“已观察技术”面板:真实的技术,真实的命中次数,没有任何虚构。 **一个真实的架构限制,已显露出来而不是隐藏起来**:网络传感器衍生的事件(影子 AI 目击、被动平台检测)被归因于无论哪个 endpoint 的 daemon 正在追踪 Zeek/Suricata 日志 —— 目前仅限宿主机,因为第 3 阶段的集群容器不运行自己的传感器。在数据中直接确认:每个 `is_shadow_ai=true` 的 `platform_events` 行都归因于宿主机 endpoint,即使是 `karan.iyer` 的容器通过访问模拟 AI 域名实际生成的那些。如果没有更深层次的宿主机端关联(超出了本项目范围),单凭数据包捕获无法将 TLS 连接归因于特定容器。Dashboard 的 endpoint 表依然诚实地展示了这一点,而不是假装拥有它并不具备的按容器的归因 —— 请参阅 `agent/internal/store/dashboard.go` 中关于 `EndpointRollup` 的注释。 **一个值得保留的 SQL 陷阱**:Postgres 不会直接解析在 `ORDER BY` 表达式内部组合的两个 `SELECT` 列表别名(即当 `a`/`b` 本身是别名子查询时的 `ORDER BY (a + b)`)—— 经验证实(`column "..." does not exist`)。通过将查询包装在子查询中并对外部查询进行排序来解决。 ## 已知限制,直言不讳(不要让答辩专家组先发现这些) - 账户身份抓取(`content-isolated/platform-adapters/index.ts`)使用了一种通用的启发式方法,**不是针对每个平台已登录的实时会话验证的选择器** —— 此环境无法检查真实的已登录 DOM 结构。预期它会在 UI 重新设计时遗漏账户。 - DLP 模块的 MITRE ATLAS 技术 ID 未解析(schema 中的 `DLP-MODULE-TODO`)—— 在报告中引用 ID 之前,请手动在 atlas.mitre.org 上确认;OWASP LLM Top 10 LLM02:2025 是安全的临时引用。 - `injection_scoring` 的指标权重是一个基于判断的起点;第 3 阶段的集群运行给了它们一次真实的(虽然略显不足,只有 70 页)评估 —— 见上面的 A/B/C 表 —— 而不是让它们纯粹停留在理论层面。在称其为校准完毕之前,仍值得使用更大的语料库。 - 影子 AI 聚类规则(在 ≥2 个不同的非已知域名中复用 JA4 指纹 → “candidate”)是真实的,并经过经验证实能正确触发,但其在**实践中的精确度很差** —— 见上面“根据实际运行发现的问题”的注释:一个通用的浏览器指纹会将 Chrome 自身的所有后台流量与真正的影子 AI 命中一起拉入。可用作分流信号(排列候选者供人类检查),而不是作为自动判定,除非进行进一步细化(例如,排除浏览器自身众所周知的遥测/更新域名)。 - **在第 3 阶段评估期间发现约 5% 的跨访问确定性差距**:`eval/evaluate.py` 会标记同一个静态页面在不同访问中获得不同标记(flagged/a_flagged/b_flagged)的情况 —— 在 280 个匹配的行中有 14 例这种情况,主要发生在已注入页面的仅关键词 (A) 基线上。最可能的原因:`injection-scan.ts` 在 `document_idle` 时运行,这可能会在 CSS/布局完全解析之前触发,偶尔会因为竞态条件让隐藏文本泄露到基于 `innerText` 的可见文本扫描中。已记录在案,本轮不再进一步深究 —— 完整细节在 `eval/results/phase3-injection-eval.json` 的 `determinism_issues` 中。 - **网络传感器事件归因是宿主机级别的,而不是按容器的**(在构建第 4 阶段 Dashboard 时发现):影子 AI/被动平台事件被归因于运行 Zeek/Suricata 的 endpoint —— 只有宿主机,因为第 3 阶段的集群容器不运行自己的传感器。Dashboard 的 endpoint 表诚实地反映了这一点,而不是暗示系统实际并不具备的按容器归因。
标签:AI安全, Chat Copilot, Metaprompt, Rootkit, Zeek, 入侵检测系统(IDS), 提示词注入检测, 数据防泄漏(DLP), 日志审计, 测试用例, 浏览器扩展, 网络流量分析, 自动化攻击, 请求拦截, 逆向工具