ToolJet/ToolJet · critical · QueryError
Redirect blocked by SSRF protection
Error message
Redirect blocked by SSRF protection
What it means
Thrown by the beforeRedirect hook attached to outgoing requests. When the server returns a redirect, the Location header is validated through validateUrlForSSRF; if it fails, the redirect is blocked and the original validation error is wrapped with context. This closes the open-redirect-to-SSRF bypass where an allowed domain redirects to a private/metadata target.
Source
Thrown at marketplace/plugins/common/lib/ssrf-protection.ts:710
const ssrfOptions: any = {
...existingOptions,
// Custom DNS lookup function to validate resolved IPs
dnsLookup: createSSRFSafeLookup(config),
};
// Redirect validation hook - prevents SSRF bypass via open redirects
// This validates redirect URLs using the same SSRF rules as the initial request,
// blocking attacks where an allowed domain redirects to a private IP/endpoint
const beforeRedirectHook = async (options: any, response: any) => {
// Validate redirect URL
const redirectUrl = response.headers.location;
if (redirectUrl) {
try {
// Validate the redirect URL
await validateUrlForSSRF(redirectUrl, config);
} catch (error) {
throw new QueryError(
'Redirect blocked by SSRF protection',
`Redirect to "${redirectUrl}" was blocked: ${error.message}`,
{ redirectUrl, originalError: error }
);
}
}
};
// Properly merge hooks
if (existingOptions?.hooks) {
ssrfOptions.hooks = {
...existingOptions.hooks,
beforeRedirect: [
...(existingOptions.hooks.beforeRedirect || []),
beforeRedirectHook
]
};
} else {View on GitHub (pinned to 20602a8e10)
Solutions
- Inspect error.data.redirectUrl and error.data.originalError to see which SSRF rule the redirect violated.
- If the redirect target is legitimate on a self-hosted instance, add it to SSRF_ALLOWED_HOSTNAMES.
- Disable redirect-following for the request (followRedirects:false) and resolve the final URL yourself if you need explicit control.
- Audit the upstream API: an unexpected redirect to a private target may indicate a compromised or misconfigured service.
Example fix
// before — got(url, { followRedirect: true }) where upstream redirects to http://169.254.169.254/...
// after — got(url, { followRedirect: false }) then explicitly fetch the validated final URL, or allowlist the legitimate redirect target Defensive patterns
Strategy: validation
Validate before calling
function shouldFollowRedirect(currentUrl: string, nextUrl: string): boolean {
// caller-controlled: validate nextUrl against SSRF policy (or the allowlist) before following
try { /* sync-validate nextUrl */; return true; } catch { return false; }
} Try / catch
try { await got(url, ssrfOptions); } // ssrfOptions wires the beforeRedirect hook
catch (e) {
if (e instanceof QueryError && e.message === 'Redirect blocked by SSRF protection') {
// inspect e.data.redirectUrl and e.data.originalError; either allowlist the target or disable followRedirect for this call
}
throw e;
} Prevention
- Where possible, set followRedirect:false and resolve the final URL explicitly so you control validation.
- Allowlist only known-good redirect targets (e.g., a CDN's signed-URL host).
- Audit upstream APIs that redirect unexpectedly — they may be misconfigured or compromised.
When it happens
Trigger: An allowed host returns a 3xx with a Location pointing at a private IP, metadata endpoint, blocked scheme, or localhost; the redirect chain crosses into a blocked hostname; the Location header is itself malformed.
Common situations: Legitimate APIs that redirect to S3-style signed URLs (rarely blocked) versus a crafted API that redirects to 169.254.169.254; CDNs that redirect to internal addresses on misconfigured origins; login flows that redirect to an internal IdP.
Related errors
- Redirect blocked by SSRF protection
- Invalid URL format
- Private IP in URL credentials blocked
- Hostname blocked
- URL scheme blocked
AI-assisted analysis of ToolJet/ToolJet@20602a8e10 (2026-08-13).
Data as JSON: /api/errors/02a4c68e6f3a63a1.
Report an issue: GitHub.