[Bug] SafePath 误拦截 Roundcube/ACME 公共路由,普通用户必须先访问管理员入口
Author: zhoushun98Created Aug 22, 2026Updated Aug 28, 2026
Operating System
Linux
OS Version
Debian GNU/Linux 12
System Architecture
x86_64
Docker Version
Docker version 29.2.0, build 0b9d198
Docker Compose Version
Docker Compose version v5.0.2
Reproducible in Latest Version?
Yes, occurs in the latest stable release (billionmail/core:4.9.3)
Reproduction Steps
- 安装 BillionMail,并在
.env中配置非空的SafePath,例如AdminSecretPath。 - 使用全新的无痕窗口直接访问
https://mail.example.com/roundcube或/roundcube/。 - 页面返回
404 Not Found。 - 在同一浏览器中先访问
https://mail.example.com/AdminSecretPath。 - 再访问
/roundcube,此时返回 200,Roundcube 登录页可以正常打开。
Observed Behavior
- Roundcube 是普通邮箱用户的公开 Webmail 登录入口,却依赖管理员
SafePath设置的safe_path_pass会话标记。 - 普通邮箱用户因此必须知道管理员安全入口;无痕窗口、不同浏览器或会话过期后都会再次遇到 404。
/.well-known/acme-challenge/*也被同一检查提前拦截,内置 HTTP-01 申请/续期会收到 404。- 返回发生在 Roundcube 和 ACME handler 之前,因此与 Roundcube、PHP-FPM、证书或 DNS 本身无关。
Expected Behavior
/roundcube、/roundcube/及其子路径应直接进入 Roundcube 自身的登录和会话机制。- 访问 Roundcube 不应设置或绕过管理员的
safe_path_pass;其他管理路径仍应返回 404。 /.well-known/acme-challenge/应允许匿名访问,以便 HTTP-01 验证。- 管理后台的其他路径仍必须先访问配置的
SafePath。
Supplemental Information
根因位于全局 HookBeforeServe:只有精确命中的 excludesURIs 和静态文件被放行,其他动态路由全部要求 safe_path_pass。
相关代码:
最小修复示例:
_, isExcludedURI := excludesURIs[r.URL.Path]
isRoundcubeURI := r.URL.Path == "/roundcube" ||
strings.HasPrefix(r.URL.Path, "/roundcube/")
isACMEChallengeURI := strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge/")
if isExcludedURI || isRoundcubeURI || isACMEChallengeURI {
return
}本地基于官方 4.9.3 对应源码验证:
- 全新会话访问
/roundcube:200 - Roundcube 设置 cookie 后访问
/overview:仍为 404 - 管理员
SafePath:仍正常工作 - HTTPS/SMTP/IMAP 服务不受影响
gofmt、go vet ./...与短测试通过
关联问题:#61、#338、#30。
Source: Billionmail/BillionMail