Skip to content

[GHSA-h4ph-crvj-9h92] Pimcore Admin Classic Bundle Vulnerable to SQL Injection in Translation Grid Date Filter via Unsanitized Property Parameter#7899

Open
kingjia90 wants to merge 2 commits into
kingjia90/advisory-improvement-7899from
kingjia90-GHSA-h4ph-crvj-9h92
Open

[GHSA-h4ph-crvj-9h92] Pimcore Admin Classic Bundle Vulnerable to SQL Injection in Translation Grid Date Filter via Unsanitized Property Parameter#7899
kingjia90 wants to merge 2 commits into
kingjia90/advisory-improvement-7899from
kingjia90-GHSA-h4ph-crvj-9h92

Conversation

@kingjia90
Copy link
Copy Markdown

Updates

  • Affected products

Comments
a lower version with the security fix for LTS purposes got released after first publish

@github
Copy link
Copy Markdown
Collaborator

github commented Jun 5, 2026

Hi there @kingjia90! A community member has suggested an improvement to your security advisory. If approved, this change will affect the global advisory listed at github.com/advisories. It will not affect the version listed in your project repository.

This change will be reviewed by our Security Curation Team. If you have thoughts or feedback, please share them in a comment here! If this PR has already been closed, you can start a new community contribution for this advisory

Copilot AI review requested due to automatic review settings June 5, 2026 12:24
@github-actions github-actions Bot changed the base branch from main to kingjia90/advisory-improvement-7899 June 5, 2026 12:26
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Updates a GitHub-reviewed advisory entry for GHSA-h4ph-crvj-9h92, revising the write-up and changing the affected/fixed version metadata.

