JavaScript Application Security: Top 10 Vulnerabilities for Beginners
Web application security is one of the most important topics for any developer. JavaScript (especially on the server side with Node.js) often becomes a target for attackers due to its popularity. In this article, we will cover the 10 most common vulnerabilities that beginner developers face and show how to avoid them.
1. XSS (Cross-Site Scripting)
XSS is one of the most common attacks, where an attacker injects a malicious script into a web page. This happens when user data is inserted into HTML without escaping.
Dangerous code (vulnerable):
app.get('/search', (req, res) => { const query = req.query.q; res.send(`<h1>Search results: ${query}</h1>`);});Safe code (protection):
const escapeHtml = require('escape-html');
app.get('/search', (req, res) => { const query = escapeHtml(req.query.q); res.send(`<h1>Search results: ${query}</h1>`);});2. SQL Injection
If you use SQL databases (e.g., SQLite or PostgreSQL), unescaped queries can lead to data leaks.
Dangerous code:
const user = req.body.username;db.query(`SELECT * FROM users WHERE name = '${user}'`);Safe code (use parameterized queries):
const user = req.body.username;db.query('SELECT * FROM users WHERE name = $1', [user]);3. Insecure Deserialization
Using JSON.parse() on untrusted data can lead to "prototype pollution" attacks.
Example of vulnerability:
const data = JSON.parse(req.body.jsonData);// If data contains __proto__, it can change the Object prototypeProtection: always validate data before parsing or use libraries like fast-json-stable-stringify.
4. Lack of Input Validation
Never trust user data. Always check the type, length, and format of the data.
// Bad: accept everythingapp.post('/profile', (req, res) => { const { name, age } = req.body; // ...});
// Good: validateconst schema = { name: 'string', age: 'number' };if (typeof req.body.name !== 'string') throw new Error('Invalid name');5. CSRF (Cross-Site Request Forgery)
An attack where an attacker forces a user to perform an unwanted action on a site where they are authenticated.
Protection: use CSRF tokens.
const csrf = require('csurf');app.use(csrf({ cookie: true }));
app.get('/form', (req, res) => { res.render('form', { csrfToken: req.csrfToken() });});6. Information Leakage Through Errors
Never show detailed error messages to the user — this gives hackers information about your application's structure.
Bad:
app.use((err, req, res, next) => { res.status(500).send(err.stack); // Leaks the call stack!});Good:
app.use((err, req, res, next) => { console.error(err.stack); // Log for ourselves res.status(500).send('Internal server error');});7. Unsafe Use of eval() and Function()
The eval() and new Function() functions execute a string as code — this is extremely dangerous if the string contains user data.
// Dangerous! Never do thisconst userInput = req.body.code;eval(userInput); // An attacker can execute any codeAlternative: