Open Redirect with Api Keys
How Open Redirect Manifests in Api Keys
Open Redirect vulnerabilities in API keys contexts typically occur when API key validation or redirection logic fails to properly sanitize user-controlled input. This can lead to attackers crafting URLs that redirect users to malicious sites, often combined with API key exfiltration.
Common manifestations include:
- Redirect Parameters with API Keys: Endpoints that accept redirect URLs and API keys as query parameters, allowing attackers to redirect users to phishing sites while passing their API keys
- Authorization Redirects: OAuth or similar flows where API keys are embedded in redirect URLs without proper validation
- Callback URL Abuse: API endpoints that redirect to callback URLs containing API keys in the URL fragment or query string
Here's a vulnerable pattern commonly seen in API key implementations:
app.get('/auth/callback', (req, res) => {
const { code, redirect_uri } = req.query;
// Vulnerable: No validation of redirect_uri
const apiKey = getApiKeyFromCode(code);
const redirectUrl = `${redirect_uri}?api_key=${apiKey}`;
res.redirect(redirectUrl);
});An attacker could set redirect_uri to https://evil.com/auth?callback= and steal the API key when the user is redirected.
Another variant involves API key validation endpoints:
@app.route('/validate', methods=['POST'])
def validate_api_key():
data = request.json
api_key = data.get('api_key')
redirect = data.get('redirect', '/dashboard')
if validate_key(api_key):
# Vulnerable: redirect can be any URL
return redirect(redirect)
return jsonify({'error': 'Invalid API key'}), 401Attackers can submit { "api_key": "valid-key", "redirect": "https://malicious-site.com" } to redirect users to phishing sites.
Api Keys-Specific Detection
Detecting Open Redirect vulnerabilities in API key contexts requires both static analysis and dynamic testing. Here are effective detection strategies:
Static Analysis
Search your codebase for patterns that combine URL handling with API key processing:
# Look for redirect patterns with API key handling
grep -r "redirect(" . --include="*.py" --include="*.js" --include="*.java"
grep -r "api_key" . --include="*.py" --include="*.js" --include="*.java"
Focus on endpoints that:
- Accept URL parameters for redirection
- Combine API key validation with redirect logic
- Handle OAuth callbacks or similar flows
Dynamic Testing with middleBrick
middleBrick's black-box scanning approach is particularly effective for detecting Open Redirect vulnerabilities in API keys contexts. The scanner tests unauthenticated endpoints for redirect abuse patterns.
Run middleBrick to scan for Open Redirect vulnerabilities:
npm install -g middlebrick
middlebrick scan https://api.yourdomain.com/auth/callback
middleBrick tests for:
- URL redirection with embedded API keys
- Callback URL parameter manipulation
- Authorization flow abuse
- Cross-site request forgery via redirects
The scanner provides a security score and specific findings with severity levels, helping you prioritize fixes.
Manual Testing Checklist
Complement automated scanning with manual testing:
| Test Case | Expected Behavior | Vulnerability Indicator |
|---|---|---|
| Redirect with external URL | Blocked or internal redirect only | Redirects to external site |
| API key in redirect URL | API key not exposed in URL | API key appears in Location header |
| Callback URL manipulation | Callback URLs validated against whitelist | Arbitrary callback URLs accepted |
Api Keys-Specific Remediation
Fixing Open Redirect vulnerabilities in API key contexts requires a defense-in-depth approach. Here are specific remediation strategies:
1. URL Validation and Whitelisting
Always validate redirect URLs against a whitelist of allowed domains:
from urllib.parse import urlparse, urljoin
def is_safe_redirect(redirect_url, allowed_domains=None):
if allowed_domains is None:
allowed_domains = ['https://yourapp.com']
try:
parsed = urlparse(redirect_url)
# Check if scheme is http or https
if parsed.scheme not in ('http', 'https'):
return False
# Check if domain is in allowed list
return any(parsed.netloc == urlparse(domain).netloc
for domain in allowed_domains)
except:
return False
# Usage in API endpoint
@app.route('/auth/callback')
def auth_callback():
code = request.args.get('code')
redirect_uri = request.args.get('redirect_uri', '/dashboard')
if not is_safe_redirect(redirect_uri):
return jsonify({'error': 'Invalid redirect URI'}), 400
api_key = get_api_key_from_code(code)
return redirect(f'{redirect_uri}?api_key={api_key}')
2. Avoid API Keys in URLs
Never expose API keys in URL parameters or redirect URLs. Use secure alternatives:
// Instead of passing API key in URL
app.get('/auth/callback', async (req, res) => {
const { code } = req.query;
const session = await getSessionFromCode(code);
// Store API key in secure HTTP-only cookie
res.cookie('api_key', session.apiKey, {
httpOnly: true,
secure: true,
sameSite: 'lax'
});
res.redirect('/dashboard');
});
3. State Parameter for CSRF Protection
Use state parameters in OAuth flows to prevent CSRF and open redirect attacks:
import secrets
@app.route('/oauth/authorize')
def oauth_authorize():
state = secrets.token_urlsafe(16)
session['oauth_state'] = state
# Store allowed redirect in session, not in URL
session['oauth_redirect'] = '/dashboard'
return redirect(f'https://oauth-provider.com/auth?client_id=...&state={state}')
@app.route('/oauth/callback')
def oauth_callback():
code = request.args.get('code')
state = request.args.get('state')
if state != session.get('oauth_state'):
return jsonify({'error': 'Invalid state'}), 400
api_key = get_api_key_from_code(code)
session['api_key'] = api_key
return redirect(session.get('oauth_redirect', '/dashboard'))
4. middleBrick Integration for Continuous Security
Integrate middleBrick into your development workflow to catch these issues early:
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run middleBrick Scan
run: |
npm install -g middlebrick
middlebrick scan https://staging-api.yourdomain.com
continue-on-error: true
- name: Fail on High Risk
if: failure()
run: |
echo "Security scan failed. Check middleBrick report for details."
exit 1
This ensures Open Redirect vulnerabilities are caught before deployment.