Fix open redirect in Vanta authorization redirect endpoint (#49077)

<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** NA (found via Aikido SAST triage)

## What changed

`GET /redirect-vanta-authorization-request` is a public, unauthenticated
endpoint that set signed cookies and then redirected the browser to the
caller-supplied `vantaAuthorizationRequestURL` with no validation.
Because the redirect target came straight from a query parameter, the
endpoint could be abused as an open redirect: an attacker could craft a
`https://fleetdm.com/redirect-vanta-authorization-request?...&vantaAuthorizationRequestURL=https://evil.example.com`
link that bounces a victim to an arbitrary domain (phishing). The only
prior gate was a `VantaConnection.findOne({vantaSourceId})` lookup,
which does not bind the source ID to the redirect target and is
satisfiable by anyone who has ever initiated a Vanta connection.

This adds a host/scheme allowlist before redirecting. The legitimate
destination is always `https://app.vanta.com/oauth/authorize?...`
(constructed server-side in `create-vanta-authorization-request.js`), so
the endpoint now only redirects when the parsed URL is `https:` and its
host is `app.vanta.com`; otherwise it returns `badRequest`.

# Checklist for submitter

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.

## Testing

- [x] QA'd all new/changed functionality manually

Legitimate flow (redirect target `https://app.vanta.com/...`) still
redirects as before; a target on any other host or a non-`https` scheme
now returns `badRequest` instead of redirecting.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved safety for authorization redirects by validating the
destination before sending users onward.
* Redirects now only proceed when the target uses a secure connection
and the approved site.
* Invalid or malformed redirect links now return a clear bad-request
response instead of continuing.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Luke Heath
2026-07-10 12:54:57 -05:00
committed by GitHub
parent e7c2f10192
commit 6ed8217583
@@ -36,6 +36,10 @@ module.exports = {
description: 'No Vanta connection could be found using the provided vantaSourceId',
responseType: 'badRequest'
},
invalidVantaAuthorizationRequestURL: {
description: 'The provided vantaAuthorizationRequestURL is not a valid Vanta authorization URL.',
responseType: 'badRequest'
},
},
@@ -49,6 +53,18 @@ module.exports = {
throw 'noMatchingVantaConnection';
}
// Since this is a public endpoint and the destination is caller-supplied, only allow redirecting
// to Vanta's authorization host. This prevents the endpoint from being abused as an open redirect.
let parsedVantaAuthorizationRequestURL;
try {
parsedVantaAuthorizationRequestURL = new URL(vantaAuthorizationRequestURL);
} catch (unusedErr) {
throw 'invalidVantaAuthorizationRequestURL';
}
if(parsedVantaAuthorizationRequestURL.protocol !== 'https:' || parsedVantaAuthorizationRequestURL.host !== 'app.vanta.com') {
throw 'invalidVantaAuthorizationRequestURL';
}
// Set a 'state' and 'vantaSourceId' cookie on the users browser.
this.res.cookie('redirectAfterSetup', redirectAfterSetup, {signed: true});
this.res.cookie('state', state, {signed: true});