<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: building-headless-browser-templates
description: >-
  Build Nuclei headless browser templates for detecting vulnerabilities
  that require JavaScript execution. Covers DOM-based XSS, client-side
  injection, SPA crawling, and browser-rendered content analysis.
domain: cybersecurity
subdomain: nuclei-templating
tags:
  - nuclei
  - headless
  - browser
  - javascript
  - dom-xss
  - spa
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: ["T1189"]
---

# Building Headless Browser Templates

## Overview

Headless browser templates use a real browser engine to render pages, execute
JavaScript, and interact with DOM elements. This enables detection of
client-side vulnerabilities invisible to traditional HTTP scanning — DOM-based
XSS, JavaScript-driven misconfigurations, and SPA-specific flaws.

Mode: `[MODE: RED]` — Client-side vulnerability detection via headless browser.

## Prerequisites

| Requirement | Details |
|---|---|
| Nuclei v3+ with headless support enabled | Required |
| Chrome/Chromium installed on the scanning host | Required |
| `-headless` flag passed to nuclei at runtime | Required |

## Key Concepts

### Basic Headless Navigation

```yaml
id: dom-xss-detection

info:
  name: DOM-Based XSS Detection
  author: nerf
  severity: high
  description: |
    Detects DOM-based cross-site scripting by injecting payloads into
    URL fragments and monitoring JavaScript execution context.
  classification:
    cwe-id: CWE-79
  tags: xss,dom,headless,javascript
  metadata:
    max-request: 1

headless:
  - steps:
      - action: navigate
        args:
          url: "{{BaseURL}}/#<img src=x onerror=alert(document.domain)>"
      - action: waitload
      - action: script
        args:
          code: |
            () => {
              let result = document.querySelector('img[src="x"]');
              return result !== null ? 'xss-confirmed' : 'safe';
            }
        name: xss_check
    matchers:
      - type: word
        part: xss_check
        words:
          - "xss-confirmed"
```

### Form Interaction Template

```yaml
id: reflected-xss-form

info:
  name: Reflected XSS via Form Input
  author: nerf
  severity: high
  classification:
    cwe-id: CWE-79
  tags: xss,reflected,headless,form
  metadata:
    max-request: 1

headless:
  - steps:
      - action: navigate
        args:
          url: "{{BaseURL}}/search"
      - action: waitload
      - action: text
        args:
          by: x
          xpath: "//input[@name='q']"
          value: '<script>alert(1)</script>'
      - action: click
        args:
          by: x
          xpath: "//button[@type='submit']"
      - action: waitload
      - action: script
        args:
          code: |
            () => {
              return document.body.innerHTML;
            }
        name: page_content
    matchers:
      - type: word
        part: page_content
        words:
          - "<script>alert(1)</script>"
```

### Cookie Security Audit

```yaml
id: insecure-cookie-flags

info:
  name: Insecure Cookie Flags Detection
  author: nerf
  severity: medium
  description: |
    Detects cookies set without Secure, HttpOnly, or SameSite flags
    using headless browser to capture JavaScript-accessible cookies.
  classification:
    cwe-id: CWE-614
  tags: cookie,security,headless,misconfig
  metadata:
    max-request: 1

headless:
  - steps:
      - action: navigate
        args:
          url: "{{BaseURL}}"
      - action: waitload
      - action: script
        args:
          code: |
            () => {
              return document.cookie || 'no-js-cookies';
            }
        name: cookies
    matchers-condition: and
    matchers:
      - type: word
        part: cookies
        words:
          - "session"
          - "token"
          - "auth"
        condition: or
      - type: word
        part: cookies
        negative: true
        words:
          - "no-js-cookies"
```

### Screenshot and Visual Analysis

```yaml
id: defacement-detection

info:
  name: Web Defacement Detection
  author: nerf
  severity: high
  tags: defacement,headless,monitoring
  metadata:
    max-request: 1

headless:
  - steps:
      - action: navigate
        args:
          url: "{{BaseURL}}"
      - action: waitload
      - action: script
        args:
          code: |
            () => {
              let title = document.title;
              let bodyText = document.body.innerText.substring(0, 500);
              return JSON.stringify({title: title, body: bodyText});
            }
        name: page_info
    matchers:
      - type: word
        part: page_info
        words:
          - "hacked"
          - "defaced"
          - "pwned"
          - "owned by"
        condition: or
```

## Workflow

### Step 1: Run Headless Scan

```bash
node scripts/agent.js --action scan --target https://staging.example.com \
  --template headless-template.yaml --output /tmp/headless-scan.json
```

### Step 2: Validate Template

```bash
node scripts/agent.js --action validate --template headless-template.yaml
```

## Verification

- [ ] Template uses `headless` protocol block (not `http`)
- [ ] Steps include `waitload` after navigation
- [ ] Script actions return named values for matcher reference
- [ ] JavaScript code is wrapped in arrow function `() => {}`
- [ ] XPath or CSS selectors target correct DOM elements
- [ ] Tested with `-headless` flag enabled
- [ ] Timeout considerations for slow-loading SPAs

## References

- [Nuclei Headless Protocol](https://docs.projectdiscovery.io/templates/protocols/headless/basic-headless)
- [OWASP DOM XSS Guide](https://owasp.org/www-community/attacks/DOM_Based_XSS)
