26 views
This guide focuses on SSRF Hardening in Node for production systems, with practical trade-offs for reliability, security, and cost.
User-supplied URLs (avatar, webhook, import from URL) turn your Node service into an HTTP client inside the VPC. Attackers aim at 169.254.169.254, link-local, and DNS rebinding. The unfair advantage is pinning the resolved address at connect time—deny private ranges after DNS, not just after parsing the hostname string.
⚡ TL;DR: Parse URL; resolve DNS yourself; reject private/link-local/metadata IPs; connect to the pinned address with Host header; block redirects to private targets; prefer egress proxy allowlists. Pair with Lambda Outbound Proxies and Node Permission Model.
SSRF Hardening in Node: production guidance
text
1) Attacker URL: http://evil.example/img → resolves to 1.2.3.4 (public) ✅ passes check
2) TTL expires / rebind → 169.254.169.254 at connect time ❌ SSRF
typescript
// ✅ Pin address after resolution (sketch)
import dns from "node:dns/promises";
import net from "node:net";
import { Agent, fetch } from "undici";
const BLOCK = [
/^127\./, /^10\./, /^172\.(1[6-9]|2\d|3[0-1])\./, /^192\.168\./,
/^169\.254\./, /^0\./, /^100\.64\./, /^::1$/, /^fc00:/i, /^fe80:/i,
];
function isBlockedIp(ip: string): boolean {
return BLOCK.some((re) => re.test(ip));
}
export async function safeFetch(userUrl: string): Promise<Response> {
const u = new URL(userUrl);
if (!["http:", "https:"].includes(u.protocol)) throw new Error("scheme");
const { address, family } = await dns.lookup(u.hostname, { verbatim: true });
if (isBlockedIp(address)) throw new Error("ssrf_blocked");
// Connect to pinned IP; send original Host
const pinned = family === 6 ? `http://[${address}]${u.pathname}${u.search}`
: `http://${address}${u.pathname}${u.search}`;
const httpsUrl = u.protocol === "https:"
? pinned.replace("http://", "https://")
: pinned;
return fetch(httpsUrl, {
method: "GET",
redirect: "manual", // ✅ inspect Location yourself
headers: { Host: u.host },
dispatcher: new Agent({ connect: { timeout: 2000 } }),
});
}
typescript
// ❌ Trusting only URL.hostname string checks
if (userUrl.includes("169.254.169.254")) throw new Error("no");
await fetch(userUrl); // rebinding / DNS / redirects still bite
Redirects and IPv6 tricks
Follow redirects manually: re-run the IP check on everyLocation. Deny decimal/octal IP forms, DNS to @, and credentialed URLs. Prefer an egress proxy (Lambda Outbound Proxies) so the task role never reaches IMDS.
| Control | Stops |
|---|---|
| Pin + private IP deny | Direct metadata / RFC1918 |
| Manual redirects | Open redirect to IMDS |
| IMDS hop limit / IMDSv2 | Host metadata from task |
| Egress allowlist proxy | Defense in depth |
Closing checklist
✅ Dos – ✅ Resolve then deny private/link-local/metadata ranges – ✅ Pin IP for the TCP connect; setHost explicitly
– ✅ Re-validate on every redirect hop
– ✅ Force IMDSv2 + hop limit on EC2/ECS hosts
– ✅ Default-deny egress except proxy / known peers
❌ Don’ts
– ❌ Don’t fetch(userUrl) with auto-redirect
– ❌ Don’t rely on string denylists alone
– ❌ Don’t allow file:, gopher:, or weird schemes
– ❌ Don’t give the app role broad ec2:Describe* just because SSRF “might need it”
Related reading
- Lambda Outbound Proxies: Egress Allowlists That Block SSRF Paths
- Node Permission Model: Lock Down Production Processes Running Plugins
- Secret-Aware Context Filters
- Agent Tool Allowlists
Watch: 100 Days of AI on YouTube
Short videos from CheatCoders, one AI engineering topic per day.
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- Claude Code vs Cursor vs GitHub Copilot: Choose by Workflow, and Set Up One Repo That Works With All Three
- AI Agent Frameworks in 2025: LangGraph vs CrewAI vs AutoGen vs Raw API
- Python String Methods: Every str Method With Real Production Examples
- Css Animation Performance: Performance-Optimized Motion for Modern UIs
Newly added
- AWS Systems Manager Parameter Store: Hierarchical Runtime Config for Coding Agents
- Amazon Cognito Identity Pools: Federate Coding-Agent Tool Callers Without Long-Lived Keys
- Amazon Athena for Coding Agents: Query Tool Audit Logs and Eval Traces on S3 Without a Warehouse
- AWS Batch for Coding Agents: Parallel Overnight PR Reviews and Long-Running Jobs Without Lambda Timeouts
- Amazon Bedrock Prompt Management: Version and A/B Test Coding-Agent System Prompts
Deep-dive PDF
Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.
Already subscribed? or open the subscribe page.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