Changes:

  • Updated the advisory details markdown content (removing “Draft” wording and reformatting the narrative).
  • Changed the fixed version and last-known-affected version range from the 2.3.x line to the 1.7.x line.
  • Bumped the modified timestamp.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

],
"summary": "Pimcore Admin Classic Bundle Vulnerable to SQL Injection in Translation Grid Date Filter via Unsanitized Property Parameter",
"details": "# GitHub Security Advisory Draft — GM-369\n\n## Summary\nSQL injection in Pimcore's translation grid date filter — the user-supplied `property` field from the filter JSON is interpolated directly into a `UNIX_TIMESTAMP(DATE(FROM_UNIXTIME(...)))` SQL expression without parameterization or allowlist validation.\n\n## Affected Component\n- **Package:** `pimcore/admin-ui-classic-bundle`\n- **File:** `src/Controller/Admin/TranslationController.php`\n- **Lines:** 565 (input), 569 (inadequate sanitization), 593 (injection point)\n- **Endpoint:** `POST /admin/translation/translations`\n\n## Description\nThe translation grid endpoint processes JSON filter parameters. When a filter has `type: \"date\"`, the `property` field is extracted and used to construct a SQL expression:\n\n```php\n$fieldname = $filter[$propertyField]; // Line 565 — user input\n$fieldname = str_replace('--', '', $fieldname); // Line 569 — trivially bypassable\n$fieldname = $tableName . '.' . $fieldname; // Line 577\n$fieldname = \"UNIX_TIMESTAMP(DATE(FROM_UNIXTIME({$fieldname})))\"; // Line 593 — injection\n```\n\nThe `str_replace('--', '')` sanitization is trivially bypassable (use `/**/` comments or `----`). In non-language mode, `$fieldname` is concatenated directly into the SQL condition without quoting or parameterization.\n\n## Impact\nAuthenticated user with translations view permission can extract arbitrary database data via UNION-based or error-based SQL injection. Combined with GM-249 (unsafe unserialize), this enables an SQLi → deserialization → RCE chain.\n\n## Proof of Concept\n```\nPOST /admin/translation/translations\nfilter=[{\"property\":\"1))) UNION SELECT password FROM users WHERE ((1\",\"type\":\"date\",\"operator\":\"eq\",\"value\":\"2026-01-01\"}]\n```\n\n## Suggested Fix\nValidate `$fieldname` against an allowlist of valid column names before SQL interpolation:\n```php\n$allowedDateColumns = ['creationDate', 'modificationDate'];\nif (!in_array($fieldname, $allowedDateColumns, true)) {\n continue;\n}\n```\n\n## References\n- CWE-89: SQL Injection\n- Related: CVE-2026-27461 (RLIKE injection in Dependency/Dao.php — different code path)\n\n\n---\n\n## Suggested Fix\n\nIn `TranslationController.php`: (1) Add allowlist check for non-language fieldnames before processing. (2) Replace raw string interpolation `UNIX_TIMESTAMP(DATE(FROM_UNIXTIME({$fieldname})))` with `$db->quoteIdentifier($fieldname)` to prevent SQL injection in date filter expressions.\n\n```diff\n--- a/src/Controller/Admin/TranslationController.php\n+++ b/src/Controller/Admin/TranslationController.php\n@@ -569,7 +569,15 @@ class TranslationController extends AdminAbstractController\n $fieldname = str_replace('--', '', $fieldname);\n \n if (!$languageMode && in_array($fieldname, $validLanguages)\n || $languageMode && !in_array($fieldname, $validLanguages)) {\n continue;\n }\n \n+ // Allowlist non-language fieldnames to prevent SQL injection\n+ $allowedNonLanguageFields = ['key', 'type', 'creationDate', 'modificationDate'];\n+ if (!$languageMode && !in_array($fieldname, $allowedNonLanguageFields) && !in_array($fieldname, $validLanguages)) {\n+ continue;\n+ }\n+\n if (!$languageMode) {\n $fieldname = $tableName . '.' . $fieldname;\n }\n@@ -582,7 +590,7 @@ class TranslationController extends AdminAbstractController\n } elseif ($filter[$operatorField] == 'eq') {\n $operator = '=';\n- $fieldname = \"UNIX_TIMESTAMP(DATE(FROM_UNIXTIME({$fieldname})))\";\n+ // Use validated fieldname only — never interpolate raw user input into SQL functions\n+ $fieldname = sprintf('UNIX_TIMESTAMP(DATE(FROM_UNIXTIME(%s)))', $db->quoteIdentifier($fieldname));\n }\n\n```\n\n---\n\n## Proposed Fix\n\n```diff\n--- a/src/Controller/Admin/TranslationController.php\n+++ b/src/Controller/Admin/TranslationController.php\n@@ -569,7 +569,15 @@ class TranslationController extends AdminAbstractController\n $fieldname = str_replace('--', '', $fieldname);\n \n if (!$languageMode && in_array($fieldname, $validLanguages)\n || $languageMode && !in_array($fieldname, $validLanguages)) {\n continue;\n }\n \n+ // Allowlist non-language fieldnames to prevent SQL injection\n+ $allowedNonLanguageFields = ['key', 'type', 'creationDate', 'modificationDate'];\n+ if (!$languageMode && !in_array($fieldname, $allowedNonLanguageFields) && !in_array($fieldname, $validLanguages)) {\n+ continue;\n+ }\n+\n if (!$languageMode) {\n $fieldname = $tableName . '.' . $fieldname;\n }\n@@ -582,7 +590,7 @@ class TranslationController extends AdminAbstractController\n } elseif ($filter[$operatorField] == 'eq') {\n $operator = '=';\n- $fieldname = \"UNIX_TIMESTAMP(DATE(FROM_UNIXTIME({$fieldname})))\";\n+ // Use validated fieldname only — never interpolate raw user input into SQL functions\n+ $fieldname = sprintf('UNIX_TIMESTAMP(DATE(FROM_UNIXTIME(%s)))', $db->quoteIdentifier($fieldname));\n }\n```\n\nHappy to submit this as a PR against a private fork if that is the preferred workflow.",
"details": "# GM-369\n\n## Summary\nSQL injection in Pimcore's translation grid date filter — the user-supplied `property` field from the filter JSON is interpolated directly into a `UNIX_TIMESTAMP(DATE(FROM_UNIXTIME(...)))` SQL expression without parameterization or allowlist validation.\n\n## Affected Component\n- **Package:** `pimcore/admin-ui-classic-bundle`\n- **File:** `src/Controller/Admin/TranslationController.php`\n- **Lines:** 565 (input), 569 (inadequate sanitization), 593 (injection point)\n- **Endpoint:** `POST /admin/translation/translations`\n\n## Description\nThe translation grid endpoint processes JSON filter parameters. When a filter has `type: \"date\"`, the `property` field is extracted and used to construct a SQL expression:\n\n```php\n$fieldname = $filter[$propertyField]; // Line 565 — user input\n$fieldname = str_replace('--', '', $fieldname); // Line 569 — trivially bypassable\n$fieldname = $tableName . '.' . $fieldname; // Line 577\n$fieldname = \"UNIX_TIMESTAMP(DATE(FROM_UNIXTIME({$fieldname})))\"; // Line 593 — injection\n```\n\nThe `str_replace('--', '')` sanitization is trivially bypassable (use `/**/` comments or `----`). In non-language mode, `$fieldname` is concatenated directly into the SQL condition without quoting or parameterization.\n\n## Impact\nAuthenticated user with translations view permission can extract arbitrary database data via UNION-based or error-based SQL injection. Combined with GM-249 (unsafe unserialize), this enables an SQLi → deserialization → RCE chain.\n\n## Proof of Concept\n```\nPOST /admin/translation/translations\nfilter=[{\"property\":\"1))) UNION SELECT password FROM users WHERE ((1\",\"type\":\"date\",\"operator\":\"eq\",\"value\":\"2026-01-01\"}]\n```\n\n## Suggested Fix\nValidate `$fieldname` against an allowlist of valid column names before SQL interpolation:\n```php\n$allowedDateColumns = ['creationDate', 'modificationDate'];\nif (!in_array($fieldname, $allowedDateColumns, true)) {\n continue;\n}\n```\n\n## References\n- CWE-89: SQL Injection\n- Related: CVE-2026-27461 (RLIKE injection in Dependency/Dao.php — different code path)\n\n\n---\n\n## Suggested Fix\n\nIn `TranslationController.php`: (1) Add allowlist check for non-language fieldnames before processing. (2) Replace raw string interpolation `UNIX_TIMESTAMP(DATE(FROM_UNIXTIME({$fieldname})))` with `$db->quoteIdentifier($fieldname)` to prevent SQL injection in date filter expressions.\n\n```diff\n--- a/src/Controller/Admin/TranslationController.php\n+++ b/src/Controller/Admin/TranslationController.php\n@@ -569,7 +569,15 @@ class TranslationController extends AdminAbstractController\n $fieldname = str_replace('--', '', $fieldname);\n \n if (!$languageMode && in_array($fieldname, $validLanguages)\n || $languageMode && !in_array($fieldname, $validLanguages)) {\n continue;\n }\n \n+ // Allowlist non-language fieldnames to prevent SQL injection\n+ $allowedNonLanguageFields = ['key', 'type', 'creationDate', 'modificationDate'];\n+ if (!$languageMode && !in_array($fieldname, $allowedNonLanguageFields) && !in_array($fieldname, $validLanguages)) {\n+ continue;\n+ }\n+\n if (!$languageMode) {\n $fieldname = $tableName . '.' . $fieldname;\n }\n@@ -582,7 +590,7 @@ class TranslationController extends AdminAbstractController\n } elseif ($filter[$operatorField] == 'eq') {\n $operator = '=';\n- $fieldname = \"UNIX_TIMESTAMP(DATE(FROM_UNIXTIME({$fieldname})))\";\n+ // Use validated fieldname only — never interpolate raw user input into SQL functions\n+ $fieldname = sprintf('UNIX_TIMESTAMP(DATE(FROM_UNIXTIME(%s)))', $db->quoteIdentifier($fieldname));\n }\n\n```\n\n---\n\n## Proposed Fix\n\n```diff\n--- a/src/Controller/Admin/TranslationController.php\n+++ b/src/Controller/Admin/TranslationController.php\n@@ -569,7 +569,15 @@ class TranslationController extends AdminAbstractController\n $fieldname = str_replace('--', '', $fieldname);\n \n if (!$languageMode && in_array($fieldname, $validLanguages)\n || $languageMode && !in_array($fieldname, $validLanguages)) {\n continue;\n }\n \n+ // Allowlist non-language fieldnames to prevent SQL injection\n+ $allowedNonLanguageFields = ['key', 'type', 'creationDate', 'modificationDate'];\n+ if (!$languageMode && !in_array($fieldname, $allowedNonLanguageFields) && !in_array($fieldname, $validLanguages)) {\n+ continue;\n+ }\n+\n if (!$languageMode) {\n $fieldname = $tableName . '.' . $fieldname;\n }\n@@ -582,7 +590,7 @@ class TranslationController extends AdminAbstractController\n } elseif ($filter[$operatorField] == 'eq') {\n $operator = '=';\n- $fieldname = \"UNIX_TIMESTAMP(DATE(FROM_UNIXTIME({$fieldname})))\";\n+ // Use validated fieldname only — never interpolate raw user input into SQL functions\n+ $fieldname = sprintf('UNIX_TIMESTAMP(DATE(FROM_UNIXTIME(%s)))', $db->quoteIdentifier($fieldname));\n }\n```\n\nHappy to submit this as a PR against a private fork if that is the preferred workflow.",
Comment on lines 28 to +37
"introduced": "0"
},
{
"fixed": "2.3.6"
"fixed": "1.7.18"
}
]
}
],
"database_specific": {
"last_known_affected_version_range": "<= 2.3.5"
"last_known_affected_version_range": "<= 1.7.17"
@github
Copy link
Copy Markdown
Collaborator

github commented Jun 5, 2026

Hi there @kingjia90! A community member has suggested an improvement to your security advisory. If approved, this change will affect the global advisory listed at github.com/advisories. It will not affect the version listed in your project repository.

This change will be reviewed by our Security Curation Team. If you have thoughts or feedback, please share them in a comment here! If this PR has already been closed, you can start a new community contribution for this advisory

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants