ATS follow-redirect treats 0.0.0.0/8 as routable
Apache Traffic Server 10.2.0 redirect.actions routable:follow still classifies 0.0.0.0/8 as FOLLOW. Default CONNECT dest deny and ESI validator already reject those ranges. number_of_redirections=1 follows Location http://0.0.0.1/. Loopback RETURN. 0.0.0.0 400. Labbed. Default counter is 0.
- Name
- ATS follow-redirect treats 0.0.0.0/8 as routable
- Type
- 0-day analysis
- CVE
- n/a
- CVE Risk
- high
- Disclosure Status
- public
- Vendor
- Apache Traffic Server (ASF)
- Affected
- Apache Traffic Server 10.2.0 (b1df7334) follow-redirect when number_of_redirections > 0 (or a plugin TSHttpTxnRedirectUrlSet). Default counter is 0. Compiled redirect.actions is routable:follow.
- Published
- 13 Oct 2026
- Updated
- 14 Oct 2026
- Tags
- 0-day, trafficserver, ssrf, redirect, cwe-918
CONNECT already knew 0.0.0.0/8 was not routable. Follow-redirect did not.
I am @abraxas_null. The proof of concept is on GitHub: abraxas/ats-redirect-zero-net (loopback client). The lab stack is lab/: Dockerfile, docker-compose.yml, run.sh, poc.py, stub.py. Authorized lab only. It talks to loopback.
This is Apache Traffic Server 10.2.0 (b1df7334b39a878971c376da849e8da4984918b6). No CVE yet. CWE-918. 8.6 High (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N). Remote SSRF. Scope Changed. Follow-redirect on.
Default number_of_redirections is 0. redirect.actions default is routable:follow, but it is not evaluated until follow is on. A loaded plugin that calls TSHttpTxnRedirectUrlSet still forces one hop even when the counter is 0. CVE-2026-58189 counter reset is closed. The one hop remains.
Loopback is 127.0.0.0/8 and ::1. 0.0.0.0/8 is not in that bucket. ats_is_ip_any rejects 0.0.0.0 and :: before the map. 0.0.0.1 falls through to ROUTABLE fill of 0/0. FOLLOW.
Default ip_allow.yaml CONNECT dest deny already lists 0.0.0.0/8 and ::ffff:0:0/96. ESI IncludeUrlValidator treats 0.0.0.0/8 as private as part of CVE-2026-58178. Core follow-redirect did not get the same ranges.
On Linux, 0.0.0.1 is local. Remap is skipped on the follow hop. ATS dials it as the ATS uid.
Why Traffic Server
SSRF on a reverse proxy is the sport of 2026. ATS spent July closing ESI includes, plugin redirect counters, prefetch .., CONNECT dest, hop-by-hop. Follow-redirect is the other origin-controlled dial. The action map looks complete until you notice loopback was drawn as 127/8 in 1981 and 0/8 is the other historical "this host" net.
I only wanted Critical or High. Default follow-off is not a skip when the compiled routable:follow is the thing operators turn on with a single integer, and when a plugin hop still fires at 0.
Pinning 10.2.0
Tag 10.2.0, peel b1df7334b39a878971c376da849e8da4984918b6. Lab image ats-10.2.0-lab:local. number_of_redirections: 1. remap_required: 1. redirect.actions left at compiled default.
Witness binds 0.0.0.1:18080 inside the netns so FOLLOW is observable. Loopback secret binds 127.0.0.1:18080. TEST-NET 203.0.113.10 proves routable still FOLLOW. 0.0.0.0 proves INADDR_ANY still 400.
The skip list is half the hunt
- CVE-2026-58189 plugin redirect-counter reset:
InkAPI.ccno longer zerosredirection_tries. Closed. One hop remains by design. - CVE-2026-58178 ESI include SSRF: private literals including 169.254/16, IPv4-mapped unwrap, nested comments, depth cap.
0.0.0.0/8is private there. - CVE-2026-58183 prefetch crash / relative-path constrain:
makeSafeRelativeFetchPath. Closed. - FetchSM does not follow
Location.http+unixis inbound remap-match, not an outbound origin. - Parent table ships as comments.
remap_required: 1404s a miss. - Default follow is off. A leftover of the July SSRF work still counts when follow is the documented knob.
How the map misses 0/8
parse_redirect_actions (HttpConfig.cc:1747-1787):
- private:
10/8,100.64/10,172.16/12,192.168/16,fc00::/7 - loopback:
127/8and::1only - multicast:
224/4,ff00::/8 - linklocal:
169.254/16,fe80::/10 - then
fill(0/0)/fill(::/0)with ROUTABLE=FOLLOW
fill does not change existing mappings. Everything not marked is FOLLOW. 0.0.0.1 is not marked.
HttpTransact::OSDNSLookup rejects INADDR_ANY / :: before the action map. That is why Location: http://0.0.0.0/ is 400 and http://0.0.0.1/ is not.
Follow hop skips remap (HandleRequest). remap_required: 1 does not save you on the second request. Authorization and Cookie on the client request are not stripped. I marked that inferred. The lab oracle is the witness body, not a stolen cookie.
Wrong turns, in order
Filing default follow-off as a CVE. It is not. The leftover is the map once follow is on.
Expecting loopback RETURN to cover 0/8. Loopback is 127/8. That is a different RFC.
Calling INADDR_ANY the leftover. 0.0.0.0 400 is the control. 0.0.0.1 is the leftover.
Re-filing ESI or CONNECT. Those already deny 0.0.0.0/8. The point is follow-redirect did not.
IPv4-mapped as the primary row. Sibling. CONNECT dest deny already lists ::ffff:0:0/96. Lab did not exercise mapped-v6. Marked inferred.
A reverse shell. Theatre. The oracle is client body ATS-REDIRECT-ZERO-NET-WITNESS after a 302 to 0.0.0.1.
The lab
Loopback 127.0.0.1:18790. Compose ats-redirect-zero-net. Four origin stubs:
origin-a.lab302 tohttp://0.0.0.1:18080/w(POC FOLLOW)origin-b.lab302 tohttp://127.0.0.1:18080/loop(CONTROL RETURN)origin-c.lab302 to TEST-NET (CONTROL FOLLOW)origin-any.lab302 tohttp://0.0.0.0:18080/(CONTROL 400)
Last line:
SUCCESS ats-redirect-zero-net follow-0.0.0.1=yes loopback-return=yes routable-follow=yes inaddr-any=400 remap_required=1 ATS-REDIRECT-ZERO-NET-WITNESSWhat an attacker can do
Have ATS follow Location: http://0.0.0.1/ after number_of_redirections=1 (or after a plugin TSHttpTxnRedirectUrlSet).
| Method | Sink | Privilege |
|---|---|---|
Unauth GET; origin 302 Location: http://0.0.0.1:18080/w with number_of_redirections=1 |
parse_redirect_actions ROUTABLE fill (HttpConfig.cc:1782-1787); OSDNSLookup action map |
Recon / SSRF (lab-proven): ATS follows as ROUTABLE. Client body ATS-REDIRECT-ZERO-NET-WITNESS. Remap skipped on the follow hop. |
Same hop; Authorization / Cookie copied |
HttpSM::redirect_request |
Integrity (inferred): those headers are not stripped on the follow hop. Not exercised as a write. |
IPv4-mapped ::ffff:0:0/96 |
same fill of ::/0 |
Recon (inferred): sibling of CONNECT dest deny. Not exercised. |
Lab-proven vs inferred: follow 0.0.0.1, loopback RETURN, routable FOLLOW, INADDR_ANY 400 are lab. IPv4-mapped and credential forward are inferred.
Requires: redirect.actions routable:follow (compiled default) and number_of_redirections > 0, or a plugin that sets a redirect URL. Default counter is 0.
You get an HTTP read of whatever listens on 0.0.0.1 on the ATS host, as the ATS uid, with remap skipped. You do not get 127.0.0.1 (RETURN). You do not get 0.0.0.0 (400). You do not get this when follow is off and no plugin sets a redirect URL. You do not get ESI file://. You do not get CONNECT to 0/8 (already denied).
Adjacent surface that stays closed
| Surface | Why |
|---|---|
Loopback 127.0.0.1 |
RETURN. Client never saw LOOPBACK-ONLY-SECRET. Stayed 302. |
0.0.0.0 INADDR_ANY |
400 before the action map |
Default number_of_redirections=0 |
routable:follow unevaluated |
RFC1918 / CGNAT / link-local / ::1 |
RETURN via the DEFAULT fill |
CONNECT dest deny 0.0.0.0/8 |
already in default ip_allow.yaml |
ESI include validator 0.0.0.0/8 |
already private (CVE-2026-58178) |
| Plugin redirect counter reset | closed (CVE-2026-58189) |
The fix
Mark 0.0.0.0/8 and IPv4-mapped ::ffff:0:0/96 the same way default CONNECT dest deny and ESI IncludeUrlValidator already do. Loopback is not only 127/8. ats_is_ip_any rejecting 0.0.0.0 is not enough.
Until then, leave number_of_redirections at 0, or set redirect.actions so routable is RETURN. A plugin TSHttpTxnRedirectUrlSet still forces one hop.
I am not going to print a Location you can paste at someone else's cache. The missing CIDR is the useful part. If you own the proxy, run the proof of concept against loopback.
References
- Proof of concept: abraxas/ats-redirect-zero-net · ats-redirect-zero-net-Abraxas-Labs.py
- Lab:
lab/· Dockerfile · docker-compose.yml · run.sh · poc.py - @abraxas_null · github.com/abraxas · abraxaslabs.tech · abraxas.null@proton.me
- CWE-918
- Tree: apache/trafficserver 10.2.0 (
b1df7334b39a878971c376da849e8da4984918b6) ·HttpConfig.cc·RecordsConfig.cc·InkAPI.cc·ip_allow.yaml.default - Contrast: ESI
IncludeUrlValidator0.0.0.0/8private (CVE-2026-58178) · CVE-2026-58189 plugin redirect counter