OpenProject 17.1.1 发布解析:9 项安全漏洞修复、越权与路径穿越原理及升级建议
【免费下载链接】openprojectOpenProject is the leading open source project management software for product, project and portfolio management. A powerful Jira alternative with agile planning, issue tracking, roadmaps, Gantt charts, time tracking, collaboration features, and more. Available on premises or in the cloud. ⭐ Star us on GitHub项目地址: https://gitcode.com/GitHub_Trending/op/openproject
本文基于 OpenProject 17.1.1 发布说明 撰写,结合仓库源码(API v3 端点、Costs 模块控制器、BIM/BCF 模块等)深度解析本次补丁修复的安全漏洞成因、受影响端点与修复思路,并给出升级建议。阅读本文后,你将掌握 17.1.1 的完整变更清单、每个 CVE 的攻击路径与修复要点,并能据此评估自身实例的暴露面与升级优先级。
OpenProject 于 2026-02-18 发布了 17.1.1 版本。这是一个以安全修复为主的补丁版本:共修复 9 个 CVE 安全漏洞(含 2 个可导致远程代码执行 RCE 的路径穿越漏洞),以及 7 个功能 Bug。官方在发布说明中明确建议所有用户升级到最新版本。本文以该发布说明为主体,逐项拆解每个漏洞的技术细节,并深入对应源码位置,帮助运维人员与开发者理解问题本质、做好升级与自查。
版本概览
| 项目 | 内容 |
|---|---|
| 版本号 | 17.1.1 |
| 发布日期 | 2026-02-18 |
| 发布类型 | 安全补丁(Bugfix + Security) |
| 安全漏洞 | 9 个 CVE(含 2 个可致 RCE 的路径穿越) |
| 功能 Bug 修复 | 7 个 |
| 官方建议 | 强烈建议升级到最新版本 |
官方版本跟踪链接:OpenProject 17.1.1 版本页。以下漏洞大多由社区安全研究员通过 YesWeHack.com OpenProject Bug Bounty 赏金计划 报告,该计划由欧盟委员会(European Commission)赞助。
一、Security fixes:9 个 CVE 深度解析
1. CVE-2026-26966:/api/v3/queriesPOST 越权创建项目查询(Improper Access Control)
漏洞描述:/api/v3/queries端点存在失效的访问控制,允许普通已认证用户在没有足够权限的情况下创建私有项目查询(private project queries)。
攻击方式:攻击者复用管理员生成的有效请求,将请求中的 session cookie 与 CSRF token 替换为低权限用户的对应凭据后重放,后端仍会接受该请求并成功创建查询。该操作本应仅限具备相应角色的授权用户执行,暴露了查询创建流程中缺失或不充分的授权检查。
源码印证:查询 API 定义于 queries_api.rb。可以看到:
post &::API::V3::Utilities::Endpoints::Create.new(model: Query).mount(L100-L102)直接挂载了通用的 Create 端点;- 而
route_param :id下的get、patch、delete等操作均通过authorize_by_policy(:show)、authorize_by_policy(:update)、authorize_by_policy(:destroy)做了基于QueryPolicy的授权(L104-L146); - 对比可见,POST 创建路径缺少与之对等的策略级授权校验,这正是越权创建查询的根源。17.1.1 的修复方向即在创建端点补充权限检查。
自查与加固:升级后可用低权限账号向/api/v3/queries发起 POST 尝试创建私有查询,验证是否被拒绝;同时建议审计是否存在管理员与低权限用户共享会话环境的代理/网关配置。
2. CVE-2026-26968:/api/v3/capabilities未授权枚举私有项目信息
漏洞描述:/api/v3/capabilities端点允许通过将 principal 指定为内置管理员用户 ID,未授权枚举私有项目名称与详细权限信息。虽然 API 正确阻止了查询其他用户的 capabilities,但内置 Admin 账号仍可被解析(resolvable)。
危害放大:由于项目使用递增的整型 ID,且内置管理员对所有项目可见,攻击者可借此测绘(mapping)整个 OpenProject 实例:遍历 ID 即可获得全部(含私有)项目清单及其权限结构,为后续针对性攻击提供情报。
源码印证:Capabilities API 定义于 capabilities_api.rb,其列表与详情分别挂载SqlIndex与SqlShow端点(L33-L49)。问题在于 principal 解析逻辑对内置管理员未做与普通用户同等的隔离,导致权限校验被绕过。
自查与加固:升级后以低权限用户请求/api/v3/capabilities?filters=[{"principal":{"operator":"=","values":["1"]}}](1 为内置 admin 常见 ID),确认返回 403/空结果而非项目数据。此外可结合部署层限制 API 的匿名/低权限访问。
3. CVE-2026-26969:项目名称 HTML 注入
漏洞描述:应用对项目名称这一用户输入未做充分清洗(improper sanitization),攻击者可在项目名中注入任意 HTML 标签,改变页面结构;后续创建工作包(work package)时 payload 被执行。
影响:属于存储型 HTML 注入,可造成页面篡改、内容伪造;若结合浏览器特性或与其他漏洞组合,可能进一步升级为 XSS 类攻击。
修复要点:在项目名称写入与渲染链路中补充输出编码/白名单清洗。升级后建议创建含<script>、<img onerror=...>等项目名进行回归验证,确认前端与 API 返回均为转义文本。
4. CVE-2026-26970:Wiki 更新邮件中的 HTML 注入(wiki updated mailer)
漏洞描述:wiki 更新邮件发送功能未正确转义 HTML 标签。攻击路径为:
- 攻击者(或注册开放时任何用户)在用户名中携带 HTML 标签;
- 获得 wiki 页面新增/编辑权限后,其作者标签(author tag)在邮件中未转义,注入 HTML。
影响:邮件客户端中可呈现恶意 HTML,造成钓鱼、内容伪造或(在宽松邮件客户端下)类 XSS 行为。
修复要点:在邮件模板渲染用户名/作者信息处强制 HTML 转义。升级后可通过构造特殊用户名并触发 wiki 更新邮件来验证。
5. CVE-2026-26971:Hourly Rates 控制器 IDOR —— 跨项目删除小时费率
漏洞描述:Costs 模块中,一个按项目限定(project-scoped)的小时费率更新端点,通过发送省略 user 参数的构造请求,即可删除目标用户在所有项目中的小时费率。
根因:请求仅针对 URL 中的项目(:project_id)做授权,但删除查询并未按该项目作用域限定,造成跨项目失效的访问控制(水平越权,horizontal privilege escalation)。
源码印证:控制器位于 hourly_rates_controller.rb。关键在update动作:当params中不含"user"时走delete_rates分支(L96-L103),而delete_rates的实现为:
def delete_rates(user, project) if project.present? user.rates.where(project:).delete_all else user.default_rates.delete_all end end从源码结构看,该方法接受的是控制器内部解析出的@project与@user,而find_user中params[:id].blank?时回退为User.current(L146-L153)。若请求省略 user 参数,删除目标即从当前用户演变为可通过@project解析的其他用户,且删除范围若未严格限定于当前项目,便会波及该用户在所有项目下的费率。这正是 17.1.1 修复的作用域校验点。
自查与加固:升级后,使用具有某项目edit_hourly_rates权限的低权限账号,构造省略user参数的 update 请求,确认删除操作被拒绝或严格限制在本项目内。
6. CVE-2026-26976:注册邮箱字段 HTML 注入,向实例所有者发送恶意通知邮件
漏洞描述:当启用匿名注册时,未认证攻击者可在注册流程(/account/register)的邮箱字段提交恶意 payload。即使注册因免费版 10 活跃用户上限失败,系统仍会向实例所有者/管理员发送"用户数已达上限"的通知邮件,且该邮件未转义地回显了恶意邮箱 payload(body/subject/content 均可注入 HTML)。
影响:钓鱼、内容伪造,在宽松邮件客户端下可能产生管理员收件箱中的类 XSS 行为。
源码印证:用户上限逻辑位于 enterprise_token.rb(活跃用户数限制相关校验)。问题本质是通知邮件的渲染链路缺少对用户可控字段的输出编码。
自查与加固:升级后以攻击性邮箱字符串(如a"<img src=x onerror=...>"@example.com)触发一次注册尝试,检查管理员收到的限额通知邮件是否原样输出未转义内容。
7. CVE-2026-27006:BIM 版 BCF 模块路径穿越 —— 任意文件上传,可致 RCE
漏洞描述:BIM 版本中,具备 BCF 模块访问权限的已认证攻击者,可利用 BCF 导入功能的路径穿越漏洞,向服务器上任意可写目录写入任意文件。对基于 docker-compose 的部署,可进一步利用缓存反序列化(cache deserialization)扩展为远程代码执行(RCE)。
技术背景:BCF(BIM Collaboration Format)是 BIM 领域的协作格式,OpenProject BIM 版通过 BCF 导入功能解析外部 BCF 文件包(zip 结构)。问题在于解包/落盘时未对条目路径做规范化校验,允许../等穿越序列逃逸目标目录。相关代码分布于 modules/bim/app/controllers/bim/bcf/issues_controller.rb、modules/bim/app/models/bim/bcf/issue.rb 以及 bcf_xml_seeder.rb 等导入链路。
修复要点:对 BCF 压缩包内每个条目执行路径规范化(resolve + 前缀校验),拒绝含穿越序列的条目;同时对文件落盘目录与缓存目录实施最小权限。BIM/BCF 用户应优先升级。
8. CVE-2026-27019:入站邮件附件路径穿越 —— 任意文件写入与 RCE
漏洞描述:当 OpenProject 配置为接收并处理入站邮件时,攻击者可发送携带特制附件的邮件,附件被写入文件系统预定义位置之外的任意路径。凡是openproject系统用户可写的位置均受影响,并可升级为远程代码执行。
影响面:启用邮件接收(mail-in / incoming email handler)的实例直接暴露。该功能常见于"邮件创建/回复工作包"场景。
修复要点:对入站邮件附件的存储路径做严格规范化与白名单约束,确保文件名/路径不可穿越附件存储根目录;同时建议以最小权限运行openproject系统用户、对附件目录启用强制访问控制。
9. 安全修复小结表
| CVE | 类型 | 受影响模块/端点 | 攻击者前提 | 最坏影响 |
|---|---|---|---|---|
| CVE-2026-26966 | 越权访问控制 | /api/v3/queriesPOST | 低权限已认证用户 | 未授权创建私有项目查询 |
| CVE-2026-26968 | 越权访问控制 | /api/v3/capabilities | 低权限已认证用户 | 枚举私有项目/实例测绘 |
| CVE-2026-26969 | HTML 注入 | 项目名称 | 可创建/编辑项目的用户 | 存储型页面篡改,工作包创建时执行 |
| CVE-2026-26970 | HTML 注入 | Wiki 更新邮件 | 可编辑 wiki 的用户 | 邮件内容伪造/钓鱼 |
| CVE-2026-26971 | IDOR 水平越权 | Costs 小时费率控制器 | 具项目费率编辑权限的用户 | 跨项目删除他人小时费率 |
| CVE-2026-26976 | HTML 注入 | /account/register通知邮件 | 未认证(注册开放时) | 向管理员投递恶意邮件 |
| CVE-2026-27006 | 路径穿越 → 任意文件写 → RCE | BIM/BCF 导入 | BCF 模块已认证用户 | 任意文件写入,docker-compose 下 RCE |
| CVE-2026-27019 | 路径穿越 → 任意文件写 → RCE | 入站邮件附件 | 可向实例发送邮件的攻击者 | 任意文件写入,可升级 RCE |
(注:上述 9 个 CVE 中的第 9 项信息请以官方 GitHub Advisory 为准,完整公告见发布说明中对应链接。)
二、Bug fixes:7 个功能修复清单
17.1.1 同时修复了 7 个功能 Bug,覆盖前端、国际化、文档模块、邮件链接、导出与管理员安全边界:
| 问题类型 | 描述 |
|---|---|
| Bugfix | Documents 模块:iOS 上缩放问题(#71023) |
| Bugfix | 简体中文(zh-TW)环境的 Seeding 失败(#71869) |
| Bugfix | 每次 OpenProject 更新后,默认文档类型被重复创建(#71877) |
| Bugfix | 通知邮件中的外部链接未被捕获(#71907) |
| Bugfix | 路径中含编码空格的外部链接跳转到 OpenProject 首页(#71931) |
| Bugfix | 封面图片文件存储损坏时,会议 PDF 导出报错(#71945) |
| Bugfix | 最后一个管理员可以删除自己(#71980) |
其中值得关注的两项:
- 最后一个管理员自删(#71980):这是典型的管理员锁死问题——若实例仅剩一个管理员账号且可被删除,将导致实例失去管理入口。该修复通常会在删除操作前校验管理员数量下限;
- zh-TW seeding 失败(#71869):影响
db:seed及安装向导在新语言环境下的初始化流程,关系到 db/seeds.rb 与各语言 locale 文件的完整性。
三、升级建议与自查清单
升级优先级评估
结合漏洞危害与利用前提,建议按以下优先级安排升级:
- 立即升级:启用入站邮件处理(CVE-2026-27019)、使用 BIM 版并开放 BCF(CVE-2026-27006)的实例,两者均可能导向 RCE;
- 尽快升级:开放匿名注册的实例(CVE-2026-26976)、多租户/多项目共用实例(CVE-2026-26966、CVE-2026-26968、CVE-2026-26971);
- 随常规升级窗口处理:其余 HTML 注入类漏洞(CVE-2026-26969、CVE-2026-26970)。
升级后回归验证清单
- 以低权限账号分别尝试 POST
/api/v3/queries与查询/api/v3/capabilities,确认越权路径已封闭; - 创建含 HTML 标签的项目名与用户名,检查页面渲染与 Wiki/注册通知邮件均为转义输出;
- 在 Costs 模块中构造省略
user参数的费率更新请求,确认删除被限制于当前项目; - BIM 实例导入含
../路径条目的 BCF 文件,确认被拒绝; - 入站邮件功能实例发送含特制文件名的附件,确认落盘路径被限制在附件根目录内。
四、致谢与参考
OpenProject 官方在发布说明中对社区成员 Andreas H. 及所有提交 Bug 报告的社区成员表达了感谢。本版本的安全漏洞主要由 YesWeHack.com 赏金计划研究员发现与报告,包括 slashx0x、syndrome_impostor、noidont、roro1702、yokokho、sam91281、pdowski、shafouzzz 等。
延伸阅读(仓库内)
- 发布说明原文:docs/release-notes/17-1-1/README.md
- 查询 API 实现:lib/api/v3/queries/queries_api.rb
- Capabilities API 实现:lib/api/v3/capabilities/capabilities_api.rb
- 小时费率控制器:modules/costs/app/controllers/hourly_rates_controller.rb
- 用户上限校验:app/models/enterprise_token.rb
- BIM/BCF 导入链路:modules/bim/app/controllers/bim/bcf/issues_controller.rb、modules/bim/app/models/bim/bcf/issue.rb
【免费下载链接】openprojectOpenProject is the leading open source project management software for product, project and portfolio management. A powerful Jira alternative with agile planning, issue tracking, roadmaps, Gantt charts, time tracking, collaboration features, and more. Available on premises or in the cloud. ⭐ Star us on GitHub项目地址: https://gitcode.com/GitHub_Trending/op/openproject
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考