modelcontextprotocol / modelcontextprotocol/servers
Security Hardening Recommendations for Fetch Server (SSRF Prevention)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 90.5k
- Forks
- 11.7k
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 5
Description
Security Review: Fetch Server
I have been building MCP servers for production use (12 servers, 280+ tools deployed) and noticed some security considerations for the fetch server that could benefit the reference implementation:
1. URL Validation
Current:
const url = new URL(args.url);
Issue: This allows fetching from internal network addresses (169.254.x.x, 10.x.x.x, etc.) which could expose metadata services or internal APIs.
Recommendation:
const BLOCKED_HOSTS = [
/^169\.254\./, // Link-local
/^10\./, // Private A
/^172\.(1[6-9]|2[0-9]|3[0-1])\./, // Private B
/^192\.168\./, // Private C
/^127\./, // Loopback
/^0\./, // Current network
/^::1$/, // IPv6 loopback
/^fc00:/i, // IPv6 private
/^fe80:/i, // IPv6 link-local
];
function isUrlAllowed(url: URL): boolean {
const hostname = url.hostname;
return !BLOCKED_HOSTS.some(pattern => pattern.test(hostname));
}
2. Content-Type Validation
Current: No validation on returned content types.
Risk: Could fetch binary executables or malicious content.
Recommendation:
const ALLOWED_CONTENT_TYPES = [
'text/html',
'text/plain',
'text/markdown',
'application/json',
'application/xml',
];
// Validate before processing
const contentType = response.headers.get('content-type') || '';
if (!ALLOWED_CONTENT_TYPES.some(t => contentType.includes(t))) {
throw new Error(`Content type not allowed: ${contentType}`);
}
3. Response Size Limits
Current: No limit on response size.
Risk: Memory exhaustion from huge responses.
Recommendation:
const MAX_RESPONSE_SIZE = 10 * 1024 * 1024; // 10MB
const contentLength = response.headers.get('content-length');
if (contentLength && parseInt(contentLength) > MAX_RESPONSE_SIZE) {
throw new Error(`Response too large: ${contentLength} bytes`);
}
4. Timeout Configuration
Current: Uses default fetch timeout.
Risk: Hanging connections consuming resources.
Recommendation:
const FETCH_TIMEOUT = 30000; // 30 seconds
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT);
try {
const response = await fetch(url, {
signal: controller.signal,
// ... other options
});
} finally {
clearTimeout(timeout);
}
5. Redirect Handling
Current: Default redirect behavior.
Risk: Open redirect vulnerabilities.
Recommendation:
const response = await fetch(url, {
redirect: 'manual', // Handle redirects explicitly
// ...
});
if (response.status >= 300 && response.status < 400) {
const location = response.headers.get('location');
// Validate redirect target before following
const redirectUrl = new URL(location!, url);
if (!isUrlAllowed(redirectUrl)) {
throw new Error('Redirect to blocked host');
}
}
Context
I run mcp-kali-orchestration and mcp-proxmox-admin in production environments where these security patterns are essential. Happy to discuss implementation details or contribute a PR.
Author: Eric Grill (https://ericgrill.com)
Related work: https://github.com/EricGrill/mcp-kali-orchestration
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the fetch server's URL-fetching entry point and review the five proposed areas: private-host validation, content types, response size, timeout handling, and redirects. Define tests for each security constraint and consider how the fetch server should report rejected requests; done means the agreed protections are implemented and covered by tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, security
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100