FastGPT axios SSRF guard can be bypassed with an HTTP redirect
Summary
FastGPT's shared SSRF guard validates only the initial request URL before handing the request to axios. Axios follows redirects by default. If an attacker-controlled public URL returns a 302 redirect to a blocked target such as http://169.254.169.254/ or http://127.0.0.1/, the redirected request is made without running the SSRF guard again.
The reachable workflow sink returns the response body to the workflow caller, so this is a non-blind SSRF against endpoints that the guard is specifically intended to block.
Root cause
The shared axios helper enforces SSRF protection as an axios request interceptor. That interceptor validates the URL supplied by the FastGPT caller before the request is handed to axios, but redirect handling happens later inside axios/follow-redirects. Redirect Location targets do not pass through isInternalAddress() again.
FastGPT already has internal-address and resolved-IP checking primitives, but the resolved-IP recheck is wired to the code-sandbox path rather than the main shared axios path used by workflow HTTP requests. The main axios layer also does not disable redirects or use a redirect hook to validate each hop.
Auth boundary
The intended boundary is that an authenticated workflow user may request external public HTTP resources, but should not be able to use the FastGPT backend as a proxy to cloud metadata, loopback, Kubernetes service hostnames, or other protected internal services.
That boundary is crossed because the user controls the initial workflow HTTP URL, and an attacker-controlled public URL can redirect the server-side request to a target the SSRF guard would block if supplied directly. The HTTP workflow node returns rawResponse, so the protected service response is exposed back to the workflow caller.
Affected code
Verified at FastGPT main commit 82fa431a819ed56276209915609a15141b571206 on 2026-06-07.
Relevant paths:
packages/service/common/api/axios.ts
packages/global/common/system/network.ts
packages/service/core/workflow/dispatch/tools/http468.ts
packages/service/core/workflow/dispatch/index.ts
addSSRFInterceptor uses an axios request interceptor. That hook checks isInternalAddress(requestUrl) for the original URL, but there is no maxRedirects: 0, beforeRedirect, response hook, or per-hop validation. Current-source checks confirmed no redirect validation in the shared axios guard or the workflow HTTP sink.
The workflow HTTP request node calls the guard on the configured URL and then calls axios with that URL. The node returns rawResponse, making the SSRF non-blind.
Proof of concept
The PoC imports the real FastGPT network.ts guard and recreates the axios interceptor behavior. It starts:
- a protected local server representing a blocked endpoint, and
- a guard-passing redirect server that returns
302 Location: http://127.0.0.1:<port>/latest/meta-data/.
Control checks show the real guard blocks direct requests to:
http://127.0.0.1/
http://169.254.169.254/latest/meta-data/
http://metadata.google.internal/
http://100.100.100.200/
The same interceptor then accepts the guard-passing redirect URL, axios follows the 302, and the protected server body is returned.
Transcript excerpt:
[A] CONTROL - real isInternalAddress() on direct URLs:
blocked http://127.0.0.1:44067/latest/meta-data/
blocked http://127.0.0.1/
blocked http://169.254.169.254/latest/meta-data/
blocked http://metadata.google.internal/
blocked http://100.100.100.200/
ALLOWED http://172.18.0.1:37349/fetch <- guard-passing carrier
[B] GAP - axios.get(redirector) with the REAL SSRF interceptor:
http://172.18.0.1:37349/fetch -302-> http://127.0.0.1:44067/latest/meta-data/
interceptor validated only the initial (LAN) url; redirect target NOT re-checked
leaked blocked-loopback body (returned as rawResponse) = true
body -> "INTERNAL-ONLY-RESPONSE: metadata-body-from-blocked-target"
The local loopback target is used to keep the PoC non-destructive. A redirect to 169.254.169.254 follows the same unvalidated redirect path. This is a source-faithful harness using the real guard plus recreated shared axios interceptor and source-confirmed workflow sink, not a full FastGPT workflow-server run.
Impact
An authenticated FastGPT user who can create or run a workflow can configure an HTTP request node to call an attacker-controlled URL. That URL can redirect the FastGPT server to cloud metadata, loopback, or internal services that are blocked on direct request. Because the HTTP node returns the response body, this can expose metadata credentials or internal service responses to the workflow caller.
Difference from the known DNS rebinding issue
This is distinct from the existing DNS rebinding advisory for isInternalAddress.
| Issue |
Technique |
Why it works |
Required fix |
| DNS rebinding |
Same hostname resolves to a safe IP at validation time and an internal IP at connection time |
The validated hostname is fetched later after DNS changes |
Resolve and pin the IP used for the connection |
| Redirect-follow bypass |
Initial URL is safe, then axios follows Location to a blocked URL or literal internal IP |
Redirect target is a new URL and is never validated |
Disable redirects or validate every redirect hop before following |
DNS pinning the initial host would not stop 302 Location: http://169.254.169.254/...; redirect validation or redirect disabling is needed.
Recommended fix
Apply redirect-aware SSRF protection in the shared axios layer. Safe options include:
- set
maxRedirects: 0 and reject redirects unless the application explicitly validates and follows them, or
- add a
beforeRedirect hook that validates every Location target with the same SSRF policy before the redirected request is made, and
- use the existing connect-time internal-IP check for the actual socket target, not only in the code-sandbox path.
This should be applied to the shared axios helper so all URL-fetching callers receive the same redirect protection.
FastGPT axios SSRF guard can be bypassed with an HTTP redirect
Summary
FastGPT's shared SSRF guard validates only the initial request URL before handing the request to axios. Axios follows redirects by default. If an attacker-controlled public URL returns a 302 redirect to a blocked target such as
http://169.254.169.254/orhttp://127.0.0.1/, the redirected request is made without running the SSRF guard again.The reachable workflow sink returns the response body to the workflow caller, so this is a non-blind SSRF against endpoints that the guard is specifically intended to block.
Root cause
The shared axios helper enforces SSRF protection as an axios request interceptor. That interceptor validates the URL supplied by the FastGPT caller before the request is handed to axios, but redirect handling happens later inside axios/follow-redirects. Redirect
Locationtargets do not pass throughisInternalAddress()again.FastGPT already has internal-address and resolved-IP checking primitives, but the resolved-IP recheck is wired to the code-sandbox path rather than the main shared axios path used by workflow HTTP requests. The main axios layer also does not disable redirects or use a redirect hook to validate each hop.
Auth boundary
The intended boundary is that an authenticated workflow user may request external public HTTP resources, but should not be able to use the FastGPT backend as a proxy to cloud metadata, loopback, Kubernetes service hostnames, or other protected internal services.
That boundary is crossed because the user controls the initial workflow HTTP URL, and an attacker-controlled public URL can redirect the server-side request to a target the SSRF guard would block if supplied directly. The HTTP workflow node returns
rawResponse, so the protected service response is exposed back to the workflow caller.Affected code
Verified at FastGPT
maincommit82fa431a819ed56276209915609a15141b571206on 2026-06-07.Relevant paths:
packages/service/common/api/axios.tspackages/global/common/system/network.tspackages/service/core/workflow/dispatch/tools/http468.tspackages/service/core/workflow/dispatch/index.tsaddSSRFInterceptoruses an axios request interceptor. That hook checksisInternalAddress(requestUrl)for the original URL, but there is nomaxRedirects: 0,beforeRedirect, response hook, or per-hop validation. Current-source checks confirmed no redirect validation in the shared axios guard or the workflow HTTP sink.The workflow HTTP request node calls the guard on the configured URL and then calls axios with that URL. The node returns
rawResponse, making the SSRF non-blind.Proof of concept
The PoC imports the real FastGPT
network.tsguard and recreates the axios interceptor behavior. It starts:302 Location: http://127.0.0.1:<port>/latest/meta-data/.Control checks show the real guard blocks direct requests to:
http://127.0.0.1/http://169.254.169.254/latest/meta-data/http://metadata.google.internal/http://100.100.100.200/The same interceptor then accepts the guard-passing redirect URL, axios follows the 302, and the protected server body is returned.
Transcript excerpt:
The local loopback target is used to keep the PoC non-destructive. A redirect to
169.254.169.254follows the same unvalidated redirect path. This is a source-faithful harness using the real guard plus recreated shared axios interceptor and source-confirmed workflow sink, not a full FastGPT workflow-server run.Impact
An authenticated FastGPT user who can create or run a workflow can configure an HTTP request node to call an attacker-controlled URL. That URL can redirect the FastGPT server to cloud metadata, loopback, or internal services that are blocked on direct request. Because the HTTP node returns the response body, this can expose metadata credentials or internal service responses to the workflow caller.
Difference from the known DNS rebinding issue
This is distinct from the existing DNS rebinding advisory for
isInternalAddress.Locationto a blocked URL or literal internal IPDNS pinning the initial host would not stop
302 Location: http://169.254.169.254/...; redirect validation or redirect disabling is needed.Recommended fix
Apply redirect-aware SSRF protection in the shared axios layer. Safe options include:
maxRedirects: 0and reject redirects unless the application explicitly validates and follows them, orbeforeRedirecthook that validates everyLocationtarget with the same SSRF policy before the redirected request is made, andThis should be applied to the shared axios helper so all URL-fetching callers receive the same redirect protection.