@ivangrynenko/javascript-server-side-request-forger
Javascript Server Side Request Forgery cursor rules
prpm install @ivangrynenko/javascript-server-side-request-forger0 total downloads
📄 Full Prompt Content
---
description: Detect and prevent Server-Side Request Forgery (SSRF) vulnerabilities in JavaScript applications as defined in OWASP Top 10:2021-A10
globs: **/*.js, **/*.jsx, **/*.ts, **/*.tsx, !**/node_modules/**, !**/dist/**, !**/build/**, !**/coverage/**
---
# JavaScript Server-Side Request Forgery (OWASP A10:2021)
<rule>
name: javascript_server_side_request_forgery
description: Detect and prevent Server-Side Request Forgery (SSRF) vulnerabilities in JavaScript applications as defined in OWASP Top 10:2021-A10
actions:
- type: enforce
conditions:
# Pattern 1: URL from User Input
- pattern: "(fetch|axios\\.get|axios\\.post|axios\\.put|axios\\.delete|axios\\.patch|http\\.get|http\\.request|https\\.get|https\\.request|\\$\\.ajax|XMLHttpRequest|got|request|superagent|needle)\\s*\\([^)]*(?:\\$_GET|\\$_POST|\\$_REQUEST|req\\.(?:body|query|params)|request\\.(?:body|query|params)|event\\.(?:body|queryStringParameters|pathParameters)|params|userInput|data\\["
message: "Potential SSRF vulnerability: URL constructed from user input. Implement URL validation, allowlisting, or use a URL parser library to validate and sanitize user-provided URLs."
# Pattern 2: Dynamic URL in HTTP Request
- pattern: "(fetch|axios|http\\.get|http\\.request|https\\.get|https\\.request|\\$\\.ajax|XMLHttpRequest|got|request|superagent|needle)\\s*\\(\\s*['\"`]https?:\\/\\/[^'\"`]*['\"`]\\s*\\+\\s*"
message: "Potential SSRF vulnerability: Dynamic URL in HTTP request. Use URL parsing and validation before making the request."
# Pattern 3: URL Redirection Without Validation
- pattern: "(res\\.redirect|res\\.location|window\\.location|location\\.href|location\\.replace|location\\.assign|location\\.port|history\\.pushState|history\\.replaceState)\\s*\\([^)]*(?:req\\.(?:query|body|params)|request\\.(?:query|body|params)|userInput)"
message: "URL redirection without proper validation may lead to SSRF. Implement strict validation for URLs before redirecting."
# Pattern 4: Direct IP Address Usage
- pattern: "(fetch|axios\\.get|axios\\.post|axios\\.put|axios\\.delete|axios\\.patch|http\\.get|http\\.request|https\\.get|https\\.request)\\s*\\(\\s*['\"`]https?:\\/\\/\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"
message: "Direct use of IP addresses in requests may bypass hostname-based restrictions. Consider using allowlisted hostnames instead."
# Pattern 5: Local Network Access
- pattern: "(fetch|axios\\.get|axios\\.post|axios\\.put|axios\\.delete|axios\\.patch|http\\.get|http\\.request|https\\.get|https\\.request)\\s*\\(\\s*['\"`]https?:\\/\\/(?:localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0|192\\.168\\.|10\\.|172\\.(?:1[6-9]|2[0-9]|3[0-1])\\.|::1)"
message: "Request to internal network address detected. Restrict access to internal resources to prevent SSRF attacks."
# Pattern 6: File Protocol Usage
- pattern: "(fetch|axios\\.get|axios\\.post|axios\\.put|axios\\.delete|axios\\.patch|http\\.get|http\\.request|https\\.get|https\\.request)\\s*\\(\\s*['\"`]file:\\/\\/"
message: "Use of file:// protocol may lead to local file access. Block or restrict file:// protocol usage."
# Pattern 7: Missing URL Validation
- pattern: "(fetch|axios\\.get|axios\\.post|axios\\.put|axios\\.delete|axios\\.patch|http\\.get|http\\.request|https\\.get|https\\.request)\\s*\\([^)]*\\burl\\b[^)]*\\)"
negative_pattern: "(validat|sanitiz|check|parse).*\\burl\\b|allowlist|whitelist|URL\\.(parse|canParse)|new URL\\(|isValidURL"
message: "HTTP request without URL validation. Implement URL validation before making external requests."
# Pattern 8: HTTP Request in User-Defined Function
- pattern: "function\\s+[a-zA-Z0-9_]*(?:request|fetch|get|http|curl)\\s*\\([^)]*\\)\\s*\\{[^}]*(?:fetch|axios|http\\.get|http\\.request|https\\.get|https\\.request)"
negative_pattern: "(validat|sanitiz|check|parse).*\\burl\\b|allowlist|whitelist|new URL\\(|isValidURL"
message: "User-defined HTTP request function without URL validation. Implement proper URL validation and sanitization."
# Pattern 9: Proxy Functionality
- pattern: "(?:proxy|forward|relay).*(?:req\\.(?:url|path)|request\\.(?:url|path))"
negative_pattern: "(validat|sanitiz|check|parse).*\\burl\\b|allowlist|whitelist"
message: "Proxy or request forwarding functionality detected. Implement strict URL validation and allowlisting."
# Pattern 10: Alternative HTTP Methods
- pattern: "(fetch|axios)\\s*\\([^)]*method\\s*:\\s*['\"`](?:GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD)['\"`]"
negative_pattern: "(validat|sanitiz|check|parse).*\\burl\\b|allowlist|whitelist|new URL\\(|isValidURL"
message: "HTTP request with explicit method without URL validation. Implement URL validation for all HTTP methods."
# Pattern 11: URL Building from Parts
- pattern: "new URL\\s*\\((?:[^,)]+,\\s*){1,}(?:req\\.(?:body|query|params)|request\\.(?:body|query|params)|userinput)"
message: "Building URL with user input. Validate and sanitize all URL components and use an allowlist for base URLs."
# Pattern 12: Protocol-Relative URLs
- pattern: "(fetch|axios)\\s*\\(['\"`]\\/\\/[^'\"`]+['\"`]"
message: "Protocol-relative URL usage may lead to SSRF. Always specify the protocol and validate URLs."
# Pattern 13: Express-like Route with URL Parameter
- pattern: "app\\.(?:get|post|put|delete|patch)\\s*\\(['\"`][^'\"`]*\\/:[a-zA-Z0-9_]+(?:\\/|['\"`])"
negative_pattern: "(validat|sanitiz|check|parse).*\\burl\\b|allowlist|whitelist|new URL\\(|isValidURL"
message: "Route with dynamic parameter that might be used in URL construction. Ensure proper validation before making any HTTP requests within this route handler."
# Pattern 14: URL Parsing without Validation
- pattern: "URL\\.parse\\s*\\(|new URL\\s*\\("
negative_pattern: "try\\s*\\{|catch\\s*\\(|validat|sanitiz|check"
message: "URL parsing without validation or error handling. Implement proper error handling and validation for URL parsing."
# Pattern 15: Service Discovery / Cloud Metadata Access
- pattern: "(fetch|axios\\.get|http\\.get)\\s*\\(['\"`]https?:\\/\\/(?:169\\.254\\.169\\.254|fd00:ec2|metadata\\.google|metadata\\.azure|169\\.254\\.169\\.254\\/latest\\/meta-data)"
message: "Access to cloud service metadata endpoints detected. Restrict access to cloud metadata services to prevent server information disclosure."
- type: suggest
message: |
**JavaScript Server-Side Request Forgery (SSRF) Prevention Best Practices:**
1. **Implement URL Validation and Sanitization:**
- Use built-in URL parsing libraries to validate URLs
- Validate both the URL format and components
- Example:
```javascript
function isValidUrl(url) {
try {
const parsedUrl = new URL(url);
// Check protocol is http: or https:
if (!/^https?:$/.test(parsedUrl.protocol)) {
return false;
}
// Additional validation logic here
return true;
} catch (error) {
// Invalid URL format
return false;
}
}
// Usage
const userProvidedUrl = req.body.targetUrl;
if (!isValidUrl(userProvidedUrl)) {
return res.status(400).json({ error: 'Invalid URL format or protocol' });
}
// Now make the request with the validated URL
```
2. **Implement Strict Allowlisting:**
- Define allowlist of permitted domains and endpoints
- Reject requests to any domains not on the allowlist
- Example:
```javascript
const ALLOWED_DOMAINS = [
'api.example.com',
'cdn.example.com',
'partner-api.trusted-domain.com'
];
function isAllowedDomain(url) {
try {
const parsedUrl = new URL(url);
return ALLOWED_DOMAINS.includes(parsedUrl.hostname);
} catch (error) {
return false;
}
}
// Usage
const targetUrl = req.body.webhookUrl;
if (!isAllowedDomain(targetUrl)) {
logger.warn({
message: 'SSRF attempt blocked: domain not in allowlist',
url: targetUrl,
ip: req.ip,
userId: req.user?.id
});
return res.status(403).json({ error: 'Domain not allowed' });
}
```
3. **Block Access to Internal Networks:**
- Prevent requests to private IP ranges
- Block localhost and internal hostnames
- Example:
```javascript
function isInternalHostname(hostname) {
// Check for localhost and common internal hostnames
if (hostname === 'localhost' || hostname.endsWith('.local') || hostname.endsWith('.internal')) {
return true;
}
return false;
}
function isPrivateIP(ip) {
// Check for private IP ranges
const privateRanges = [
/^127\./, // 127.0.0.0/8
/^10\./, // 10.0.0.0/8
/^172\.(1[6-9]|2[0-9]|3[0-1])\./, // 172.16.0.0/12
/^192\.168\./, // 192.168.0.0/16
/^169\.254\./, // 169.254.0.0/16
/^::1$/, // localhost IPv6
/^f[cd][0-9a-f]{2}:/i, // fc00::/7 unique local IPv6
/^fe80:/i // fe80::/10 link-local IPv6
];
return privateRanges.some(range => range.test(ip));
}
function isUrlSafe(url) {
try {
const parsedUrl = new URL(url);
// Block internal hostnames
if (isInternalHostname(parsedUrl.hostname)) {
return false;
}
// Resolve hostname to IP (in real implementation, use async DNS resolution)
// This example is simplified - in production you would use DNS resolution
let ip;
try {
// Note: This is a pseudo-code example
// In real code, you'd use a DNS resolution library
ip = dnsResolve(parsedUrl.hostname);
// Block private IPs
if (isPrivateIP(ip)) {
return false;
}
} catch (error) {
// If DNS resolution fails, err on the side of caution
return false;
}
return true;
} catch (error) {
return false;
}
}
```
4. **Disable Dangerous URL Protocols:**
- Restrict allowed URL protocols to HTTP and HTTPS
- Block file://, ftp://, gopher://, etc.
- Example:
```javascript
function hasAllowedProtocol(url) {
try {
const parsedUrl = new URL(url);
const allowedProtocols = ['http:', 'https:'];
return allowedProtocols.includes(parsedUrl.protocol);
} catch (error) {
return false;
}
}
// Usage
const targetUrl = req.body.documentUrl;
if (!hasAllowedProtocol(targetUrl)) {
logger.warn({
message: 'SSRF attempt blocked: disallowed protocol',
url: targetUrl,
protocol: new URL(targetUrl).protocol,
ip: req.ip
});
return res.status(403).json({ error: 'URL protocol not allowed' });
}
```
5. **Implement Network-Level Protection:**
- Use firewall rules to block outbound requests to internal networks
- Configure proxy servers to restrict external requests
- Example:
```javascript
// Using a proxy for outbound requests
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
// Configure proxy with appropriate controls
const httpsAgent = new HttpsProxyAgent({
host: 'proxy.example.com',
port: 3128,
// This proxy should be configured to block access to internal networks
});
// Make requests through the proxy
async function secureExternalRequest(url) {
try {
const response = await axios.get(url, {
httpsAgent,
timeout: 5000, // Set reasonable timeout
maxRedirects: 2 // Limit redirects
});
return response.data;
} catch (error) {
logger.error({
message: 'External request failed',
url,
error: error.message
});
throw new Error('Failed to fetch external resource');
}
}
```
6. **Use Service-Specific Endpoints:**
- Instead of passing full URLs, use service identifiers
- Map identifiers to URLs on the server side
- Example:
```javascript
// Client makes request with service identifier, not raw URL
app.get('/proxy-service/:serviceId', async (req, res) => {
const { serviceId } = req.params;
// Service mapping defined server-side
const serviceMap = {
'weather-api': 'https://api.weather.example.com/current',
'news-feed': 'https://api.news.example.com/feed',
'product-info': 'https://api.products.example.com/details'
};
// Check if service is defined
if (!serviceMap[serviceId]) {
return res.status(404).json({ error: 'Service not found' });
}
try {
// Make request to mapped URL (not user-controlled)
const response = await axios.get(serviceMap[serviceId]);
return res.json(response.data);
} catch (error) {
return res.status(500).json({ error: 'Service request failed' });
}
});
```
7. **Implement Context-Specific Encodings:**
- Use context-appropriate encoding for URL parameters
- Don't rely solely on standard URL encoding
- Example:
```javascript
function safeUrl(baseUrl, params) {
// Start with a verified base URL
const url = new URL(baseUrl);
// Add parameters safely
for (const [key, value] of Object.entries(params)) {
// Ensure values are strings and properly encoded
url.searchParams.append(key, String(value));
}
// Verify the final URL is still valid
if (!isAllowedDomain(url.toString())) {
throw new Error('URL creation resulted in disallowed domain');
}
return url.toString();
}
// Usage
try {
const apiUrl = safeUrl('https://api.example.com/data', {
id: userId,
format: 'json'
});
const response = await axios.get(apiUrl);
// Process response
} catch (error) {
// Handle error
}
```
8. **Use Defense in Depth:**
- Combine multiple validation strategies
- Don't rely on a single protection measure
- Example:
```javascript
async function secureExternalRequest(url, options = {}) {
// 1. Validate URL format
if (!isValidUrl(url)) {
throw new Error('Invalid URL format');
}
// 2. Check against allowlist
if (!isAllowedDomain(url)) {
throw new Error('Domain not in allowlist');
}
// 3. Verify not internal network
const parsedUrl = new URL(url);
if (await isInternalNetwork(parsedUrl.hostname)) {
throw new Error('Access to internal networks not allowed');
}
// 4. Validate protocol
if (!hasAllowedProtocol(url)) {
throw new Error('Protocol not allowed');
}
// 5. Set additional security headers and options
const secureOptions = {
...options,
timeout: options.timeout || 5000,
maxRedirects: options.maxRedirects || 2,
headers: {
...options.headers,
'User-Agent': 'SecureApp/1.0'
}
};
// 6. Make request with all validations passed
try {
return await axios(url, secureOptions);
} catch (error) {
logger.error({
message: 'Secure external request failed',
url,
error: error.message
});
throw new Error('External request failed');
}
}
```
9. **Validate and Sanitize Request Parameters:**
- Don't trust any user-supplied input for URL construction
- Validate all components used in URL building
- Example:
```javascript
// API that fetches weather data for a city
app.get('/api/weather', async (req, res) => {
const { city } = req.query;
// 1. Validate parameter exists and is valid
if (!city || typeof city !== 'string' || city.length > 100) {
return res.status(400).json({ error: 'Invalid city parameter' });
}
// 2. Sanitize the parameter
const sanitizedCity = encodeURIComponent(city.trim());
// 3. Construct URL with validated parameter
const weatherApiUrl = `https://api.weather.example.com/current?city=${sanitizedCity}`;
// 4. Additional validation of the final URL
if (!isValidUrl(weatherApiUrl)) {
return res.status(400).json({ error: 'Invalid URL construction' });
}
try {
const response = await axios.get(weatherApiUrl);
return res.json(response.data);
} catch (error) {
logger.error({
message: 'Weather API request failed',
city,
error: error.message
});
return res.status(500).json({ error: 'Failed to fetch weather data' });
}
});
```
10. **Implement Request Timeouts:**
- Set appropriate timeouts for all HTTP requests
- Prevent long-running SSRF probes
- Example:
```javascript
async function fetchWithTimeout(url, options = {}) {
// Default timeout of 5 seconds
const timeout = options.timeout || 5000;
// Create an abort controller to handle timeout
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(timeoutId);
return response;
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error(`Request timed out after ${timeout}ms`);
}
throw error;
}
}
// Usage
try {
const response = await fetchWithTimeout('https://api.example.com/data', {
timeout: 3000, // 3 seconds timeout
headers: { 'Content-Type': 'application/json' }
});
const data = await response.json();
// Process data
} catch (error) {
console.error('Request failed:', error.message);
}
```
11. **Rate Limit External Requests:**
- Implement rate limiting for outbound requests
- Prevent SSRF probing and DoS attacks
- Example:
```javascript
const { RateLimiter } = require('limiter');
// Create a rate limiter: 100 requests per minute
const externalRequestLimiter = new RateLimiter({
tokensPerInterval: 100,
interval: 'minute'
});
async function rateLimitedRequest(url, options = {}) {
// Check if we have tokens available
const remainingRequests = await externalRequestLimiter.removeTokens(1);
if (remainingRequests < 0) {
throw new Error('Rate limit exceeded for external requests');
}
// Proceed with the request
return axios(url, options);
}
// Usage
app.get('/api/external-data', async (req, res) => {
const { url } = req.query;
if (!isValidUrl(url) || !isAllowedDomain(url)) {
return res.status(403).json({ error: 'URL not allowed' });
}
try {
const response = await rateLimitedRequest(url);
return res.json(response.data);
} catch (error) {
if (error.message === 'Rate limit exceeded for external requests') {
return res.status(429).json({ error: 'Too many requests' });
}
return res.status(500).json({ error: 'Failed to fetch data' });
}
});
```
12. **Use Web Application Firewalls (WAF):**
- Configure WAF rules to detect and block SSRF patterns
- Implement server-side firewall rules
- Example:
```javascript
// Middleware to detect SSRF attack patterns
function ssrfProtectionMiddleware(req, res, next) {
const url = req.query.url || req.body.url;
if (!url) {
return next();
}
// Check for suspicious URL patterns
const ssrfPatterns = [
/file:\/\//i,
/^(ftps?|gopher|data|dict):\/\//i,
/^\/\/\//,
/(localhost|127\.0\.0\.1|0\.0\.0\.0|::1)/i,
/^(10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.)/
];
if (ssrfPatterns.some(pattern => pattern.test(url))) {
logger.warn({
message: 'Potential SSRF attack detected',
url,
ip: req.ip,
path: req.path,
method: req.method,
userId: req.user?.id
});
return res.status(403).json({
error: 'Access denied - suspicious URL detected'
});
}
next();
}
// Apply middleware to all routes
app.use(ssrfProtectionMiddleware);
```
13. **Implement Centralized Request Services:**
- Create a dedicated service for external requests
- Implement all security controls in one place
- Example:
```javascript
// externalRequestService.js
const axios = require('axios');
class ExternalRequestService {
constructor(options = {}) {
this.allowedDomains = options.allowedDomains || [];
this.maxRedirects = options.maxRedirects || 2;
this.timeout = options.timeout || 5000;
this.logger = options.logger || console;
}
async request(url, options = {}) {
// Validate URL
if (!this._isValidUrl(url)) {
throw new Error('Invalid URL format');
}
// Check allowlist
if (!this._isAllowedDomain(url)) {
throw new Error('Domain not in allowlist');
}
// Configure request options
const requestOptions = {
...options,
timeout: options.timeout || this.timeout,
maxRedirects: options.maxRedirects || this.maxRedirects,
validateStatus: status => status >= 200 && status < 300
};
try {
const response = await axios(url, requestOptions);
return response.data;
} catch (error) {
this.logger.error({
message: 'External request failed',
url,
error: error.message
});
throw new Error(`External request failed: ${error.message}`);
}
}
_isValidUrl(url) {
try {
const parsedUrl = new URL(url);
return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:';
} catch (error) {
return false;
}
}
_isAllowedDomain(url) {
try {
const parsedUrl = new URL(url);
return this.allowedDomains.includes(parsedUrl.hostname);
} catch (error) {
return false;
}
}
}
module.exports = ExternalRequestService;
// Usage in application
const ExternalRequestService = require('./externalRequestService');
const requestService = new ExternalRequestService({
allowedDomains: [
'api.example.com',
'cdn.example.com',
'partner.trusted-domain.com'
],
logger: appLogger,
timeout: 3000
});
app.get('/api/external-data', async (req, res) => {
try {
// Use the service for all external requests
const data = await requestService.request('https://api.example.com/data');
return res.json(data);
} catch (error) {
return res.status(500).json({ error: error.message });
}
});
```
14. **Monitor and Audit External Requests:**
- Log all external requests for audit purposes
- Implement anomaly detection
- Example:
```javascript
// Middleware to log and monitor all external requests
function requestMonitoringMiddleware(req, res, next) {
// Only intercept routes that might make external requests
if (!req.path.startsWith('/api/proxy') && !req.path.startsWith('/api/external')) {
return next();
}
// Store original fetch/http.request methods
const originalFetch = global.fetch;
const originalHttpRequest = require('http').request;
const originalHttpsRequest = require('https').request;
// Override fetch
global.fetch = async function monitoredFetch(url, options) {
const requestId = uuid.v4();
const startTime = Date.now();
logger.info({
message: 'External request initiated',
requestId,
url,
method: options?.method || 'GET',
userContext: {
userId: req.user?.id,
ip: req.ip,
userAgent: req.headers['user-agent']
},
timestamp: new Date().toISOString()
});
try {
const response = await originalFetch(url, options);
// Log successful request
logger.info({
message: 'External request completed',
requestId,
url,
statusCode: response.status,
duration: Date.now() - startTime,
timestamp: new Date().toISOString()
});
return response;
} catch (error) {
// Log failed request
logger.error({
message: 'External request failed',
requestId,
url,
error: error.message,
duration: Date.now() - startTime,
timestamp: new Date().toISOString()
});
throw error;
}
};
// Similar overrides for http.request and https.request
// ...
// Continue with the request
res.on('finish', () => {
// Restore original methods after request completes
global.fetch = originalFetch;
require('http').request = originalHttpRequest;
require('https').request = originalHttpsRequest;
});
next();
}
// Apply middleware
app.use(requestMonitoringMiddleware);
```
15. **Implement Output Validation:**
- Validate responses from external services
- Use schema validation for expected formats
- Example:
```javascript
const Joi = require('joi');
// Define expected schemas for external APIs
const apiSchemas = {
weatherApi: Joi.object({
location: Joi.string().required(),
temperature: Joi.number().required(),
conditions: Joi.string().required(),
forecast: Joi.array().items(Joi.object())
}),
userApi: Joi.object({
id: Joi.string().required(),
name: Joi.string().required(),
email: Joi.string().email().required()
})
};
async function validateExternalResponse(data, schemaName) {
const schema = apiSchemas[schemaName];
if (!schema) {
throw new Error(`Schema not found: ${schemaName}`);
}
try {
const result = await schema.validateAsync(data);
return result;
} catch (error) {
logger.error({
message: 'External API response validation failed',
schemaName,
error: error.message,
data: JSON.stringify(data).substring(0, 200) // Log partial data for debugging
});
throw new Error(`Invalid response format from external API: ${error.message}`);
}
}
// Usage
app.get('/api/weather/:city', async (req, res) => {
const { city } = req.params;
try {
// Fetch data from external API
const apiUrl = `https://api.weather.example.com/current?city=${encodeURIComponent(city)}`;
const response = await axios.get(apiUrl);
// Validate the response against the expected schema
const validatedData = await validateExternalResponse(response.data, 'weatherApi');
// Return the validated data
return res.json(validatedData);
} catch (error) {
return res.status(500).json({ error: error.message });
}
});
```
- type: validate
conditions:
# Check 1: URL validation
- pattern: "function\\s+(?:isValidUrl|validateUrl|checkUrl)\\s*\\([^)]*\\)\\s*\\{[^}]*new URL\\([^)]*\\)"
message: "Using URL validation function with proper parsing."
# Check 2: Domain allowlisting
- pattern: "(?:allowlist|whitelist|allowed(?:Domain|Host))\\s*=\\s*\\["
message: "Implementing domain allowlisting for outbound requests."
# Check 3: Private IP filtering
- pattern: "(?:isPrivateIP|isInternalNetwork|blockInternalAddresses)"
message: "Checking for and blocking private IP addresses."
# Check 4: Protocol restriction
- pattern: "(?:allowedProtocols|validProtocols)\\s*=\\s*\\[\\s*['\"]https?:['\"]"
message: "Restricting URL protocols to HTTP/HTTPS only."
# Check 5: Request timeout implementation
- pattern: "timeout:\\s*\\d+"
message: "Setting timeouts for outbound HTTP requests."
metadata:
priority: high
version: 1.0
tags:
- security
- javascript
- nodejs
- browser
- ssrf
- owasp
- language:javascript
- framework:express
- framework:react
- framework:vue
- framework:angular
- category:security
- subcategory:ssrf
- standard:owasp-top10
- risk:a10-server-side-request-forgery
references:
- "https://owasp.org/Top10/A10_2021-Server-Side_Request_Forgery_%28SSRF%29/"
- "https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html"
- "https://portswigger.net/web-security/ssrf"
- "https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.md"
- "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/19-Server-Side_Request_Forgery"
- "https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html#ssrf-protection"
</rule>
💡 Suggested Test Inputs
Loading suggested inputs...
🎯 Community Test Results
Loading results...
📦 Package Info
- Format
- cursor
- Type
- rule
- Category
- languages
- License
- MIT