Skip to content

Storage emulator authorizes object names with '..' segments as one path but stores them under another (path.join) #11301

Open

Description

@DirtyBeann

[REQUIRED] Environment info

firebase-tools: 15.8.0 (the same code is in 15.34.0, lib/emulator/storage/files.js lines 296-297)

Platform: Windows 11, Node 24

[REQUIRED] Test case

The Storage emulator evaluates security rules against the object name as requested, but stores and reads the bytes under a key built with path.join(bucket, object). path.join collapses . and .. segments, so two different object names that Cloud Storage keeps distinct (object names are literal, dot segments included) end up as one key in the emulator.

With a common ownership rule:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/{allPaths=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

[REQUIRED] Steps to reproduce

  1. Start the Storage and Auth emulators with the rules above.
  2. As user B, upload users/B/photo.png.
  3. As user A, upload to the object name users/A/../B/photo.png (for example with the Web SDK, uploadBytes(ref(storage, 'users/A/../B/photo.png'), bytes)).
  4. As user B, download users/B/photo.png.

[REQUIRED] Expected behavior

Step 3 creates a separate object literally named users/A/../B/photo.png (as Cloud Storage does), and user B's users/B/photo.png is unchanged. Rules decide on the same name that is stored.

[REQUIRED] Actual behavior

The rule matches userId == "A" for step 3, so the write is allowed, but the emulator stores it at users/B/photo.png. Step 4 returns user A's bytes. Reads and deletes behave the same way: a name with .. is authorized as one path and applied to another.

The result is that rules tests run against the emulator can pass or fail for the wrong reason around dot segments, so the emulator is not a reliable check for path rules. Suggested fix: key stored objects by the literal (encoded) object name instead of path.join, or reject object names whose segments are . or .. the same way for both rule evaluation and storage.

Activity

  1. aalej commented on Oct 20, 2026

    @aalej
    Contributor

    Thanks for the report @DirtyBeann! I am working on reproducing the reported behavior but I am encountering a different issue. I created this repro and when I tried reproducing the issue - instead of overwriting the contents of uses/B/photo.png, if user A uploads users/A/../B/photo.png it will instead remove uses/B/photo.png, but still create users/A/../B/photo.png.

    I do think the issue I encountered is a bug, however since it looks like we're encountering 2 different behaviors, I'd like to ask if you could check the repro to let me know in case I missed anything? By any chance if you could provide an mcve to help us accurately reproduce the issue, it would be highly appreciated.

  2. self-assigned this
    on Oct 20, 2026
  3. google-oss-bot commented on Oct 28, 2026

    @google-oss-bot
    Collaborator

    Hey @DirtyBeann. We need more information to resolve this issue but there hasn't been an update in 7 weekdays. I'm marking the issue as stale and if there are no new updates in the next 3 days I will close it automatically.

    If you have more information that will help us get to the bottom of this, just add a comment!

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    ⌂ Proxy