Skip to content

fix: prefix match for root check to empty folders in file driver - #1302

Merged
ferhatelmas merged 1 commit into
masterfrom
ferhat/prefix-root
Aug 5, 2026
Merged

fix: prefix match for root check to empty folders in file driver#1302
ferhatelmas merged 1 commit into
masterfrom
ferhat/prefix-root

Conversation

@ferhatelmas

Copy link
Copy Markdown
Member

What kind of change does this PR introduce?

Bug fix

What is the current behavior?

Empty check does prefix matching and it can match sibling directory.
It is guarded by resolve secure path so not exploitable as it is but error-prone if subclassed.

What is the new behavior?

Do cross platform relative check from the root.
This is just defense in depth.

Signed-off-by: ferhat elmas <elmas.ferhat@gmail.com>
@ferhatelmas
ferhatelmas requested a review from a team as a code owner August 5, 2026 15:11
Copilot AI review requested due to automatic review settings August 5, 2026 15:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens FileBackend’s empty-directory cleanup logic to avoid accidental deletions when a target path shares a prefix with the storage root (e.g., /tmp/root vs /tmp/root-sibling). It replaces a string prefix check with a cross-platform “is dirPath inside filePath?” check using path.relative, and adds a regression test to cover the sibling-directory case.

Changes:

  • Replace startsWith(storageRoot) directory-boundary logic with a path.relative-based containment check.
  • Prevent cleanup of the storage root itself and any directory outside the storage root.
  • Add a test ensuring sibling directories sharing a storage-root prefix are not removed.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/storage/backend/file.ts Uses path.relative() + ../absolute checks to ensure cleanup never escapes the storage root and never deletes the root itself.
src/storage/backend/file.test.ts Adds regression coverage for the sibling-prefix scenario and cleans up the created sibling directory in teardown.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@claude claude 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.

LGTM — this is a small, well-tested defense-in-depth fix.

Extended reasoning...

Overview

The PR changes cleanupEmptyDirectories in src/storage/backend/file.ts to replace a string-prefix check (dirPath.startsWith(this.filePath)) with a proper path.relative-based containment check, so that a sibling directory sharing the storage root as a string prefix (e.g. /data/storage vs /data/storage-sibling) is no longer misidentified as being inside the storage root. A new test case explicitly verifies the sibling-directory scenario is not cleaned up.

Security risks

As the PR description notes, this path is already gated by resolveSecureFilesystemPath for all real callers (deleteObject, deleteObjects, abortMultipartUpload), so dirPath passed into cleanupEmptyDirectories is always already confined to the storage root in current usage. This change is purely defense-in-depth for subclasses/future callers that might invoke it with untrusted paths directly. No new attack surface is introduced; the new logic is strictly more conservative than the old one (it can only refuse to clean up cases the old code would have accepted, not the reverse) — I traced through the three call sites and confirmed all pass in an already-secure path derived from resolveSecurePath.

Level of scrutiny

This warrants light scrutiny: it's a small, self-contained change to non-critical cleanup logic (best-effort empty-directory removal, wrapped in try/catch and ignored on error), not to auth, data access, or request handling. The fix itself is a standard, idiomatic Node.js pattern for safe subpath containment checks (relative-path based rather than string-prefix based), and correctly handles the root-equals case, the ..-prefix case, and the cross-platform absolute-path case (relevant for Windows drive-letter edge cases).

Other factors

Test coverage is good — the new test directly exercises the bug being fixed (sibling directory sharing a prefix) and the existing tests for normal cleanup and root-boundary behavior still pass conceptually with the new logic. No CODEOWNER-restricted paths, no config changes, no external interfaces affected.

@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 31019005254

Coverage increased (+0.005%) to 80.653%

Details

  • Coverage increased (+0.005%) from the base build.
  • Patch coverage: 3 of 3 lines across 1 file are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 12665
Covered Lines: 10639
Line Coverage: 84.0%
Relevant Branches: 7519
Covered Branches: 5640
Branch Coverage: 75.01%
Branches in Coverage %: Yes
Coverage Strength: 434.41 hits per line

💛 - Coveralls

@ferhatelmas
ferhatelmas merged commit 714623a into master Aug 5, 2026
31 checks passed
@ferhatelmas
ferhatelmas deleted the ferhat/prefix-root branch August 5, 2026 15:19
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.

4 participants