Medium CVSS 6.5 webkit Logic Error 🔧 Commit mapped

Overview

Medium
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionA maliciously crafted webpage may be able to fingerprint the user
ComponentWebCore Entriesapi
Bug ClassLogic Error
Tracker283117
Fix commitbddd7907adf8 (WebKit/WebKit)
CWECWE-862
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
CISA KEVNot listed
Creditedan anonymous researcher
Disclosed2025-01-27

Background

Entries API (webkitEntries)
A DOM API exposing FileSystemEntry/FileSystemDirectoryEntry objects from a DataTransfer or file input, allowing scripted navigation of dropped files and folders.
DOMFileSystem m_rootPath
The base filesystem path that scopes all path resolution for a DOMFileSystem instance to authorized content; an empty value means no legitimate root was established.
getParent / readEntries
FileSystemEntry operations that walk to a containing directory or enumerate a directory’s children, both of which reach real-filesystem metadata calls in WebCore.
Fingerprinting oracle
A side channel where success-vs-error callbacks (or returned metadata) let a page infer the existence or attributes of local files without directly reading their contents.
Work queue dispatch
The pattern of moving blocking filesystem I/O to a background thread and marshalling the result back to the main thread via callOnMainThread; the guard is added before this dispatch.

Root Cause Analysis

The patch touches Source/WebCore/Modules/entriesapi/DOMFileSystem.cpp, the implementation behind the Entries API (webkitEntries / FileSystemEntry) that a page can obtain from a DataTransfer during drag-and-drop or a file input. Each DOMFileSystem is created with an m_rootPath that scopes all path resolution to files the user actually granted. In DOMFileSystem::listDirectory and DOMFileSystem::getParent, the code resolved a virtual path and then dispatched work to a background queue to enumerate directory children (listDirectoryWithMetadata) or validate/stat the parent directory on the real filesystem. The violated invariant is that these filesystem operations must only run when the object has a valid, non-empty root path scoping it to authorized content; when m_rootPath is empty (for example an entry synthesized from a dropped File whose real path was never actually admitted), path evaluation can still resolve to something outside the intended sandbox, letting the background job touch and report metadata about the local filesystem.

The fix adds an explicit guard at the top of both functions: if m_rootPath.isEmpty(), immediately invoke the completion handler/callback with a NotFoundError (‘Path does not exist’) and return, before any work is dispatched to the work queue. This ensures that an un-rooted DOMFileSystem cannot be used to enumerate a directory’s children or walk to a parent directory. The updated LayoutTest confirms the intent: it now also adds a directory File to the DataTransfer and, for each entry, calls entry.file(), entry.getParent(), and (for directories) createReader().readEntries(), all of which must fail with ‘Should not receive file’ errors. Notably file() was already guarded (the pre-existing single PASS), but getParent() and readEntries() were the newly-closed holes, which is exactly what the two new guards in listDirectory and getParent cover.

The result is that previously an attacker could distinguish existence/metadata of local paths (a fingerprinting/info-leak oracle) via these two entry points; the fix removes the oracle by refusing the operation outright when there is no legitimate root.

Key insight
A missing ‘is this object actually rooted?’ precondition check (m_rootPath.isEmpty()) let two Entries-API operations (getParent, readEntries) touch and report real filesystem metadata for un-authorized paths; the file() path was already guarded, so this fix closes the sibling entry points that shared the same trust assumption but not the same check.

Attack Path

  1. Obtain a FileSystemEntry without a real root Get the page to receive entries via webkitEntries from a DataTransfer (drag-and-drop or a crafted file input), producing a DOMFileSystem whose m_rootPath is empty.
  2. Walk to a parent directory Call entry.getParent(success, error); before the fix this dispatched a background job that resolved and validated a full filesystem path despite the empty root.
  3. Enumerate directory children For a directory entry, call entry.createReader().readEntries(…) which reached listDirectory and ran listDirectoryWithMetadata against a path outside the intended sandbox.
  4. Read back the outcome as an oracle Observe whether the success or error callback fires (and any returned metadata) to infer the existence and attributes of local files/directories, building a fingerprint of the user’s system.
  5. Repeat across paths Probe multiple candidate paths to accumulate fingerprinting signal about installed software, usernames, or directory layout.

Impact Assessment

The primitive is an information-disclosure/fingerprinting oracle, not memory corruption: a page could learn about the existence and metadata of local filesystem paths through getParent and readEntries on an un-rooted DOMFileSystem, consistent with the CVE’s ‘fingerprint the user’ description and medium severity. There is no write or control-flow primitive here and no path to code execution from this bug alone. It is confined to the WebContent process’s WebCore layer, but the leaked signal is about the host filesystem, so the privacy impact crosses the sandbox conceptually even though execution stays in-process. Escalation would be limited to enriching a broader fingerprint or informing a separate exploit, not to direct compromise.

Changed Functions

FunctionChangeNotes
DOMFileSystem::listDirectory
Source/WebCore/Modules/entriesapi/DOMFileSystem.cpp
modified Adds an early guard: if m_rootPath.isEmpty(), return a NotFoundError via completionHandler before dispatching the directory-enumeration job to the work queue.
DOMFileSystem::getParent
Source/WebCore/Modules/entriesapi/DOMFileSystem.cpp
modified Adds the same guard after path evaluation: if m_rootPath.isEmpty(), return a NotFoundError via completionCallback before dispatching the parent-directory validation job.
file-system-access-via-dataTransfer test (runTest)
LayoutTests/http/tests/security/file-system-access-via-dataTransfer.html
modified Extends the regression test to also add a directory entry and to exercise getParent() and readEntries() in addition to file(), asserting all must error.
expected results
LayoutTests/http/tests/security/file-system-access-via-dataTransfer-expected.txt
modified Adds two more 'PASS Should not receive file' lines reflecting the newly-guarded getParent/readEntries paths.
mac-wk1 expected results
LayoutTests/platform/mac-wk1/http/tests/security/file-system-access-via-dataTransfer-expected.txt
added New WebKit1/mac platform-specific expectation file with four PASS lines for the expanded test.

Audit Directions

  • Other DOMFileSystem entry points
    Review every public method of DOMFileSystem.cpp that resolves or evaluates a path (grep for ’evaluatePath’, ‘resolveRelativeVirtualPath’, ’m_workQueue->dispatch’, ’listDirectoryWithMetadata’, ‘validatePathIsExpectedType’) and confirm each has the m_rootPath.isEmpty() guard before dispatching filesystem work.
  • Root/precondition consistency across the Entries API
    Check FileSystemEntry, FileSystemDirectoryEntry, FileSystemDirectoryReader and DOMFileSystemSync for the same class of missing guard; grep for ‘rootPath’, ‘isEmpty()’ near path evaluation and ensure new operations added later inherit the check.
  • Empty/unvalidated base-path assumptions elsewhere
    Search WebCore filesystem and File/Blob code for callbacks that return metadata based on a stored base path without validating it is non-empty and in-sandbox; grep for ‘crossThreadCopy’ of a fullPath immediately after ’evaluatePath’ without a preceding emptiness/authorization check.

Original Bug Report

The reporter's bug is still restricted on the tracker.