Lukas' Notes

web security mobile

The same-origin policy ties every input field in the DOM to an origin, so it is tempting to believe autofill is just SOP applied at a different layer: the password manager reads the origin off each field and offers that origin’s credentials. That picture is correct on the desktop web and wrong on mobile.

The tempting picture: SOP already binds each field to an origin

On desktop a password manager is a browser extension with direct DOM access. It walks the DOM, sees the document’s origin, and reads each <input> in that context. If a form lives inside a cross-origin iframe, the browser’s process model and the same-origin policy already enforce that the parent page’s script cannot read the iframe’s DOM — and the extension, running at a privileged level, sees both origins correctly distinguished. Origin is a property the DOM already carries; the PWM merely reads it.

Move to mobile and that inheritance vanishes.

The mechanism: the DOM is rendered a second time, as a ViewStructure

On Android the password manager cannot read the DOM at all. The OS Autofill Framework sits between the PWM and the page, and the PWM receives a ViewStructure — an OS-level description of the on-screen input fields. For native UI elements the system produces this description. For HTML, the browser has to translate the DOM into a ViewStructure itself, including the part that matters here: which origin each field belongs to.

That translation is a second rendering of the page, and it is where the inherited-origin picture breaks down. The DOM does carry origin as a hard property — enforced by SOP at the browser-engine level. The ViewStructure does not inherit it; the browser reconstructs it, field by field, and hands the reconstruction to the PWM. The link between “this input field” and “the origin it belongs to” is now a claim made by one browser component, in a format no standard constrains, rather than a fact of the DOM.

The consequence: a same-origin boundary the page never declared is broken at the autofill layer

There is no agreed-upon definition of the ViewStructure between password managers and browsers. Each browser reconstructs the field-to-origin mapping independently, and they do not always agree — especially for fields inside cross-origin iframes, where the field’s true origin and the surrounding page’s origin differ.

The concrete failure mode is symmetric: a page on a.com embeds a login form in an iframe from b.com. Some browsers describe the iframe form to the PWM as “a form in a.com”. The PWM, trusting that description, offers the stored a.com credentials for a field that actually belongs to b.com. If the user accepts the suggestion, credentials meant for a.com are sent to b.com — an origin the page never declared, and one the passwords were never meant for.

The left column shows the inherited picture: the DOM carries b.com and the PWM reads it. The right column shows the reconstructed picture: the browser translates the iframe field into a ViewStructure and may report a.com, so the PWM offers the wrong origin’s credentials.

The corrected model

Integrity of “which origin owns this field” is not a property of the DOM alone — it has to be re-asserted at the ViewStructure layer, and today it is not. Same-origin is a promise the browser engine keeps inside the DOM; autofill is a second system that reads the page through a translation, and a translation can drop the very thing the first system guaranteed. The seam the mobile-web threat models exploit in WebView — the app sits between the user and the page — reappears here between the PWM and the page, with the browser’s DOM-to-ViewStructure translation in the middle, and no shared contract to make that translation faithful.