Security of TypeScript Applications: Top 10 Vulnerabilities in Practice

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Security of TypeScript Applications: Top 10 Vulnerabilities in Practice



TypeScript is a superset of JavaScript that adds static typing. Many developers mistakenly believe that strict typing automatically makes an application secure. This is not the case. The TypeScript compiler checks types, but does not protect against logical errors, injections, or authentication issues. In this article, we will analyze the 10 most common vulnerabilities in TypeScript applications, show code examples, and provide specific recommendations for protection. The article will be useful for both beginners and experienced developers.



1. Cross-Site Scripting (XSS) via Improper Input Handling



XSS remains one of the most dangerous vulnerabilities. TypeScript does not automatically escape output. If you insert user data into an HTML template without sanitization, you open the door to attacks.



Vulnerable Code

function renderComment(comment: string): string {  return `<div>${comment}</div>`;}

// Attacker passes: <script>alert('XSS')</script>


Fixed Code

import { escape } from 'lodash';

function renderComment(comment: string): string { const safeComment = escape(comment); return `<div>${safeComment}</div>`;}


Recommendation: Always use libraries for escaping (DOMPurify, lodash.escape) or template engines with auto-escaping (React JSX, Handlebars).



2. SQL Injection via Template Strings



TypeScript allows using template strings to build SQL queries. This is a direct path to SQL injection if you substitute user data.



Vulnerable Code

async function getUser(id: string): Promise<User | null> {  const query = `SELECT * FROM users WHERE id = '${id}'`;  const result = await db.query(query);  return result.rows[0];}


Fixed Code

async function getUser(id: string): Promise<User | null> {  const query = 'SELECT * FROM users WHERE id = $1';  const result = await db.query(query, [id]);  return result.rows[0];}


Recommendation: Use parameterized queries or ORM (TypeORM, Prisma, Sequelize). Never concatenate strings for SQL.



3. Insecure Password Comparison



An error in implementing password comparison can lead to timing attacks. TypeScript developers often use the === operator to compare hashes, which is insecure.



Vulnerable Code

async function verifyPassword(  inputPassword: string,   storedHash: string): Promise<boolean> {  const inputHash = await bcrypt.hash(inputPassword, 10);  return inputHash === storedHash; // Vulnerability: timing attack}


Fixed Code

import bcrypt from 'bcrypt';

async function verifyPassword( inputPassword: string, storedHash: string): Promise<boolean> { return bcrypt.compare(inputPassword, storedHash);}


Recommendation: Use built-in comparison functions from hashing libraries (bcrypt.compare, argon2.verify). They are protected against timing attacks.



4. Prototype Pollution via Recursive Object Merging



TypeScript applications often use functions for deep copying or merging objects. If keys are not controlled, an attacker can pollute the Object.prototype.



Vulnerable Code

function merge(target: Record<string, any>, source: Record<string, any>) {  for (const key in source) {    if (typeof source[key] === 'object') {      target[key] = merge(target[key] || {}, source[key]);    } else {      target[key] = source[key];    }  }  return target;}

// Attacker pe

Blogs

Book Recommendations