Skip to content

fix: validate datapack update filenames and enforce path containment#3046

Merged
DotnetInstall merged 2 commits into
devfrom
codex/fix-path-traversal-vulnerability-in-datapack-updates
Jun 12, 2026
Merged

fix: validate datapack update filenames and enforce path containment#3046
DotnetInstall merged 2 commits into
devfrom
codex/fix-path-traversal-vulnerability-in-datapack-updates

Conversation

@lhx077

@lhx077 lhx077 commented Jun 6, 2026

Copy link
Copy Markdown
Member

Motivation

  • Prevent a path-traversal / arbitrary file write vulnerability where remote update metadata FileName was concatenated into temporary and datapacks destinations without sanitization or containment checks.
  • Ensure datapack update flow only downloads and moves files that resolve to safe filenames inside the expected directories.

Description

  • Added TryGetSafeDatapackUpdateFileName to validate remote CompFile.FileName is non-empty, ends with .zip, contains no path separators/invalid characters and is a plain filename (no ./..).
  • Added TryBuildDatapackUpdatePath to build full paths with Path.GetFullPath and verify the destination is contained inside the intended root directory before using it.
  • Reworked UpdateResource in PageInstanceSavesDatapack.xaml.cs to skip unsafe entries, log/notify skips, and only queue downloads and delete/replace files for entries that passed validation; updated download progress weighting to count only validated entries.
  • Added null-safe trimming for filenames and used Path.Combine/full-path checks when constructing temporary and final paths.

Testing

  • Ran git diff --check to detect whitespace/merge issues (passed).
  • Attempted dotnet build 'Plain Craft Launcher 2/Plain Craft Launcher 2.csproj' -c CI --no-restore, but the environment is missing dotnet so a full build could not be executed.

Codex Task

Summary by Sourcery

验证数据包更新文件名,并确保更新路径保持在预期目录内,以防止在数据包更新过程中发生不安全的文件写入。

Bug Fixes:

  • 通过拒绝不安全的更新文件名并验证目标路径是否包含在临时目录和数据包目录内,防止在数据包更新流程中出现路径遍历和任意文件写入问题。

Enhancements:

  • 跳过不安全的数据包更新条目,同时记录日志并通知用户这些被跳过的文件,并调整下载进度权重,使其只考虑已验证的更新条目。
Original summary in English

Summary by Sourcery

Validate datapack update filenames and ensure update paths remain within the expected directories to prevent unsafe file writes during the datapack update process.

Bug Fixes:

  • Prevent a path traversal and arbitrary file write issue in the datapack update flow by rejecting unsafe update filenames and verifying destination paths are contained within the temp and datapacks directories.

Enhancements:

  • Skip unsafe datapack update entries while logging and notifying users about skipped files, and adjust download progress weighting to account only for validated update entries.

@lhx077 lhx077 added the aardvark label Jun 6, 2026
@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

审阅者指南

在 datapack 更新流程中新增文件名校验和路径包含性检查,以防止路径遍历;并重构更新逻辑,仅对已验证的条目进行操作,同时相应调整进度统计与用户反馈。

经过校验的 datapack 更新流程图

flowchart TD
    Start([UpdateResource called]) --> Init[Initialize fileList, fileCopyList, updateEntryList, tempRoot, datapackRoot, skippedUnsafeFileCount]

    Init --> ForEachEntry{{For each Entry in datapackList}}

    ForEachEntry --> CheckAvailable{Entry.UpdateFile.Available}
    CheckAvailable -- No --> ForEachEntry
    CheckAvailable -- Yes --> ValidateFileName[TryGetSafeDatapackUpdateFileName]

    ValidateFileName -- Fail --> IncSkip[Increment skippedUnsafeFileCount and log]
    IncSkip --> ForEachEntry

    ValidateFileName -- Pass --> BuildTemp[TryBuildDatapackUpdatePath with tempRoot]
    BuildTemp -- Fail --> IncSkip
    BuildTemp -- Pass --> BuildReal[TryBuildDatapackUpdatePath with datapackRoot]
    BuildReal -- Fail --> IncSkip

    BuildReal -- Pass --> QueueUpdate[Add to fileList, fileCopyList, updateEntryList]
    QueueUpdate --> ForEachEntry

    ForEachEntry --> AfterLoop[After loop]

    AfterLoop --> CheckSkipped{skippedUnsafeFileCount > 0}
    CheckSkipped -- Yes --> ShowHint[ModMain.Hint about skipped unsafe filenames]
    CheckSkipped -- No --> CheckFiles

    ShowHint --> CheckFiles{fileList.Any}
    CheckFiles -- No --> EndReturn[Return]
    CheckFiles -- Yes --> CreateLoaders[Create LoaderDownload and LoaderTask]

    CreateLoaders --> SetWeight[Set ProgressWeight = updateEntryList.Count * 1.5]
    SetWeight --> ReplaceFiles[LoaderTask deletes old files for updateEntryList]
    ReplaceFiles --> End[End]
Loading

文件级更改

