Skip to content
Exploit for Heap-based Buffer Overflow in F5 Nginx_Gateway_Fabric

Exploit for Heap-based Buffer Overflow in F5 Nginx_Gateway_Fabric

Sploitus • September 10, 2026

nginx evaluates directive values (`proxy_set_header`, `return`, `add_header`, etc.)

in **two passes** using a shared mutable array `r->captures`:

| **LEN** | Measure buffer size needed | Yes — to get `$1` length |

| *(regex map evaluates here, CLOBBERING `r->captures`)* | | |

| **VALUE** | Write data into allocated buffer | Yes — but now `$1` points elsewhere |

~*(bot|crawl|spider) 1; # ← regex map = clobber trigger

location ~ "^/api/v1/(.+)$" { # ← regex capture source

proxy_set_header X-Route "$1 — $is_bot"; # ← two-pass sink

# capture ref + map var in same buffer = BUG

| Direction | URI size | Map input size | Result |

|-----------|----------|----------------|--------|

| **Overflow** | Short (3 B) | Long (4096 B) | LEN allocates small, VALUE writes large → heap overflow |

| **Info Leak** | Long (8000 B) | Short (5 B) | LEN allocates large, VALUE writes small → heap residue in response |

| `/api/v1/{path}` | `proxy_set_header` | `$is_bot` (User-Agent) | Overflow |

| `/leak/{path}` | `return` + `add_header` | `$ref_domain` (Referer) | Info leak |

| `/rce/{path}` | `set` + `return` | `$is_bot` (User-Agent) | Overflow |

| `/safe/{path}` | `return` (no map) | None | Control (safe) |

| `docker-compose.yml` | Lab orchestration |

| `Dockerfile.nginx-vuln` | Vulnerable nginx 1.26.x |

| `Dockerfile.nginx-patched` | Patched nginx 1.30.4 |

| `nginx-vuln.conf` | Vulnerable configuration with annotated patterns |

| `backend.py` | Echo server to inspect proxied headers |

| `poc_overflow.py` | Heap overflow PoC (escalating payload sizes) |

| `poc_infoleak.py` | Info leak PoC (heap residue detection) |

| `poc_curl.sh` | Quick curl-based tests |

Use the [config scanner](

python3 nginx_capture_clobber_scan.py /etc/nginx/nginx.conf

1. **Separate** regex captures and regex map variables into different directives/locations

2. Use **named captures** and reference them only inside the block holding the regex match

3. Avoid `~` / `~*` regex patterns in `map` when captures are used elsewhere

- [Researcher writeup (cyberstan.co.uk)](

- [NVD entry](

- [Config scanner](

- [nginx advisory](

**FOR EDUCATIONAL AND AUTHORIZED SECURITY TESTING ONLY.**

Extracted Entities

Domains (1)