
CVE-2026-75827 के लिए प्रूफ-ऑफ-कॉन्सेप्ट और लैब, जो Blueprint dynamic-data error_log के माध्यम से Grav में मनमानी फ़ाइल लेखन की कमज़ोरी है, जिसमें पुनरुत्पादन स्क्रिप्ट और Docker लैब शामिल है।
abraxaslabs.tech · github.com/abraxas · @abraxas_null · CVE-2026-75827
grav 2.0.13 — getgrav
Grav 2.0.15 से पहले के संस्करणों में Blueprint dynamic-data bare-function validation में एक arbitrary file write vulnerability मौजूद है, जो सकारात्मक allowlist के बजाय एक अपूर्ण denylist का उपयोग करता है। page-edit या blueprint-config एक्सेस रखने वाले हमलावर data directive के माध्यम से error_log function को invoke कर सकते हैं ताकि web-accessible फ़ाइलों में PHP payloads जोड़ सकें, जिससे remote code execution प्राप्त होता है।
| CVE | CVE-2026-75827 · CVE.org |
| CWE | CWE-94 |
| CVSS | High: 8.8 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Product | grav |
| Affected | 2.0.13 तक के सभी संस्करण (सम्मिलित) |
| Patched | 2.0.15 और बाद के संस्करण |
| Auth | कोई नहीं (source map देखें) |
| Lab | केवल 127.0.0.1 · vendor/client disclosure pack, स्कैनर नहीं |
Arbitrary file write, form blueprint में data-options@ के माध्यम से error_log है, upload action= नहीं। HTTP GET /poc-form है, फिर GET /poc-witness.txt।
GET/poc-formLab seed: admin user + Form plugin + page 03.poc-form with data-options@: error_logGET /poc-form → Form::getBlueprint() → Blueprint::dynamicData → isSafeDynamicCall('error_log') true → error_log(witness, 3, poc-witness.txt)GET /poc-witness.txt → POCWitness75827GET /poc-witness.txt body में POCWitness75827 होना चाहिए। Home HTML या खाली 404 file-write witness नहीं है।
पहले यह करें: grav को 2.0.15 या नए संस्करण में अपडेट करें।
अपग्रेड के बाद सत्यापित करें
CVE-2026-75827-Abraxas-Labs.py दोबारा चलाएँ: mapped witness नहीं दिखना चाहिए।यदि आप तुरंत अपडेट नहीं कर सकते
लक्ष्य केवल http://127.0.0.1:8088 (या जो loopback आपने bind किया है)। इस स्क्रिप्ट को इंटरनेट की ओर निर्देशित न करें।
python3 CVE-2026-75827-Abraxas-Labs.py
सफलता response body में ऊपर दिया गया witness है। Generic 200 HTML नहीं।
Reproduce करने के लिए उपयोग किया गया loopback stack। Official images, जब तक इस फ़ोल्डर में Dockerfile source से build न करे।
cd lab
docker compose up --force-recreate
यदि YAML कोई local directory mount करता है (version table से plugin zip / source tag) तो vulnerable product tree को Compose के बगल में bind करें। 127.0.0.1 के अलावा कुछ publish न करें।
# CVE-2026-75827 (structured records)
- input: `https://nvd.nist.gov/vuln/detail/CVE-2026-75827`
- CWE: CWE-94
- published: 2026-08-18T12:19:32.553
## NVD description
Grav before 2.0.15 contains an arbitrary file write vulnerability in the Blueprint dynamic-data bare-function validation that uses an incomplete denylist instead of a positive allowlist. Attackers with page-edit or blueprint-config access can invoke the error_log function through a data directive to append PHP payloads to web-accessible files, achieving remote code execution.
## MITRE description
Grav before 2.0.15 contains an arbitrary file write vulnerability in the Blueprint dynamic-data bare-function validation that uses an incomplete denylist instead of a positive allowlist. Attackers with page-edit or blueprint-config access can invoke the error_log function through a data directive to append PHP payloads to web-accessible files, achieving remote code execution.
## Affected
- getgrav grav 0 affected, 2.0.15 unaffected
- OSV:
## References (JSON sources only)
- https://github.com/getgrav/grav/security/advisories/GHSA-f8wv-xp27-6gq7
- https://www.vulncheck.com/advisories/grav-before-arbitrary-file-write-via-error-log
- https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/75xxx/CVE-2026-75827.json
- https://nvd.nist.gov/vuln/detail/CVE-2026-75827
- https://github.com/advisories/GHSA-f8wv-xp27-6gq7
## GitHub advisory
Grav: Blueprint dynamic-data bare-function branch is denylist-gated and omits error_log, giving arbitrary file write
## Affected versions and vulnerable location
- Confirmed on grav core at `78ebfc1` (tag 2.0.13).
- Sinks:
- `system/src/Grav/Common/Data/Blueprint.php:455-458` `call_user_func_array($o, $params)` (bare-function dynamic-data provider).
- Twin: `system/src/Grav/Framework/Flex/FlexDirectory.php:936-938` `call_user_func_array($function, $params)`.
- Validation gate: `Blueprint::isSafeDynamicCall()` at `Blueprint.php:514-536`.
- `Class::method` branch (`:514-527`) uses a strict positive allowlist `self::$allowedDynamicCallables`.
- Bare-function branch (`:530-534`) uses only a denylist: `if (is_string($function) && Utils::isDangerousFunction($function)) return false; return !self::paramsContainDangerousCallable($params);`.
- Denylist: `Utils::isDangerousFunction()` (`system/src/Grav/Common/Utils.php`, list around `:2020-2270`).
## Root cause
GHSA-7pgq/CVE-2026-64850 hardened the `Class::method` half of the dynamic-callable validation to a positive allowlist because a page-edit account could otherwise name any static method as a provider and reach file/secret gadgets. The bare-function half was left on a denylist (`isDangerousFunction`). Any bare PHP function not on that list executes.
`error_log` is not on the denylist (verified: no occurrence in `Utils.php`). `error_log($message, 3, $destination)` appends attacker-controlled `$message` to attacker-controlled file `$destination`, an arbitrary-file-append primitive. `paramsContainDangerousCallable()` (`:587-603`) only scans params for dangerous callable strings, so a PHP payload string and a destination path both pass. (`stream_socket_client`, `dl`, and `mb_send_mail` are likewise absent, giving SSRF/other primitives.)
## Attacker model
The same surface the published dynamic-data advisories accept as reachable: a `data-*@` directive in a form blueprint the Form plugin assembles from page frontmatter (GHSA-fj2p), or a `data@` field in a Flex directory/pages/users blueprint (GHSA-c4wf). A page-edit / blueprint-config account, no shell.
## Reachability trace
1. Author a blueprint field with a bare-function data directive, e.g.
`data-options@: ['error_log', '<?php system($_GET[0]); ?>', 3, 'user/data/x.php']`.
2. `Blueprint::init()` resolves the directive; `isSafeDynamicCall('error_log', $params)` reaches the bare-function branch (`:530`), `isDangerousFunction('error_log')` is false, `paramsContainDangerousCallable([...])` is false (no callable strings),
यह pack vendor, site owner, और licensed labs के लिए है। स्क्रिप्ट 127.0.0.1 से बात करती है। जिन सिस्टम्स के आप मालिक नहीं हैं उनके विरुद्ध इसका उपयोग Abraxas Labs द्वारा अधिकृत नहीं है। कोई वारंटी नहीं।