CVE-2023-30849 (PHP, published 2023-04-27T16:15Z)
Description: value: Pimcore is an open source data and experience management platform. Prior to version 10.5.21, A SQL injection vulnerability exists in the translation export API. Users should update to version 10.5.21 to receive a patch or, as a workaround, or apply the patch manually.
Severity: nan (CVSS v3 base score: 8.8)
Weakness: CWE-89 \u2014 Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
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.
Repository: https://github.com/pimcore/pimcore
Files changed:
bundles/AdminBundle/Controller/Admin/TranslationController.php
Commit message: [Security] Fix Admin Translation Export SQL Injection (#14968)

* Fix admin translation export sql injection

* Change to setConditon

* Add SyntaxError Exception, replace sql comments

* Remove empty line

* Use const, remove unecessary line

Vulnerable code:
        $condition = $this->getGridFilterCondition($request, $tableName, false, $admin);
        if ($condition) {
            $list->setCondition($condition);
        $list->load();
            $condition = $this->getGridFilterCondition($request, $tableName, false, $admin);
            if ($condition) {
                $list->setCondition($condition);
            $list->load();
     *
     * @return array|null|string
                        $conditionFilters[] = $condition;
            $filterTerm = $db->quote('%' . mb_strtolower($request->get('searchString')) . '%');
            $conditionFilters[] = '(lower(' . $tableName . '.key) LIKE ' . $filterTerm . ' OR lower(' . $tableName . '.text) LIKE ' . $filterTerm . ')';
            $result = [
            return $result;
        } else {
            if (!empty($conditionFilters)) {
                return implode(' AND ', $conditionFilters);
            return null;

Fixed code:
use Doctrine\DBAL\Exception\SyntaxErrorException;
    protected const PLACEHOLDER_NAME = 'placeHolder';

        $conditions = $this->getGridFilterCondition($request, $tableName, false, $admin);
        if (!empty($conditions)) {
            $list->setCondition($conditions['condition'], $conditions['params']);

        try {
            $list->load();
        } catch (SyntaxErrorException $syntaxErrorException) {
            throw new \InvalidArgumentException('Check your arguments.');
        }
            $conditions = $this->getGridFilterCondition($request, $tableName, false, $admin);

            if (!empty($conditions)) {
                $list->setCondition($conditions['condition'], $conditions['params']);
            try {
                $list->load();
            } catch (SyntaxErrorException $syntaxErrorException) {
                throw new \InvalidArgumentException('Check your arguments.');
            }
     * @param bool $admin
     * @return array
        $placeHolderCount = 0;

                $fieldname = str_replace('--', '', $fieldname);
                        $placeHolderName = self::PLACEHOLDER_NAME . $placeHolderCount;
                        $placeHolderCount++;
                        $conditionFilters[] = [
                            'condition' => $field . ' ' . $operator . ' :' . $placeHolderName,
                            'field' => $placeHolderName,
                            'value' => $value
                        ];
            $conditionFilters[] = [
                'condition' => '(lower(' . $tableName . '.key) LIKE :filterTerm OR lower(' . $tableName . '.text) LIKE :filterTerm)',
                'field' => 'filterTerm',
                'value' => '%' . mb_strtolower($request->get('searchString')) . '%'
            ];
            return [
        }
        if(!empty($conditionFilters)) {
            $conditions = [];
            $params = [];
            foreach($conditionFilters as $conditionFilter) {
                $conditions[] = $conditionFilter['condition'];
                $params[$conditionFilter['field']] = $conditionFilter['value'];
            $conditionFilters = [
                'condition' => implode(' AND ', $conditions),
                'params' => $params
            ];
        return $conditionFilters;