├── .github └── workflows │ ├── gh-pages.yml │ └── pr-checks.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── archetypes └── default.md ├── config.toml ├── content ├── _index.md └── docs │ ├── attacks │ ├── _index.md │ ├── browser-features │ │ ├── _index.md │ │ ├── corb.md │ │ └── corp.md │ ├── cache-probing.md │ ├── css-injection.md │ ├── css-tricks.md │ ├── element-leaks.md │ ├── error-events.md │ ├── experiments │ │ ├── _index.md │ │ ├── portals.md │ │ └── scroll-to-text-fragment.md │ ├── frame-counting.md │ ├── historical │ │ ├── _index.md │ │ ├── content-type.md │ │ ├── download-bar.md │ │ └── stateful-browser-features.md │ ├── id-attribute.md │ ├── navigations.md │ ├── postmessage-broadcasts.md │ ├── timing-attacks │ │ ├── _index.md │ │ ├── clocks.md │ │ ├── connection-pool.md │ │ ├── execution-timing.md │ │ ├── hybrid-timing.md │ │ ├── network-timing.md │ │ └── performance-api.md │ ├── window-references.md │ └── xs-search.md │ ├── contributions │ └── _index.md │ └── defenses │ ├── _index.md │ ├── design-protections │ ├── _index.md │ ├── cache-protections.md │ └── subresource-protections.md │ ├── isolation-policies │ ├── _index.md │ ├── framing-isolation.md │ ├── navigation-isolation.md │ ├── resource-isolation.md │ └── strict-isolation.md │ ├── opt-in │ ├── _index.md │ ├── coop.md │ ├── corp.md │ ├── document-policies.md │ ├── fetch-metadata.md │ ├── same-site-cookies.md │ └── xfo.md │ └── secure-defaults │ ├── _index.md │ ├── corb.md │ └── partitioned-cache.md └── themes └── book ├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── archetypes ├── docs.md └── posts.md ├── assets ├── _custom.scss ├── _defaults.scss ├── _fonts.scss ├── _main.scss ├── _markdown.scss ├── _print.scss ├── _shortcodes.scss ├── _utils.scss ├── _variables.scss ├── book.scss ├── manifest.json ├── menu-reset.js ├── normalize.css ├── plugins │ ├── _dark.scss │ ├── _numbered.scss │ └── _scrollbars.scss ├── search-data.js ├── search.js ├── sw-register.js └── sw.js ├── exampleSite ├── assets │ ├── _custom.scss │ └── _variables.scss ├── config.toml ├── config.yaml ├── content.ru │ └── _index.md ├── content.zh │ └── _index.md ├── content │ ├── _index.md │ ├── docs │ │ ├── example │ │ │ ├── _index.md │ │ │ ├── collapsed │ │ │ │ ├── 3rd-level │ │ │ │ │ ├── 4th-level.md │ │ │ │ │ └── _index.md │ │ │ │ └── _index.md │ │ │ ├── hidden.md │ │ │ └── table-of-contents │ │ │ │ ├── _index.md │ │ │ │ ├── with-toc.md │ │ │ │ └── without-toc.md │ │ └── shortcodes │ │ │ ├── _index.md │ │ │ ├── buttons.md │ │ │ ├── columns.md │ │ │ ├── details.md │ │ │ ├── expand.md │ │ │ ├── hints.md │ │ │ ├── katex.md │ │ │ ├── mermaid.md │ │ │ ├── section │ │ │ ├── _index.md │ │ │ ├── page1.md │ │ │ └── page2.md │ │ │ └── tabs.md │ ├── menu │ │ └── index.md │ └── posts │ │ ├── _index.md │ │ ├── creating-a-new-theme.md │ │ ├── goisforlovers.md │ │ ├── hugoisforlovers.md │ │ └── migrate-from-jekyll.md └── resources │ └── _gen │ └── assets │ └── scss │ ├── book.scss_50fc8c04e12a2f59027287995557ceff.content │ ├── book.scss_50fc8c04e12a2f59027287995557ceff.json │ └── example │ ├── book.scss_50fc8c04e12a2f59027287995557ceff.content │ └── book.scss_50fc8c04e12a2f59027287995557ceff.json ├── i18n ├── cn.yaml ├── de.yaml ├── en.yaml ├── es.yaml ├── fr.yaml ├── ja.yaml ├── jp.yaml ├── ko.yaml ├── nb.yaml ├── pt.yaml ├── ru.yaml ├── sv.yaml ├── uk.yaml └── zh.yaml ├── images ├── screenshot.png └── tn.png ├── layouts ├── 404.html ├── _default │ ├── _markup │ │ ├── render-heading.html │ │ ├── render-image.html │ │ └── render-link.html │ ├── baseof.html │ ├── list.html │ └── single.html ├── partials │ └── docs │ │ ├── brand.html │ │ ├── comments.html │ │ ├── date.html │ │ ├── footer.html │ │ ├── header.html │ │ ├── html-head.html │ │ ├── inject │ │ ├── body.html │ │ ├── content-after.html │ │ ├── content-before.html │ │ ├── footer.html │ │ ├── head.html │ │ ├── menu-after.html │ │ └── menu-before.html │ │ ├── languages.html │ │ ├── menu-bundle.html │ │ ├── menu-filetree.html │ │ ├── menu-hugo.html │ │ ├── menu.html │ │ ├── post-meta.html │ │ ├── search.html │ │ ├── taxonomy.html │ │ ├── title.html │ │ └── toc.html ├── posts │ ├── list.html │ └── single.html ├── shortcodes │ ├── button.html │ ├── columns.html │ ├── details.html │ ├── expand.html │ ├── hint.html │ ├── katex.html │ ├── mermaid.html │ ├── section.html │ ├── tab.html │ └── tabs.html └── taxonomy │ ├── list.html │ └── taxonomy.html ├── static ├── favicon.png ├── favicon.svg ├── flexsearch.min.js ├── fonts │ ├── roboto-mono-v6-latin-regular.woff │ ├── roboto-mono-v6-latin-regular.woff2 │ ├── roboto-v19-latin-300italic.woff │ ├── roboto-v19-latin-300italic.woff2 │ ├── roboto-v19-latin-700.woff │ ├── roboto-v19-latin-700.woff2 │ ├── roboto-v19-latin-regular.woff │ └── roboto-v19-latin-regular.woff2 ├── katex │ ├── auto-render.min.js │ ├── fonts │ │ ├── KaTeX_AMS-Regular.ttf │ │ ├── KaTeX_AMS-Regular.woff │ │ ├── KaTeX_AMS-Regular.woff2 │ │ ├── KaTeX_Caligraphic-Bold.ttf │ │ ├── KaTeX_Caligraphic-Bold.woff │ │ ├── KaTeX_Caligraphic-Bold.woff2 │ │ ├── KaTeX_Caligraphic-Regular.ttf │ │ ├── KaTeX_Caligraphic-Regular.woff │ │ ├── KaTeX_Caligraphic-Regular.woff2 │ │ ├── KaTeX_Fraktur-Bold.ttf │ │ ├── KaTeX_Fraktur-Bold.woff │ │ ├── KaTeX_Fraktur-Bold.woff2 │ │ ├── KaTeX_Fraktur-Regular.ttf │ │ ├── KaTeX_Fraktur-Regular.woff │ │ ├── KaTeX_Fraktur-Regular.woff2 │ │ ├── KaTeX_Main-Bold.ttf │ │ ├── KaTeX_Main-Bold.woff │ │ ├── KaTeX_Main-Bold.woff2 │ │ ├── KaTeX_Main-BoldItalic.ttf │ │ ├── KaTeX_Main-BoldItalic.woff │ │ ├── KaTeX_Main-BoldItalic.woff2 │ │ ├── KaTeX_Main-Italic.ttf │ │ ├── KaTeX_Main-Italic.woff │ │ ├── KaTeX_Main-Italic.woff2 │ │ ├── KaTeX_Main-Regular.ttf │ │ ├── KaTeX_Main-Regular.woff │ │ ├── KaTeX_Main-Regular.woff2 │ │ ├── KaTeX_Math-BoldItalic.ttf │ │ ├── KaTeX_Math-BoldItalic.woff │ │ ├── KaTeX_Math-BoldItalic.woff2 │ │ ├── KaTeX_Math-Italic.ttf │ │ ├── KaTeX_Math-Italic.woff │ │ ├── KaTeX_Math-Italic.woff2 │ │ ├── KaTeX_SansSerif-Bold.ttf │ │ ├── KaTeX_SansSerif-Bold.woff │ │ ├── KaTeX_SansSerif-Bold.woff2 │ │ ├── KaTeX_SansSerif-Italic.ttf │ │ ├── KaTeX_SansSerif-Italic.woff │ │ ├── KaTeX_SansSerif-Italic.woff2 │ │ ├── KaTeX_SansSerif-Regular.ttf │ │ ├── KaTeX_SansSerif-Regular.woff │ │ ├── KaTeX_SansSerif-Regular.woff2 │ │ ├── KaTeX_Script-Regular.ttf │ │ ├── KaTeX_Script-Regular.woff │ │ ├── KaTeX_Script-Regular.woff2 │ │ ├── KaTeX_Size1-Regular.ttf │ │ ├── KaTeX_Size1-Regular.woff │ │ ├── KaTeX_Size1-Regular.woff2 │ │ ├── KaTeX_Size2-Regular.ttf │ │ ├── KaTeX_Size2-Regular.woff │ │ ├── KaTeX_Size2-Regular.woff2 │ │ ├── KaTeX_Size3-Regular.ttf │ │ ├── KaTeX_Size3-Regular.woff │ │ ├── KaTeX_Size3-Regular.woff2 │ │ ├── KaTeX_Size4-Regular.ttf │ │ ├── KaTeX_Size4-Regular.woff │ │ ├── KaTeX_Size4-Regular.woff2 │ │ ├── KaTeX_Typewriter-Regular.ttf │ │ ├── KaTeX_Typewriter-Regular.woff │ │ └── KaTeX_Typewriter-Regular.woff2 │ ├── katex.min.css │ └── katex.min.js ├── mermaid.min.js └── svg │ ├── calendar.svg │ ├── edit.svg │ ├── hint-icons.svg │ ├── menu.svg │ ├── toc.svg │ └── translate.svg └── theme.toml /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | with: 14 | submodules: true 15 | fetch-depth: 0 16 | 17 | - name: Setup Hugo 18 | uses: peaceiris/actions-hugo@v2 19 | with: 20 | hugo-version: 'latest' 21 | extended: true 22 | 23 | - name: Build 24 | run: hugo --minify 25 | 26 | - name: Deploy 27 | uses: peaceiris/actions-gh-pages@v3 28 | with: 29 | deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }} 30 | publish_dir: ./public 31 | cname: xsleaks.dev 32 | user_name: 'github-actions[bot]' 33 | user_email: 'github-actions[bot]@users.noreply.github.com' 34 | -------------------------------------------------------------------------------- /.github/workflows/pr-checks.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request Checks 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | with: 12 | submodules: true 13 | fetch-depth: 0 14 | 15 | - name: Setup Hugo 16 | uses: peaceiris/actions-hugo@v2 17 | with: 18 | hugo-version: 'latest' 19 | extended: true 20 | 21 | - name: Build 22 | run: hugo --minify 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /hugo 2 | docs/public* 3 | /.idea 4 | hugo.exe 5 | *.test 6 | *.prof 7 | nohup.out 8 | cover.out 9 | *.swp 10 | *.swo 11 | .DS_Store 12 | *~ 13 | vendor/*/ 14 | *.bench 15 | *.debug 16 | coverage*.out 17 | 18 | dock.sh 19 | 20 | GoBuilds 21 | dist 22 | 23 | hugolib/hugo_stats.json 24 | resources/sunset.jpg 25 | 26 | vendor 27 | 28 | resources/ 29 | public/ 30 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [twitter.com/manuelvsousa](http://twitter.com/manuelvsousa). All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XS-Leaks Wiki 2 | 3 | ## Build Process 4 | 5 | ### Build locally 6 | 7 | 1. Install the [Hugo Framework](https://gohugo.io/getting-started/installing/) **extended** version > 0.68 8 | 2. Clone this repo 9 | 3. Run `hugo server --minify` in root directory 10 | 4. Open your browser and go to http://localhost:1313 (or as indicated by hugo output) 11 | 12 | ### Generate static files 13 | 14 | 1. Run `hugo --buildDrafts` 15 | 16 | ## Automatic Deployment 17 | 18 | This repository uses [Github Actions](https://github.com/features/actions) to automatically build and publish a static version of the XS-Leaks Wiki once a Pull Request is accepted. To bring Github Pages automation into Github Actions we use [actions-gh-pages](https://github.com/peaceiris/actions-gh-pages). To automatically build a website with the Hugo Framework, we use [actions-hugo](https://github.com/peaceiris/actions-hugo) 19 | 20 | The strategy used to give the workflow access to this repository uses a [deploy_key](https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-set-ssh-private-key-deploy_key) which is privately set in this repository. -------------------------------------------------------------------------------- /archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | draft: true 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /config.toml: -------------------------------------------------------------------------------- 1 | baseURL = "https://xsleaks.dev/" 2 | languageCode = "en-us" 3 | title = "XS-Leaks Wiki" 4 | enableGitInfo = true 5 | theme = "book" 6 | 7 | [params] 8 | # Set source repository location. 9 | # Used for 'Last Modified' and 'Edit this page' links. 10 | BookRepo = 'https://github.com/xsleaks/wiki' 11 | 12 | # Enable "Edit this page" links for 'doc' page type. 13 | # Disabled by default. Uncomment to enable. Requires 'BookRepo' param. 14 | # Edit path must point to root directory of repo. 15 | BookEditPath = 'edit/master/content' 16 | 17 | # Configure the date format used on the pages 18 | # - In git information 19 | # - In blog posts 20 | BookDateFormat = 'January 2, 2006' 21 | 22 | # /!\ This is an experimental feature, might be removed or changed at any time 23 | # (Optional, experimental, default false) Enables service worker that caches visited pages and resources for offline use. 24 | BookServiceWorker = true 25 | 26 | [taxonomies] 27 | abuse = "Abuse" 28 | category = "Category" 29 | defense = "Defenses" 30 | 31 | [markup] 32 | [markup.highlight] 33 | style = "dracula" 34 | -------------------------------------------------------------------------------- /content/docs/attacks/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 1 3 | bookFlatSection: true 4 | title: "Attacks" 5 | --- -------------------------------------------------------------------------------- /content/docs/attacks/browser-features/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 4 3 | --- -------------------------------------------------------------------------------- /content/docs/attacks/browser-features/corp.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "CORP Leaks" 3 | description = "" 4 | date = "2020-10-01" 5 | category = "Attack" 6 | abuse = [ 7 | "Browser Feature", 8 | ] 9 | defenses = [ 10 | "Fetch Metadata", 11 | "SameSite Cookies", 12 | ] 13 | menu = "main" 14 | weight = 2 15 | +++ 16 | 17 | ## Explanation 18 | 19 | [Cross-Origin Resource Policy]({{< ref "/docs/defenses/opt-in/corp.md" >}}) (CORP) is a web platform security feature that allows websites to prevent certain resources from being loaded by other origins. This protection complements [CORB]({{< ref "/docs/defenses/secure-defaults/corb.md" >}}) since it is an opt-in defense, whereas CORB blocks some cross-origin reads by default. Unfortunately, similar to [CORB]({{< ref "corb.md" >}}), applications can introduce a new XS-Leak if they misconfigure the use of this protection. 20 | 21 | A webpage will introduce an XS-Leak if `CORP` is enforced based on user data. If a page search feature enforces `CORP` when showing results, but doesn't do so when returning no results, an attacker will be able to distinguish the two scenarios. This occurs because a page/resource protected by `CORP` will return an error when fetched cross-origin. [Run demo](https://xsinator.com/testing.html#CORP%20Leak) 22 | 23 | ## Defense 24 | 25 | An application can avoid this XS-Leak if it guarantees `CORP` is deployed in all application resources/endpoints. Moreover, generic security mechanisms that allow the invalidation of cross-site requests will also help prevent this attack. 26 | 27 | | [SameSite Cookies (Lax)]({{< ref "/docs/defenses/opt-in/same-site-cookies.md" >}}) | [COOP]({{< ref "/docs/defenses/opt-in/coop.md" >}}) | [Framing Protections]({{< ref "/docs/defenses/opt-in/xfo.md" >}}) | [Isolation Policies]({{< ref "/docs/defenses/isolation-policies" >}}) | 28 | | :--------------------------------------------------------------------------------: | :-------------------------------------------------: | :---------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------: | 29 | | ✔️ | ❌ | ❌ | [RIP]({{< ref "/docs/defenses/isolation-policies/resource-isolation" >}}) 🔗 [NIP]({{< ref "/docs/defenses/isolation-policies/navigation-isolation" >}}) | 30 | 31 | 🔗 – Defense mechanisms must be combined to be effective against different scenarios. 32 | -------------------------------------------------------------------------------- /content/docs/attacks/experiments/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | bookCollapseSection: true 3 | weight: 10 4 | title: "Experiments" 5 | --- 6 | 7 | # Experiments 8 | 9 | This section presents XS-Leaks that affect experimental features. Experimental features are usually hidden under a browser preference flag and their exact specification is under active discussion. It's important to be aware of these features and follow their development from the early stages of implementation to prevent XS-Leaks from happening. 10 | -------------------------------------------------------------------------------- /content/docs/attacks/experiments/portals.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Portals" 3 | description = "" 4 | date = "2020-10-01" 5 | category = "Experiments" 6 | menu = "main" 7 | +++ 8 | 9 | [Portals](https://web.dev/hands-on-portals/) are a new feature of the web which is similar to `iframes`, but with more emphasis on speed and user experience. The [`portal`](https://web.dev/hands-on-portals/) element is only available on Chromium-based browsers under a preference flag. The corresponding [specification](https://wicg.github.io/portals/) is still under active discussion. 10 | 11 | Unfortunately, research of this new feature has discovered some critical issues, including new XS-Leaks [^2]. 12 | 13 | ## ID Leaks 14 | 15 | Portals can be abused as an alternative to the [ID Attribute XS-Leak]({{< ref "../id-attribute.md" >}}). If a website sets [framing protections]({{< ref "../../defenses/opt-in/xfo.md" >}}), the same technique can be applied using the `portal` element instead [^1]. 16 | 17 | ## References 18 | 19 | [^1]: Detecting IDs using Portal, [link](https://portswigger.net/research/xs-leak-detecting-ids-using-portal) 20 | [^2]: Security analysis of \ element, [link](https://research.securitum.com/security-analysis-of-portal-element/) 21 | -------------------------------------------------------------------------------- /content/docs/attacks/historical/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | bookCollapseSection: true 3 | weight: 100 4 | --- 5 | 6 | # Historical Attacks 7 | 8 | The articles in this section present XS-Leaks that have been addressed within browsers and no longer work. Different mitigation strategies were applied, such as: 9 | 10 | - Reducing the accuracy of some powerful APIs. 11 | - Adding noise to a certain measurement to prevent any malicious inference from it. 12 | - Deprecating and removing features and APIs. 13 | - Changing the feature's behavior. 14 | -------------------------------------------------------------------------------- /content/docs/attacks/historical/content-type.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Content-Type" 3 | description = "" 4 | date = "2020-10-01" 5 | category = "Historical" 6 | abuse = [ 7 | "typeMustMatch", 8 | "iframes", 9 | "Content-Type", 10 | "Status Code", 11 | ] 12 | defenses = [ 13 | "Deprecation" 14 | ] 15 | menu = "main" 16 | +++ 17 | 18 | Leaking the Content-Type of a request would provide attackers with a new way of distinguishing two requests from each other. 19 | 20 | ## typeMustMatch 21 | 22 | [`typeMustMatch`](https://web.archive.org/web/20210421092442/https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/typeMustMatch) is a Boolean that reflects the `typeMustMatch` attribute of the `object` element. It ensures that a certain MIME type must be enforced when loading an object, by verifying if the `Content-Type` of the resource is the same as the one provided in the object. Unfortunately, this enforcement also allowed attackers to leak the `Content-Type` and Status Codes returned by a website [^1]. 23 | 24 | ### Root Cause 25 | 26 | Considering the snippet below, `not_loaded` would be rendered if the returned `Content-Type` of `https://target/api` did not match the one in `type`, or if the server returned a status different than `200`. 27 | 28 | ```html 29 | 32 | not_loaded 33 | ``` 34 | 35 | #### Issues 36 | 37 | An attacker could leak the `Content-Type` and Status Codes of a website by detecting whether the object rendered, which happens when [all conditions]({{< ref "#root-cause" >}}) are met. The attacker could check the values of `clientHeight` and `clientWidth` which are likely to be different than 0 when the object renders (and returns status `200`). Since `typeMustMatch` requires the server to return status `200` to load a resource, it would be possible to detect error pages, similar to [Error Events]({{< ref "../error-events.md" >}}) XS-Leaks. 38 | 39 | The example below shows how this behavior could be detected by embedding an object inside an `iframe` and checking the values of `clientHeight` and `clientWidth` when the `iframe` triggers the `onload` event. 40 | 41 | 42 | ```javascript 43 | // Set the destination URL 44 | var url = 'https://example.org'; 45 | // The content type we want to check for 46 | var mime = 'application/json'; 47 | var ifr = document.createElement('iframe'); 48 | // Load an object inside iframe since object does not trigger onload event 49 | ifr.srcdoc = ` 50 | 51 | error 52 | `; 53 | document.body.appendChild(ifr); 54 | 55 | // When the iframe loads, read the height of the object. If it is the height 56 | // of a single line of text, then the content type of the resource was not 57 | // `application/json`. If it is a different height, then it was `application/json`. 58 | ifr.onload = () => { 59 | console.log(ifr.contentWindow.obj.clientHeight) 60 | }; 61 | ``` 62 | 63 | ### Fix 64 | 65 | Firefox was the only browser that supported the `typeMustMatch` attribute [^2], and since no other browsers offered support, it was removed in version 68 and from the HTML Living Standard. 66 | 67 | ## References 68 | 69 | [^1]: Cross-Site Content and Status Types Leakage, [link](https://medium.com/bugbountywriteup/cross-site-content-and-status-types-leakage-ef2dab0a492) 70 | [^2]: Remove support for typemustmatch, [link](https://bugzilla.mozilla.org/show_bug.cgi?id=1548773) 71 | -------------------------------------------------------------------------------- /content/docs/attacks/historical/download-bar.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Download Bar" 3 | description = "" 4 | date = "2024-04-23" 5 | category = "Historical" 6 | abuse = [ 7 | "Downloads" 8 | ] 9 | defenses = [ 10 | "Deprecation" 11 | ] 12 | menu = "main" 13 | +++ 14 | 15 | In Chromium-based browsers, when a file was downloaded, a preview of the download process appeared in a bar at the bottom, integrated into the browser window. By monitoring the window height, attackers could detect whether the "download bar" opened: 16 | 17 | 18 | ```javascript 19 | // Read the current height of the window 20 | var screenHeight = window.innerHeight; 21 | // Load the page that may or may not trigger the download 22 | window.open('https://example.org'); 23 | // Wait for the tab to load 24 | setTimeout(() => { 25 | // If the download bar appears, the height of all tabs will be smaller 26 | if (window.innerHeight < screenHeight) { 27 | console.log('Download bar detected'); 28 | } else { 29 | console.log('Download bar not detected'); 30 | } 31 | }, 2000); 32 | ``` 33 | 34 | {{< hint important >}} 35 | This attack was only possible in Chromium-based browsers with automatic downloads enabled. In addition, the attack can't be repeated since the user needs to close the download bar for it to be measurable again. 36 | {{< /hint >}} 37 | 38 | ### Fix 39 | Chromium moved away from a download bar, They explain why in the blog post [Redesigning Chrome downloads](https://blog.chromium.org/2023/08/redesigning-chrome-downloads-to-keep.html) it helps create a clearer separation of trusted browser UI from web content among other reasons. 40 | -------------------------------------------------------------------------------- /content/docs/attacks/historical/stateful-browser-features.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Stateful Browser Features" 3 | description = "" 4 | date = "2020-10-01" 5 | category = "Historical" 6 | defenses = [ 7 | "Browser Fix" 8 | ] 9 | menu = "main" 10 | +++ 11 | 12 | Some browser features/extensions change the way requests are processed, depending on certain website states generated by the browser. Attackers can sometimes observe the whole process and mess with the browser, triggering actions that produce side effects on those states. 13 | 14 | ## WebKit – ITP 15 | 16 | [Intelligent Tracking Prevention](https://webkit.org/tracking-prevention/) (ITP) is a privacy feature which is part of [WebKit Tracking Prevention technologies](https://webkit.org/tracking-prevention/). It's a conjunction of several features and aims to prevent a website from tracking a user under a third-party context. Unfortunately, the initial design introduced a new XS-Leak [^1], allowing attackers to abuse the states implicitly created by ITP to classify websites as trackers. 17 | 18 | ### Root Cause 19 | 20 | To classify whether a website has tracking capabilities, ITP collects statistics on resource loads as well as on user interactions with websites such as clicks, taps, or text entries. Based on the classification of these statistics, ITP gives a strike to a website if it is believed to have tracking capabilities. After 3 strikes, a website is put on a deny list and is treated differently by the browser in future requests. 21 | 22 | #### Issues 23 | 24 | One of the issues of ITP is that attackers can manipulate it to arbitrarily enforce certain behaviors. For example, an attacker could force ITP to give a strike to a domain and check if the domain entered the deny list. This information could be leveraged in different ways, for example to: 25 | 26 | - Leak the user's browsing habits based on how many strikes are necessary for a domain to enter the deny list. 27 | - Use the deny list to implement an XS-Search attack against a page that includes cross-site resources only when results are present. 28 | 29 | ### Fix 30 | 31 | To [fix the issue](https://webkit.org/blog/9661/preventing-tracking-prevention-tracking/), ITP now considers every site to be a "tracking" site by default, instead of relying on classifications. This removes the implicit states which allowed attackers to detect certain ITP behaviors. 32 | 33 | ## References 34 | 35 | [^1]: Information Leaks via Safari’s Intelligent Tracking Prevention, [link](https://arxiv.org/pdf/2001.07421.pdf) 36 | [^2]: Preventing Tracking Prevention Tracking, [link](https://webkit.org/blog/9661/preventing-tracking-prevention-tracking/) 37 | -------------------------------------------------------------------------------- /content/docs/attacks/postmessage-broadcasts.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "postMessage Broadcasts" 3 | description = "" 4 | date = "2020-10-01" 5 | category = [ 6 | "Attack", 7 | ] 8 | abuse = [ 9 | "postMessage", 10 | ] 11 | defenses = [ 12 | "Application Fix", 13 | ] 14 | menu = "main" 15 | weight = 3 16 | +++ 17 | 18 | Applications often use [postMessage broadcasts](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) to share information with other origins. Using `postMessage` can lead to two kinds of XS-Leaks: 19 | 20 | * Sharing sensitive messages with untrusted origins 21 | * The `postMessage` API supports a `targetOrigin` parameter that can be used to restrict which origins can receive the message. If the message contains any sensitive data, it is important to use this parameter. 22 | 23 | * Leaking information based on varying content or on the presence of a broadcast 24 | * Similar to other XS-Leak techniques, this could be used to form an oracle. For example, if an application sends a postMessage broadcast saying "Page Loaded" only if a user with a given username exists, this could be used to leak information. 25 | 26 | ## Defense 27 | 28 | There is no clear solution to mitigate this XS-Leak as it depends deeply on the purpose of sending a postMessage broadcast. Applications should limit postMessage communications to a group of known origins. When this is not possible, the communications should behave consistently regardless of the state to prevent attackers from inferring information based on differences between the communications. 29 | 30 | ## References 31 | 32 | [^1]: Cross-Origin State Inference (COSI) Attacks: Leaking Web Site States through XS-Leaks, [link](https://arxiv.org/pdf/1908.02204.pdf) 33 | -------------------------------------------------------------------------------- /content/docs/attacks/timing-attacks/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 5 3 | --- -------------------------------------------------------------------------------- /content/docs/attacks/timing-attacks/hybrid-timing.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Hybrid Timing" 3 | description = "" 4 | date = "2020-10-01" 5 | category = "Attack" 6 | abuse = [ 7 | "iframes", 8 | ] 9 | defenses = [ 10 | "Fetch Metadata", 11 | "SameSite Cookies", 12 | "COOP", 13 | ] 14 | menu = "main" 15 | weight = 3 16 | +++ 17 | 18 | Hybrid Timing Attacks allow attackers to measure the sum of a group of factors that influence the final timing measurement. These factors include: 19 | 20 | - [Network delays]({{< ref "network-timing.md" >}}) 21 | - Document parsing 22 | - Retrieval and processing of subresources 23 | - [Code execution]({{< ref "execution-timing.md" >}}) 24 | 25 | Some of the factors differ in value depending on the application. This means that [Network Timing]({{< ref "network-timing.md" >}}) might be more significant for pages with more backend processing, while [Execution Timing]({{< ref "execution-timing.md" >}}) can be more significant in applications processing and displaying data within the browser. Attackers can also eliminate some of these factors to obtain more precise measurements. For example, an attacker could preload all of the subresources by embedding the page as an `iframe` (forcing the browser to cache the subresources) and then perform a second measurement, which excludes any delay introduced by the retrieval of those subresources. 26 | 27 | ## Frame Timing Attacks (Hybrid) 28 | 29 | If a page does not set [Framing Protections]({{< ref "../../defenses/opt-in/xfo.md" >}}), an attacker can obtain a hybrid measurement that considers all of the factors. This attack is similar to a [Network-based Attack]({{< ref "network-timing.md#frame-timing-attacks-network" >}}), but when the resource is retrieved, the page is rendered and executed by the browser (subresources fetched and JavaScript executed). In this scenario, the `onload` event only triggers once the page fully loads (including subresources and script execution). 30 | 31 | ```javascript 32 | var iframe = document.createElement('iframe'); 33 | // Set the URL of the destination website 34 | iframe.src = "https://example.org"; 35 | document.body.appendChild(iframe); 36 | 37 | // Measure the time before the request was initiated 38 | var start = performance.now(); 39 | 40 | iframe.onload = () => { 41 | // When iframe loads, calculate the time difference 42 | var time = performance.now() - start; 43 | console.log("The iframe and subresources took %d ms to load.", time) 44 | } 45 | ``` 46 | 47 | ## Defense 48 | 49 | | Attack Alternative | [SameSite Cookies (Lax)]({{< ref "/docs/defenses/opt-in/same-site-cookies.md" >}}) | [COOP]({{< ref "/docs/defenses/opt-in/coop.md" >}}) | [Framing Protections]({{< ref "/docs/defenses/opt-in/xfo.md" >}}) | [Isolation Policies]({{< ref "/docs/defenses/isolation-policies" >}}) | 50 | | :-------------------: | :--------------------------------------------------------------------------------: | :-------------------------------------------------: | :---------------------------------------------------------------: | :----------------------------------------------------------------------: | 51 | | Frame Timing (Hybrid) | ✔️ | ❌ | ✔️ | [FIP]({{< ref "/docs/defenses/isolation-policies/framing-isolation" >}}) | 52 | -------------------------------------------------------------------------------- /content/docs/attacks/window-references.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Window References" 3 | description = "" 4 | date = "2020-10-08" 5 | category = [ 6 | "Attack", 7 | ] 8 | abuse = [ 9 | "Window References", 10 | ] 11 | defenses = [ 12 | "Fetch Metadata", 13 | "SameSite Cookies", 14 | "COOP" 15 | ] 16 | menu = "main" 17 | weight = 2 18 | +++ 19 | 20 | 21 | If a page sets its `opener` property to `null` or is using [COOP]({{< ref "/docs/defenses/opt-in/coop.md" >}}) protection depending on the users' state, it becomes possible to infer cross-site information about that state. For example, attackers can detect whether a user is logged in by opening an endpoint in an iframe (or a new window) which only authenticated users have access to, simply by checking its window reference. [Run demo](https://xsinator.com/testing.html#COOP%20Leak) 22 | 23 | ## Code Snippet 24 | The below snippet demonstrates how to detect whether the `opener` property was set to `null`, or whether the [COOP]({{< ref "/docs/defenses/opt-in/coop.md" >}}) header is present with a value other than `unsafe-none`. This can be done with both iframes and new windows. 25 | 26 | ```javascript 27 | // define the vulnerable URL 28 | const v_url = 'https://example.org/profile'; 29 | 30 | const exploit = (url, new_window) => { 31 | let win; 32 | if(new_window) { 33 | // open the url in a new tab to see if win.opener was affected by COOP 34 | // or set to null 35 | win = open(url); 36 | } else { 37 | // create an iframe to detect whether the opener is defined 38 | // won't work for COOP detection, or if a page has implemented framing protections 39 | document.body.insertAdjacentHTML('beforeend', '