Skip to content

fix(download): 限制依赖库下载路径#3035

Open
lhx077 wants to merge 1 commit into
devfrom
codex/propose-fix-for-library-path-vulnerability
Open

fix(download): 限制依赖库下载路径#3035
lhx077 wants to merge 1 commit into
devfrom
codex/propose-fix-for-library-path-vulnerability

Conversation

@lhx077

@lhx077 lhx077 commented Jun 6, 2026

Copy link
Copy Markdown
Member

Motivation

  • Prevent attacker-controlled downloads.*.path values from escaping the intended libraries folder and enabling arbitrary file writes.
  • Close a regression where deep-cloned MultiMC/LiteLoader library metadata reached the downloader without canonicalization or containment checks.

Description

  • Added a helper McLibGetSafeDownloadPath(customMcFolder, JsonNode) that normalizes the metadata path, rejects absolute/drive/UNC paths and .. traversal, and verifies the resolved path is inside customMcFolder\libraries using Files.IsPathWithinDirectory.
  • Replaced direct Path.Combine(customMcFolder, "libraries", ...) usages for artifact and native-classifier paths with McLibGetSafeDownloadPath and added using PCL.Core.IO to the file.
  • The helper throws IOException for invalid or escaping paths to stop processing untrusted metadata.
  • Existing behavior for entries without a metadata path is preserved by keeping the McLibGet fallback.

Testing

  • Ran git diff --check and it completed without whitespace/format errors.
  • Attempted dotnet --info to run build/tests but dotnet is not available in the execution environment, so compile-time tests were not run.

Codex Task

由 Sourcery 提供的摘要

加强对 Minecraft 库下载的处理,防止不安全的元数据路径逃离预期的 libraries 目录。

错误修复:

  • 防止由攻击者控制的库下载路径通过元数据逃离 Minecraft 的 libraries 文件夹,从而实现任意文件写入。

功能改进:

  • 引入集中式辅助工具,在解析本地下载位置之前,用于验证和规范库元数据路径。
Original summary in English

Summary by Sourcery

Harden Minecraft library download handling to prevent unsafe metadata paths from escaping the intended libraries directory.

Bug Fixes:

  • Prevent attacker-controlled library download paths in metadata from escaping the Minecraft libraries folder and enabling arbitrary file writes.

Enhancements:

  • Introduce a centralized helper to validate and normalize library metadata paths before resolving their local download location.

@pcl-ce-automation pcl-ce-automation Bot added 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 size: M PR 大小评估:中型 and removed codex labels Jun 6, 2026
@sourcery-ai

sourcery-ai Bot commented Jun 6, 2026

Copy link
Copy Markdown

审阅者指南

添加了一个强化的辅助方法,用于解析库下载路径,并将其接入 Minecraft 的库下载代码中,以防止路径遍历以及逃逸出预期的 libraries 目录。

文件级变更

变更 详情 文件
引入一个安全的库下载路径解析辅助方法,强制要求解析结果必须包含在 libraries 文件夹内。
  • 添加 McLibGetSafeDownloadPath(customMcFolder, JsonNode),该方法会规范化斜杠、拒绝根路径/盘符路径/UNC 路径以及包含 '..' 的路径遍历,并在 customMcFolder\libraries 下解析出完整路径。
  • 使用 Files.IsPathWithinDirectory 确保解析后的路径仍在 libraries 目录内,当验证失败时抛出 IOException。
  • 在摘要注释中为该辅助方法编写文档,以澄清其目的和行为。
Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.cs
用安全辅助方法替换用于 artifact 和 native classifier 下载的直接路径拼接。
  • 更新 artifact 下载的 LocalPath 初始化逻辑:在有 metadata 路径时改为委托给 McLibGetSafeDownloadPath,并在缺少 metadata 路径时保留现有的 McLibGet 回退行为。
  • 更新 natives-windows classifier 下载路径的构造逻辑:使用 McLibGetSafeDownloadPath 替代手动组合和规范化路径。
  • 添加 using PCL.Core.IO 指令,以支持 Files.IsPathWithinDirectory 的使用。
Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.cs

提示与命令

与 Sourcery 交互

  • 触发一次新的审阅: 在 Pull Request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub Issue: 通过回复审阅评论请求 Sourcery 从该评论创建一个 Issue。你也可以在审阅评论中回复 @sourcery-ai issue 来从该评论创建 Issue。
  • 生成 Pull Request 标题: 在 Pull Request 标题的任意位置写上 @sourcery-ai,即可随时生成标题。你也可以在 Pull Request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 Pull Request 概要: 在 Pull Request 正文的任意位置写上 @sourcery-ai summary,即可在你想要的位置生成 PR 概要。你也可以在 Pull Request 中评论 @sourcery-ai summary 来在任意时间(重新)生成概要。
  • 生成审阅者指南: 在 Pull Request 中评论 @sourcery-ai guide,即可在任意时间(重新)生成审阅者指南。
  • 批量解决所有 Sourcery 评论: 在 Pull Request 中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,这会非常有用。
  • 批量忽略所有 Sourcery 审阅: 在 Pull Request 中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审阅。若你想从一次全新的审阅开始,这尤其有用——别忘了再评论 @sourcery-ai review 来触发新的审阅!

自定义你的使用体验

