CVE-2026-115938

Low privilege condition filter escapes Twig sandbox, recovers "securityKey" and reaches RCE

High 8.7

Craft CMS allows any authenticated control panel user to submit an element-search condition whose element selector is evaluated as a sandboxed Twig object template. Craft’s allowed column filter delegates property lookup to Yii ArrayHelper, outside Twig’s SecurityPolicy. Repeated single-segment lookups therefore bypass the sandbox’s empty property/method allowlists. The vulnerable condition value is ultimately cast to an integer. That does not protect the secret: the template can return author ID 1 when a guessed key character is correct and an impossible ID otherwise. The JSON endpoint returns entries for the first case and an empty array for the second, forming a stable remote character oracle. After recovering GeneralConfig::securityKey, the same user can compute Craft’s generic HMAC wire format offline. Signed parameters such as redirect are then accepted and passed to unsandboxed View::renderObjectTemplate(), where Twig’s string-callable form can invoke native PHP callables. The regression proof uses the harmless substr() callback and observes abcdef becoming cdef; it does not execute an OS command.

Assigner
Hackrate
Published
2026-10-23
Updated
2026-10-23
Reserved
2026-10-23

Scores

SourceCVSSScoreSeverityVector
Hackrate4.08.7HighCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Hackrate3.18.8HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Weaknesses

Affected

VendorProductVersions
craftcms cms 5.0.0 to < 5.11.2 (affected)
4.0.0 to < 4.18.9 (affected)
others: unaffected

References

Full CVE JSON record (5.2)

API · GitHub · cve.org

