<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: implementing-template-matchers
description: >-
  Master Nuclei template matchers and extractors for precise vulnerability
  detection. Covers word, regex, status, DSL, binary, and size matchers
  with condition logic, negative matching, and multi-layer strategies.
domain: cybersecurity
subdomain: nuclei-templating
tags:
  - nuclei
  - matchers
  - extractors
  - dsl
  - detection-logic
  - false-positives
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: []
---

# Implementing Template Matchers

## Overview

Matchers are the detection engine of Nuclei templates. They evaluate response
data against defined conditions to determine if a vulnerability exists. Proper
matcher design is the difference between actionable findings and noise.
Multi-layer matching strategies dramatically reduce false positives.

Mode: `[MODE: BLUE]` — Precision detection engineering.

## Prerequisites

| Requirement | Details |
|---|---|
| Nuclei v3+ for DSL matcher support | Required |
| Understanding of regex and boolean logic | Required |
| Sample vulnerable and patched responses for testing | Required |

## Key Concepts

### Word Matcher

```yaml
# Simple word match — fastest matcher type
matchers:
  - type: word
    part: body
    words:
      - "root:x:0:0:"
      - "/etc/passwd"
    condition: or

# Case-insensitive word match
matchers:
  - type: word
    part: body
    words:
      - "SQL syntax"
      - "mysql_fetch"
    condition: or
    case-insensitive: true
```

### Regex Matcher

```yaml
# Version extraction with regex
matchers:
  - type: regex
    part: body
    regex:
      - 'Apache/([0-9]+\.[0-9]+\.[0-9]+)'
      - 'Server:\s*nginx/([0-9]+\.[0-9]+)'
    condition: or

# Negative regex — match if pattern NOT found
matchers:
  - type: regex
    part: header
    regex:
      - 'X-Frame-Options:\s*(DENY|SAMEORIGIN)'
    negative: true
```

### Status Code Matcher

```yaml
# Single status
matchers:
  - type: status
    status:
      - 200

# Multiple acceptable statuses
matchers:
  - type: status
    status:
      - 200
      - 301
      - 302
```

### DSL Matcher

```yaml
# Complex conditions with DSL expressions
matchers:
  - type: dsl
    dsl:
      - 'status_code == 200 && contains(body, "admin")'
      - 'len(body) > 0 && !contains(body, "error")'
    condition: and

# Response time analysis
matchers:
  - type: dsl
    dsl:
      - 'duration >= 5'  # Time-based blind injection indicator

# Content length comparison
matchers:
  - type: dsl
    dsl:
      - 'content_length > 1024'
      - 'contains(content_type, "application/json")'
    condition: and
```

### Binary Matcher

```yaml
# Match hex patterns in binary responses
matchers:
  - type: binary
    binary:
      - "504b0304"  # ZIP file signature
      - "1f8b0800"  # GZIP signature
    condition: or
    part: body
```

### Size Matcher

```yaml
# Match exact response size
matchers:
  - type: size
    size:
      - 1234
    part: body
```

### Multi-Layer Matcher Strategy

```yaml
id: sql-injection-error-based

info:
  name: SQL Injection Error-Based Detection
  author: nerf
  severity: high
  classification:
    cwe-id: CWE-89
  tags: sqli,injection,database

http:
  - method: GET
    path:
      - "{{BaseURL}}/search?q=1'%20OR%20'1'='1"
    matchers-condition: and
    matchers:
      # Layer 1: SQL error strings
      - type: word
        part: body
        words:
          - "SQL syntax"
          - "mysql_fetch"
          - "ORA-01756"
          - "PostgreSQL"
          - "SQLite3::"
        condition: or
      # Layer 2: Successful HTTP response
      - type: status
        status:
          - 200
          - 500
      # Layer 3: NOT a custom error page
      - type: word
        part: body
        words:
          - "404 Not Found"
          - "Page not found"
        negative: true
      # Layer 4: Minimum response size
      - type: dsl
        dsl:
          - 'len(body) > 100'
    extractors:
      - type: regex
        part: body
        group: 1
        regex:
          - '(?i)(sql syntax.*?near.*?line \d+)'
          - '(?i)(ORA-\d{5}:.*?)[\r\n]'
```

### Condition Logic

```yaml
# AND — all matchers must match (strict, fewer FPs)
matchers-condition: and
matchers:
  - type: word
    words: ["indicator_1"]
  - type: status
    status: [200]

# OR — any matcher can match (broad, more FPs)
matchers-condition: or
matchers:
  - type: word
    words: ["indicator_1"]
  - type: word
    words: ["indicator_2"]
```

### Extractors

```yaml
extractors:
  # Regex extractor with capture group
  - type: regex
    part: body
    group: 1
    regex:
      - 'Version:\s*([0-9.]+)'
    name: version

  # JSON path extractor
  - type: json
    part: body
    json:
      - '.data.user.email'
    name: leaked_email

  # Key-value from headers
  - type: kval
    kval:
      - server
      - x-powered-by
    name: server_info

  # DSL extractor
  - type: dsl
    dsl:
      - 'status_code'
      - 'content_length'
      - 'len(body)'
    name: response_meta
```

## Workflow

### Step 1: Analyze Response Differences

```bash
node scripts/agent.js --action compare \
  --vulnerable-response vuln.txt --patched-response patched.txt \
  --output /tmp/matcher-analysis.json
```

### Step 2: Validate Matcher Precision

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

## Verification

- [ ] Multi-layer matchers used (word + status + negative at minimum)
- [ ] `matchers-condition: and` for high-confidence detection
- [ ] Negative matchers exclude common false positive patterns
- [ ] DSL expressions validated against edge cases
- [ ] Extractors pull evidence for finding reports
- [ ] Tested against both vulnerable and patched responses

## References

- [Nuclei Matchers](https://docs.projectdiscovery.io/templates/reference/matchers)
- [Nuclei Extractors](https://docs.projectdiscovery.io/templates/reference/extractors)
- [Nuclei DSL Reference](https://docs.projectdiscovery.io/templates/reference/helper-functions)
