# Grav: Twig sandbox allows editor-role users to exfiltrate all plugin secrets via Config::toArray()

Grav's Twig sandbox allow-list permits Config::toArray(), letting editor-role users dump all plugin secrets (SMTP, AWS, OAuth keys) into rendered HTML.

- Payout: Research
- Severity: high
- Program: Grav
- Found by: Revanth011
- Disclosed: 2026-05-13
- CVE: CVE-2026-44738
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-j274-39qw-32c9
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-j274-39qw-32c9
- Tags: area:web domain:web impact:data-leak impact:internal-access kind:research platform:ghsa sev:high tech:php technique:source-review vuln:access-control vuln:info-disclosure vuln:secrets-leak

**Target:** Twig sandbox / admin page editor in Grav CMS
**Root cause:** The Twig sandbox allow-list in system/config/security.yaml explicitly permits Config::toArray(), and the full merged config object is injected into every sandboxed render, exposing all plugin secrets to any user who can render Twig.
**Steps:**
1. Read system/config/security.yaml: allow-list includes `methods: 'get, toarray, value, default, offsetget, offsetexists'` for `Grav\Common\Config\Config`.
2. Note Twig.php line 292 injects `'config' => $config` into sandboxed render vars.
3. Log in as editor (admin.pages only) via /admin with login-nonce.
4. Save a page with frontmatter `process:\n    twig: true` and body `{{ config.toArray()|json_encode|raw }}`.
5. Fetch the rendered page and grep for secrets, e.g. `grep -o '"password":"[^"]*"'`.
**How found:** Code review of the Twig sandbox allow-list in security.yaml and the Twig.php render variable injection, spotting that Config::toArray() was permitted and the full config object was passed into sandboxed renders.
**Exploitation:** An authenticated editor with only admin.pages saves a page with process.twig:true and the payload {{ config.toArray()|json_encode|raw }}; on render the merged config tree (including user/config/plugins/*.yaml secrets) is emitted as JSON in the HTML, which the attacker reads to harvest SMTP passwords, AWS keys, OAuth secrets and API tokens.
**Escalation:** Each extracted credential independently compromises the connected external service (SMTP, AWS, OAuth providers), extending impact beyond the CMS.
**Insight:** When auditing Twig/sandbox allow-lists, check for getter methods like toArray()/all() on config or container objects that are injected into render scope — a single permitted method can dump the entire merged config including plugin secrets.

## Proof of concept (copied exactly from the original report)

**Twig payload dumping full config as JSON**

```
{{ config.toArray()|json_encode|raw }}
```

