Skip to content

fix(oauth): G6.3 补丁——OAuth AS 真实认证+授权边界(D45) - #23

Merged
Windsander merged 2 commits into
mainfrom
fix/g6-oauth-hardening
Sep 14, 2026
Merged

Windsander merged 2 commits into
mainfrom
fix/g6-oauth-hardening

Conversation

@Windsander

Copy link
Copy Markdown
Owner

缺陷

内置 OAuth AS 让匿名者自助领取 memory.admin(公网零授权)。证据(修复前):

  • /authorize 无用户认证/同意、无客户端校验,scope 取自请求
  • client_credentials 无凭据即签发
  • /register 开放 DCR,client_id 全程未绑定
  • verify-mcp-http 只覆盖 PKCE happy path 与 401/403

修复(D45,实现前已冻结于 project-status.md)

  1. /authorize 强制「管理员口令(env MEBULAR_OAUTH_ADMIN_SECRET)或一次性本地同意码(mebular token consent)」,缺一即 401、绝不 302;方案并存,常量时间比较。
  2. 关闭开放 DCR:mebular token client add --redirect <uri> --scope <s> 预注册;client_id/authorize/token 强制校验;/register 默认 404,仅 MEBULAR_OAUTH_REGISTER_SECRET 时开放(scope 上限 memory.read)。
  3. 移除 client_credentials(metadata 与 /token 一致)。
  4. redirect_uri 精确匹配预注册值。
  5. scope = 请求 ∩ 客户端 allowed_scopes ∩ 用户同意;超界 → 403 insufficient_scope;默认 memory.read
  6. jti 撤销/refresh 轮换落盘 .mebular/auth/revoked.json(0600),跨重启生效;/authorize/token 按 IP 限流 → 429。
  7. fail-closed 不弱化(非环回仍需 TLS 且 auth != none);stdio/bearer 语义不变。

红灯 → 绿灯(E1)

scripts/verify-mcp-oauth-hardening.mjs(commit d355746 先落红灯):

  • 修复前:① 匿名 client_credentials → 200 有 token;② 匿名 /authorize → 302 带 code;③ 未注册 redirect → 302;④ 超界 scope → 302;⑤ 匿名 /register → 201;另撤销持久/限流为红。
  • 修复后:① 400 ② 401 ③ 400 ④ 403 ⑤ 404;合法同意码路径 302→token→/mcp tools/list=11;撤销/轮换跨重启仍失效;限流 429。全部 ✓。

验收

  • 红灯 1–5 修复前确实失败,修复后 1–8 全绿(npm run verify:mcp:oauth 退出码 0)
  • metadata 不再广告 client_credentials,grant_types_supported=['authorization_code','refresh_token']
  • /authorize 强制用户认证/同意 + client 校验 + redirect 精确匹配 + scope 交集
  • /register 默认禁用
  • 撤销持久(跨重启)
  • 不回归:verify:mcp:http(合法路径更新为新模型)、verify:mcp:stdioverify:mcp:skillverify:mcp:publishbuild && test:coverage && lint 全绿;50 套件/377 用例不回退;npm run verify 0–6 全绿

非目标:不实现完整 IdP;不处理 memory_import 任意路径读取与 memory_sync SSRF 面(另开条目)。

依赖 D45;对应 docs.design/g6-plan.md §6/§11 与 goal-v0.1.md G6.3 补丁 KR。

- scripts/verify-mcp-oauth-hardening.mjs:断言匿名 client_credentials、匿名 /authorize、
  未注册 redirect_uri、超界 scope、匿名 /register 均被拒;合法同意码路径、撤销/轮换跨重启持久、限流 429。
- 修复前实测:1–5 及撤销持久/限流为红(见 PR 描述)。
- fix(oauth): /authorize 强制「管理员口令(env MEBULAR_OAUTH_ADMIN_SECRET)或一次性本地同意码」,
  缺一即 401、绝不 302;预注册 client_id 校验;redirect_uri 精确匹配;scope=请求∩allowed∩同意,超界 403
- fix(oauth): 移除 client_credentials(metadata.grant_types_supported 与 /token 分支一致)
- fix(oauth): /register 默认禁用(404);仅 MEBULAR_OAUTH_REGISTER_SECRET 时开放,scope 上限 memory.read
- fix(oauth): jti 撤销/refresh 轮换落盘 .mebular/auth/revoked.json(0600),跨重启仍生效
- feat(oauth): /authorize、/token 按 IP 限流(MEBULAR_OAUTH_RATE_LIMIT,默认 60/min)→ 429 + Retry-After
- feat(cli): token client add|list|remove、token consent(一次性短时同意码)
- test(http): verify:mcp:http 合法 PKCE 路径更新为预注册+同意码,不回归
- test(oauth): verify:mcp:oauth 修复后 1–8 全绿并接入 CI build-test-lint

对應 goal-v0.1.md G6.3 補丁與 project-status.md D45。
@Windsander
Windsander merged commit 1bc5960 into main Sep 14, 2026
4 checks passed
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