Share
## https://sploitus.com/exploit?id=638CA901-49ED-594C-BD8A-656389B1155C
# way2poc_cve-2026-34475
 CVE-2026-34475 β€” Nuclei Detection Templates

> Two-stage Nuclei detection for CVE-2026-34475: fingerprint vulnerable Varnish instances, verify cache-key collision behavior, and confirm exploitability via VCL inspection β€” without triggering the bug.

**As some tried to make themselves super-smart. VSV00018 Β· Varnish Cache req.url Mishandling Β· CVSS 5.4 (Medium)**
** It would be nice if someone gets to a real exploit script but the potential attack surface is limited to "root" URLs with a path of /, such as https://megacorpexample.com/ β€” but not https://megacorpexample.com/whatever. That is a very narrow condition. CISA rates the vulnerability as currently not exploited, not automatable, and with only partial technical impact.**
---

## Overview

This repository contains [Nuclei](https://github.com/projectdiscovery/nuclei) templates for **passive detection and active verification** of systems potentially affected by CVE-2026-34475.

### What is CVE-2026-34475?

In certain configurations, Varnish Cache mishandles the internal variable `req.url` when HTTP/1.1 requests arrive with a root path (`/`). Specifically: if `req.url` is passed unchecked to a backend that accepts *absolute-form URIs* (e.g. `GET https://example.com/ HTTP/1.1` instead of `GET / HTTP/1.1`), an attacker can leverage this for **cache poisoning** or **authentication bypass**.

The attack surface is limited to root URLs β€” paths like `/api/users` are **not** affected.

**Official references:**
- [VSV00018 β€” varnish-cache.org](https://varnish-cache.org/security/VSV00018.html)
- [VSV00018 β€” docs.varnish-software.com](https://docs.varnish-software.com/security/VSV00018/)
- [CVE-2026-34475 β€” cve.org](https://vulners.com/cve/CVE-2026-34475)

---

## Affected Versions

| Product | Affected | Fixed |
|---|---|---|
| Varnish Cache (Open Source) | ≀ 8.0.0 (all releases) | 8.0.1 |
| Varnish Cache 6.0 LTS | ≀ 6.0.16 | 6.0.17 |
| Varnish Enterprise | 6.0.x ≀ 6.0.16r11 | 6.0.16r12 |

---

## How the Detection Template Works

The detect template sends only **standard origin-form HTTP requests** β€” no vulnerability is triggered, no manipulated request is sent, no exploitation is attempted. Detection is based purely on passive header analysis.

### Step 1 β€” Varnish Fingerprinting

```yaml
method: GET
path:
  - "{{BaseURL}}/"
```

A plain `GET /` request is sent to the target in origin-form β€” exactly as any browser or HTTP client would send it. Indistinguishable from regular traffic.

### Step 2 β€” Matcher: Is Varnish Running?

```yaml
matchers:
  - type: status
    status: [200, 301, 302, 403, 404]

  - type: regex
    part: header
    regex:
      - "(?i)X-Varnish:\\s*[0-9]+"
```

The first matcher simply checks that the target responds. The key matcher is the second: it looks for the `X-Varnish` header in the response.

**Why `X-Varnish` is reliable:** Varnish sets this header on every outgoing response β€” it contains the internal transaction ID (VXP). It is a dependable fingerprint signal since it is typically only set by Varnish itself and cannot easily be spoofed without removing it entirely.

The template only fires when both matchers hit β€” response present **and** `X-Varnish` set. This keeps false positives to a minimum.

### Step 3 β€” Extractors: Reading Version and Cache State

The template extracts seven values from response headers:

```yaml
extractors:
  - name: x_varnish         # Transaction IDs β€” confirms Varnish is running
  - name: server_header     # May contain explicit version string
  - name: via_header        # Often: "1.1 varnish (Varnish/6.0)" β€” version info
  - name: varnish_version   # Regex extracts "6.0", "8.0.0" etc. directly
  - name: cache_age         # Age > 0 β†’ response served from cache
  - name: cache_control     # Cache directives of the target
  - name: x_cache           # HIT/MISS status if present
```

#### `Via` Header as Version Source

Per RFC 7230, proxies are required to set the `Via` header, which typically includes the protocol and proxy name. Varnish sets it in the form:

```
Via: 1.1 varnish (Varnish/6.0)
```

The regex `(?i)Varnish/([0-9]+\.[0-9]+\.?[0-9]*)` extracts the version string, which can be matched directly against the affected versions table above.

#### `Server` Header as Fallback

Some Varnish deployments explicitly set the `Server` header to `Varnish` or include a version string. The extractor captures the full value, e.g.:

```
Server: Varnish/8.0.0
```

#### `Age` Header as Caching Indicator

`Age` indicates how many seconds a cached response has been in the cache. A value > 0 confirms that Varnish is actively caching responses β€” relevant to the cache poisoning attack vector.

---

## Interpreting Results

### Scenario A β€” Version Clearly Readable

Extractors return a concrete version string (e.g. `6.0.14` via the `Via` header):

- Version in the affected range? β†’ **Vulnerable, immediate action required**
- Version above the fixed releases? β†’ **Not affected**

### Scenario B β€” Varnish Detected, Version Not Readable

`X-Varnish` header is present, but neither `Via` nor `Server` yield a version. This is common in hardened deployments (header stripping via custom VCL rules).

In this case: **treat as potentially affected** and check the version directly on the server:

```bash
varnishd -V
```

### Scenario C β€” No Match

The template does not fire. Either Varnish is not running on the target, or `X-Varnish` has been fully removed from responses. The latter is uncommon since the header is set internally by Varnish and removing it requires explicit VCL configuration.

---

## Three-Stage Workflow

Detection is intentionally split across two templates with different precision levels and activity footprints, followed by a manual whitebox step.

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 1: detect.yaml       β”‚  Passive. Header analysis only.
β”‚  Detects: Varnish present   β”‚  No unusual traffic generated.
β”‚  + version if readable      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
             β”‚ Match β†’ Varnish running, version potentially affected
             β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stage 2: verify.yaml       β”‚  Active. Sends absolute-form request.
β”‚  Checks: cache-key collisionβ”‚  Visible in server logs.
β”‚  between origin-form and    β”‚  Authorized targets only.
β”‚  absolute-form request      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
             β”‚ Match β†’ strong indicator of exploitable configuration
             β–Ό
     Stage 3: Whitebox VCL inspection
     (bereq.url = req.url without sanitization?)
```

### Why Two Templates?

HTTP headers alone cannot reliably determine whether an instance is actually exploitable. The vulnerability requires two conditions to be true simultaneously:

1. **Affected version** ( **Notice:** Both templates must only be used against systems for which explicit written authorization exists. The verify template generates traffic that will be visible in server logs.

---

## Stage 3 β€” Whitebox VCL Assessment

After a positive verify result, inspect the VCL configuration directly on the server. Three conditions must all be true for an instance to be actually exploitable.

### Condition 1 β€” `req.url` is Passed Without Sanitization

```vcl
# VULNERABLE: no prefix check before using req.url
sub vcl_recv {
    set req.http.X-Forwarded-Path = req.url;
}

sub vcl_backend_fetch {
    set bereq.url = req.url;  # absolute-form reaches the backend
}
```

```vcl
# SAFE: official workaround rejects absolute-form requests
sub vsv18 {
    if (req.method == "CONNECT") { return; }
    if (req.url == "*" && req.method == "OPTIONS") { return; }
    if (req.url !~ "^/") { return (synth(400)); }
}
sub vcl_recv { call vsv18; }
```

**What to look for:** Any location in `vcl_recv` or `vcl_backend_fetch` where `req.url` or `bereq.url` is set or used as a routing basis β€” without a prior `!~ "^/"` check.

### Condition 2 β€” The Backend Accepts Absolute-Form URIs

Varnish alone is not sufficient β€” the backend must also process the absolute-form URI. Typical risk profile by backend:

| Backend | Risk | Notes |
|---|---|---|
| Apache (ProxyPass) | High | Accepts absolute-form in many configurations |
| Node.js / Express | High | Parses `req.url` directly, no automatic check |
| Java (Jetty, Tomcat) | Medium | Historically tolerant of absolute-form |
| nginx | Low | Rejects absolute-form by default |

**Verification method:** Send a direct absolute-form request to the backend port (bypassing Varnish) β€” if the backend responds with 200 instead of 400, it accepts absolute-form URIs.

### Condition 3 β€” Cache Key Does Not Normalize `req.url`

```vcl
# VULNERABLE: Varnish default key applies, req.url not normalized
# β†’ absolute-form and origin-form may produce different keys
# or β€” depending on Varnish version β€” collide on the same key

# SAFE: explicit cache key that strips schema+host from req.url
sub vcl_hash {
    hash_data(regsub(req.url, "^https?://[^/]+", ""));
    hash_data(req.http.host);
    return (lookup);
}
```

**What to look for:** Does `vcl_hash` contain an explicit `hash_data()` call that normalizes `req.url`? If not, the Varnish default applies β€” and that default is vulnerable in affected versions.

### VCL Inspection Checklist

| Check | Sub | Vulnerable if... |
|---|---|---|
| `req.url` usage | `vcl_recv` | No `!~ "^/"` check present |
| `bereq.url` assignment | `vcl_backend_fetch` | Assigned directly from `req.url` without transformation |
| Hash basis | `vcl_hash` | `req.url` used in `hash_data()` without normalization |
| Host-based routing | `vcl_recv` | Routing decisions based on `req.url` instead of `req.http.host` |
| Built-in VCL version | β€” | Pre-fix built-in VCL contained no `^/` check |

### Exploitability Matrix

```
Condition 1 (req.url unchecked)
        +
Condition 2 (backend accepts absolute-form)
        +
Condition 3 (cache key not normalized)
        =  Cache Poisoning exploitable

Condition 1 (req.url unchecked)
        +
Condition 2 (backend makes auth decisions based on host in req.url)
        =  Authentication Bypass exploitable
```

Once all relevant conditions are confirmed, exploitability is established β€” without executing an active exploit. This is the methodologically clean conclusion of an authorized assessment.

---

## Mitigation

### Option 1 β€” Upgrade (recommended)

Upgrade to a fixed version per the affected versions table above.

### Option 2 β€” VCL Workaround

If an immediate upgrade is not possible, the following VCL snippet provides protection:

```vcl
sub vsv18 {
    if (req.method == "CONNECT") { return; }
    if (req.url == "*" && req.method == "OPTIONS") { return; }
    if (req.url !~ "^/") { return (synth(400)); }
}

sub vcl_recv {
    call vsv18;
}
```

This snippet rejects all requests where `req.url` does not begin with `/` β€” i.e. all absolute-form URIs. It must be placed at the top of the VCL so it runs before any other `vcl_recv` logic.

The workaround is confirmed safe by the official advisory and has since been incorporated into the built-in VCL as a forward-looking precaution.

---

## Template Limitations

### detect.yaml
- **No version β†’ no certainty:** If `Via` and `Server` headers contain no version information, the template only establishes: *Varnish is running here.* Check the version directly on the server (`varnishd -V`).
- **Header stripping:** Deployments that remove `X-Varnish` via VCL (`unset resp.http.X-Varnish`) will not be detected β€” even if Varnish is active. These setups typically have additional hardening measures in place.

### verify.yaml
- **Nuclei cannot compare cross-request values natively:** The cache HIT indicator (two IDs in `X-Varnish`) only works if the baseline request was actually cached before the absolute-form request arrives. Very short TTLs or `no-store` policies will prevent the comparison from firing.
- **Not proof of exploitability:** Even a cache key collision does not prove that an attacker can inject malicious content. That requires confirming that `req.url` is passed to a backend that accepts absolute-form β€” which requires whitebox access.
- **Timing-dependent:** Cache entries may expire between request 1 and request 2. With very short TTL values, consider using `-rate-limit 1` and manually checking the time delta.

---

## Files

| File | Stage | Type | Description |
|---|---|---|---|
| `cve-2026-34475-detect.yaml` | 1 | Passive | Varnish fingerprint + version check |
| `cve-2026-34475-verify.yaml` | 2 | Active | Cache-key collision test via absolute-form |
| `README.md` | 3 | Whitebox | VCL inspection checklist for manual assessment |

---

## Resources

- [Nuclei Documentation](https://docs.projectdiscovery.io/tools/nuclei/overview)
- [Varnish VCL Reference](https://varnish-cache.org/docs/trunk/reference/vcl.html)
- [CWE-180: Incorrect Behavior Order β€” Validate Before Canonicalize](https://cwe.mitre.org/data/definitions/180.html)
- [RFC 7230 β€” HTTP/1.1 Message Syntax (absolute-form)](https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.2)