AgentMoss
AgentMoss 是一个可被任意 AI Agent 调用的独立通用安全分析服务。基于 OS Profile 机制,自动适配 Linux/Windows 的 syscall 检测模式,提供三层防御安全分析(特征匹配 → 逻辑规则 → LLM 语义分析)。
v2 更新:新增 OS Profile 系统(Linux/Windows 自适应)、两级快速放行白名单、rm 命令分级检测、脚本内容预扫描、LLM 结果缓存、Provider 自动识别与 Header 注入、fail-closed 安全原则。
v0.4.0 新增:非交互式密码修改检测(passwd/chpasswd/newusers/lnewusers 等)、密码修改授权检测(ask_user_question 前置检查)、内置安全 Skill 白名单(xiaoo-guardian 直接放行)、系统信息命令快速放行(whoami/id/hostname 等 12 个命令)、shell 重定向写入检测、AcTrail 执法事件上报。
v0.5.0 新增:L1/L2 规则收窄减少误杀(sudo 只拦截危险命令、rm -rf /tmp 不拦截、dd/mkfs/format 收窄、/etc/passwd 仅从 L1 移除、git push --force 降级为 medium)、nmap/masscan/zmap 网络扫描检测、lnewusers 批量用户添加检测、L2 通配符删除排除临时目录、用户/组删除授权检测、chgpasswd/lpasswd/gpasswd 检测。
目录
- 架构
- 快速开始
- LLM 配置
- AcTrail 集成
- openEuler 部署
- API 参考
- Policy Console(策略管控台)
- runtime_config(运行时持久化配置)
- 配置
- 项目结构
- 测试
- 环境变量参考
- 竞争力说明(规则集来源 / 竞品对比 / 测试准确率 / L3 token 消耗)
- 形式化引擎与组合攻击链路 — 实现总览
架构
┌─────────────────────────────────────────────────────────────┐
│ 调用入口 (HTTP / Unix Socket / Hook) │
│ POST /api/v1/analyze │
│ GET /api/v1/health │
├─────────────────────────────────────────────────────────────┤
│ ObservableAdapter │
│ AgentOS 可观测服务 syscall → 标准格式 │
├─────────────────────────────────────────────────────────────┤
│ OS Profile 选择 │
│ ┌──────────┐ ┌──────────┐ │
│ │ Linux │ │ Windows │ │
│ │ Profile │ │ Profile │ │
│ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 两级快速放行白名单 │
│ 完全安全 (ls/pwd/echo/whoami/hostname...) → 跳过 L2+L3 │
│ 只读敏感 (cat/grep/head...) → 跳过 L3,保留 L2 │
│ 内置安全 Skill (xiaoo-guardian) → 跳过 L2+L3 │
│ ★ agent 定制白名单 (按 agent_id 加载,如 opendesk 的 │
│ memory-*/todomgr-* 纯数据操作) → 跳过 L2+L3 │
│ ★ 安全兜底: 完整命令管道尾部扫描,防止白名单绕过 │
├─────────────────────────────────────────────────────────────┤
│ 安全分析引擎 (三层防御) │
│ │
│ 层1: 特征匹配静态检测 (<1ms) │
│ ├── 用户自定义规则匹配 │
│ ├── 危险命令正则 (38+ 模式,rm 分级检测,sudo 只拦截危险命令) │
│ ├── 非交互式密码修改检测 (| passwd/chpasswd/newusers/lnewusers 等) │
│ ├── → high/critical → 直接 Deny │
│ ├── → 内联脚本 file_access 转层3 │
│ │ (避免 'python -c "cat /etc/shadow"' 假阳性) │
│ └── Prompt 注入检测 (62 个中英关键词,9 类) │
│ │
│ 层2: 逻辑规则检测 (<1ms) │
│ ├── Rule 1: read-before-write 原则 (含 shell 重定向检测) │
│ ├── Rule 2: 意图偏离检测 │
│ ├── Rule 3: 敏感路径访问 (含凭据 6 条目, │
│ │ \b 边界匹配避免部分匹配误报) │
│ ├── Rule 4: 危险操作模式 (通配符删除/重定向覆盖, 临时目录排除) │
│ ├── Rule 5: 密码修改授权检测 (非交互式需 ask_user_question) │
│ ├── Rule 6: 用户/组删除授权检测 (需 ask_user_question) │
│ ├── Rule 7: 提权检测 (sudo+危险命令/su/chmod u+s) │
│ └── Rule 8: 横向移动检测 (ssh/scp/rsync) │
│ │
│ 层3: LLM + Skill 深度分析 (2-5s) │
│ ├── 脚本内容预扫描 (18 个可疑模式,4 组合风险) │
│ ├── Skill 规则匹配 (12 个 Skill,关键词加权评分) │
│ ├── LLM 结果缓存 (200 条 FIFO) │
│ ├── Provider 自动识别 (15+ Provider) │
│ └── LLM 语义安全判断 (fail-closed) │
├─────────────────────────────────────────────────────────────┤
│ AcTrail 事件上报 (fire-and-forget) │
│ Allow/Deny 决策 → AcTrail SQLite Enforcement 事件 │
└─────────────────────────────────────────────────────────────┘
设计原则
- 适配在 OS 层,不在 Agent 层 — 不同 Agent 最终都会调用操作系统的 syscall,这是确定性的
- 标准化 I/O 契约 — 任何 Agent 遵循 API 格式即可接入,无需关心内部实现
- fail-closed 安全原则 — LLM 调用失败时默认拒绝,不确定时拒绝
- 两级快速放行 — 完全安全命令跳过 L2+L3,只读敏感命令跳过 L3,降低性能开销
- 安全兜底 — 白名单放行前扫描完整命令管道尾部,防止
echo ... | passwd等绕过 - 内置 Skill 信任 — 系统安全 Skill(如 xiaoo-guardian)加载时直接放行,不走 LLM 审计
- rm 命令分级检测 — 根据 flag 危险度 + 目标路径敏感度分级,
/tmp等临时目录不再拦截 - sudo 收窄 — 不再一刀切拦截所有 sudo,只拦截 sudo 后跟的危险命令(rm/chmod/dd/mkfs 等)
- 内联脚本假阳性防护 —
python -c "x = 'cat /etc/shadow'; print(x)"等字符串字面量中的敏感路径不立即拦截,转层3 LLM 语义判断 - 目录遍历动态文件访问检测 — 检测
os.listdir()+open()等通过目录遍历动态发现文件并读写的行为,防止绕过静态路径匹配 - 敏感路径读写区分 — 凭据文件(credentials.yml、.env、SSH 密钥等)读写均拦截;系统配置文件(/etc/hosts、/boot/ 等)仅写拦截;特殊设备(/dev/random)仅读拦截
- Shell 重定向智能识别 — 识别
2>/dev/null等丢弃写法不计入写操作,lsblk/blockdev等只读系统工具后的重定向也不判定为写入 - 凭据文件边界匹配 —
credentials.yml、.env等使用\b边界匹配避免非文件名拼接(如something_credentials_yml)误报 - 密码修改授权 — 非交互式密码修改(
| passwd、chpasswd等)必须有ask_user_question用户授权 - Shell 重定向写入检测 —
echo data > file等重定向操作识别为写入,纳入 read-before-write 规则
快速开始
安装
Python (PyPI):
pip install agent-moss
TypeScript (npm):
npm install @kenhkl/agent-moss
如需从源码安装:
git clone git@gitcode.com:kenhkl/AgentMoss.git
cd AgentMoss
# Python 版
pip install -e .
# TypeScript 版
cd ts && npm install && npm run build
CLI 使用
# 生成输入模板 (v2: 含 os_type 和 cwd 字段)
agent-moss init -o input.json
# 运行安全分析
agent-moss analyze input.json
# 安装 systemd service(有 sudo 时)
# 自动创建 /etc/systemd/system/agent_moss.service,--enable 开机自启
agent-moss install --enable
# 无 sudo 时跳过 systemd,提示手动启动:
# agent-moss server --port 0
agent-moss install
# 查看服务状态(端口、版本、Console URL、三层开关)
agent-moss status
# 启动 HTTP 服务 (TCP)
# 端口被占时自动 findFreePort 往上找空闲端口(9090→9091→…,扫 100 个)
agent-moss server --port 0
# 消费方(xiaoO bridge.py)探测 9090-9095 的 /api/v1/health 自动连上实际端口。
# 启动 Unix Domain Socket 服务(同机部署推荐)
agent-moss server --mode socket --socket /var/run/agent_moss/agent_moss.sock
# 指定配置文件
agent-moss server --mode socket --config /etc/agent_moss/agent_moss.yaml
API 调用
HTTP TCP 方式:
curl -X POST http://127.0.0.1:9090/api/v1/analyze \
-H 'Content-Type: application/json' \
-d '{
"session_id": "test-001",
"prompt_session": "列出系统文件",
"action_history": [],
"a_next": {
"action_type": "bash",
"action_detail": "ls -la /tmp"
},
"reason": "查看临时目录",
"os_type": "",
"cwd": "/home/user"
}'
Unix Domain Socket 方式(同机低延迟):
curl --unix-socket /var/run/agent_moss/agent_moss.sock \
-X POST http://localhost/api/v1/analyze \
-H 'Content-Type: application/json' \
-d '{
"session_id": "test-001",
"a_next": {
"action_type": "bash",
"action_detail": "ls -la /tmp"
}
}'
响应示例 (Allow):
{
"decision": "Allow",
"risk_level": "low",
"risk_type": "",
"violated_layers": [],
"confidence": 100,
"analysis_duration_ms": 10.8
}
TypeScript / Node.js 调用
import { createApp } from '@kenhkl/agent-moss';
const app = createApp();
// 通过 Hono app.fetch 在 Node.js / Bun / Electron 中调用
// 或启动独立服务: npx agent-moss server --port 9090
也可以直接 HTTP 调用:
const resp = await fetch('http://127.0.0.1:9090/api/v1/analyze', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
session_id: 'sess-001',
a_next: { action_type: 'bash', action_detail: 'ls -la' },
os_type: 'linux',
cwd: '/home/user',
}),
});
const result = await resp.json();
// → { decision: 'Allow'|'Deny', risk_level: 'low'|'...', ... }
响应示例 (Deny):
{
"decision": "Deny",
"reason": "检测到递归强制删除关键路径 (rm -rf /...)",
"risk_level": "critical",
"risk_type": "script_execution",
"violated_layers": ["L1.1"],
"confidence": 95,
"analysis_duration_ms": 1.2
}
LLM 配置
AgentMoss 的三层防御中,层3(LLM 语义分析)是可选的。层1+层2 的静态规则可以独立运行。
L3 输入构成与 token 消耗(为什么不会上下文爆炸)
客户常有的顾虑:最坏情况下一个 session 里的每个 tool call 都会走到 L3 LLM 分析,会不会像 Agent 主循环那样把历史会话不断叠加导致上下文爆炸?不会。AgentMoss 的 L3 每次调用都是有界的独立请求,输入只包含当前这次判定的必要上下文,不随 session 长度无限累积。
每次 L3 调用的输入构成(固定模板 + 当前判定要素):
| 组成部分 | 内容 | 是否有界 |
|---|---|---|
| 固定 prompt 模板 | 安全审计员角色 + 判定维度 + JSON 输出格式 | ✓ 固定 |
| 原始用户 prompt | prompt_session(本次 session 的用户意图) |
有界(用户单次输入) |
| 待执行动作 | action_type + action_detail(当前这一次 tool call) |
✓ 单次动作 |
| 执行理由 | reason |
✓ 当前动作的理由 |
| 历史动作序列 | action_history(本次 session 已执行的动作,每条仅 name + action_detail) |
有界(本次 session 的有限动作) |
| 安全检测规则 | 最多 3 个 Skill(按关键词相关度从全集选 top-3,每个 Skill 29-39 行) | ✓ 最多 3 个 |
| 前置检测结果 | L1/L2 的命中提示(仅命中时才有) | ✓ 按需 |
| 脚本内容分析 | 内联脚本/管道的静态分析(仅脚本类动作才有) | ✓ 按需 |
关键边界:
- Skill 最多 3 个:L3 从全部安全 Skill 中按关键词相关度评分取 top-3 注入 prompt(无匹配时兜底
general_tool_risk_guard1 个),不会把全部 Skill 都塞进去。每个 Skill 文件 29-39 行。 - 每次调用独立:L3 是"判定单个待执行动作 a_next"的独立请求,不是把 agent 的全部历史对话叠加进上下文。每次输入 = 固定模板 + 本次 a_next + 本次 session 的历史动作 + ≤3 个 Skill,彼此之间无累积。
- 实测输入大小:典型 L3 调用 prompt 长度约 3500-3700 字符(~1k-1.5k token),多次调用稳定在该量级,不随 session 延长而膨胀。
- 与 Agent 主循环的区别:Agent 主循环调 LLM 时通常把全部历史对话(user/assistant 往返)叠加进上下文,session 越长 token 越大;AgentMoss L3 每次只判一个动作,历史只传"已执行动作的摘要"(name + action_detail),且本次判定完即丢弃,不在 L3 侧累积。
最坏情况(session 内每个 tool call 都走 L3)下,单次 L3 的输入 token 仍有界(~1.5k token 量级),代价是调用次数 × 单次 token,而非单次 token 随历史爆炸。结果缓存(200 条 FIFO)会进一步消减重复调用的实际 LLM 消耗。
启用 LLM
方式 1:环境变量(推荐)
export AGENT_MOSS_LLM_API_KEY="sk-your-key"
# 可选:自定义模型和 API 端点
export AGENT_MOSS_LLM_MODEL="glm-5.0"
export AGENT_MOSS_LLM_BASE_URL="https://api.nextapi.store/v1"
方式 2:配置文件
首次运行 AgentMoss 时,会自动在 ~/.config/agentmoss/config.json 创建默认配置文件。编辑该文件:
{
"llm": {
"api_key": "sk-your-key",
"model": "glm-5.0",
"base_url": "https://api.nextapi.store/v1"
}
}
配置文件优先级:
- 环境变量(
AGENT_MOSS_LLM_API_KEY等)— 最高优先级 AGENT_MOSS_CONFIG_PATH环境变量指定的路径~/.config/agentmoss/config.json— 首次运行自动创建- 包内默认配置
方式 3:YAML 配置文件
通过 --config 或 AGENT_MOSS_CONFIG_PATH 指定 YAML 文件:
agent-moss server --config /etc/agent_moss/agent_moss.yaml
编辑 config/agent_moss.yaml:
llm:
provider: "zhipu"
model: "glm-5.0"
base_url: "https://api.nextapi.store/v1"
api_key_env: "AGENT_MOSS_LLM_API_KEY"
temperature: 0.1
max_tokens: 4096
security:
llm_analysis:
enabled: true
禁用 LLM(仅静态规则)
export AGENT_MOSS_DISABLE_LLM=1
支持的 LLM Provider
| Provider | URL 匹配 | Provider Hint | 说明 |
|---|---|---|---|
| OpenAI | api.openai.com |
openai |
默认模型 |
| Anthropic | anthropic.com |
claude / anthropic |
Claude 系列 |
generativelanguage.googleapis.com |
google / gemini |
Gemini 系列 | |
| DeepSeek | api.deepseek.com |
deepseek |
DeepSeek 系列 |
| 智谱 (GLM) | open.bigmodel.cn |
zhipu / glm-cn / bigmodel |
GLM / CogView |
| 智谱 Coding Plan | api.z.ai |
zai-coding-plan |
智谱编程套餐 |
| OpenRouter | openrouter.ai |
openrouter |
多模型中转 |
| Groq | api.groq.com |
groq |
高速推理 |
| Mistral | api.mistral.ai |
mistral |
Mistral 系列 |
| Together | api.together.xyz |
together |
开源模型聚合 |
| xAI | api.x.ai |
xai / xai-grok |
Grok 系列 |
| MiniMax | api.minimaxi.com |
minimax |
MiniMax 系列 |
| GitCode | api-ai.gitcode.com |
gitcode |
GitCode AI |
| Ollama | :11434 |
ollama |
本地模型 |
| 任意兼容 | — | other / custom / local |
任何 OpenAI 兼容 API |
自动识别 Provider 后,OpenRouter 和 xAI 会注入特定 HTTP Header(Referer、Title),确保平台正确计费。
AcTrail 集成
AgentMoss 可以将每次安全分析的 allow/deny 决策作为 Enforcement 事件写入 AcTrail 的存储,实现统一的 agent 行为审计。
启用
# 环境变量方式
export ACTRAIL_ENABLED=1
export ACTRAIL_STORAGE_PATH=/tmp/actrail.sqlite # 默认路径
# 启动 AgentMoss
agent-moss server --port 9090
Policy Console(策略管控台)
AgentMoss 自带浏览器策略管控台,可视化调整三层开关、规则启停、deny_mode、skill 开关,查看 token 用量统计。Python 版和 TS 版功能对等(同一套前端 SPA,同一套 HTTP API 契约)。
访问:服务启动后,浏览器打开 http://127.0.0.1:9090/console(端口随服务实际监听端口)。
鉴权:默认本机(127.0.0.1)免鉴权,便于 iframe 嵌入;如需远程访问,设 AGENT_MOSS_CONSOLE_TOKEN 环境变量,请求带 Authorization: Bearer <token>。
Console API(前端 SPA 调用,也可直接 curl):
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/console |
返回 SPA index.html |
GET / PUT |
/console/api/layers |
查/改三层开关(L1/L2/L3 启停) |
GET |
/console/api/rules |
查全量规则(L1/L2,含 builtin + 自定义) |
PUT |
/console/api/rules/enabled |
翻转规则启停 |
PUT |
/console/api/rules/deny_mode |
改 deny_mode(deny_write/deny_read/deny_both) |
PUT |
/console/api/rules/skip_l3 |
改规则禁用时是否跳过 L3 |
PUT |
/console/api/categories/enabled |
改分类开关 |
POST / DELETE |
/console/api/rules |
增/删自定义规则(builtin 不可删) |
GET |
/console/api/skills |
查 L3 skill 全集 |
PUT |
/console/api/skills/enabled |
翻转 skill 启停 |
PUT |
/console/api/skill-categories/enabled |
改 skill 分类开关 |
POST / DELETE |
/console/api/skills |
增/删自定义 skill(写 markdown 文件) |
GET |
/console/api/skills/{id}/content |
查 skill markdown 内容 |
GET |
/console/api/agents |
查 agent 定制规则(按 agent_id 分区,含 enabled 状态) |
PUT |
/console/api/agents/rules/enabled |
翻转某 agent 某条规则启停 |
POST / DELETE |
/console/api/agents/rules |
增/删 agent 定制规则条目 |
GET |
/console/api/config |
查完整 runtime config + 路径 |
GET |
/console/api/env-overrides |
查被环境变量接管的开关(灰色不可改) |
POST |
/console/api/reset |
重置为出厂默认 |
GET |
/console/api/token-stats |
token 用量统计 |
GET |
/console/api/token-stats/recent |
最近 N 条调用记录 |
GET |
/console/api/token-stats/trend |
趋势(日期×模型) |
POST |
/console/api/token-stats/reset |
清空统计 |
Console UI 采用 OpenDesk
--ag-设计 token + 暗色模式,为后续原生嵌入 OpenDesk 安全网关新页面预留视觉对齐。
runtime_config(运行时持久化配置)
runtime config 是 AgentMoss 的运行时策略持久化层,区别于启动时读的 YAML 配置:
- 存储:
~/.config/agentmoss/agent_moss_runtime.json(AGENT_MOSS_RUNTIME_CONFIG_PATH覆盖) - 内容:三层开关、L1/L2 规则启停状态、deny_mode、skip_l3、L3 skill 开关
- seed:首次加载时若文件不存在,自动从源码常量 seed 出厂默认(含全部 builtin 规则)并落盘
- merge:每次加载时与源码默认 merge——保留用户开关,补入新 builtin,源码已删的 builtin 标记
source_removed+禁用(指纹去重,跨 id 变更识别同一规则) - 优先级:
AGENT_MOSS_DISABLE_*env > runtime JSON >agent_moss_settings.json> 默认。env 永远最高(Console 会展示被 env 接管的开关为灰色不可改) - 热生效:
is_layer_enabled每次判定现读 runtime JSON,Console 改完立刻生效,无需重启服务 - query 写操作:Python 和 TS 均实现全套(seed/merge/CRUD/update_*/
_or_default回退),双栈行为一致
Console UI 即是对 runtime config 的可视化操作层;直接编辑 JSON 或用 env 覆盖是另外两个入口,三者最终都落到同一份 runtime JSON。
配置
| 环境变量 | 说明 | 默认值 |
|---|---|---|
ACTRAIL_ENABLED |
设为 1 启用上报 |
未设置(禁用) |
ACTRAIL_STORAGE_PATH |
AcTrail SQLite 数据库路径 | /tmp/actrail.sqlite |
ACTRAIL_TIMEOUT_MS |
写入超时(毫秒) | 100 |
事件格式
AgentMoss 写入 AcTrail 的 events 表,payload 格式为 Enforcement 类型:
{
"backend": "agent-moss",
"operation": "tool_call",
"decision": "allow|deny",
"result": "allowed|denied",
"tool.name": "bash",
"tool.command": "cat /var/log/syslog",
"agent.session_id": "session-001",
"agent.prompt": "read log file",
"risk.level": "low",
"risk.type": "",
"reason": "...",
"violated_layers": "1,2",
"confidence": "100",
"duration_ms": "2.3"
}
架构
AgentMoss (Python HTTP) AcTrail (eBPF daemon)
┌─────────────────┐ ┌─────────────────┐
│ POST /analyze │ │ │
│ ↓ │ │ SQLite 存储 │
│ 三层防御分析 │ │ (events 表) │
│ ↓ │ fire-and- │ │
│ Allow/Deny │──forget────▶│ Enforcement │
│ ↓ │ 写入 SQLite │ 事件落库 │
│ 返回给调用方 │ │ │
└─────────────────┘ └─────────────────┘
↓
actrailviewer / actrailweb
统一查看 agent 行为审计
openEuler 部署
前提
- openEuler 22.03 LTS+
- Python 3.10+
- root 权限
一键安装
sudo dnf install -y python3 python3-pip python3-devel
git clone <repo-url> agent_moss
cd agent_moss
sudo bash scripts/install.sh
配置 LLM(生产环境)
# 写入 API Key(文件权限 600)
echo "AGENT_MOSS_LLM_API_KEY=sk-your-key" | sudo tee /etc/agent_moss/agent_moss.env
sudo chmod 600 /etc/agent_moss/agent_moss.env
# 编辑 LLM model / base_url
sudo vim /etc/agent_moss/agent_moss.yaml
启动方式
# HTTP TCP 模式(默认,适合跨机/调试)
sudo systemctl enable --now agent_moss
# Unix Socket 模式(同机部署推荐,更低延迟)
# 编辑 /etc/agent_moss/agent_moss.yaml 中 server.mode: "socket"
# 或修改 /etc/systemd/system/agent_moss.service 中的 ExecStart
启动与验证
sudo systemctl enable --now agent_moss
# HTTP 模式验证
curl http://127.0.0.1:9090/api/v1/health
# {"status":"healthy","version":"<当前版本,见 pyproject.toml / ts/package.json>"}
# Socket 模式验证
curl --unix-socket /var/run/agent_moss/agent_moss.sock \
http://localhost/api/v1/health
管理命令
| 命令 | 说明 |
|---|---|
systemctl start agent_moss |
启动 |
systemctl stop agent_moss |
停止 |
systemctl restart agent_moss |
重启 |
systemctl status agent_moss |
查看状态 |
journalctl -u agent_moss -f |
查看日志 |
systemctl disable agent_moss |
取消开机启动 |
多实例(instance 归属)
同机可并存多套 agentmoss(如 xiaoO 与 OpenDesk 各自起一个),通过 AGENT_MOSS_INSTANCE 环境变量区分归属。status 命令严格按此字段过滤,只认属于自己 instance 的服务:
# 不带 instance → 期望匹配空串。若 9091 上是 xiaoo 的实例,会报"未运行"并提示检测到其他实例
agent-moss status
# ❌ AgentMoss 服务未运行(instance=(空))
# ⚠️ 检测到其他 agent 的 agentmoss 实例: 端口 9091 (instance=xiaoo)
# 带 instance → 精确匹配,正常显示运行中
AGENT_MOSS_INSTANCE=xiaoo agent-moss status
# ✅ AgentMoss 服务运行中
# Instance: xiaoo
# 端口: 9091
instance 隔离「进程识别 + token 消耗」,不隔离规则配置。 同机所有实例共享同一份
~/.config/agentmoss/agent_moss_runtime.json(除非显式设AGENT_MOSS_RUNTIME_CONFIG_PATH指向不同文件)。通用 L1/L2/L3 规则全局一致;不同 agent 的定制规则在文件内按agent_rules.<agent_id>分区天然隔离。任意 console 修改都写入共享文件,其他实例同步生效。
token 消耗按实例隔离:设了
AGENT_MOSS_INSTANCE=<name>时,token 统计文件落在<data_root>/<instance>/agent_moss_token_stats.json(如opendesk→~/.config/agentmoss/opendesk/...),各 agent 只读写自己实例的文件;未设则用默认~/.config/agentmoss/agent_moss_token_stats.json。「最近调用」(consoletoken-stats/recent) 读同一文件,随之隔离。详见docs/ENV_VARS.md。
防火墙(HTTP 模式需要)
sudo firewall-cmd --add-port=9090/tcp --permanent
sudo firewall-cmd --reload
API 参考
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/api/v1/health |
健康检查 |
POST |
/api/v1/analyze |
安全分析 |
POST /api/v1/analyze
请求体 (v2):
{
"session_id": "会话ID (必填)",
"prompt_session": "原始任务描述 (可选,用于注入检测)",
"action_history": [{"action_type": "...", "action_detail": "..."}],
"a_next": {
"action_type": "bash",
"action_detail": "cat /etc/passwd"
},
"reason": "执行理由 (可选)",
"os_type": "",
"cwd": "/home/user/project",
"metadata": {"agent_id": "...", "sandbox_id": "..."}
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
session_id |
string | 是 | 会话唯一标识 |
prompt_session |
string | 否 | 原始任务描述(层1 注入检测会扫描此字段) |
action_history |
array | 否 | 历史动作序列 |
a_next.action_type |
string | 是 | 动作类型 (bash/file_read/file_write 等) |
a_next.action_detail |
string | 是 | 命令/动作详情 |
reason |
string | 否 | 执行理由 |
os_type |
string | 否 | "linux" / "windows",留空自动检测 |
cwd |
string | 否 | 当前工作目录 |
agent_id |
string | 否 | 调用方 agent 标识(如 xiaoo / opendesk)。留空走通用模式。详见 SECURITY_RULES.md「三方 agent 定制规则」 |
metadata |
object | 否 | 扩展元数据(llm_config/llm_log_path per-request LLM 配置) |
响应字段:
| 字段 | 类型 | 说明 |
|---|---|---|
decision |
string | Allow / Deny |
reason |
string | 决策原因 |
risk_level |
string | low / medium / high / critical |
risk_type |
string | 风险类别 (file_access, script_execution, data_exfiltration, prompt_injection, privilege_escalation, lateral_movement, ...) |
violated_layers |
array | 触发的检测层,如 ["1", "2"] |
violated_policy |
string | 违反的具体条款 (Deny 时) |
policy |
string | Cerberus TOML 策略 (Allow 时) |
confidence |
int | 置信度 0-100 |
analysis_duration_ms |
float | 分析耗时(毫秒) |
配置
优先级:环境变量 > YAML 配置文件 > 内置默认值
环境变量
完整清单(含 audit_agent 迁移对照、bridge.py 端口变量、配置优先级)见
docs/ENV_VARS.md。
| 变量 | 说明 | 默认值 |
|---|---|---|
AGENT_MOSS_LLM_API_KEY |
LLM API Key(兼容 fallback OPENROUTER_API_KEY / OPENAI_API_KEY) |
未设置 |
AGENT_MOSS_LLM_MODEL |
LLM 模型名称 | gpt-4o (TS) / anthropic/claude-3.5-sonnet (Python) |
AGENT_MOSS_LLM_BASE_URL |
LLM API 端点 | https://api.openai.com/v1 (TS) / https://openrouter.ai/api/v1 (Python) |
AGENT_MOSS_LLM_PROVIDER |
Provider 标识(决定注入 HTTP headers) | 从 base_url 推断 |
AGENT_MOSS_LLM_TEMPERATURE |
LLM 采样温度 | 0.1 |
AGENT_MOSS_LLM_MAX_TOKENS |
LLM 最大输出 token 数 | 4096 |
AGENT_MOSS_LLM_TIMEOUT |
LLM 单次调用超时(秒) | 300 |
AGENT_MOSS_LLM_RETRIES |
LLM 调用重试次数 | 2(共 3 次尝试) |
AGENT_MOSS_LLM_FAIL_MODE |
LLM 失败策略:fail_open(默认 Allow+warn)/ fail_closed(Deny) |
fail_open |
AGENT_MOSS_DISABLE_LLM |
设为 1 禁用层3 LLM |
未设置 |
AGENT_MOSS_DISABLE_HEURISTIC |
设为 1 禁用层1 特征匹配 |
未设置 |
AGENT_MOSS_DISABLE_LOGIC_RULES |
设为 1 禁用层2 逻辑规则 |
未设置 |
AGENT_MOSS_LOG_PATH |
全量 hook 日志 + LLM prompt 日志(bridge 记 HOOK_INPUT/OUTPUT,L3 记 prompt,写同文件;对应 audit_agent AUDIT_LOG_PATH) |
未设置(不记录) |
AGENT_MOSS_CUSTOM_RULES |
自定义规则 JSON 数组 | [] |
AGENT_MOSS_ENABLE_POLICY_GEN |
设为 1 启用 Policy 生成 |
未设置 |
AGENT_MOSS_CONFIG_PATH |
主配置 YAML 路径 | ~/.config/agentmoss/agent_moss.yaml |
AGENT_MOSS_DATA_DIR |
数据根目录(所有 ~/.config/agentmoss 文件落盘位置)。systemd 下即使 root 启动也按安装用户落盘 |
~/.config/agentmoss |
AGENT_MOSS_RUNTIME_CONFIG_PATH |
runtime JSON(层级开关+规则启停持久化) | ~/.config/agentmoss/agent_moss_runtime.json |
AGENT_MOSS_TOKEN_STATS_PATH |
token 用量统计 JSON(显式优先于 instance 派生路径) | 见「token 消耗按实例隔离」 |
AGENT_MOSS_SETTINGS_PATH |
agent_moss_settings.json 路径 |
包内默认 |
AGENT_MOSS_CONSOLE_TOKEN |
Console Bearer 鉴权 token | 未设(本机免鉴权) |
AGENT_MOSS_URL / HOST / PORT |
bridge.py 连服务用(端口被占自动 findFreePort) | 127.0.0.1:9090 |
ACTRAIL_ENABLED |
设为 1 启用 AcTrail 事件上报 |
未设置(禁用) |
ACTRAIL_STORAGE_PATH |
AcTrail SQLite 数据库路径 | /tmp/actrail.sqlite |
ACTRAIL_TIMEOUT_MS |
AcTrail 写入超时(毫秒) | 100 |
配置文件
参考 config/agent_moss.yaml。
自定义规则
通过 AGENT_MOSS_CUSTOM_RULES 环境变量注入自定义正则规则:
export AGENT_MOSS_CUSTOM_RULES='[
{"pattern": "kubectl delete namespace", "action": "Deny", "severity": "critical"},
{"pattern": "docker rm -f", "action": "Deny", "severity": "high"}
]'
配置模板
# OS Profile 自动选择
os_profile:
type: "" # 留空自动检测,可手动指定 linux / windows
# 服务调用模式
server:
mode: "http" # "http" (TCP) 或 "socket" (Unix Domain Socket)
socket_path: "/var/run/agent_moss/agent_moss.sock"
项目结构
AgentMoss/
├── agent_moss/ # Python 实现 (PyPI: agent-moss)
│ ├── __init__.py
│ ├── cli.py # 命令行工具 (init/analyze/server)
│ ├── __version__.py
│ ├── profiles/ # OS Profile 系统
│ │ ├── base.py # OSProfile 抽象基类
│ │ ├── linux.py # LinuxProfile
│ │ └── windows.py # WindowsProfile
│ ├── engine/ # 安全分析引擎
│ │ ├── analyzer.py # 分析入口
│ │ ├── coordinator.py # 三层协调器 + L1.2/L2.3 递归脚本链 + fail-open
│ │ ├── heuristic.py # 层1: 特征匹配检测 (危险命令 + 注入关键词,热重载 runtime_config)
│ │ ├── logic_rules.py # 层2: 逻辑规则 (敏感路径/意图/密码/用户删除,credential 区分)
│ │ ├── llm_analyzer.py # 层3: LLM + Skill 深度分析 (skip_l3_hints + token 记录)
│ │ ├── script_analyzer.py # 脚本预扫描
│ │ ├── script_content_analyzer.py # L1.2/L2.3 递归脚本链内容分析 (移植自 audit_agent)
│ │ ├── inline_analyzer.py # 内联脚本/文本区分
│ │ ├── skill_engine.py # Skill 匹配引擎 (热重载 runtime_config 禁用 skill)
│ │ └── types.py
│ ├── infra/ # 基础设施
│ │ ├── config.py # 配置管理 (YAML + 环境变量 + 继承 xiaoo config.toml)
│ │ ├── runtime_config.py # runtime JSON:seed/merge/CRUD/层级开关持久化 (51 函数)
│ │ ├── token_stats.py # token 用量统计 (JSON 持久化)
│ │ ├── llm_client.py # LLM 客户端 (流式回退 + Provider header 适配)
│ │ ├── actrail.py # AcTrail 事件上报
│ │ ├── logging.py / parsers.py / policy_cache.py / prompt_templates.py
│ ├── server/ # HTTP API 服务层 (FastAPI)
│ │ ├── app.py # 应用 + run_server + _find_free_port (端口动态分配)
│ │ ├── routes.py # /api/v1/* 路由 (health/analyze/brain)
│ │ ├── models.py / middleware.py / socket_server.py
│ ├── console/ # Policy Console (FastAPI sub-router, 23 路由)
│ │ ├── router.py # /console/api/* (layers/rules/skills/config/env/reset/token-stats)
│ │ └── static/index.html # 自包含 SPA (--ag- 风格 + 暗色模式)
│ ├── adapters/ # 适配器层 (observable)
│ ├── skills/ # 安全 Skill 规则 (Markdown)
│ ├── templates/ # Prompt 模板 + policy_mapping
│ ├── agents/ # 三方 agent 定制化扩展 (xiaoO / opendesk) — rules.json 单一事实源,py+ts 共享
│ └── brain/ # 规则自学习/存储
│
├── ts/ # TypeScript 实现 (npm: @kenhkl/agent-moss) — 功能与 Python 对等
│ ├── src/
│ │ ├── cli.ts # CLI 入口 (init/analyze/server)
│ │ ├── config.ts # 配置 (环境变量 + fail-open)
│ │ ├── models.ts # Zod 数据模型
│ │ ├── routes.ts # Hono API 路由 (health/analyze)
│ │ ├── server.ts # Hono HTTP + findFreePort + 挂载 Console
│ │ ├── actrail.ts / package-json.ts
│ │ ├── engine/ # 三层防御引擎 (与 py 对等)
│ │ │ ├── coordinator.ts / heuristic.ts / logic-rules.ts
│ │ │ ├── llm-analyzer.ts / script-analyzer.ts / script-content-analyzer.ts
│ │ │ ├── inline-analyzer.ts / skill-loader.ts / template-loader.ts
│ │ │ ├── token-stats.ts / types.ts
│ │ ├── infra/runtime-config.ts # runtime JSON 全功能 (seed/merge/CRUD/query,对齐 py)
│ │ └── console/ # Policy Console (Hono sub-app, 23 路由 1:1 对齐 py)
│ │ ├── router.ts / index.ts
│ │ └── static/index.html # 复用 py 的同一份 SPA
│ └── package.json
│
├── hooks/xiaoO/ # xiaoO hook 桥接 (bridge.py + plugin.json)
│ └── bridge.py # stdin JSON → POST /api/v1/analyze → stdout {result,reason};探测兜底
├── config/agent_moss.yaml # YAML 配置模板
├── docs/
│ ├── design.md # 架构需求设计
│ ├── ENV_VARS.md # 环境变量参考 + audit_agent 迁移对照
│ └── ...
└── tests/
├── conftest.py / test_all_cases.py / test_agents_xiaoo.py / test_brain.py
├── test_find_free_port.py # 端口动态分配单测
└── cases/ # 测试用例 JSON
测试
用例归一:单一事实源
所有安全分析测试用例集中在 tests/cases/{l1,l2,l3}/*.json(226 个,按 L1/L2/L3 分子目录),Python 与 TypeScript 双端共用同一批 case(双端各自另有语言特有的手写单测,故 pytest/vitest 报告 passed 总数 > JSON 数且两数不同,详见 tests/cases/README.md)。每个 JSON 含:
| 字段 | 说明 |
|---|---|
expected_decision |
期望决策(Deny/Allow),双端都断言 |
expected_risk_level |
期望风险等级(critical/high/medium/low),双端都断言 |
expected_risk_type |
期望风险类型(文档用,不断言) |
expected_layers |
期望命中层(文档用,不断言) |
llm_required |
L3 case 标 true:禁 LLM 时 skip,需有效 LLM key 真跑 |
input |
{session_id, action_history, a_next, reason, os_type, cwd} |
按子目录分层:l1/ 164 个(特征匹配命中+放行)、l2/ 25 个(逻辑规则命中+放行)、l3/ 28 个(13 个 security skill 命中+放行,llm_required:true)。
新增 case 只改一个 JSON,双端自动跑:
# 新增 case:复制一个现有 JSON 改内容即可(按层放对应子目录)
cp tests/cases/l1/deny-01-chmod-777.json tests/cases/l1/deny-99-mine.json
# 编辑 deny-99-mine.json 的 desc / expected_* / input
Python 端
# 前两层静态规则(禁用 LLM,CI 默认跑法,189 个 L1+L2 case 全绿)
python3 -m pytest tests/test_all_cases.py::TestLayer1And2 -v
# 仅跑 JSON case 加载器(L1+L2,禁 LLM)
AGENT_MOSS_DISABLE_LLM=1 python3 -m pytest tests/test_all_cases.py::TestLayer1And2 -v
# 包含 L3 LLM 层(需有效 LLM key,28 个 L3 case 真调 LLM,串行跑约 2~4 分钟)
# key/地址/model 从 env 或 ~/.config/agentmoss/config.json 统一判定 + 连通性探测,
# 判定通过才真跑;缺 key 或 key 不通则 skip(见下「L3 判定策略」)
python3 -m pytest tests/test_all_cases.py::TestLayer3 -v
# 若需显式覆盖 config.json,仍可传环境变量:
# AGENT_MOSS_LLM_API_KEY="sk-xxx" AGENT_MOSS_LLM_BASE_URL="https://api.deepseek.com/v1" AGENT_MOSS_LLM_MODEL="deepseek-v4-flash"
入口:tests/test_all_cases.py
TestLayer1And2参数化读tests/cases/{l1,l2}/*.json,断言expected_decision/expected_risk_levelTestLayer3参数化读tests/cases/l3/*.json,跑不跑由llm_probe_availablefixture 决定(判定源 env+config.json 有 key 且连通性探测通过才真调 LLM,否则pytest.skip)TestHeuristicDetector/TestLogicRules/TestOSProfile/TestCoordinator跑各子模块单测
L3 判定策略(双端统一)
L3 是否真跑由统一判定源 + 连通性探测决定,Python 与 TS 对称(避免两端判定不一致 + 坏 key fail-open 假通过):
- 判定源:
AGENT_MOSS_LLM_API_KEYenv → 否则~/.config/agentmoss/config.json的llm.api_key(Python 走get_default_config().llm.api_key,TS 走isLLMAvailable())。 - 连通性探测:有 key 再发一次
max_tokens=1ping(Python_probe_llm/ TSprobeLLMConnection)。连通才真跑;key 无效/网络不通 → 明确提示 + skip,不假通过。 - 同源:probe 的 base_url/model/api_key 与 L3 实际调用一致,probe 通过即真跑可信。
TypeScript 端
cd ts
# JSON case 加载器(L1+L2,禁用 LLM,189 个 L1+L2 case 全绿)
npx vitest run src/__tests__/json-cases.test.ts
# 全量(含 heuristic / logic-rules / coordinator / agents 等)
npx vitest run
# 类型检查
npx tsc --noEmit
# 包含 L3 LLM 层(需有效 LLM key,28 个 L3 case 真调 LLM)
# 注意 TS 端与 Python 端有两个差异:
# 1) vitest 默认每 test 5s 超时,L3 跑 LLM 慢需加 --test-timeout=120000
# 2) 加载器并行跑 28 个 L3 case 会撞 LLM rate limit 走 fallback 假命中,
# 已加串行 gate + --no-file-parallelism 避免
# key/地址/model 从 env 或 config.json 统一判定 + 连通性探测,判定通过才真跑
npx vitest run src/__tests__/json-cases.test.ts --no-file-parallelism --test-timeout=120000
# 若需显式覆盖:
# AGENT_MOSS_LLM_API_KEY="sk-xxx" AGENT_MOSS_LLM_BASE_URL="https://api.deepseek.com/v1" AGENT_MOSS_LLM_MODEL="deepseek-v4-flash"
入口:ts/src/__tests__/json-cases.test.ts
beforeAll:判定源(isLLMAvailable,env + config.json)无 key → 设AGENT_MOSS_DISABLE_LLM=1(仅跑 L1+L2,对齐 Python);有 key →probeLLMConnection()发一次 ping,连通才保留 LLM;key 无效/网络不通 → 禁 LLM + 明确提示,避免坏 key fail-open 假通过- 读
tests/cases/{l1,l2,l3}/*.json,转snake_case → camelCase,调runAnalysis,断言expected_decision/expected_risk_level - L1/L2 用例(非
llm_required)强制禁 LLM(对齐 Pythondefault_config):只测 L1+L2 静态结果,避免 LLM 二次判定翻盘(Allow 变 Deny)导致波动。仅llm_required的 L3 case 在 LLM 可用时真跑 - risk_level 断言:仅对 L1/L2 case 断言;L3 case 只断言
expected_decision(LLM 层 risk_level 有非确定性波动,对齐 PythonTestLayer3) llm_required:true的 L3 case:禁 LLM 时it.skip;有 key + 探测通过时串行 gate(promise 链)一次只跑一个,避免并行撞 LLM rate limit 走 fail-open fallback 假命中- 与 Python
TestLayer1And2/TestLayer3共用同一批 case,双端行为不一致会立刻暴露
双端跑 L3 差异说明
| 差异点 | Python | TypeScript |
|---|---|---|
| L3 跑法 | TestLayer3 参数化串行跑,pytest 自带 test 超时足够 |
加载器需 --test-timeout=120000(vitest 默认 5s 不够)+ --no-file-parallelism(串行 gate 避免撞 rate limit) |
| LLM 字段名 | Python 解析兼容 risk_level/riskLevel 两种 |
TS 已修 runLLMAnalysis 兼容两种(之前只取 riskLevel 拿不到走兜底 'low') |
| 禁 LLM 跑 L3 | TestLayer3 全 skip |
加载器 llm_required:true case 单个 skip |
| L3 判定源 | get_default_config().llm.api_key(env + config.json) |
isLLMAvailable()(env + config.json) |
| 连通性探测 | conftest.py _probe_llm(session 缓存,只 ping 一次) |
config.ts probeLLMConnection()(beforeAll 探测一次) |
LLM 测试与 API Key
- L3 是否真跑由统一判定源 + 连通性探测决定,Python 与 TS 对称(见上文「L3 判定策略」):
- 判定源:
AGENT_MOSS_LLM_API_KEYenv → 否则~/.config/agentmoss/config.json的llm.api_key - 连通性探测:有 key 再发
max_tokens=1ping,连通才真跑;key 无效/网络不通 → 明确提示 + skip(不假通过)
- 判定源:
- 无 Key 时:Python
TestLayer3skip;TS 加载器设AGENT_MOSS_DISABLE_LLM=1,L3 caseit.skip - 禁用 LLM 跑纯静态测试:TS 加载器内部已设
AGENT_MOSS_DISABLE_LLM=1;Python 默认就是不调 LLM
双端一致性核对
除 JSON case 加载器外,还有专项一致性测试:
| 测试 | 核对内容 |
|---|---|
ts/src/__tests__/dual-parity.test.ts |
isWriteOperation 双端对同一批 case 返回一致 |
ts/src/__tests__/json-cases.test.ts |
226 个 JSON case 双端 decision + risk_level 一致 |
归一前:Python 跑 Python 的
test_all_cases.py,TS 跑 TS 的*.test.ts,期望值各写各的,双端不一致发现不了。归一后:期望值写在 JSON 里,双端共用,改一处 JSON 双端同步——ts/src/__tests__/json-cases.test.ts加载器一上线就暴露了 2 处真实代码差异 + 3 处 JSON 期望值错误。
Metadata
Release files for agent-moss 0.15.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| agent_moss-0.15.2.tar.gz | 425.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agent_moss-0.15.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 811.8 kB
Release files / agent_moss-0.15.2.tar.gz
| Download URL | agent_moss-0.15.2.tar.gz |
|---|---|
| Size | 425.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
18c6cfee48e49a1d64f12a450503b7c7dd321b0262e31f4555387082aee866d9
|
|
BLAKE2b-256 checksum How to use checksums |
6afe718d5d27fdb11209a6cb5ea1a162df8ba96f4b9f24721f72b622968bb4e0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / agent_moss-0.15.2-py3-none-any.whl
| Download URL | agent_moss-0.15.2-py3-none-any.whl |
|---|---|
| Size | 385.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
582a1b80804793bfaa5ebe6bf478785717db031915611e5a295a30dd1858b396
|
|
BLAKE2b-256 checksum How to use checksums |
fdae85a27df87e0ec82be6849a273c28639995fc94e2172c93bdacb70bac1e62
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|