前往你的 控制面板 以:

  • 启用或禁用审阅功能,例如 Sourcery 自动生成的 Pull Request 概要、审阅者指南等。
  • 更改审阅语言。
  • 添加、移除或编辑自定义审阅指令。
  • 调整其他审阅相关设置。

获取帮助

Original review guide in English

Reviewer's Guide

Adds a hardened helper for resolving library download paths and wires it into Minecraft library download code to prevent path traversal and escaping the intended libraries directory.

File-Level Changes

Change Details Files
Introduce a safe helper for resolving library download paths that enforces containment within the libraries folder.
  • Add McLibGetSafeDownloadPath(customMcFolder, JsonNode) that normalizes slashes, rejects rooted/drive/UNC paths and '..' traversal, and resolves a full path under customMcFolder\libraries.
  • Use Files.IsPathWithinDirectory to ensure the resolved path stays within the libraries directory and throw IOException when validation fails.
  • Document the helper in a summary comment to clarify its purpose and behavior.
Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.cs
Replace direct path concatenation for artifact and native classifier downloads with the safe helper.
  • Update artifact download LocalPath initialization to delegate to McLibGetSafeDownloadPath when a metadata path is present while preserving the existing McLibGet fallback when it is absent.
  • Update natives-windows classifier download path construction to use McLibGetSafeDownloadPath instead of manually combining and normalizing the path.
  • Add a using PCL.Core.IO directive to enable Files.IsPathWithinDirectory usage.
Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.cs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我这边有一些整体性的反馈:

  • McLibGetSafeDownloadPath 中,Path.IsPathRooted 已经会拒绝驱动器盘符和 UNC 根路径,因此额外的 StartsWith("\") 和驱动器盘符正则检查看起来是多余的;建议简化这部分逻辑,只依赖 Path/Files 相关的辅助方法。
  • 你在分割路径前先把分隔符统一规范为反斜杠,然后再同时按 \/ 来 split;由于 / 已经被替换过了,split 可以简化为只按 \ 分割,或者在规范化之前就进行 split,以避免多余的分隔符处理。
  • 用于检测驱动器盘符的 Regex.IsMatch 在每次调用时都会执行;如果保留这一检查,建议改为简单的字符串判断,或者使用静态预编译的正则,以减少在热点路径上的开销。
面向 AI 代理的提示
Please address the comments from this code review:

## Overall Comments
- In `McLibGetSafeDownloadPath`, `Path.IsPathRooted` already rejects drive and UNC roots, so the extra `StartsWith("\")` and drive-letter regex checks look redundant; consider simplifying this logic to rely on `Path`/`Files` helpers only.
- You normalize to backslashes before splitting on both `\` and `/`; since `/` has already been replaced, the split can be simplified to just `\` or applied before normalization to avoid redundant separators.
- The `Regex.IsMatch` for drive letters is executed on every call; if you keep it, consider replacing it with a simple string check or a static precompiled regex to reduce overhead in hot paths.

Sourcery 对开源项目是免费的——如果你觉得我们的代码审查有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的审查。
Original comment in English

Hey - I've left some high level feedback:

  • In McLibGetSafeDownloadPath, Path.IsPathRooted already rejects drive and UNC roots, so the extra StartsWith("\") and drive-letter regex checks look redundant; consider simplifying this logic to rely on Path/Files helpers only.
  • You normalize to backslashes before splitting on both \ and /; since / has already been replaced, the split can be simplified to just \ or applied before normalization to avoid redundant separators.
  • The Regex.IsMatch for drive letters is executed on every call; if you keep it, consider replacing it with a simple string check or a static precompiled regex to reduce overhead in hot paths.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `McLibGetSafeDownloadPath`, `Path.IsPathRooted` already rejects drive and UNC roots, so the extra `StartsWith("\")` and drive-letter regex checks look redundant; consider simplifying this logic to rely on `Path`/`Files` helpers only.
- You normalize to backslashes before splitting on both `\` and `/`; since `/` has already been replaced, the split can be simplified to just `\` or applied before normalization to avoid redundant separators.
- The `Regex.IsMatch` for drive letters is executed on every call; if you keep it, consider replacing it with a simple string check or a static precompiled regex to reduce overhead in hot paths.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 872b249674

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

? McLibGet((string)library["name"], customMcFolder: customMcFolder)
: Path.Combine(customMcFolder, "libraries", library["downloads"]["artifact"]["path"].ToString()
.Replace("/", @"\")),
: McLibGetSafeDownloadPath(customMcFolder, library["downloads"]["artifact"]["path"]),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not swallow rejected artifact paths

When an untrusted manifest supplies a downloads.artifact.path that McLibGetSafeDownloadPath rejects, this call is still inside the broad try whose catch below adds a fallback token using localPath derived from the same manifest's name. That means rejected metadata does not stop processing; if the same library name contains traversal separators in its non-group fields, the downloader can still receive a path from McLibGet outside libraries, bypassing the new containment check. Let the IOException propagate or skip the library instead of falling back after a containment failure.

Useful? React with 👍 / 👎.

@SALTWOOD SALTWOOD changed the title fix: constrain library download paths fix(download): 限制依赖库下载路径 Jun 6, 2026

@whitecat346 whitecat346 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

使用源生成器版的正则匹配;
添加日志记录

@LinQingYuu LinQingYuu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

应避免在高频热点代码上抛出无关紧要的 Exception

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

Labels

size: M PR 大小评估:中型 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants