← All posts

How to Fix SSRF in Vibe-Coded Apps: A Practical Guide

O

OverMCP Team

Quick answer

SSRF (Server-Side Request Forgery) in vibe-coded apps happens when an AI-generated backend makes HTTP requests to URLs provided by user input without proper validation. This allows attackers to make your server fetch internal resources, like cloud metadata endpoints, leading to data breaches. Fix it by validating and allowlisting URLs, blocking private IP ranges, and using a robust SSRF protection library or service.

What is SSRF and why should vibe-coders care?

If you've built an app with Cursor, Bolt.new, or Replit Agent, you've likely used AI to generate code that fetches external URLs. Think of features like: a webhook that pulls data from a URL, an image proxy, a PDF generator that fetches remote resources, or a social media preview tool. AI tools are great at generating the happy path code, but they often skip security checks. SSRF is one of those silent killers that can turn your innocent feature into a gateway to your internal network.

In a vibe-coded app, SSRF vulnerabilities often come from AI generating code that directly uses user input in a fetch request without validation. For example, a simple endpoint like /fetch?url=... is a classic SSRF vector. Attackers can replace the URL with internal addresses like http://169.254.169.254/latest/meta-data/ (AWS metadata) or http://localhost:3000/admin to probe your internal services.

What to check first

Before you start fixing, audit your app for SSRF. Here's a checklist:

  • [ ] Search your codebase for fetch( or axios.get( calls that use variables from request parameters, body, or headers.
  • [ ] Look for any feature that accepts a URL from the client (e.g., webhook URL, image URL, import from URL).
  • [ ] Check if you have any internal services running (like a database admin panel) that should not be accessible from the public internet.
  • [ ] Test your endpoints with a tool like curl or Postman: send a request with url=http://169.254.169.254/latest/meta-data/ and see if you get a response.
  • [ ] Review your server logs for any requests to internal IP addresses (10.x.x.x, 172.16.x.x, 192.168.x.x).
  • If you find any of these, you likely have an SSRF vulnerability.

    Step-by-step fix

    1. Validate and sanitize user input

    Never trust user-supplied URLs. Start by validating the input is a valid URL and the scheme is http or https.

    const url = new URL(input);
    if (!['http:', 'https:'].includes(url.protocol)) {
      throw new Error('Invalid protocol');
    }

    2. Implement an allowlist for domains

    If your app only needs to fetch from specific domains (e.g., api.example.com), allowlist them. This is the safest approach.

    const allowedHosts = ['api.example.com', 'images.example.com'];
    if (!allowedHosts.includes(url.hostname)) {
      throw new Error('Host not allowed');
    }

    3. Block private IP addresses and link-local ranges

    Attackers can use DNS rebinding or redirects to bypass simple hostname checks. Resolve the hostname to an IP and verify it's not private or reserved.

    const dns = require('dns').promises;
    const ip = (await dns.lookup(url.hostname)).address;
    if (isPrivateIP(ip)) {
      throw new Error('Private IP blocked');
    }
    
    function isPrivateIP(ip) {
      const parts = ip.split('.').map(Number);
      if (parts[0] === 10) return true;
      if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true;
      if (parts[0] === 192 && parts[1] === 168) return true;
      if (parts[0] === 169 && parts[1] === 254) return true; // link-local
      return false;
    }

    4. Use a dedicated SSRF protection library

    Consider using a library like ssrf-req-filter or axios-ssrf that handles these checks for you. For example, with ssrf-req-filter:

    const { createClient } = require('ssrf-req-filter');
    const client = createClient();
    const response = await client.get(userUrl);

    5. Disable redirects or validate them

    AI-generated code often follows redirects automatically. Attackers can use a redirect from an allowed domain to an internal IP. Disable redirects or validate each redirect target.

    const response = await fetch(userUrl, { redirect: 'manual' });
    if (response.status >= 300 && response.status < 400) {
      const redirectUrl = new URL(response.headers.get('location'), userUrl);
      // Re-validate redirectUrl with the same checks
    }

    6. Use a network-level solution

    If you're on a platform like Vercel, you can configure a proxy or use a serverless function that restricts outbound traffic. Some cloud providers offer VPC endpoints that block public internet access.

    7. Run a security scan

    After implementing fixes, run a security scan to catch any remaining issues. Tools like OverMCP's free AI app security scanner can automatically detect SSRF vulnerabilities and other common issues in vibe-coded apps. You can also use our continuous security monitoring to get alerts if new vulnerabilities appear.

    Common mistakes

    Vibe-coded apps often have these SSRF pitfalls:

  • Only checking the hostname, not the resolved IP: Attackers can use DNS rebinding to make a domain resolve to a private IP after your check.
  • Ignoring IPv6: Private IPv6 ranges (like ::1 for localhost) are often overlooked. Make sure your IP blocking handles both IPv4 and IPv6.
  • Forgetting about redirects: As mentioned, redirects can bypass validation.
  • Using user input directly in `fetch` without any validation: This is the most common mistake. AI-generated code often does this for simplicity.
  • Not blocking non-HTTP schemes: URLs like file://, gopher://, or dict:// can be dangerous.
  • Real-world example

    Imagine you built a social media dashboard that fetches a user-provided image URL to generate a preview. The AI-generated code might look like:

    app.get('/preview', async (req, res) => {
      const imageUrl = req.query.url;
      const response = await fetch(imageUrl);
      res.send(await response.buffer());
    });

    This is a textbook SSRF. An attacker could request /preview?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ and steal your cloud credentials. The fix is to validate the URL, resolve the hostname, and check the IP, as shown earlier.

    Beyond SSRF: Secure your vibe-coded app

    SSRF is just one of many vulnerabilities that AI-generated code can introduce. To protect your app comprehensively, consider:

  • Checking security headers: Use our security headers checker to ensure your app is sending proper CSP, HSTS, and other headers.
  • Verifying SSL/TLS: Ensure your app uses valid certificates with our SSL certificate checker.
  • Scanning for leaked secrets: AI tools often leave API keys in code. Use our secret leak scanner to find exposed keys.
  • Integrating with Vercel: If you deploy on Vercel, use our Vercel security scanner to automate security checks in your CI/CD pipeline.
  • FAQ

    What is SSRF in simple terms?

    SSRF (Server-Side Request Forgery) is when an attacker tricks your server into making requests to unintended destinations, often internal or private network resources. It's like handing someone a phone and asking them to call a number, but they call your internal extension instead.

    How do I know if my vibe-coded app has SSRF?

    Look for any endpoint that takes a URL from user input and fetches it. Test it with a known internal IP like http://127.0.0.1 or http://169.254.169.254. If you get a response, you're vulnerable. Also, review your code for fetch or axios calls using unsanitized user input.

    Can I fix SSRF without changing my app's architecture?

    Yes, you can fix SSRF with proper input validation, IP blocking, and using libraries that handle these checks. For more robust protection, consider network-level controls like a firewall or a proxy that filters outbound requests. Tools like OverMCP can help you identify and fix these issues automatically.

    Is your app secure?

    Free scan in 30 seconds. No signup needed.

    Scan My App Free