# JavaScript Vulnerability Examples and Fixes

> **Use this page when:** reviewing Node/Express backends, admin dashboards, browser-heavy workflows, and old JavaScript where “just one helper” quietly became part of the trust boundary.

## How to read these examples

* **Vulnerable snippet** shows the unsafe habit.
* **Safer pattern** shows the direction you want in production code.
* **Why it matters** ties the defect to attacker value and business impact.
* **Review cue** is phrased so it can become a pull-request comment or checklist item.

## Example 1 — DOM XSS via innerHTML

### Vulnerable snippet

```javascript
const params = new URLSearchParams(location.search);
document.getElementById('welcome').innerHTML = params.get('name');
```

### Safer pattern

```javascript
const params = new URLSearchParams(location.search);
document.getElementById('welcome').textContent = params.get('name') || '';
```

**Why it matters**

* `innerHTML` treats attacker-controlled content as markup and script-capable DOM input.

**Business impact**

* Session theft, account takeover, malicious actions in the victim session, and browser-side trust collapse.

**Review cue**

* Prefer `textContent` for plain text. Use trusted sanitization only when rich HTML is actually required.

## Example 2 — NoSQL injection in login flow

### Vulnerable snippet

```javascript
app.post('/login', async (req, res) => {
  const user = await db.collection('users').findOne({
    email: req.body.email,
    password: req.body.password
  });
  if (user) res.sendStatus(200);
});
```

### Safer pattern

```javascript
app.post('/login', async (req, res) => {
  const email = String(req.body.email || '');
  const password = String(req.body.password || '');
  const user = await db.collection('users').findOne({ email });
  if (!user) return res.sendStatus(401);
  const ok = await bcrypt.compare(password, user.passwordHash);
  if (!ok) return res.sendStatus(401);
  res.sendStatus(200);
});
```

**Why it matters**

* When request bodies are used as query objects or compared directly, attacker-crafted structures can alter query meaning.

**Business impact**

* Authentication bypass, user enumeration, and exposure of account existence or account takeover paths.

**Review cue**

* Cast request fields to expected scalar types and separate identity lookup from password verification.

## Example 3 — Path traversal in file download endpoint

### Vulnerable snippet

```javascript
app.get('/download', (req, res) => {
  const filePath = '/srv/public/' + req.query.name;
  res.sendFile(filePath);
});
```

### Safer pattern

```javascript
const path = require('node:path');
app.get('/download', (req, res) => {
  const base = '/srv/public';
  const target = path.resolve(base, String(req.query.name || ''));
  if (!target.startsWith(path.resolve(base) + path.sep)) {
    return res.status(400).send('invalid path');
  }
  res.sendFile(target);
});
```

**Why it matters**

* Concatenating file paths allows `../` traversal or unexpected absolute paths to escape the intended directory.

**Business impact**

* Disclosure of secrets, source code, configs, keys, or operational documents on the host.

**Review cue**

* Normalize and resolve paths against a fixed base, then verify the resolved prefix before serving a file.

## Example 4 — JWT misuse by decoding without verification

### Vulnerable snippet

```javascript
app.get('/admin', (req, res) => {
  const token = req.headers.authorization?.replace('Bearer ', '');
  const claims = jwt.decode(token);
  if (claims?.role === 'admin') return res.send('ok');
  res.sendStatus(403);
});
```

### Safer pattern

```javascript
app.get('/admin', (req, res) => {
  const token = req.headers.authorization?.replace('Bearer ', '');
  try {
    const claims = jwt.verify(token, PUBLIC_KEY, { algorithms: ['RS256'] });
    if (claims.role !== 'admin') return res.sendStatus(403);
    return res.send('ok');
  } catch {
    return res.sendStatus(401);
  }
});
```

**Why it matters**

* `decode()` reads claims but does not prove signature, issuer, audience, or token validity.

**Business impact**

* Privilege escalation, admin impersonation, and broken trust in every downstream authorization decision.

**Review cue**

* Only verified claims may influence authorization. Require explicit algorithm and key expectations.

## Example 5 — Prototype pollution through unsafe deep merge

### Vulnerable snippet

```javascript
const settings = merge(defaultSettings, req.body);
// later logic trusts merged object
```

### Safer pattern

```javascript
const allowed = (({ theme, locale, pageSize }) => ({ theme, locale, pageSize }))(req.body || {});
const settings = { ...defaultSettings, ...allowed };
```

**Why it matters**

* Deep-merging untrusted objects can modify inherited properties or unexpected control flags used later in the application.

**Business impact**

* Authorization confusion, logic corruption, denial of service, and hard-to-debug cross-request behavior.

**Review cue**

* Do not deep-merge untrusted objects into trusted configuration; use allowlisted fields and plain object construction.

## Related pages

* [Node / Next.js / React Security Review Guide](https://github.com/D3One/Product-Security-Gitbook/blob/main/20-stack-specific-secure-engineering/node-nextjs-react-security-review-guide.md)
* [Frontend Security Review Playbook](https://github.com/D3One/Product-Security-Gitbook/blob/main/18-frontend-and-browser-security/frontend-security-review-playbook.md)
* [Browser Security Foundations: CSP, CORS, Cookies, and Sessions](/application-security-and-secure-sdlc/index-2/browser-security-foundations-csp-cors-cookies-and-sessions.md)

***

*Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.product-security.expert/application-security-and-secure-sdlc/index-4/javascript-vulnerability-examples-and-fixes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