{
  "containers": {
    "cna": {
      "affected": [
        {
          "collectionURL": "https://packagist.org",
          "defaultStatus": "unaffected",
          "packageName": "craftcms/cms",
          "product": "cms",
          "vendor": "craftcms",
          "versions": [
            {
              "lessThan": "5.11.2",
              "status": "affected",
              "version": "5.0.0",
              "versionType": "semver"
            },
            {
              "lessThan": "4.18.9",
              "status": "affected",
              "version": "4.0.0",
              "versionType": "semver"
            }
          ]
        }
      ],
      "cpeApplicability": [
        {
          "nodes": [
            {
              "cpeMatch": [
                {
                  "criteria": "cpe:2.3:a:craftcms:cms:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "5.11.2",
                  "versionStartIncluding": "5.0.0",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:a:craftcms:cms:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "4.18.9",
                  "versionStartIncluding": "4.0.0",
                  "vulnerable": true
                }
              ],
              "negate": false,
              "operator": "OR"
            }
          ],
          "operator": "OR"
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "reporter",
          "value": "Mohamed Wagdy (@Kalawy)"
        },
        {
          "lang": "en",
          "type": "coordinator",
          "value": "Hackrate"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "supportingMedia": [
            {
              "base64": false,
              "type": "text/html",
              "value": "\u003cp\u003eCraft CMS allows any authenticated control panel user to submit an element-search condition whose element selector is evaluated as a sandboxed Twig object template. Craft\u2019s allowed\u0026nbsp;\u003ccode\u003ecolumn\u003c/code\u003e\u0026nbsp;filter delegates property lookup to Yii\u0026nbsp;\u003ccode\u003eArrayHelper\u003c/code\u003e, outside Twig\u2019s\u0026nbsp;\u003ccode\u003eSecurityPolicy\u003c/code\u003e. Repeated single-segment lookups therefore bypass the sandbox\u2019s empty property/method allowlists.\u003c/p\u003e\u003cp\u003eThe vulnerable condition value is ultimately cast to an integer. That does not protect the secret: the template can return author ID\u0026nbsp;\u003ccode\u003e1\u003c/code\u003e\u0026nbsp;when a guessed key character is correct and an impossible ID otherwise. The JSON endpoint returns entries for the first case and an empty array for the second, forming a stable remote character oracle.\u003c/p\u003e\u003cp\u003eAfter recovering\u0026nbsp;\u003ccode\u003eGeneralConfig::securityKey\u003c/code\u003e, the same user can compute Craft\u2019s generic HMAC wire format offline. Signed parameters such as\u0026nbsp;\u003ccode\u003eredirect\u003c/code\u003e\u0026nbsp;are then accepted and passed to unsandboxed\u0026nbsp;\u003ccode\u003eView::renderObjectTemplate()\u003c/code\u003e, where Twig\u2019s string-callable form can invoke native PHP callables. The regression proof uses the harmless\u0026nbsp;\u003ccode\u003esubstr()\u003c/code\u003e\u0026nbsp;callback and observes\u0026nbsp;\u003ccode\u003eabcdef\u003c/code\u003e\u0026nbsp;becoming\u0026nbsp;\u003ccode\u003ecdef\u003c/code\u003e; it does not execute an OS command.\u003c/p\u003e"
            }
          ],
          "value": "Craft CMS allows any authenticated control panel user to submit an element-search condition whose element selector is evaluated as a sandboxed Twig object template. Craft\u2019s allowed\u00a0column\u00a0filter delegates property lookup to Yii\u00a0ArrayHelper, outside Twig\u2019s\u00a0SecurityPolicy. Repeated single-segment lookups therefore bypass the sandbox\u2019s empty property/method allowlists.\n\n\n\nThe vulnerable condition value is ultimately cast to an integer. That does not protect the secret: the template can return author ID\u00a01\u00a0when a guessed key character is correct and an impossible ID otherwise. The JSON endpoint returns entries for the first case and an empty array for the second, forming a stable remote character oracle.\n\n\n\nAfter recovering\u00a0GeneralConfig::securityKey, the same user can compute Craft\u2019s generic HMAC wire format offline. Signed parameters such as\u00a0redirect\u00a0are then accepted and passed to unsandboxed\u00a0View::renderObjectTemplate(), where Twig\u2019s string-callable form can invoke native PHP callables. The regression proof uses the harmless\u00a0substr()\u00a0callback and observes\u00a0abcdef\u00a0becoming\u00a0cdef; it does not execute an OS command."
        }
      ],
      "metrics": [
        {
          "cvssV4_0": {
            "Automatable": "NOT_DEFINED",
            "Recovery": "NOT_DEFINED",
            "Safety": "NOT_DEFINED",
            "attackComplexity": "LOW",
            "attackRequirements": "NONE",
            "attackVector": "NETWORK",
            "baseScore": 8.7,
            "baseSeverity": "HIGH",
            "exploitMaturity": "NOT_DEFINED",
            "privilegesRequired": "LOW",
            "providerUrgency": "NOT_DEFINED",
            "subAvailabilityImpact": "NONE",
            "subConfidentialityImpact": "NONE",
            "subIntegrityImpact": "NONE",
            "userInteraction": "NONE",
            "valueDensity": "NOT_DEFINED",
            "vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
            "version": "4.0",
            "vulnAvailabilityImpact": "HIGH",
            "vulnConfidentialityImpact": "HIGH",
            "vulnIntegrityImpact": "HIGH",
            "vulnerabilityResponseEffort": "NOT_DEFINED"
          },
          "format": "CVSS",
          "scenarios": [
            {
              "lang": "en",
              "value": "GENERAL"
            }
          ]
        },
        {
          "cvssV3_1": {
            "attackComplexity": "LOW",
            "attackVector": "NETWORK",
            "availabilityImpact": "HIGH",
            "baseScore": 8.8,
            "baseSeverity": "HIGH",
            "confidentialityImpact": "HIGH",
            "integrityImpact": "HIGH",
            "privilegesRequired": "LOW",
            "scope": "UNCHANGED",
            "userInteraction": "NONE",
            "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
            "version": "3.1"
          },
          "format": "CVSS",
          "scenarios": [
            {
              "lang": "en",
              "value": "GENERAL"
            }
          ]
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-1336",
              "description": "CWE-1336 Improper neutralization of special elements used in a template engine",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-10-23T21:58:51.816Z",
        "orgId": "7004884b-51e2-48e8-b4a2-5ca29e80453e",
        "shortName": "Hackrate"
      },
      "references": [
        {
          "tags": [
            "third-party-advisory",
            "technical-description",
            "mitigation"
          ],
          "url": "https://www.hckrt.com/hacktivity/HCKRT-DRNL9W"
        },
        {
          "tags": [
            "release-notes"
          ],
          "url": "https://github.com/craftcms/cms/releases/tag/5.11.2"
        },
        {
          "tags": [
            "product"
          ],
          "url": "https://github.com/craftcms/cms"
        },
        {
          "tags": [
            "third-party-advisory"
          ],
          "url": "https://github.com/craftcms/cms/security/advisories/GHSA-v4q3-2g5g-wjj6"
        }
      ],
      "source": {
        "advisory": "GHSA-v4q3-2g5g-wjj6",
        "discovery": "UNKNOWN"
      },
      "title": "Low privilege condition filter escapes Twig sandbox, recovers \"securityKey\" and reaches RCE",
      "x_generator": {
        "engine": "Vulnogram 1.0.4"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "7004884b-51e2-48e8-b4a2-5ca29e80453e",
    "assignerShortName": "Hackrate",
    "cveId": "CVE-2026-115938",
    "datePublished": "2026-10-23T21:58:51.816Z",
    "dateReserved": "2026-10-23T21:25:32.945Z",
    "dateUpdated": "2026-10-23T21:58:51.816Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}