Open Redirect in Restify
How Open Redirect Manifests in Restify
Open Redirect vulnerabilities in Restify applications typically occur when the framework's built-in redirect functionality is used with untrusted user input. Restify's res.redirect() method accepts a URL parameter that, if not properly validated, can be manipulated by attackers to redirect users to malicious sites.
const restify = require('restify');
const server = restify.createServer();
server.get('/login', (req, res) => {
const redirectUrl = req.query.returnTo || '/dashboard';
res.redirect(302, redirectUrl);
});In this Restify pattern, an attacker can craft a URL like /login?returnTo=https://evil.com to redirect victims to phishing sites. The vulnerability is particularly dangerous because it exploits the trust users have in your domain.
Restify's middleware chain can also introduce open redirect risks. When using server.router or custom middleware that performs redirects based on request parameters, the same validation issues apply:
server.use((req, res, next) => {
if (req.query.next) {
res.redirect(302, req.query.next); // Vulnerable!
}
next();
});Another Restify-specific pattern involves the res.send() method with redirect codes. While res.redirect() is the standard approach, developers sometimes use:
res.send(302, '', { Location: req.query.url });This achieves the same vulnerable behavior but bypasses some of Restify's built-in protections.
Open redirects can also manifest through Restify's route parameter handling. When redirect destinations are constructed from URL parameters or path variables:
server.get('/redirect/:target', (req, res) => {
res.redirect(302, req.params.target); // Vulnerable to parameter tampering
});The key insight is that Restify treats redirect URLs as opaque strings without inherent validation, making it the developer's responsibility to ensure they're safe.
Restify-Specific Detection
Detecting open redirects in Restify applications requires examining both the codebase and runtime behavior. Start by searching for redirect patterns in your Restify routes:
grep -r 'res\.redirect' routes/ --include='*.js'
grep -r 'Location:' routes/ --include='*.js'Look for instances where redirect URLs come from:
req.queryparameters (query strings)req.params(route parameters)req.body(POST data)- Headers like
RefererorOrigin
middleBrick's scanner can automatically detect open redirect vulnerabilities in your Restify APIs without requiring source code access. The scanner tests redirect endpoints by:
- Identifying potential redirect handlers through request/response pattern analysis
- Submitting test payloads with known malicious domains
- Verifying if the application follows the redirect to external sites
- Checking for open redirect in both authenticated and unauthenticated contexts
The scanner evaluates 12 security categories including Authentication, BOLA/IDOR, and Input Validation to provide a comprehensive security assessment. For open redirects specifically, it checks:
// middleBrick would detect this pattern
server.get('/auth/callback', (req, res) => {
const target = req.query.target || '/home';
res.redirect(302, target); // Scanner flags this
middleBrick's continuous monitoring (Pro plan) can alert you when new redirect endpoints are added to your API or when existing ones become vulnerable due to code changes.
Restify-Specific Remediation
Fixing open redirects in Restify requires implementing strict URL validation and using safe redirect patterns. The most effective approach is to maintain a whitelist of allowed redirect destinations:
const allowedRedirects = new Set([
'/dashboard',
'/profile',
'/settings',
'https://trusted-partner.com/callback'
]);
function safeRedirect(req, res, next) {
const target = req.query.returnTo || '/dashboard';
if (allowedRedirects.has(target)) {
res.redirect(302, target);
} else {
// Default to safe location
res.redirect(302, '/dashboard');
}
next();
}For applications that need to redirect to dynamic partner URLs, implement domain validation:
function validateRedirectUrl(url) {
try {
const parsed = new URL(url);
const allowedDomains = [
'yourdomain.com',
'partner1.com',
'partner2.com'
];
return allowedDomains.includes(parsed.hostname);
} catch (e) {
return false;
}
}
server.get('/oauth/callback', (req, res) => {
const redirectUrl = req.query.redirect_uri;
if (validateRedirectUrl(redirectUrl)) {
res.redirect(302, redirectUrl);
} else {
res.send(400, { error: 'Invalid redirect URI' });
}
});Restify's middleware system can help centralize redirect validation:
function redirectValidator(req, res, next) {
if (req.query.redirect || req.query.returnTo) {
const url = req.query.redirect || req.query.returnTo;
if (!validateRedirectUrl(url)) {
return res.send(400, { error: 'Invalid redirect destination' });
}
}
next();
}
server.use(redirectValidator);For absolute safety, consider using path-based redirects instead of URL-based ones:
const redirectPaths = {
'home': '/dashboard',
'profile': '/user/profile',
'settings': '/user/settings'
};
server.get('/go/:path', (req, res) => {
const target = redirectPaths[req.params.path] || '/dashboard';
res.redirect(302, target);
});This approach eliminates the possibility of external redirects while maintaining user experience.