Skip to content

Reject diff manifest patch paths outside __hcp_patches/ - #66

Merged
ofalvai merged 1 commit into
masterfrom
push-rtklrwwnpxxu
Sep 24, 2026
Merged

ofalvai merged 1 commit into
masterfrom
push-rtklrwwnpxxu

Conversation

@ofalvai

@ofalvai ofalvai commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Why

The server puts every bsdiff patch file in a reserved __hcp_patches/ folder of the update ZIP. The install flow already depends on this. After patching, it removes that folder from the new package. Until now, nothing checked that the patch paths in a diff manifest actually point into that folder.

What

  • Manifest parsers (iOS + Android) reject a patchedFiles entry whose patch value does not start with __hcp_patches/. The error names the entry and the expected prefix.
  • Android resolveWithin rejects a path that resolves to the base folder itself, for example __hcp_patches/... iOS already did this, so the two platforms now agree.

Decisions

  • The prefix is a format contract, not a security boundary, so the path prefix is only enforced at the manifest parsing phase. Every file under unzipped/ comes from the ZIP. A patch path that leaves __hcp_patches/ but stays inside unzipped/ can only read bytes that the ZIP could also have put under the prefix. The real protection is still the existing containment check against unzipped/, plus the folder hash and signature checks. My first version also enforced the subfolder in the patchers. I removed it, because it needed a new iOS API and symlink handling and it did not make the install any safer.

Out of scope

  • A manifest without the prefix now fails the update. There is no fallback at the moment. It is planned to have a generic fallback logic that runs the non-delta-update flow in case of any error in the delta update flow, but that's outside the scope of this PR.
  • The parsers do not reject patchedFiles keys or deletedFiles entries that point inside __hcp_patches/. This only happens if an app ships its own folder with that name, and the server should reject such a release.

🤖 Generated with Claude Code

manifestFromJSON: (iOS) and parseDiffManifest (Android) validated only
that `patch` was a non-empty string, not that it stayed under the
reserved patches folder prefix. A manifest pointing `patch` elsewhere
left a stray file behind after install (the cleanup step only deletes
__hcp_patches by name), which verifyFolderHash still caught, but as a
generic integrity-check failure instead of a clear manifest error.

RA-4925

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings September 23, 2026 12:38

Copilot AI 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.

Copilot review overview

🟢 Approval recommended

The validation is consistent across platforms and adequately covered by focused tests.

Review effort: Balanced
Findings: None

What changed in this PR

Validates binary-diff patch paths against the reserved patch folder and aligns Android path containment with iOS.

Changes:

  • Rejects manifest patch paths lacking the __hcp_patches/ prefix.
  • Shares the iOS patch-folder constant.
  • Prevents Android paths from resolving to the base directory itself.
File Description
ios/​CodePushTests/​CodePushDiffManifestTests.swift Tests invalid patch prefixes.
ios/​CodePush/​CodePushPackage.m Uses the shared folder constant.
ios/​CodePush/​CodePushDiffManifest.m Adds prefix validation and shared constant.
ios/​CodePush/​CodePushDiffManifest.h Declares the shared constant.
android/​app/​src/​test/​java/​com/​microsoft/​codepush/​react/​diffpatch/​DiffManifestTest.kt Tests parser rejection behavior.
android/​app/​src/​test/​java/​com/​microsoft/​codepush/​react/​diffpatch/​BinaryDiffPatcherTest.kt Tests base-directory resolution rejection.
android/​app/​src/​main/​java/​com/​microsoft/​codepush/​react/​diffpatch/​DiffManifest.kt Validates the reserved prefix.
android/​app/​src/​main/​java/​com/​microsoft/​codepush/​react/​diffpatch/​BinaryDiffPatcher.kt Tightens containment validation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ofalvai
ofalvai merged commit 5e77599 into master Sep 24, 2026
7 checks passed
@ofalvai
ofalvai deleted the push-rtklrwwnpxxu branch September 24, 2026 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants