Closed Bug 1857908 Opened 1 year ago Closed 1 year ago

XrayWrapper around retrieved values from IndexedDB

Categories

(WebExtensions :: Untriaged, defect, P3)

Firefox 118
defect

Tracking

(firefox118 affected, firefox119 affected, firefox120 affected)

RESOLVED WORKSFORME
Tracking Status
firefox118 --- affected
firefox119 --- affected
firefox120 --- affected

People

(Reporter: chuckySTAR+bugzilla, Unassigned)

References

Details

(Keywords: dev-doc-needed)

Attachments

(1 file)

Steps to reproduce:

Given a WebExtension which utilizes an IndexedDB within a content script, the retrieved values are wrapped by the XrayWrapper, which prevents the assignment of objects on those values.

A WebExtension to reproduce the error:
manifest.json:

{
	"manifest_version": 2,
	"name": "XRayed",
	"version": "0.1",
	"permissions": [
		"https://*/*"
	],
	"content_scripts": [
		{
			"matches": [
				"https://*/*"
			],
			"js": ["content.js"],
			"run_at": "document_start"
		}
	]
}

content.js:

let req = indexedDB.open('xray', 1)
req.onsuccess = e => {
	let db = req.result
	let ob = db.transaction('test', 'readwrite').objectStore('test')
	ob.put({ a: 5, }, 1).onsuccess = () => {
		ob.get(1).onsuccess = e => {
			let clone = structuredClone(e.target.result)
			clone.b = {}
			console.log(clone)

			e.target.result.b = {} // Error: Not allowed to define cross-origin object as property on [Object] or [Array] XrayWrapper
			console.log(e.target.result)
		}
	}
}
req.onupgradeneeded = e => {
	if (e.oldVersion < 1) {
		req.result.createObjectStore('test')
	}
}

The lines around structuredClone() are a workaround to this problem.
Assigning b on e.target.result to an object results in the error:
Error: Not allowed to define cross-origin object as property on [Object] or [Array] XrayWrapper
Is this intended behavior?
It works in Chrome.
All values added to IndexedDB are structured clones according to the documentation on MDN, therefore all objects in IndexedDB should be safe to use, right?
Or are there any other ways to store unsafe values in IndexedDB?
Or does the use of structuredClone() even make it safe? It works for my workaround though.

Actual results:

Error: Not allowed to define cross-origin object as property on [Object] or [Array] XrayWrapper

The Bugbug bot thinks this bug should belong to the 'Core::Storage: IndexedDB' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → Storage: IndexedDB
Product: Firefox → Core

Jan, can you please help with triage here?

Flags: needinfo?(jvarga)
Severity: -- → S3
Flags: needinfo?(jvarga)
Priority: -- → P3

I think IndexedDB's behavior is correct here given the setup of the different globals and that the content script sandbox explicitly is setting wantXrays to true. But this should probably be evaluated by the WebExtensions team since the emergent difference in behavior is causing compat problems between browsers because of differences in how content scripts are implemented in the different browsers.

If it helps for specific uses-cases, I should note we do have the ability to effectively do what we already do for tests with the ChromeOnly IDBFactory.openForPrincipal and expose an IDBFactory instance that is bound to the storage key of the page but bound to a global that could be on the other side of the xray membrane, etc.

Unfortunately this seems like a pretty complex standardization issue; hopefully the webext standardization process is converging to providing consistent semantics around JS in a safe way...

Severity: S3 → --
Component: Storage: IndexedDB → Untriaged
Priority: P3 → --
Product: Core → WebExtensions

Hello,

I reproduced the issue on the latest Nightly (120.0a1/20231019213231), Beta (119.0/20231019122658) and Release (118.0.2/20231009140911) under Windows 10 x64 and Ubuntu 22.04 LTS using the attached extension.

With the extensions loaded via about:debugging, accessing https://www.wikipedia.org/ and opening the web console reveals the mentioned error.

For more details, see the attached screenshot.

Status: UNCONFIRMED → NEW
Ever confirmed: true

This (and many other issues such as bug 1681809) are caused by the (to extension developers) surprising behavior of Xrays.

All values added to IndexedDB are structured clones according to the documentation on MDN, therefore all objects in IndexedDB should be safe to use, right?

IndexedDB in content scripts is the one shared with the origin the content script is running in. While the objects themselves are "safe" from the perspective of not having unwanted side effects (due to the protections of Xrays!), do note that the page can observe, read and modify the IndexedDB content.

Or does the use of structuredClone() even make it safe?

Yes. structuredClone() creates a clone in the context of the content script. The original object is actually an object from the page, because indexedDB in the content script is a XrayWrapper around indexedDB from the page, thus any objects returned by the indexedDB API are also XrayWrapped versions of the objects from the page.

Severity: -- → S3
Status: NEW → RESOLVED
Closed: 1 year ago
Keywords: dev-doc-needed
Priority: -- → P3
Resolution: --- → WORKSFORME
See Also: → 1681809
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: