Skip to content

Security: 登录限流 + SSRF 防护 + CORS 收紧 + 默认回环 + Docker 非 root(独立审计修复) - #134

Open
wangzunxiang wants to merge 3 commits into
Autumn-27:mainfrom
wangzunxiang:security-hardening-20260916
Open

wangzunxiang wants to merge 3 commits into
Autumn-27:mainfrom
wangzunxiang:security-hardening-20260916

Conversation

@wangzunxiang

Copy link
Copy Markdown

安全加固(基于 2026-09 代码安全审计)

独立安全审计发现的多项问题修复,全部为向后兼容的加固改动,go build / go vet / gofmt / 单元测试均通过。

安全修复

  1. 登录爆破面/api/auth/login/api/auth/init 增加按 IP 令牌桶限流(burst 5,60s 补 1,超限 429 + Retry-After)。原实现无节流且默认用户名固定为 ARTEX。
  2. 默认监听回环main.go -addr 默认由 :8787 改为 127.0.0.1:8787(宿主机部署不再默认对外暴露);docker-compose.yml 的 8787 端口默认绑宿主机回环(ARTEX_HOST_BIND 可覆盖);start.sh 支持 ARTEX_ADDR/ARTEX_PROXY 覆盖。
  3. 出站 SSRF 防护(新包 netguard:用户可配的所有出站目标(LLM base_url、自定义 http 工具、MCP/SSE 端点)在 DialContext 内解析后校验全部 IP,防 DNS 重绑定。默认拒绝链路本地(含云元数据 169.254.169.254)/组播/未指定;ARTEX_SSRF_STRICT=1 加严到拒绝全部私网;ARTEX_SSRF_ALLOW 可显式放行。默认策略保持对本地/内网 LLM 网关的兼容。
  4. CORS 收紧:原实现无条件回显任意 Origin(等价 *)且预检放行任意 Origin,与 ?token=*** 查询参数认证通道叠加后可被第三方页面跨域读取受保护数据。改为仅回显 ARTEX_CORS_ORIGINS` 白名单,默认同源。
  5. 安全响应头:新增 securityHeaders(nosniff / DENY / no-referrer / Permissions-Policy)。CSP 因静态导出前端内联脚本多暂不启用(注释已说明)。
  6. 拦截层失败策略:LLM 裁判不可用/超时/输出无法解析时由 allow 改为 deny(fail-closed)。
  7. SQL 注入面CREATE DATABASE 库名严格白名单。
  8. Docker 非 root:新增 artex 用户运行(selfupdate 换装需要的 /app 写权限已保留;Playwright 浏览器固定装到 /ms-playwright)。
  9. 供应链:release.yml 全部 GitHub Actions 钉到完整 commit SHA。

测试

  • 新增 server/auth_sec_test.gonetguard/netguard_test.go(共 9 个用例,全部通过)
  • go build ./...go vet 全通过;我改动的文件 gofmt 干净
  • 注:server 包既有测试需要 Postgres DSN(环境依赖),与本次改动无关

建议但未包含(需产品决策)

  • 自定义工具 permission.Allowed() 无条件放行 → 建议至少对非 system 工具走拦截层
  • LLM API key 明文落库 → 建议加密存储(需数据迁移)
  • Agent 宿主机执行 shell 无沙箱 + 目标内容进入 LLM 上下文 = 提示注入面 → 建议评估 seccomp/容器沙箱
  • 完整漏洞详情已通过 GitHub 私有漏洞报告(PVR)单独提交

审计方:kylinor(独立代码审计,白盒 + 攻击链推演)

- server/auth.go: /api/auth/login 与 /api/auth/init 增加按 IP 令牌桶限流
  (burst 5,60s 补 1,超限 429 + Retry-After,bucket 30min 未活动回收),
  缓解默认用户名 ARTEX + 无认证节流下的口令爆破面
- intercept/intercept.go: LLM 裁判不可用/超时/输出无法解析时的失败动作
  由 allow 改为 deny(fail-closed),防止提示注入场景下拦截层整体失效
- cmd/artex/main.go: -addr 默认 0.0.0.0:8787 改为 127.0.0.1:8787,
  宿主机部署不再默认对外暴露;需对外时显式 -addr :8787
- start.sh: 支持 ARTEX_ADDR / ARTEX_PROXY 环境变量覆盖(Docker 不受影响)
- docker-compose.yml: 8787 端口默认仅绑宿主机回环(ARTEX_HOST_BIND 可覆盖)
- db/db.go: CREATE DATABASE 前对库名做严格白名单校验(标识符白名单,
  消除双引号逃逸可能)
- netguard(新包): 对用户可配的出站目标做解析后 IP 校验(含防 DNS
  重绑定,DialContext 内先解析再校验全部 A/AAAA 记录)。默认拒绝
  链路本地(含云元数据 169.254.169.254)/组播/未指定地址;
  ARTEX_SSRF_STRICT=1 加严到拒绝全部私网+环回;ARTEX_SSRF_ALLOW
  可显式放行网段。兼容本地/内网 LLM 网关的默认用法
- 接入点: agent/provider.go(LLM base_url)、server/customtool.go
  (自定义 http 工具,直连与代理两条路径)、mcphttp/client.go
  (streamable HTTP + SSE 客户端)
- server.go: setLLM/testLLM 保存前校验 base_url;server_mgmt.go
  pgSaveProfile 同样校验(含 MCP 行入库路径)
- server.go CORS: 原实现无条件回显 Origin 且预检放行任意 Origin
  (等价于 Access-Control-Allow-Origin: *),与 ?token= 查询参数
  通道叠加可被第三方页面跨域读取受保护数据。改为仅回显
  ARTEX_CORS_ORIGINS 白名单中的 Origin,默认同源
- server.go: 新增 securityHeaders(X-Content-Type-Options: nosniff、
  X-Frame-Options: DENY、Referrer-Policy: no-referrer、
  Permissions-Policy 禁地理/麦克风/摄像头);CSP 因前端静态导出
  内联脚本多暂不启用,留待内联脚本拆分后引入
- 新增单元测试: server/auth_sec_test.go(限流器、429 响应、clientIP、
  CORS 白名单、安全头)、netguard/netguard_test.go(禁网段策略、
  Dialer 替换、元数据地址拒连)
- Dockerfile: 新增 artex 系统用户(USER artex),容器内 Agent 本身
  要执行 shell,root 运行会把代码执行/逃逸问题放大为宿主级风险;
  selfupdate 换装重写 /app 下二进制与脚本,故 /app 整体 chown artex
  可写;Playwright 浏览器固定装到 /ms-playwright(构建期 root 的
  ~/.cache 运行时不可见),ENV PLAYWRIGHT_BROWSERS_PATH 同用于运行
- release.yml: 全部 GitHub Actions 从 major tag(v4/v5/v6,可被移动)
  钉到完整 commit SHA(均经 GitHub API 核实对应版本),降低供应链
  投毒面
@vercel

vercel Bot commented Sep 16, 2026

Copy link
Copy Markdown

@wangzunxiang is attempting to deploy a commit to the Autumn's projects Team on Vercel.

A member of the Team first needs to authorize it.

@wangzunxiang

Copy link
Copy Markdown
Author

审计漏洞清单(白盒审计,v0.3.11 / commit 80a085d

本 PR 覆盖其中可安全加固的部分。完整 12 项清单如下(本仓库未开启 PVR,故在此列出;
如希望不公开,我可立即删除此评论,经您提供的邮箱另行发送)。

严重(1)

V-01 提示注入 → 无审批任意命令执行 → 数据外传(CVSS 9.1)

  • guard/guard.go applyIntercept 默认 fail-open:无规则命中 + LLM 裁判默认关闭 → allow;
    裁判启用后超时/报错/解析失败 → defaultJudgeFailAction = "allow" 仍放行(intercept.go:84-98)。
  • 唯一拦截数据外传的规则默认禁用(误报率高,intercept/intercept.go)。
  • Agent 在宿主机直接执行 shell,无 seccomp/chroot/cgroup 沙箱(全库 grep 确认)。
  • 目标站点/页面内容(不可信输入)进入 LLM 上下文:攻击者在被渗透目标页面埋入
    注入文本,即可诱导 Agent 在用户宿主机执行任意命令并外传 LLM API key、
    流量抓包(含 Cookie/Authorization 头,可经 /api/workspace/download 获取)。
  • 本 PR 修复:裁判失败策略改 deny(fail-closed)。建议根本性修复
    Agent 执行加沙箱 + 目标内容进上下文前做 untrusted 边界隔离。

高危(4)

  • V-02 登录爆破面:/api/auth/login 无节流 + 固定默认用户名 ARTEX(auth.go)
    • 默认监听 0.0.0.0:8787(main.go)+ Docker root。本 PR 修复:限流 429 +
      默认回环 + 非 root。
  • V-03 登录态任意执行:/api/tools/custom/test 接受任意 command/script/http
    (customtool.go pgTestCustomTool,10 分钟超时),自定义工具
    permission.Allowed() 无条件放行、不走拦截层。
  • V-04 自更新供应链:SHA256 manifest 与二进制来自同一 GitHub Release/账号
    (selfupdate/stage.go),账号被接管 = 投毒;/api/update/apply 仅需登录。
    建议引入独立信任锚(GPG 签名 / 多账号复核)。
  • V-05 敏感数据明文:LLM API key 明文存 Postgres llm_profiles.api_key
    (db/schema.sql:364);流量抓包含凭证头,可下载。

中危(7)

  • V-06 JWT 同时接受 `?token=*** 查询参数(auth.go:92,日志/Referer 泄漏面)
  • V-07 LLM base_url / 自定义 http 工具 / MCP 端点无 SSRF 校验
    (可打 169.254.169.254 云元数据)。本 PR 修复(netguard)。
  • V-08 mcphttp/client.go + enrich/enrich.go InsecureSkipVerify: true
    (保留开关,建议改为可配置的 CA 校验 + 告警)。本 PR 已叠加 SSRF 出口校验。
  • V-09 CORS Access-Control-Allow-Origin: * + 预检放行任意 Origin
    (server.go:3724),与 V-06 叠加可跨域读数据。本 PR 修复
  • V-10 LLM 裁判自身可被提示注入(review 输入含不可信参数)。
  • V-11 Docker 无 USER、compose 8787 绑 0.0.0.0。本 PR 修复
  • V-12 单管理员 + 7 天 JWT 无吊销 + 无操作审计归属。

低危(6,摘要)

CI Actions 未钉 SHA(本 PR 修复)、CSP 等安全头缺失(本 PR 部分修复)、
CREATE DATABASE 标识符拼接(本 PR 修复)、bcrypt cost 默认、
JWT 7 天 TTL、演示站静态导出无后端(非漏洞)。


审计方法:白盒源码审计(Go ~8 万行 + Next.js 前端)+ gosec/semgrep 全量扫描人工复核

  • 攻击链推演;demo 站为纯静态导出,未做动态利用验证(norma 上游 SDK 不在本仓库,
    Bash 执行层未审计)。如需完整报告(Word/Excel,含逐项代码定位与证据),
    请留一个联系邮箱,我单独发送。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant