1785154351
%255B625b700dd45b3c21ba7267cb7c50ca69%255D%255B1%255D
s:36295:"{"version":"2.0.13","date":"2026-07-25T20:22:57Z","url":"https:\/\/github.com\/getgrav\/grav\/releases\/tag\/2.0.13","min_php":"7.2.3","assets":{"grav-admin":{"name":"grav-admin-v2.0.13.zip","type":"binary\/octet-stream","size":22553088,"download":"https:\/\/getgrav.org\/download\/core\/grav-admin\/2.0.13","content_sha256":"7cad15fcb27b1ff50bc3faa77c1841fd9046c48f50c467407b83131286b0fbda","sha256":"13a6ebc4c82c8603066e0d1b20f77545a0c8784a623c6d3c7ed047ec737504d5"},"grav-update":{"name":"grav-update-v2.0.13.zip","type":"binary\/octet-stream","size":8284259,"download":"https:\/\/getgrav.org\/download\/core\/grav-update\/2.0.13","content_sha256":"1d7fd14f74f53b8c52a74c746341a77c8d28cf906cb6108995748bb83413f235","sha256":"dc10909bf992bd739fafe57f41b176df257e1403583dedc0b456248c6d151cd5"},"grav":{"name":"grav-v2.0.13.zip","type":"binary\/octet-stream","size":10136684,"download":"https:\/\/getgrav.org\/download\/core\/grav\/2.0.13","content_sha256":"29a002138bfd45c365e8973cec5a7743b3ccc87c983a65228a8ecf25b720c0a9","sha256":"c5993530697777e595d793632d68425d2fb795bc5a64da1224b69fb00420d9d0"}},"changelog":{"2.0.13":{"date":"07\/25\/2026","content":"1. [](#new)\n    * Added an `array_group_by` Twig filter and function for grouping a list of items by one of their values ([#4218](https:\/\/github.com\/getgrav\/grav\/pull\/4218)).\n1. [](#bugfix)\n    * [security] A configuration admin can no longer run code on the server by pointing a dynamic field's data provider at a built-in routine named as a class-and-method pair, a form that slipped past the safety check because it only inspected the single-string spelling; both forms are now vetted the same way ([GHSA-r94f-hx44-8jqf](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-r94f-hx44-8jqf)).\n    * [security] A page editor without super-admin rights can no longer store an event-handler script that runs for site visitors by hiding it behind a `>` placed inside a quoted HTML attribute; the content security scan now reads quoted attribute values the same way a browser does ([GHSA-269c-h76q-8cxw](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-269c-h76q-8cxw)).\n    * [security] A backup profile's location is now confined to the site folder, so a profile pointing outside the Grav root can no longer pull external directories into the backup archive ([GHSA-fch7-cpv4-w7hg](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-fch7-cpv4-w7hg)).\n    * [security] Uploaded filenames may no longer contain the HTML characters `<`, `>`, or `\"`, so a stored filename cannot carry markup that could run if it were later shown unescaped.\n    * [security] The `find` and `sort` Twig filters now reject a dangerous function name given as their callback, matching the protection already applied to `map`, `filter`, and `reduce`, so template values cannot use them to run code ([GHSA-xx48-97m4-h7qm](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-xx48-97m4-h7qm)).\n    * The bundled `nginx.conf` security rules are now anchored to the start of the path like the `.htaccess` rules already are, so the admin's Tools \u2192 Logs viewer works on nginx instead of being blocked ([#4223](https:\/\/github.com\/getgrav\/grav\/pull\/4223)).\n    * On non-FastCGI setups Grav no longer sends an invalid `Content-Encoding: none` header, which some strict HTTP clients rejected outright; it now closes the connection cleanly without the bogus value ([#2619](https:\/\/github.com\/getgrav\/grav\/issues\/2619)).\n"},"2.0.12":{"date":"07\/20\/2026","content":"1. [](#new)\n    * Added per-language fallbacks for unsupported browser languages during `HTTP_ACCEPT_LANGUAGE` negotiation, allowing them to resolve to supported languages without exposing additional language routes.\n1. [](#improved)\n    * The `read_file()` Twig function can now read `.css` files by default, so inline stylesheets can be embedded in a template without adjusting the security config ([#4215](https:\/\/github.com\/getgrav\/grav\/issues\/4215)).\n    * Documented that the site-wide media object resolves lazily, so its inherited collection query methods need `media_directory()` to filter or sort site media ([#4210](https:\/\/github.com\/getgrav\/grav\/issues\/4210)).\n1. [](#bugfix)\n    * Browser language codes are now matched case-insensitively during `HTTP_ACCEPT_LANGUAGE` fallback negotiation.\n"},"2.0.11":{"date":"07\/13\/2026","content":"1. [](#new)\n    * You can now filter, sort, and group a page's media by the values in their `.meta.yaml` metafiles directly in Twig, with new `filterBy`, `where`, `findBy`, `sortBy`, `groupBy`, and `withMeta` methods on `page.media`. Fixes [getgrav\/grav#4200](https:\/\/github.com\/getgrav\/grav\/issues\/4200).\n1. [](#bugfix)\n    * [security] A page editor can no longer read arbitrary files from the server by pointing an image watermark at a traversal path such as `carrier.png?watermark=..\/secret.png`; an editor-supplied watermark path is now confined to the site's media, while operator-configured watermarks and stream URIs are unaffected ([GHSA-w3f4-8pj2-599w](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-w3f4-8pj2-599w)).\n    * [security] A page-edit account can no longer reach file-disclosure or secret-read functions by naming an arbitrary `Class::method` as a dynamic field's data provider; qualified providers are now limited to a known-safe allowlist, closing a bypass of the guard added in 2.0.7 and 2.0.9 ([GHSA-7pgq-cr25-xvc8](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-7pgq-cr25-xvc8), [GHSA-cxv3-5jj3-cpgr](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-cxv3-5jj3-cpgr)).\n    * A page is no longer blanked when viewed just because a trusted plugin or shortcode on it outputs markup the content security scan flags, such as an embed, form, or icon; the check that guards against dangerous editor content now runs once when the page is saved rather than every time it is rendered ([GHSA-2c4f-86xc-cr74](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-2c4f-86xc-cr74)).\n1. [](#improved)\n    * [security] Page content that uses Twig to assemble disallowed markup at render time, such as building an event handler or a `<script>` tag from separate pieces, is now refused when you save the page instead of being allowed through to visitors.\n    * The `raw` Twig filter is no longer allowed inside editor-authored page content, so page content can no longer output unescaped dynamic values past the content security check; trusted theme templates are unaffected.\n"},"2.0.10":{"date":"07\/09\/2026","content":"1. [](#bugfix)\n    * A partial `system.pages.process` override in `user\/config\/system.yaml` (for example setting only `twig: false`) no longer silently turns off Markdown and leaves every page rendering its raw source. Because `pages.process` is a single field in the blueprint, a partial override replaced the whole map and dropped the default `markdown: true`; core now re-applies that default, so an affected site recovers on update with no change to its config. An explicit `markdown: false` is still honored.\n"},"2.0.9":{"date":"07\/09\/2026","content":"1. [](#bugfix)\n    * [security] A callable directive hidden in a Flex directory's blueprint field can no longer run commands on the server; dynamic field data on Flex types (Flex Pages, Flex Users, Flex Objects) now refuses dangerous functions, closing a path that bypassed the same guard added for page forms in 2.0.7 ([GHSA-c4wf-2xxc-68qm](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-c4wf-2xxc-68qm)).\n    * [security] The scheduler webhook trigger now fails closed when no token is configured, so an enabled webhook left without a token can no longer run scheduled jobs for anonymous callers ([GHSA-xwv3-2mv2-w33x](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-xwv3-2mv2-w33x)).\n    * Images and links whose filename contains spaces now render when the path is wrapped in angle brackets, for example `![](<My image.jpg>)`. Fixes [getgrav\/grav#4197](https:\/\/github.com\/getgrav\/grav\/issues\/4197).\n"},"2.0.8":{"date":"07\/06\/2026","content":"1. [](#bugfix)\n    * An email or `www.` URL used as the visible text of a Markdown link is no longer turned into a second, nested link when GFM autolinks are enabled. Fixes [getgrav\/grav#4191](https:\/\/github.com\/getgrav\/grav\/issues\/4191).\n    * `md5()` can once again be called as a Twig function, not just as the `|md5` filter, so themes and plugins that generate an id or cache-busting hash with `md5(...)` keep working instead of failing with an \"Unknown function\" error. Fixes [getgrav\/grav-theme-quark2#12](https:\/\/github.com\/getgrav\/grav-theme-quark2\/issues\/12).\n    * Replacing an image in place, such as swapping the image in a Flex object field, now shows the new image on the site instead of the previously cached version (updated `getgrav\/image` to v4.1.3, which includes the source file's modification time and size in the derivative cache key). Fixes [getgrav\/grav#4195](https:\/\/github.com\/getgrav\/grav\/issues\/4195).\n"},"2.0.7":{"date":"07\/04\/2026","content":"1. [](#bugfix)\n    * [security] A page editor can no longer run commands on the server by hiding a callable directive in a form field's settings; dynamic field data now refuses dangerous functions and cannot be tricked into reaching one through a helper ([GHSA-fj2p-qj2f-74v5](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-fj2p-qj2f-74v5)).\n    * A page's `translatedLanguages()` now localizes ancestor slugs too, so a nested translation whose parent folder has a localized `slug:` produces the fully translated cross-language link instead of leaving parent segments in the current language. Fixes [getgrav\/grav#4186](https:\/\/github.com\/getgrav\/grav\/issues\/4186).\n    * Pointing the log stream at `environment:\/\/` (for example `log: environment:\/\/logs`) no longer crashes the site or `bin\/grav clear` with a \"stream must either be a resource or a string\" error when the per-environment folder does not exist; logging now falls back to the default `logs\/` folder instead. Fixes [getgrav\/grav#4172](https:\/\/github.com\/getgrav\/grav\/issues\/4172).\n    * The `media:\/\/` stream now checks the per-environment `user\/env\/<host>\/media\/` folder before the shared `user\/media\/`, so site media stored per environment resolves to the correct URL in the admin and in page content instead of a broken `user\/media\/` link. Fixes [getgrav\/grav#4188](https:\/\/github.com\/getgrav\/grav\/issues\/4188).\n    * Large file downloads such as site backups are now streamed to the browser in chunks instead of being loaded into memory all at once, so a download bigger than PHP's memory limit no longer fails with a blank server error. Fixes [getgrav\/grav-plugin-api#12](https:\/\/github.com\/getgrav\/grav-plugin-api\/issues\/12).\n    * Backups initialization no longer runs twice when something that bypasses the normal request middleware (such as the API plugin) also attaches the backup scheduler listener, so the listener is registered only once.\n    * Pages accessed with URL parameters such as pagination or taxonomy filters no longer recompile every Twig template on each request, restoring full template caching on exactly the pages that get the most traffic.\n    * The per-file compiled cache for YAML and markdown files now loads through its intended opcache fast path, and a source file that has been deleted no longer serves stale cached data.\n    * A modular page that outputs trusted theme or plugin markup, such as a form with a reCAPTCHA field, is no longer wrongly blanked by the content security scan, which now checks the editor's own content instead of the finished template output. Fixes [getgrav\/grav-plugin-form#636](https:\/\/github.com\/getgrav\/grav-plugin-form\/issues\/636).\n    * Chaining media actions on page media under the content security scan, such as `{{ page.media['x.jpg'].lightbox(1024,768).cropResize(176,176).html() }}`, now works instead of being blocked, and the scan's list of allowed media methods stays in step with Grav's documented media actions automatically.\n1. [](#improved)\n    * Updating a plugin or theme whose required dependency is held back by a newer Grav or PHP requirement now explains the real fix. Instead of reporting that the needed version is \"higher than the latest release\" and suggesting a cache refresh, the updater names the newer dependency release and the Grav (or PHP) version it needs, so you know to update Grav first. Relates to [getgrav\/grav-plugin-admin2#93](https:\/\/github.com\/getgrav\/grav-plugin-admin2\/issues\/93).\n    * Backup profiles now always appear in the scheduler where each can be switched on or off with the Enabled\/Disabled toggle, instead of a profile staying hidden until its schedule was turned on; the profile's schedule setting seeds the default state and an explicit toggle takes precedence.\n    * Frontend requests are noticeably faster across the board: the scheduler, backups machinery, error page renderer and logger now initialize only when actually used instead of on every page view, cutting over 50 PHP files from a typical request.\n    * The filesystem scan that checks pages for changes now reuses its result for a couple of seconds (configurable with `cache.check.interval`), so busy sites no longer stat every page file on every single request; content edits still show up right away in normal editing workflows and admin saves remain instant.\n    * Configuration, blueprint and language file lists honor the same freshness window instead of checking every tracked file's timestamp three times per request, and theme blueprints no longer load at all on normal frontend page views.\n    * Class autoloading is faster: source installs get an optimized class map, APCu is suggested so the existing autoloader cache setting can engage, and plugin autoloaders no longer sit in front of the core one where every core class lookup had to pass through them first.\n    * Rendering a page with cached content no longer loads its whole media collection up front, the pages index no longer stores pre-computed metadata for every page, and relative markdown links resolve their target page directly instead of building the full page list per link.\n    * Assorted hot-path trims: string helpers use fast native functions for the common case, asset rendering skips per-asset integrity work when the feature is off, the site root URL is computed once per request instead of per asset, and debugger timers cost nothing when the debugger is disabled.\n    * New experimental opt-in page index (`pages.lazy_index: true`): pages, routes, children lists, sort orders and the taxonomy map load on demand from a per-page index instead of one large cache blob that has to be fully unserialized on every request, making per-request cost flat as sites grow: a 2,000 page test site renders as fast as a 2 page one and uses a quarter of the memory; SQLite powers the index when available with a pure PHP fallback, and the default behavior is completely unchanged until the flag is enabled.\n    * Page collection filters (`visible`, `routable`, `published`, module) now use menu flags recorded in the page index, so building a navigation menu that filters a folder to its visible pages no longer loads every hidden sibling first. On a 500 post blog under the Quark theme this cut the pages built for a page view from all 507 to 7 and roughly halved memory; it helps every site, most of all large ones with the experimental page index enabled.\n    * Sorting a page collection by date, title, or another common field now reads that value from the page index instead of loading every page in the collection just to read one field, and on single language sites the automatic translated filter that every collection applies no longer loads any pages at all. With the experimental page index enabled, a blog post showing a related posts grid dropped from loading every post on the site to only the handful it displays.\n    * The setting that scans page content for XSS moved to `security.content.xss_scan_output`, since it applies to all page content rather than only Twig in content; the previous `security.twig_content.xss_scan_output` location keeps working and is moved to the new one automatically on upgrade.\n"},"2.0.6":{"date":"06\/30\/2026","content":"1. [](#bugfix)\n    * [security] Flex user avatars stored under `user\/accounts\/<username>\/` (folder storage) are now served too; the 2.0.5 avatar carve-out only covered the flatfile `user\/accounts\/avatars\/` layout, so folder-storage avatars kept returning a 403. Existing sites self-heal on upgrade. Fixes [getgrav\/grav#4185](https:\/\/github.com\/getgrav\/grav\/issues\/4185).\n"},"2.0.5":{"date":"06\/30\/2026","content":"1. [](#bugfix)\n    * A page's `translatedLanguages()` now returns each language's own route, so a translation with a localized `slug:` produces the correct cross-language link instead of repeating the default language's URL. Fixes [getgrav\/grav#4183](https:\/\/github.com\/getgrav\/grav\/issues\/4183).\n    * [security] Profile avatars display again instead of returning a 403; the folder hardening that locked down `user\/accounts` now makes a narrow exception for avatar images while account data such as password hashes stays blocked, and existing sites self-heal on upgrade. Fixes [getgrav\/grav#4185](https:\/\/github.com\/getgrav\/grav\/issues\/4185).\n    * Loading a page no longer fails with a \"Failed to write cache file\" error when Grav can't save the compiled template cache, such as on a shared folder, a full disk, or during a save-then-reload race; the page still renders and the problem is logged instead. Fixes [getgrav\/grav#4184](https:\/\/github.com\/getgrav\/grav\/issues\/4184).\n"},"2.0.4":{"date":"06\/29\/2026","content":"1. [](#new)\n    * Plugins can now register trusted iframe hosts so legitimate provider embeds (such as YouTube) are no longer blanked by the content XSS scan on hardened sites.\n    * Added an `onXssTrustedMarkup` event that lets a plugin exempt its own rendered markup from the content XSS scan without weakening it for editor-authored content.\n1. [](#bugfix)\n    * [security] Grav's `.htaccess` rules blocking sensitive folders and files are now matched case-insensitively, closing a bypass where, on case-insensitive filesystems (Windows, macOS, some Docker mounts), a differently-cased request could reach files such as account and config YAML; existing sites are healed on upgrade ([GHSA-vwg3-w8w3-pc79](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-vwg3-w8w3-pc79)).\n    * [security] The `user\/data` folder now ships a media-aware allowlist that serves uploaded assets such as images, fonts, CSS and JS while keeping data files like YAML and JSON blocked, and upgrading widens an over-narrow allowlist from earlier security updates in place so legitimate theme assets stop returning 403. Fixes [getgrav\/grav#4169](https:\/\/github.com\/getgrav\/grav\/issues\/4169).\n    * [security] The Twig `regex_replace` filter now returns its input unchanged instead of null when a pattern hits a PCRE error such as a backtrack-limit, so a catastrophic pattern can no longer break output ([GHSA-37f3-6p89-6qr9](https:\/\/github.com\/getgrav\/grav\/security\/advisories\/GHSA-37f3-6p89-6qr9)).\n    * `bin\/gpm self-upgrade` no longer fails on shared-folder setups such as a VirtualBox shared folder, where the `bin` directory holding the running script could not be deleted, by overwriting the upgrade files in place instead. Fixes [getgrav\/grav#4171](https:\/\/github.com\/getgrav\/grav\/issues\/4171).\n    * Debug messages logged during API requests now reach the Admin2 API debug panel and Clockwork even when the debugger is set to PHP DebugBar, which can only display on normal pages. Fixes [getgrav\/grav-plugin-admin2#76](https:\/\/github.com\/getgrav\/grav-plugin-admin2\/issues\/76).\n    * Resizing an image larger than its original size with `?resize=` no longer pads it onto an oversized canvas with a white border, returning the image at its natural size instead unless `?forceresize` is used. Fixes [getgrav\/grav#4173](https:\/\/github.com\/getgrav\/grav\/issues\/4173).\n    * Turning off the Twig sandbox no longer breaks pages or modules that contain a form, which previously failed with a \"SandboxExtension extension is not enabled\" error. Fixes [getgrav\/grav#4175](https:\/\/github.com\/getgrav\/grav\/issues\/4175).\n    * A blueprint validation error now names the value it rejected, so a message like \"Invalid input in Process\" explains what actually caused it instead of leaving you guessing. Relates to [getgrav\/grav#4178](https:\/\/github.com\/getgrav\/grav\/issues\/4178).\n    * Adding a blocked item to the Twig sandbox allowlist from the Tools report now clears that block from the recent-blocks list, so a resolved entry no longer lingers as if nothing happened. Fixes [getgrav\/grav-plugin-admin2#85](https:\/\/github.com\/getgrav\/grav-plugin-admin2\/issues\/85).\n"},"2.0.3":{"date":"06\/25\/2026","content":"1. [](#new)\n    * Added an optional `system.session.read_and_close` setting that releases the session as soon as it has been read, so a site's simultaneous requests no longer queue up one behind another waiting on the session; off by default.\n1. [](#bugfix)\n    * A `bin\/gpm self-upgrade` that stops while replacing core files now names the exact file or folder it could not remove and the reason why, and points out when the file is owned by a different user than the one running the command, which is the usual cause of an upgrade that works from the admin but fails on the command line. Fixes [getgrav\/grav#4162](https:\/\/github.com\/getgrav\/grav\/issues\/4162).\n"},"2.0.2":{"date":"06\/24\/2026","content":"1. [](#bugfix)\n    * [security] ZIP extraction in both Direct Install and the internal archiver now enforces the uncompressed-size limit against the bytes actually written, rather than the size each entry claims, so an archive that understates its real size can no longer slip a decompression bomb past the limit (GHSA-8h9x-89f2-m7x3).\n    * [security] Editor-authored Twig in page content can no longer read configuration secrets by dumping the config object through a filter such as `print_r` or `json_encode`, closing a sandbox bypass that exposed plugin credentials and API keys (GHSA-mc5q-6hpj-rp7j).\n    * A failed `bin\/gpm self-upgrade` now reports the specific reason it stopped and records the full details in `logs\/grav.log`, instead of showing a generic \"Unknown error\" with nothing to act on. Fixes [getgrav\/grav#4158](https:\/\/github.com\/getgrav\/grav\/issues\/4158).\n    * A page that displays inline SVG or MathML icons, such as the svg-icon shortcode or GitHub-style alert callouts, no longer renders blank when page-content Twig processing is enabled, because the render-time security scan now skips that legitimate icon markup while still catching injected scripts around it.\n"},"2.0.1":{"date":"06\/23\/2026","content":"1. [](#bugfix)\n    * [security] ZIP archives extracted through the internal ZipArchiver are now rejected when their contents exceed safe limits on total uncompressed size, file count, or folder nesting depth, closing a second extraction path with the same decompression-bomb risk that was fixed for Direct Install (GHSA-928x-9mpw-8h56).\n    * [security] Editor-authored Twig in page content now has its rendered output re-checked for XSS, closing a bypass where a payload assembled at render time (such as `{{ \"on\" ~ \"error\" }}`) passed the source validator and then emitted live markup (GHSA-2c4f-86xc-cr74).\n    * A page marked Visible in the admin no longer vanishes from navigation after saving, because a blank visibility setting now falls back to its normal default instead of being read as hidden. Fixes [getgrav\/grav#4153](https:\/\/github.com\/getgrav\/grav\/issues\/4153).\n"},"2.0.0":{"date":"06\/20\/2026","content":"1. [](#new)\n    * Grav Version 2.0 stable is released - read all about it here: https:\/\/getgrav.org\/blog\/grav-2-stable-released\n1. [](#bugfix)\n    * [security] Install packages uploaded through Direct Install are now rejected when their contents exceed safe limits on total uncompressed size, file count, or folder nesting depth, so a crafted archive can no longer fill the disk, exhaust inodes, or crash extraction (GHSA-2vcx-h8p2-9pg9).\n"},"2.0.0-rc.10":{"date":"06\/18\/2026","content":"1. [](#bugfix)\n    * [security] Image `resize` in page content (for example `![logo](img.png?resize=...)`) now only accepts numeric dimensions, closing a stored CSS injection where a crafted resize value could write extra style declarations, such as a full-page overlay, into the image for a higher-privileged viewer (CWE-79). Media actions in an image URL are now limited to the documented set, so page content can no longer reach other internal methods on a media object, and inline styles are validated again when the image is rendered. Thanks to @DavidCarliez for the report.\n    * Twig in page content that puts an output tag inside an `if` block, such as `{% if x %}{{ y }}{% endif %}`, no longer fails with an \"Unknown endif tag\" error when Markdown runs first. Fixes [getgrav\/grav#4126](https:\/\/github.com\/getgrav\/grav\/issues\/4126).\n    * Twig in the content of a modular page's modules, such as a `{% include %}` tag, is now processed the same way it is in a regular page instead of being left as literal text. Fixes [getgrav\/grav#4142](https:\/\/github.com\/getgrav\/grav\/issues\/4142).\n    * Hyphenized anchors and slugs now keep accented and other Unicode letters such as `\u00e4`, `\u00f6` and `\u00fc` instead of mangling them, so on-page menu links to modules with those characters point to the right place. Thanks to @Xoriander. [getgrav\/grav#4143](https:\/\/github.com\/getgrav\/grav\/pull\/4143)\n"},"2.0.0-rc.9":{"date":"06\/16\/2026","content":"1. [](#new)\n    * Added a `GRAV_ENV_PATH` environment variable that loads the `.env` file(s) from a directory or file path outside the web root, so secrets such as API keys no longer have to live in the publicly served document root.\n    * Added an `onFlexObjectMedia` event so a plugin can rewrite a flex object's media links, letting the original files be served through a controlled route while resized or cropped versions still load straight from the image cache.\n2. [](#bugfix)\n    * [security] Inline styles set on an image from page content (for example `![logo](img.png?style=...)`) are now limited to safe layout CSS, so an editor can no longer store a full-page overlay or a `url()` callout that would target an administrator viewing the page (CWE-79). Thanks to @CyberKareem for the report.\n    * [security] Direct web access to the `user\/accounts`, `user\/config`, `user\/data` and `user\/env` folders is now blocked in every bundled webserver config, closing a hole where files such as certificates, tokens and databases stored under `user\/data` with an unlisted extension could be downloaded directly.\n    * [security] A backup deny-all `.htaccess` now ships inside `user\/accounts`, `user\/config` and `user\/data` so Apache installs stay protected even when the site root `.htaccess` has been customised or is out of date.\n    * [security] The upgrade postflight now patches an existing stock root `.htaccess` to add the folder block automatically, so installs that updated from an earlier version are protected without editing the file by hand.\n    * The new `user\/data` block now makes an exception for public media uploads, such as Flex Object images, so they keep displaying instead of returning a 403, while data files, databases and keys stay blocked. Fixes [getgrav\/grav#4129](https:\/\/github.com\/getgrav\/grav\/issues\/4129).\n    * [security] The Twig filesystem helpers such as `read_file` and `file_exists` now reject `..\/` path traversal and null bytes in their argument, an extra safeguard on top of the sandbox that already keeps these functions out of editor-authored page content.\n"},"1.7.53":{"date":"06\/16\/2026","content":"1. [](#bugfix)\n    * [security] Direct web access to the `user\/accounts`, `user\/config`, `user\/data` and `user\/env` folders is now blocked outright in every bundled webserver config, closing a hole where files such as certificates, tokens and databases stored under `user\/data` with an unlisted extension could be downloaded directly.\n    * [security] A backup deny-all `.htaccess` now ships inside `user\/accounts`, `user\/config` and `user\/data` so Apache installs stay protected even when the site root `.htaccess` has been customised or is out of date.\n    * [security] The upgrade postflight now patches an existing stock root `.htaccess` to add the folder block automatically, so installs that updated from an earlier version are protected without editing the file by hand.\n    * [security] URL query image transforms (such as `image.jpg?resize=`) are now turned off by default and, when enabled, refuse oversized dimensions above a configurable pixel limit, closing an unauthenticated denial of service where huge resize values could exhaust server memory.\n"},"2.0.0-rc.8":{"date":"06\/09\/2026","content":"1. [](#improved)\n    * Page Authors in a page's Security settings is now picked from a searchable list of the users who can edit pages, instead of typed-in usernames.\n2. [](#bugfix)\n    * [security] URL-based image resizing (e.g. `image.jpg?resize=2000,2000`) is now off by default and, when enabled, capped by a configurable total-pixel limit, so an unauthenticated visitor can no longer exhaust server memory by requesting oversized image transforms (CWE-400). Thanks to @iliaal for the report.\n    * [security] With error display off, an uncaught error no longer leaks the file path, line, and exception message to a JSON or AJAX request, which now receives a generic JSON error instead (CWE-209). Thanks to @iliaal for the report.\n    * The default theme is now `quark2` to match the theme bundled with Grav 2.0, so reverting the theme setting in the Admin panel no longer leaves the site pointing at the missing `quark` theme. Fixes [getgrav\/grav#4108](https:\/\/github.com\/getgrav\/grav\/issues\/4108).\n    * A missing theme no longer takes the Admin panel and API down along with the frontend, so the site stays reachable to fix the theme setting.\n    * A Twig template that calls a function or filter which isn't registered in the current context, such as a plugin function referenced in a template while that plugin is inactive in the Admin panel, now renders as empty again instead of failing with an \"Unknown function\" error. This also restores form notification emails whose data template uses an unregistered filter, which were arriving with the raw `{% include %}` tag in the body. Calls to real PHP functions still require an explicit `safe_functions` entry. Fixes [getgrav\/grav#4110](https:\/\/github.com\/getgrav\/grav\/issues\/4110) and [getgrav\/grav#4115](https:\/\/github.com\/getgrav\/grav\/issues\/4115).\n    * Twig in page content can again read media by filename under the security sandbox in deeply modular and nested layouts, so an expression like `{{ page.media['photo.jpg'].url }}` resolves instead of leaking its raw `{{ ... }}` into the output. Fixes [getgrav\/grav#4114](https:\/\/github.com\/getgrav\/grav\/issues\/4114).\n"},"2.0.0-rc.7":{"date":"06\/04\/2026","content":"1. [](#bugfix)\n    * Upgrading Grav core from the Admin panel no longer fails with \"Failed to upgrade Grav core\" because the installer misread the incoming release version and then wrongly flagged every installed plugin as incompatible; command line upgrades were unaffected.\n"},"2.0.0-rc.6":{"date":"06\/04\/2026","content":"1. [](#new)\n    * Added GitHub-style task lists: `- [ ]` and `- [x]` now render as (disabled) checkboxes. Can be turned off under Configuration > System > Markdown.\n    * Added `==highlight==`, `~subscript~`, and `^superscript^` inline syntax, rendering as `<mark>`, `<sub>`, and `<sup>`. Can be turned off under Markdown settings.\n    * Disallowed raw HTML tags in page content (`script`, `iframe`, `style`, `textarea`, and similar) are now escaped in the output to match GitHub Flavored Markdown. Can be turned off under Markdown settings.\n    * Bare `www.` URLs and email addresses in content are now turned into links automatically (GitHub Flavored Markdown autolinks). Can be turned off under Markdown settings.\n    * Tables gained five optional extensions, all off by default and toggled under Markdown settings: an empty cell can merge into the cell on its left (colspan), a table can start at the divider row with no header row (header-less), a `[Caption]` line immediately after a table becomes a caption, a `{.class #id}` line immediately after a table sets the class and id on the table element (the kramdown `{:.class}` form is accepted too), and a row ending in a backslash continues onto the next line so a cell can span multiple lines.\n    * Plugins can now add custom markdown block and inline syntax through a documented extension API with an element builder, instead of injecting closures and hand-building element arrays. The previous approach still works.\n    * Plugins can now register their own safe Twig functions for use inside sandboxed page content, so a plugin's custom functions work in editor-authored Twig without turning the security sandbox off.\n    * Grav now reads environment variables from a `.env` file in the site root natively, so the separate DotEnv plugin is no longer needed; `.env.local` and per-environment files such as `.env.production` are layered on top in that order, and real server-set variables always take precedence. Use it to set things like `GRAV_ENVIRONMENT` or any `GRAV_CONFIG__*` override.\n1. [](#bugfix)\n    * [security] The `ZipArchiver` extraction helper now refuses any archive entry whose path would escape the destination directory, bringing it in line with the Zip Slip guard already on the GPM installer (CWE-22). Thanks to @XananasX7 for the report.\n    * [security] Restricted scheduler job queue deserialization to the `Job` class as defense in depth, on top of the existing HMAC integrity check on queue entries (CWE-502). Thanks to @XananasX7 for the report.\n    * `bin\/grav server` no longer shows the \"PHP webserver requires a router\" message and serves the site correctly when the Symfony local server falls back to PHP's built-in web server (for example on systems without php-fpm). Fixes [getgrav\/grav#4099](https:\/\/github.com\/getgrav\/grav\/issues\/4099).\n    * Markdown Extra no longer triggers an \"implicitly marking parameter as nullable is deprecated\" notice on PHP 8.4 and newer; the bundled Markdown Extra parser is now a maintained fork with the fix applied.\n    * Fenced code blocks with a trailing attribute block (for example ` ```python {#id .class} `) now apply the id and classes to the code element instead of corrupting the language class. Requires Markdown Extra to be enabled.\n    * Twig in modular and editor page content can read page media again while the security sandbox is enabled, so expressions like `{{ page.media['photo.jpg'].url }}` work without disabling the sandbox. Fixes [getgrav\/grav#4105](https:\/\/github.com\/getgrav\/grav\/issues\/4105).\n    * [security] Removed the `undefined_functions` and `undefined_filters` Twig settings, which let any non-blocklisted PHP function be called from a template by default (deprecated since Grav 1.7). The `safe_functions` and `safe_filters` allow-lists remain as an explicit opt-in, empty by default, and now refuse command and code-execution functions outright so they can no longer be used to enable `system`, `exec`, and similar. Templates that called PHP functions directly will need those functions added to the allow-list, or registered through a plugin.\n    * Requests sending an empty or malformed `Accept` header no longer trigger a \"header string should not be empty\" error during page content-type negotiation.\n"}}}
";