Introduction: Why TypeScript Application Security is Critical
TypeScript is a superset of JavaScript that adds static typing and modern capabilities. However, typing does not guarantee security. Validation errors, improper handling of user input, and vulnerabilities in dependencies can lead to serious attacks. In this article, we will break down the top 10 most common vulnerabilities in TypeScript applications, provide code examples, and show how to avoid them.
1. Cross-Site Scripting (XSS)
XSS attacks occur when an attacker injects a malicious script into a web page. TypeScript does not automatically protect against this.
Example of vulnerable code
function renderUserInput(input: string): string { return `<div>${input}</div>`;}
// Attacker passes: <script>alert('XSS')</script>Solution
Use HTML character escaping or libraries like DOMPurify:
import DOMPurify from 'dompurify';
function renderUserInputSafe(input: string): string { const sanitized = DOMPurify.sanitize(input); return `<div>${sanitized}</div>`;}2. SQL Injection
If you use TypeScript with databases, uncontrolled string concatenation in SQL queries can lead to data leaks.
Example of vulnerable code
async function getUser(id: string): Promise<User | null> { const query = `SELECT * FROM users WHERE id = '${id}'`; return await db.query(query);}Solution
Use parameterized queries (prepared statements):
async function getUserSafe(id: string): Promise<User | null> { const query = 'SELECT * FROM users WHERE id = $1'; return await db.query(query, [id]);}3. Prototype Pollution
This vulnerability is characteristic of JavaScript/TypeScript. An attacker can modify an object's prototype, affecting all objects at runtime.
Example of vulnerable code
function merge(target: any, source: any) { for (const key in source) { if (source.hasOwnProperty(key)) { target[key] = source[key]; } }}
const user = { name: 'Alice' };merge(user, JSON.parse('{"__proto__": {"isAdmin": true}}'));// Now all objects have isAdmin: trueSolution
Check keys for dangerous properties and use safe utilities:
function safeMerge(target: Record<string, any>, source: Record<string, any>) { for (const key in source) { if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue; target[key] = source[key]; }}4. Cross-Site Request Forgery (CSRF)
CSRF attacks force a user to perform unwanted actions on a site where they are authenticated.
Solution in TypeScript
// CSRF token generationimport crypto from 'crypto';
function generateCsrfToken(): string { return crypto.randomBytes(32).toString('hex');}
// Verification in middlewarefunction csrfMiddleware(req: Request, res: Response, next: NextFunction) { const token = req.headers['x-csrf-token']; if (token !== req.session.csrfToken) { return res.status(403).json({ error: 'CSRF validation failed' }); } next();}5. Insecure Deserialization
Using JSON.parse() or eval() on unverified data can lead to arbitrary code execution.
Vulnerable example
function processData(data: string) { const obj = eval('(' + data + ')'); // ...}Safe approach
function processDataSafe(data: string) { try { const obj = JSON.parse(data); // Additional type validation if (typeof obj !== 'object' || obj === null)