Change Details Files
为 datapack 更新文件名和目标路径引入严格的校验辅助方法,以防止路径遍历和无效文件写入。
  • 新增 TryGetSafeDatapackUpdateFileName,强制仅接受非空 .zip 文件名,且不允许路径分隔符、非法字符,或 ... 等相对路径片段。
  • 新增 TryBuildDatapackUpdatePath,在指定根目录下构建完整路径,并通过完整路径包含性检查验证其仍位于该根目录之内。
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs
重构 datapack 的 UpdateResource 流程,以使用已验证的文件名/路径,跳过不安全条目,并仅基于安全的更新目标进行进度统计和文件操作。
  • 预先计算临时目录和 datapack 根目录,使用新的校验辅助方法为每个更新条目构建安全的临时路径和最终路径。
  • 统计并记录被跳过的不安全文件名,显示包含被跳过文件数量的严重提示;如果没有剩余安全文件可处理,则提前终止。
  • 将已验证条目累积到 updateEntryList 中,用其大小设置下载 Loader 的 ProgressWeight,并将删除/替换操作限制在该过滤后的列表中,而非原始的 datapackList
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.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 filename validation and path containment checks to the datapack update flow to prevent path traversal, and refactors the update logic to operate only on validated entries while adjusting progress accounting and user feedback accordingly.

Flow diagram for validated datapack update process

flowchart TD
    Start([UpdateResource called]) --> Init[Initialize fileList, fileCopyList, updateEntryList, tempRoot, datapackRoot, skippedUnsafeFileCount]

    Init --> ForEachEntry{{For each Entry in datapackList}}

    ForEachEntry --> CheckAvailable{Entry.UpdateFile.Available}
    CheckAvailable -- No --> ForEachEntry
    CheckAvailable -- Yes --> ValidateFileName[TryGetSafeDatapackUpdateFileName]

    ValidateFileName -- Fail --> IncSkip[Increment skippedUnsafeFileCount and log]
    IncSkip --> ForEachEntry

    ValidateFileName -- Pass --> BuildTemp[TryBuildDatapackUpdatePath with tempRoot]
    BuildTemp -- Fail --> IncSkip
    BuildTemp -- Pass --> BuildReal[TryBuildDatapackUpdatePath with datapackRoot]
    BuildReal -- Fail --> IncSkip

    BuildReal -- Pass --> QueueUpdate[Add to fileList, fileCopyList, updateEntryList]
    QueueUpdate --> ForEachEntry

    ForEachEntry --> AfterLoop[After loop]

    AfterLoop --> CheckSkipped{skippedUnsafeFileCount > 0}
    CheckSkipped -- Yes --> ShowHint[ModMain.Hint about skipped unsafe filenames]
    CheckSkipped -- No --> CheckFiles

    ShowHint --> CheckFiles{fileList.Any}
    CheckFiles -- No --> EndReturn[Return]
    CheckFiles -- Yes --> CreateLoaders[Create LoaderDownload and LoaderTask]

    CreateLoaders --> SetWeight[Set ProgressWeight = updateEntryList.Count * 1.5]
    SetWeight --> ReplaceFiles[LoaderTask deletes old files for updateEntryList]
    ReplaceFiles --> End[End]
Loading

File-Level Changes

Change Details Files
Introduce strict validation helpers for datapack update filenames and destination paths to prevent path traversal and invalid file writes.
  • Add TryGetSafeDatapackUpdateFileName to enforce non-empty .zip filenames without path separators, invalid characters, or relative segments like '.' and '..'.
  • Add TryBuildDatapackUpdatePath to construct full paths under a specified root and verify they remain within that root via full-path containment checks.
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs
Refactor datapack UpdateResource flow to use validated filenames/paths, skip unsafe entries, and base progress and file operations only on safe update targets.
  • Precompute temp and datapack root directories and use the new validation helpers to build safe temp and final paths for each update entry.
  • Track and log skipped unsafe filenames, show a critical hint with the count of skipped files, and abort early if no safe files remain to process.
  • Accumulate validated entries into updateEntryList, use it to size download loader ProgressWeight, and limit delete/replace operations to this filtered list instead of the original datapackList.
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.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.

嗨——我已经审查了你的更改,一切看起来都很棒!


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

Hey - I've reviewed your changes and they look great!


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: a2dc12259e

ℹ️ 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".

@lhx077 lhx077 force-pushed the codex/fix-path-traversal-vulnerability-in-datapack-updates branch from a2dc122 to d2bbb00 Compare June 12, 2026 08:57
@pcl-ce-automation pcl-ce-automation Bot added 🕑 等待合并 已处理完毕,正在等待代码合并入主分支 and removed 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 labels Jun 12, 2026
@DotnetInstall DotnetInstall merged commit 9c8b8a7 into dev Jun 12, 2026
2 checks passed
@pcl-ce-automation pcl-ce-automation Bot added 👌 完成 相关问题已修复或功能已实现,计划在下次版本更新时正式上线 and removed 🕑 等待合并 已处理完毕,正在等待代码合并入主分支 labels Jun 12, 2026
@DotnetInstall DotnetInstall deleted the codex/fix-path-traversal-vulnerability-in-datapack-updates branch June 12, 2026 09:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: M PR 大小评估:中型 👌 完成 相关问题已修复或功能已实现,计划在下次版本更新时正式上线

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants