<?xml version="1.0" encoding="UTF-8"?><rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>GitHub Advisory Database RSS - composer - reviewed</title><link>https://github.com/advisories</link><atom:link href="http://rss.144-124-237-35.sslip.io/github/advisor/data/reviewed/composer" rel="self" type="application/rss+xml"></atom:link><description>GitHub Advisory Database RSS - composer - reviewed - Powered by AtomRSS</description><generator>AtomRSS</generator><webMaster>contact@atomgroup.dev (AtomRSS)</webMaster><language>en</language><lastBuildDate>Sun, 09 Aug 2026 19:14:58 GMT</lastBuildDate><ttl>5</ttl><item><title>CodeIgniter: Uploaded file extension validation bypass in `is_image` and `mime_in` rules</title><description>&lt;h3&gt;Impact&lt;/h3&gt;
&lt;p&gt;This is an unsafe file upload validation vulnerability that can lead to remote code execution in vulnerable application configurations.&lt;/p&gt;
&lt;p&gt;Applications are impacted when they:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;validate uploads using &lt;code class=&quot;notranslate&quot;&gt;is_image&lt;/code&gt; or &lt;code class=&quot;notranslate&quot;&gt;mime_in&lt;/code&gt; without an independent safe extension check, such as &lt;code class=&quot;notranslate&quot;&gt;ext_in&lt;/code&gt; on patched versions&lt;/li&gt;
&lt;li&gt;save uploaded files using the client-supplied filename&lt;/li&gt;
&lt;li&gt;place uploads in a web-accessible directory where PHP files can execute&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Patches&lt;/h3&gt;
&lt;p&gt;Upgrade to v4.7.4 or later.&lt;/p&gt;
&lt;h3&gt;Workarounds&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Save uploads outside the public web root, preferably under &lt;code class=&quot;notranslate&quot;&gt;writable/uploads&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;code class=&quot;notranslate&quot;&gt;$file-&amp;gt;store()&lt;/code&gt; or &lt;code class=&quot;notranslate&quot;&gt;$file-&amp;gt;move($path, $file-&amp;gt;getRandomName())&lt;/code&gt; instead of preserving the original client filename.&lt;/li&gt;
&lt;li&gt;Disable script execution in any public upload directory.&lt;/li&gt;
&lt;li&gt;Manually verify the client filename extension before moving the file.&lt;/li&gt;
&lt;li&gt;For image uploads, reject files when &lt;code class=&quot;notranslate&quot;&gt;$file-&amp;gt;getClientExtension()&lt;/code&gt; is not an allowed image extension.&lt;/li&gt;
&lt;li&gt;For exact MIME-type validation, reject files when &lt;code class=&quot;notranslate&quot;&gt;$file-&amp;gt;getClientExtension()&lt;/code&gt; does not match &lt;code class=&quot;notranslate&quot;&gt;$file-&amp;gt;guessExtension()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-mmj4-63m4-r6h5&quot; href=&quot;https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-mmj4-63m4-r6h5&quot;&gt;GHSA-mmj4-63m4-r6h5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2026-63223&quot; rel=&quot;nofollow&quot;&gt;https://nvd.nist.gov/vuln/detail/CVE-2026-63223&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/codeigniter4/CodeIgniter4/commit/b6e9a4fa1dca2df3d3f261bdf61532df8c6420aa/hovercard&quot; href=&quot;https://github.com/codeigniter4/CodeIgniter4/commit/b6e9a4fa1dca2df3d3f261bdf61532df8c6420aa&quot;&gt;codeigniter4/CodeIgniter4@&lt;tt&gt;b6e9a4f&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/codeigniter4/CodeIgniter4/releases/tag/v4.7.4&quot;&gt;https://github.com/codeigniter4/CodeIgniter4/releases/tag/v4.7.4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-mmj4-63m4-r6h5</link><guid isPermaLink="false">https://github.com/advisories/GHSA-mmj4-63m4-r6h5</guid><pubDate>Fri, 07 Aug 2026 18:24:21 GMT</pubDate></item><item><title>CodeIgniter: Path traversal in UploadedFile::move() when using client-provided filenames</title><description>&lt;h3&gt;Impact&lt;/h3&gt;
&lt;p&gt;In affected versions, calling &lt;code class=&quot;notranslate&quot;&gt;UploadedFile::move()&lt;/code&gt; &lt;strong&gt;without a second argument&lt;/strong&gt; uses the client-provided filename without sanitization. Depending on the destination path and server configuration, an attacker can supply a filename containing path traversal sequences (e.g. &lt;code class=&quot;notranslate&quot;&gt;../../public/shell.php&lt;/code&gt;) to write uploaded content outside the intended upload directory.&lt;/p&gt;
&lt;p&gt;The patch sanitizes this default (no-argument) path.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The patch only sanitizes the filename when no second argument is passed. If your application &lt;strong&gt;explicitly&lt;/strong&gt; passes a client-provided name as the second argument, you remain responsible for sanitizing it - the patch does not (and cannot) sanitize a caller-supplied filename:&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-php&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// Unsafe - even after upgrading:&lt;/span&gt;
&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;file&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pl-en&quot;&gt;move&lt;/span&gt;(&lt;span class=&quot;pl-c1&quot;&gt;WRITEPATH&lt;/span&gt; . &lt;span class=&quot;pl-s&quot;&gt;&#39;&lt;span class=&quot;pl-s&quot;&gt;uploads&lt;/span&gt;&#39;&lt;/span&gt;, &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;file&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pl-en&quot;&gt;getName&lt;/span&gt;());
&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;file&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pl-en&quot;&gt;move&lt;/span&gt;(&lt;span class=&quot;pl-c1&quot;&gt;WRITEPATH&lt;/span&gt; . &lt;span class=&quot;pl-s&quot;&gt;&#39;&lt;span class=&quot;pl-s&quot;&gt;uploads&lt;/span&gt;&#39;&lt;/span&gt;, &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;file&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pl-en&quot;&gt;getClientName&lt;/span&gt;());&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Patches&lt;/h3&gt;
&lt;p&gt;Upgrade to v4.7.4 or later.&lt;/p&gt;
&lt;h3&gt;Workarounds&lt;/h3&gt;
&lt;p&gt;If you cannot upgrade immediately, use a generated filename or sanitize the client filename before passing it to &lt;code class=&quot;notranslate&quot;&gt;move()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Use a generated filename:&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-php&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;file&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pl-en&quot;&gt;move&lt;/span&gt;(&lt;span class=&quot;pl-c1&quot;&gt;WRITEPATH&lt;/span&gt; . &lt;span class=&quot;pl-s&quot;&gt;&#39;&lt;span class=&quot;pl-s&quot;&gt;uploads&lt;/span&gt;&#39;&lt;/span&gt;, &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;file&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pl-en&quot;&gt;getRandomName&lt;/span&gt;());&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or sanitize the client filename before passing it to &lt;code class=&quot;notranslate&quot;&gt;move()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-php&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-en&quot;&gt;helper&lt;/span&gt;(&lt;span class=&quot;pl-s&quot;&gt;&#39;&lt;span class=&quot;pl-s&quot;&gt;security&lt;/span&gt;&#39;&lt;/span&gt;);

&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;name&lt;/span&gt; = &lt;span class=&quot;pl-en&quot;&gt;sanitize_filename&lt;/span&gt;(&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;file&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pl-en&quot;&gt;getClientName&lt;/span&gt;());
&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;file&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pl-en&quot;&gt;move&lt;/span&gt;(&lt;span class=&quot;pl-c1&quot;&gt;WRITEPATH&lt;/span&gt; . &lt;span class=&quot;pl-s&quot;&gt;&#39;&lt;span class=&quot;pl-s&quot;&gt;uploads&lt;/span&gt;&#39;&lt;/span&gt;, &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;name&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-hhmc-q9hp-r662&quot; href=&quot;https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-hhmc-q9hp-r662&quot;&gt;GHSA-hhmc-q9hp-r662&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2026-63222&quot; rel=&quot;nofollow&quot;&gt;https://nvd.nist.gov/vuln/detail/CVE-2026-63222&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/codeigniter4/CodeIgniter4/commit/20ebcf4694d96d3c97fbc3938e360730e4f54618/hovercard&quot; href=&quot;https://github.com/codeigniter4/CodeIgniter4/commit/20ebcf4694d96d3c97fbc3938e360730e4f54618&quot;&gt;codeigniter4/CodeIgniter4@&lt;tt&gt;20ebcf4&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/codeigniter4/CodeIgniter4/releases/tag/v4.7.4&quot;&gt;https://github.com/codeigniter4/CodeIgniter4/releases/tag/v4.7.4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-hhmc-q9hp-r662</link><guid isPermaLink="false">https://github.com/advisories/GHSA-hhmc-q9hp-r662</guid><pubDate>Fri, 07 Aug 2026 18:23:46 GMT</pubDate></item><item><title>CodeIgniter: SQL injection in Query Builder deleteBatch() when used with where() conditions</title><description>&lt;h3&gt;Impact&lt;/h3&gt;
&lt;p&gt;A SQL injection vulnerability exists in the Query Builder&#39;s &lt;code class=&quot;notranslate&quot;&gt;deleteBatch()&lt;/code&gt; method. When &lt;code class=&quot;notranslate&quot;&gt;deleteBatch()&lt;/code&gt; is used together with &lt;code class=&quot;notranslate&quot;&gt;where()&lt;/code&gt; conditions, the bound values from the &lt;code class=&quot;notranslate&quot;&gt;WHERE&lt;/code&gt; clause are substituted directly into the generated SQL &lt;strong&gt;with their escape flag ignored&lt;/strong&gt;, so they are never escaped or quoted. If an application passes user-controlled input to &lt;code class=&quot;notranslate&quot;&gt;where()&lt;/code&gt; before calling &lt;code class=&quot;notranslate&quot;&gt;deleteBatch()&lt;/code&gt;, that input is interpreted as SQL rather than as a value, allowing SQL injection.&lt;/p&gt;
&lt;p&gt;This affects only the &lt;code class=&quot;notranslate&quot;&gt;deleteBatch()&lt;/code&gt; code path. Regular &lt;code class=&quot;notranslate&quot;&gt;delete()&lt;/code&gt; operations escape &lt;code class=&quot;notranslate&quot;&gt;where()&lt;/code&gt; binds correctly.&lt;/p&gt;
&lt;h3&gt;Patches&lt;/h3&gt;
&lt;p&gt;Upgrade to v4.7.4 or later.&lt;/p&gt;
&lt;h3&gt;Workarounds&lt;/h3&gt;
&lt;p&gt;If you cannot upgrade immediately:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Strictly validate and cast values (e.g. numeric IDs) before using them in conditions - though this does not fully protect string conditions.&lt;/li&gt;
&lt;li&gt;Do not pass user-controlled input to &lt;code class=&quot;notranslate&quot;&gt;where()&lt;/code&gt; when using &lt;code class=&quot;notranslate&quot;&gt;deleteBatch()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For user-controlled conditions, use a normal &lt;code class=&quot;notranslate&quot;&gt;delete()&lt;/code&gt; with Query Builder binds instead of &lt;code class=&quot;notranslate&quot;&gt;deleteBatch(&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Where possible, express required matching values through the batch data and &lt;code class=&quot;notranslate&quot;&gt;onConstraint()&lt;/code&gt; rather than as separate user-controlled &lt;code class=&quot;notranslate&quot;&gt;where()&lt;/code&gt; clauses.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-c9w5-rwh3-7pm9&quot; href=&quot;https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-c9w5-rwh3-7pm9&quot;&gt;GHSA-c9w5-rwh3-7pm9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2026-63221&quot; rel=&quot;nofollow&quot;&gt;https://nvd.nist.gov/vuln/detail/CVE-2026-63221&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/codeigniter4/CodeIgniter4/commit/f5e463b9a3e986389ce285963e51a7f1fab6559f/hovercard&quot; href=&quot;https://github.com/codeigniter4/CodeIgniter4/commit/f5e463b9a3e986389ce285963e51a7f1fab6559f&quot;&gt;codeigniter4/CodeIgniter4@&lt;tt&gt;f5e463b&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/codeigniter4/CodeIgniter4/releases/tag/v4.7.4&quot;&gt;https://github.com/codeigniter4/CodeIgniter4/releases/tag/v4.7.4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-c9w5-rwh3-7pm9</link><guid isPermaLink="false">https://github.com/advisories/GHSA-c9w5-rwh3-7pm9</guid><pubDate>Fri, 07 Aug 2026 18:22:59 GMT</pubDate></item><item><title>CodeIgniter: Spoofable forwarded HTTPS headers in IncomingRequest::isSecure()</title><description>&lt;h3&gt;Impact&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;notranslate&quot;&gt;IncomingRequest::isSecure()&lt;/code&gt; trusted the &lt;code class=&quot;notranslate&quot;&gt;X-Forwarded-Proto&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;Front-End-Https&lt;/code&gt; headers from any incoming request. In affected deployments, an attacker could spoof these headers and cause the application to incorrectly treat an HTTP request as secure.&lt;/p&gt;
&lt;p&gt;This may impact applications that rely on &lt;code class=&quot;notranslate&quot;&gt;isSecure()&lt;/code&gt;, &lt;code class=&quot;notranslate&quot;&gt;force_https()&lt;/code&gt;, &lt;code class=&quot;notranslate&quot;&gt;forceGlobalSecureRequests&lt;/code&gt;, or similar logic to enforce HTTPS-only access or make security-sensitive decisions.&lt;/p&gt;
&lt;p&gt;Exploitability depends on deployment configuration. Applications are most exposed if the backend is reachable directly over HTTP, or if a reverse proxy/load balancer forwards client-supplied forwarding headers without stripping or overwriting them.&lt;/p&gt;
&lt;h3&gt;Patches&lt;/h3&gt;
&lt;p&gt;Upgrade to v4.7.4 or later.&lt;/p&gt;
&lt;h3&gt;Workarounds&lt;/h3&gt;
&lt;p&gt;Users who cannot upgrade immediately should enforce HTTP-to-HTTPS redirects outside CodeIgniter, for example with Apache &lt;code class=&quot;notranslate&quot;&gt;.htaccess&lt;/code&gt;/virtual host rules, nginx server blocks, Caddy site config, or load balancer redirect rules.&lt;/p&gt;
&lt;p&gt;Users should also ensure that reverse proxies strip or overwrite client-supplied &lt;code class=&quot;notranslate&quot;&gt;X-Forwarded-Proto&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;Front-End-Https&lt;/code&gt; headers before forwarding requests to the application.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-7wmf-pw8j-mc78&quot; href=&quot;https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-7wmf-pw8j-mc78&quot;&gt;GHSA-7wmf-pw8j-mc78&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2026-63220&quot; rel=&quot;nofollow&quot;&gt;https://nvd.nist.gov/vuln/detail/CVE-2026-63220&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/codeigniter4/CodeIgniter4/commit/ecbf044666bed41d23f07518096d9843fe6c08b0/hovercard&quot; href=&quot;https://github.com/codeigniter4/CodeIgniter4/commit/ecbf044666bed41d23f07518096d9843fe6c08b0&quot;&gt;codeigniter4/CodeIgniter4@&lt;tt&gt;ecbf044&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/codeigniter4/CodeIgniter4/releases/tag/v4.7.4&quot;&gt;https://github.com/codeigniter4/CodeIgniter4/releases/tag/v4.7.4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-7wmf-pw8j-mc78</link><guid isPermaLink="false">https://github.com/advisories/GHSA-7wmf-pw8j-mc78</guid><pubDate>Fri, 07 Aug 2026 18:21:54 GMT</pubDate></item><item><title>API Platform Core: Relation IRIs are not type-checked: a related resource can be denormalised as the wrong resource type (type confusion)</title><description>&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;The API Platform serializer&#39;s &lt;code class=&quot;notranslate&quot;&gt;AbstractItemNormalizer&lt;/code&gt; does not validate the resource type returned when resolving relation IRIs, allowing type confusion where a resource of an unintended type can be silently assigned to a relation property.&lt;/p&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;An attacker who can submit write requests (POST/PUT/PATCH) to an API Platform endpoint with writable relations can supply a relation IRI pointing to a resource of a different type than the relation&#39;s declared class. Because &lt;code class=&quot;notranslate&quot;&gt;getResourceFromIri()&lt;/code&gt; does not pass an &lt;code class=&quot;notranslate&quot;&gt;$operation&lt;/code&gt; to &lt;code class=&quot;notranslate&quot;&gt;IriConverter::getResourceFromIri()&lt;/code&gt;, the &lt;code class=&quot;notranslate&quot;&gt;is_a&lt;/code&gt; type guard at &lt;code class=&quot;notranslate&quot;&gt;IriConverter.php:86&lt;/code&gt; is skipped. For untyped relation properties (legacy &lt;code class=&quot;notranslate&quot;&gt;@var&lt;/code&gt;-only style), the wrong-typed object is silently assigned, corrupting invariants and potentially feeding downstream logic that assumes the declared type (CWE-843). For typed properties (modern PHP 8.x), the substitution is blocked by Symfony&#39;s PropertyAccessor with an &lt;code class=&quot;notranslate&quot;&gt;InvalidTypeException&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Affected versions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;api-platform/core&lt;/code&gt; &lt;code class=&quot;notranslate&quot;&gt;&amp;lt; 4.1.30&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;api-platform/core&lt;/code&gt; &lt;code class=&quot;notranslate&quot;&gt;&amp;gt;= 4.2.0, &amp;lt; 4.2.26&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;api-platform/core&lt;/code&gt; &lt;code class=&quot;notranslate&quot;&gt;&amp;gt;= 4.3.0, &amp;lt; 4.3.12&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Older major series (&lt;code class=&quot;notranslate&quot;&gt;2.x&lt;/code&gt;, &lt;code class=&quot;notranslate&quot;&gt;3.x&lt;/code&gt;) ship the same vulnerable code path and are end-of-life; no fix is planned.&lt;/p&gt;
&lt;h2&gt;Patched versions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;4.1.30&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;4.2.26&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;4.3.12&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fix&lt;/h2&gt;
&lt;p&gt;An &lt;code class=&quot;notranslate&quot;&gt;is_a&lt;/code&gt; guard is added inside &lt;code class=&quot;notranslate&quot;&gt;AbstractItemNormalizer::getResourceFromIri()&lt;/code&gt; (and the equivalent inline call sites on 4.1) so that a mismatched IRI throws &lt;code class=&quot;notranslate&quot;&gt;InvalidArgumentException&lt;/code&gt;, mirroring the operation-aware check the &lt;code class=&quot;notranslate&quot;&gt;IriConverter&lt;/code&gt; already performs when an operation is supplied. This forces a &lt;code class=&quot;notranslate&quot;&gt;400 Bad Request&lt;/code&gt; response for cross-type IRIs instead of a silent assignment.&lt;/p&gt;
&lt;h2&gt;Workarounds&lt;/h2&gt;
&lt;p&gt;Declare a PHP type on every writable relation property (e.g. &lt;code class=&quot;notranslate&quot;&gt;public ?Foo $relation = null;&lt;/code&gt; instead of &lt;code class=&quot;notranslate&quot;&gt;@var Foo $relation&lt;/code&gt;). Symfony&#39;s &lt;code class=&quot;notranslate&quot;&gt;PropertyAccessor&lt;/code&gt; will then reject a mismatched object with &lt;code class=&quot;notranslate&quot;&gt;InvalidTypeException&lt;/code&gt;. This does not cover collections of mixed-type interfaces; upgrading to a patched version is the only complete fix.&lt;/p&gt;
&lt;h2&gt;Proof of concept&lt;/h2&gt;
&lt;p&gt;A functional test posts a &lt;code class=&quot;notranslate&quot;&gt;Bar&lt;/code&gt; IRI to a &lt;code class=&quot;notranslate&quot;&gt;Foo&lt;/code&gt;-declared relation on an untyped property. Without the fix the server responds with &lt;code class=&quot;notranslate&quot;&gt;HTTP 201&lt;/code&gt; and the Bar IRI appears in the response payload. With the fix the server responds with &lt;code class=&quot;notranslate&quot;&gt;HTTP 400&lt;/code&gt; (&lt;code class=&quot;notranslate&quot;&gt;Invalid IRI &quot;/bars/1&quot;&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Full PoC: &lt;code class=&quot;notranslate&quot;&gt;tests/Functional/Security/TypeConfusionRelationIriTest.php&lt;/code&gt; in the patched branches.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;src/Serializer/AbstractItemNormalizer.php&lt;/code&gt; — vulnerable relation IRI load&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;src/Symfony/Routing/IriConverter.php&lt;/code&gt; — conditional &lt;code class=&quot;notranslate&quot;&gt;is_a&lt;/code&gt; guard (operation-aware path)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Credit&lt;/h2&gt;
&lt;p&gt;Reported by &lt;a class=&quot;user-mention notranslate&quot; data-hovercard-type=&quot;user&quot; data-hovercard-url=&quot;/users/alexandre-daubois/hovercard&quot; data-octo-click=&quot;hovercard-link-click&quot; data-octo-dimensions=&quot;link_type:self&quot; href=&quot;https://github.com/alexandre-daubois&quot;&gt;@alexandre-daubois&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-9rjg-x2p2-h68h&quot; href=&quot;https://github.com/api-platform/core/security/advisories/GHSA-9rjg-x2p2-h68h&quot;&gt;GHSA-9rjg-x2p2-h68h&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2026-54164&quot; rel=&quot;nofollow&quot;&gt;https://nvd.nist.gov/vuln/detail/CVE-2026-54164&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/api-platform/core/commit/6bcbeb2dbee53db5bb9b4b8e343bffdf7732de1e/hovercard&quot; href=&quot;https://github.com/api-platform/core/commit/6bcbeb2dbee53db5bb9b4b8e343bffdf7732de1e&quot;&gt;api-platform/core@&lt;tt&gt;6bcbeb2&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/api-platform/core/releases/tag/v4.1.30&quot;&gt;https://github.com/api-platform/core/releases/tag/v4.1.30&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/api-platform/core/releases/tag/v4.2.26&quot;&gt;https://github.com/api-platform/core/releases/tag/v4.2.26&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/api-platform/core/releases/tag/v4.3.12&quot;&gt;https://github.com/api-platform/core/releases/tag/v4.3.12&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-9rjg-x2p2-h68h</link><guid isPermaLink="false">https://github.com/advisories/GHSA-9rjg-x2p2-h68h</guid><pubDate>Fri, 07 Aug 2026 16:54:42 GMT</pubDate></item><item><title>Smarty Security stream restriction bypass through stream: resource</title><description>&lt;p&gt;&lt;code class=&quot;notranslate&quot;&gt;smarty/smarty&lt;/code&gt; version &lt;code class=&quot;notranslate&quot;&gt;5.8.0&lt;/code&gt; can read local files through PHP stream wrappers even when Smarty Security is enabled and all streams are disabled with &lt;code class=&quot;notranslate&quot;&gt;Security::$streams = null&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The bypass uses Smarty&#39;s built-in &lt;code class=&quot;notranslate&quot;&gt;stream:&lt;/code&gt; resource type. A template such as:&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-smarty&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-pse&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;file=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;stream:php://filter/read=convert.base64-encode/resource=/tmp/secret.tpl&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;pl-pse&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;is handled as Smarty resource type &lt;code class=&quot;notranslate&quot;&gt;stream&lt;/code&gt;, so the security check that would normally reject the underlying &lt;code class=&quot;notranslate&quot;&gt;php&lt;/code&gt; wrapper is not applied. &lt;code class=&quot;notranslate&quot;&gt;StreamPlugin&lt;/code&gt; then opens the nested &lt;code class=&quot;notranslate&quot;&gt;php://filter/...&lt;/code&gt; URI directly.&lt;/p&gt;
&lt;p&gt;For comparison, the direct resource:&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-smarty&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-pse&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;file=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;php://filter/read=convert.base64-encode/resource=/tmp/secret.tpl&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;pl-pse&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;is blocked with &lt;code class=&quot;notranslate&quot;&gt;stream &#39;php&#39; not allowed by security setting&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Affected package:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ecosystem: Packagist / Composer&lt;/li&gt;
&lt;li&gt;Package: &lt;code class=&quot;notranslate&quot;&gt;smarty/smarty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Confirmed affected version: &lt;code class=&quot;notranslate&quot;&gt;5.8.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Confirmed source reference from Composer lock: &lt;code class=&quot;notranslate&quot;&gt;78d259d3b971c59a0cd719c270cc5cbb740c36a7&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Current stable version on Packagist at review time: &lt;code class=&quot;notranslate&quot;&gt;v5.8.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Packagist usage at review time: 41,113,855 total downloads and 840,604 monthly downloads&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Relevant code paths:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;Smarty\Resource\BasePlugin::load(...)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;Smarty\Resource\StreamPlugin::getContent(...)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;Smarty\Security::isTrustedStream(...)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code class=&quot;notranslate&quot;&gt;BasePlugin::load()&lt;/code&gt; maps the built-in resource name &lt;code class=&quot;notranslate&quot;&gt;stream&lt;/code&gt; directly to &lt;code class=&quot;notranslate&quot;&gt;StreamPlugin&lt;/code&gt; before the code path that checks PHP stream wrappers with &lt;code class=&quot;notranslate&quot;&gt;stream_get_wrappers()&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;Security::isTrustedStream($type)&lt;/code&gt;. &lt;code class=&quot;notranslate&quot;&gt;StreamPlugin::getContent()&lt;/code&gt; later calls &lt;code class=&quot;notranslate&quot;&gt;fopen($filepath, &#39;r+&#39;)&lt;/code&gt; on the nested URI when the resource name contains &lt;code class=&quot;notranslate&quot;&gt;://&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Preconditions:&lt;/p&gt;
&lt;p&gt;An application must render templates that are not fully trusted while relying on Smarty Security to restrict local files and PHP stream wrappers. The PoC sets:&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-php&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;smarty&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pl-en&quot;&gt;enableSecurity&lt;/span&gt;();
&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;smarty&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pl-c1&quot;&gt;security_policy&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pl-c1&quot;&gt;streams&lt;/span&gt; = &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Local reproduction:&lt;/p&gt;
&lt;p&gt;The PoC creates a disposable template directory and a separate outside directory. It enables Smarty Security, disables all streams, and then compares three includes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;../outside/secret.tpl&lt;/code&gt; to confirm the ordinary trusted-directory boundary is enforced.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;php://filter/...&lt;/code&gt; to confirm direct PHP streams are blocked by &lt;code class=&quot;notranslate&quot;&gt;Security::$streams = null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;stream:php://filter/...&lt;/code&gt; to show the built-in &lt;code class=&quot;notranslate&quot;&gt;stream:&lt;/code&gt; resource bypasses the same restriction and reads the outside file.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Run:&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;php -d display_errors=1 poc.php&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Observed sanitized output:&lt;/p&gt;
&lt;pre lang=&quot;text&quot; class=&quot;notranslate&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;package=smarty/smarty
installed_version=v5.8.0
template_dir=&amp;lt;tmp&amp;gt;/templates
outside_template=&amp;lt;tmp&amp;gt;/outside/secret.tpl
plain_dotdot_include=BLOCKED:Smarty\Exception:Smarty Security: not trusted file path &#39;&amp;lt;tmp&amp;gt;/outside/secret.tpl&#39;
direct_php_filter_include=BLOCKED:Smarty\Exception:stream &#39;php&#39; not allowed by security setting
stream_php_filter_include=OK:U01BUlRZX1NUUkVBTV9XUkFQUEVSX1NFQ1VSSVRZX0VTQ0FQRQ==
expected_base64=U01BUlRZX1NUUkVBTV9XUkFQUEVSX1NFQ1VSSVRZX0VTQ0FQRQ==
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;notranslate&quot;&gt;plain_dotdot_include&lt;/code&gt; line shows the directory boundary is enforced for ordinary traversal. The &lt;code class=&quot;notranslate&quot;&gt;direct_php_filter_include&lt;/code&gt; line shows the same policy rejects &lt;code class=&quot;notranslate&quot;&gt;php://filter&lt;/code&gt; when used directly. The &lt;code class=&quot;notranslate&quot;&gt;stream_php_filter_include&lt;/code&gt; line shows that wrapping the same URI in Smarty&#39;s &lt;code class=&quot;notranslate&quot;&gt;stream:&lt;/code&gt; resource bypasses that restriction and reads the outside file.&lt;/p&gt;
&lt;p&gt;Impact:&lt;/p&gt;
&lt;p&gt;A template author can bypass Smarty Security stream restrictions and read local files that are readable by the PHP process. With &lt;code class=&quot;notranslate&quot;&gt;php://filter&lt;/code&gt;, file contents can be base64 encoded and rendered back through the template. This bypasses both the intended &lt;code class=&quot;notranslate&quot;&gt;Security::$streams = null&lt;/code&gt; restriction and the normal trusted-template-directory check that blocks &lt;code class=&quot;notranslate&quot;&gt;../&lt;/code&gt; traversal.&lt;/p&gt;
&lt;p&gt;Duplicate checks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OSV query for &lt;code class=&quot;notranslate&quot;&gt;Packagist/smarty/smarty&lt;/code&gt; version &lt;code class=&quot;notranslate&quot;&gt;5.8.0&lt;/code&gt; returned no vulnerabilities.&lt;/li&gt;
&lt;li&gt;GitHub advisory query for &lt;code class=&quot;notranslate&quot;&gt;ecosystem=composer&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;affects=smarty/smarty&lt;/code&gt; returned historical Smarty advisories, including sandbox escapes, PHP code injection, XSS, and older path traversal issues. The listed path traversal advisories affect older versions and do not describe this current &lt;code class=&quot;notranslate&quot;&gt;stream:php://filter&lt;/code&gt; resource-wrapper bypass in 5.8.0.&lt;/li&gt;
&lt;li&gt;GitHub issue search in &lt;code class=&quot;notranslate&quot;&gt;smarty-php/smarty&lt;/code&gt; for &lt;code class=&quot;notranslate&quot;&gt;stream:php://filter&lt;/code&gt; returned zero results.&lt;/li&gt;
&lt;li&gt;Public searches for &lt;code class=&quot;notranslate&quot;&gt;Smarty StreamPlugin php://filter&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;smarty/smarty isTrustedStream stream:&lt;/code&gt; did not identify a clear public duplicate during triage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Suggested remediation:&lt;/p&gt;
&lt;p&gt;When resolving the built-in &lt;code class=&quot;notranslate&quot;&gt;stream:&lt;/code&gt; resource, parse and validate the nested URI scheme before opening it. For example, &lt;code class=&quot;notranslate&quot;&gt;stream:php://filter/...&lt;/code&gt; should call &lt;code class=&quot;notranslate&quot;&gt;Security::isTrustedStream(&#39;php&#39;)&lt;/code&gt;, and &lt;code class=&quot;notranslate&quot;&gt;Security::$streams = null&lt;/code&gt; should block the resource before &lt;code class=&quot;notranslate&quot;&gt;StreamPlugin::getContent()&lt;/code&gt; reaches &lt;code class=&quot;notranslate&quot;&gt;fopen()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It would also be safer for &lt;code class=&quot;notranslate&quot;&gt;StreamPlugin&lt;/code&gt; to reject nested stream wrappers by default unless the underlying wrapper is explicitly allowed by the active security policy.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-rjhh-76wf-8xmw&quot; href=&quot;https://github.com/smarty-php/smarty/security/advisories/GHSA-rjhh-76wf-8xmw&quot;&gt;GHSA-rjhh-76wf-8xmw&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;issue-link js-issue-link&quot; data-error-text=&quot;Failed to load title&quot; data-id=&quot;4766868954&quot; data-permission-text=&quot;Title is private&quot; data-url=&quot;https://github.com/smarty-php/smarty/issues/1195&quot; data-hovercard-type=&quot;pull_request&quot; data-hovercard-url=&quot;/smarty-php/smarty/pull/1195/hovercard&quot; href=&quot;https://github.com/smarty-php/smarty/pull/1195&quot;&gt;smarty-php/smarty#1195&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/smarty-php/smarty/commit/3c9f77a2e06ce319ae0092496af32cc8f3adc52e/hovercard&quot; href=&quot;https://github.com/smarty-php/smarty/commit/3c9f77a2e06ce319ae0092496af32cc8f3adc52e&quot;&gt;smarty-php/smarty@&lt;tt&gt;3c9f77a&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/smarty-php/smarty/releases/tag/v5.8.4&quot;&gt;https://github.com/smarty-php/smarty/releases/tag/v5.8.4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-rjhh-76wf-8xmw</link><guid isPermaLink="false">https://github.com/advisories/GHSA-rjhh-76wf-8xmw</guid><pubDate>Fri, 07 Aug 2026 15:10:51 GMT</pubDate></item><item><title>Smarty: Symlink path traversal out of trusted directories</title><description>&lt;p&gt;When Smarty&#39;s Security policy is enabled, secure_dir (and the configured template/trusted directories) restrict which local files a template may read via {include} and {fetch}. The trust check in Security::_checkDir() resolved the requested path with Smarty::_realpath(), which normalizes the path as a string only and does not follow symbolic links. A symlink placed inside a trusted directory therefore passed the trust check, while the underlying file_get_contents() followed it to an arbitrary file outside the sandbox (e.g. /etc/passwd).&lt;/p&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;An attacker able to (a) cause a symlink to exist inside a trusted directory (e.g. a user-upload area located within the template path) and (b) cause a template to reference that path can read arbitrary files readable by the PHP process, escaping the secure_dir boundary. Confidentiality impact only.&lt;/p&gt;
&lt;h2&gt;Patches&lt;/h2&gt;
&lt;p&gt;Fixed in 5.8.2. Security::_checkDir() now resolves the requested file with native realpath() and re-validates the canonical, symlink-free path against the trusted directories (which are canonicalized the same way, so legitimate symlinked deployment paths such as a Capistrano current symlink or macOS /var → /private/var keep working). It falls back to string normalization only when the file does not yet exist on disk.&lt;/p&gt;
&lt;h2&gt;Workarounds&lt;/h2&gt;
&lt;p&gt;Ensure no untrusted symlinks can be created within any directory listed in secure_dir/the trusted template directories; restrict write access to those directories to trusted processes only.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Fix commit: 99c048c&lt;/li&gt;
&lt;li&gt;CWE-22&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-f6wf-28g6-769x&quot; href=&quot;https://github.com/smarty-php/smarty/security/advisories/GHSA-f6wf-28g6-769x&quot;&gt;GHSA-f6wf-28g6-769x&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/smarty-php/smarty/commit/99c048ce7a590c519b79fbd38ad0143a08183a1f/hovercard&quot; href=&quot;https://github.com/smarty-php/smarty/commit/99c048ce7a590c519b79fbd38ad0143a08183a1f&quot;&gt;smarty-php/smarty@&lt;tt&gt;99c048c&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/smarty-php/smarty/commit/a1ccdb0518021a559b4066c37b76a42c86bbce90/hovercard&quot; href=&quot;https://github.com/smarty-php/smarty/commit/a1ccdb0518021a559b4066c37b76a42c86bbce90&quot;&gt;smarty-php/smarty@&lt;tt&gt;a1ccdb0&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/smarty-php/smarty/releases/tag/v4.5.7&quot;&gt;https://github.com/smarty-php/smarty/releases/tag/v4.5.7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/smarty-php/smarty/releases/tag/v5.8.2&quot;&gt;https://github.com/smarty-php/smarty/releases/tag/v5.8.2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-f6wf-28g6-769x</link><guid isPermaLink="false">https://github.com/advisories/GHSA-f6wf-28g6-769x</guid><pubDate>Fri, 07 Aug 2026 15:02:39 GMT</pubDate></item><item><title>Craft CMS: Passkey login accepts replayed WebAuthn assertions</title><description>&lt;p&gt;Craft CMS passkey login accepts WebAuthn requestOptions from the unauthenticated login request body and does not persist the updated credential counter returned by the WebAuthn assertion validator. A captured passkey login request body can therefore be replayed because the old challenge is accepted again, and the stored credential counter remains stale.&lt;/p&gt;
&lt;p&gt;Craft CMS 5.10.3 and current &lt;code class=&quot;notranslate&quot;&gt;5.x&lt;/code&gt; HEAD accept &lt;code class=&quot;notranslate&quot;&gt;PublicKeyCredentialRequestOptions&lt;/code&gt; from the unauthenticated &lt;code class=&quot;notranslate&quot;&gt;users/login-with-passkey&lt;/code&gt; request body and do not persist the updated &lt;code class=&quot;notranslate&quot;&gt;PublicKeyCredentialSource&lt;/code&gt; returned/mutated by &lt;code class=&quot;notranslate&quot;&gt;web-auth/webauthn-lib&lt;/code&gt; after assertion validation.&lt;/p&gt;
&lt;p&gt;As a result, a captured passkey login request body is not one-time-use. Reposting the same &lt;code class=&quot;notranslate&quot;&gt;requestOptions&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;response&lt;/code&gt; can result in validation against the same stale credential counter and create another Craft session for that user. This weakens passkeys from a fresh, server-challenged authentication ceremony into a replayable bearer artifact if one successful assertion body is exposed.&lt;/p&gt;
&lt;h2&gt;Attack Scenario&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;A victim successfully logs in with a passkey.&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;notranslate&quot;&gt;POST /actions/users/login-with-passkey&lt;/code&gt; body containing &lt;code class=&quot;notranslate&quot;&gt;requestOptions&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;response&lt;/code&gt; is captured from an application/request log, debugging proxy, browser extension, compromised analytics layer, or another request-body disclosure point.&lt;/li&gt;
&lt;li&gt;The attacker reposts the same body to &lt;code class=&quot;notranslate&quot;&gt;users/login-with-passkey&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Craft deserializes the attacker-supplied &lt;code class=&quot;notranslate&quot;&gt;requestOptions&lt;/code&gt;, so the old challenge remains accepted for validation.&lt;/li&gt;
&lt;li&gt;The WebAuthn validator compares the assertion&#39;s &lt;code class=&quot;notranslate&quot;&gt;signCount&lt;/code&gt; against the stale stored credential counter.&lt;/li&gt;
&lt;li&gt;Because Craft did not persist the updated credential source on the original login, the same stale stored counter is used again.&lt;/li&gt;
&lt;li&gt;The same captured assertion validates and Craft creates another authenticated session for the victim account.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is exactly what WebAuthn&#39;s challenge and signature-counter lifecycle is meant to prevent: a successful assertion should be bound to a server-issued challenge and should update server-side credential state so it cannot be used again.&lt;/p&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;An attacker who obtains one successful passkey login request body can replay it to create additional authenticated Craft sessions for that user. This defeats WebAuthn’s intended one-time challenge and signature-counter replay protection, reducing a passkey assertion to a reusable bearer artifact if exposed through request logging, a debugging proxy, a compromised same-origin script layer, or another request-body disclosure path.&lt;/p&gt;
&lt;p&gt;The impact is an account/session takeover of the affected passkey account after a single assertion body is captured. The issue is in Craft’s native passkey login flow and affects fresh Craft installations with passkeys enabled.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-wg23-69c2-gjc8&quot; href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-wg23-69c2-gjc8&quot;&gt;GHSA-wg23-69c2-gjc8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/d71a66d69cf8852bcfca4484ca718750b5a316d6/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/d71a66d69cf8852bcfca4484ca718750b5a316d6&quot;&gt;craftcms/cms@&lt;tt&gt;d71a66d&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/5.10.5&quot;&gt;https://github.com/craftcms/cms/releases/tag/5.10.5&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-wg23-69c2-gjc8</link><guid isPermaLink="false">https://github.com/advisories/GHSA-wg23-69c2-gjc8</guid><pubDate>Fri, 07 Aug 2026 14:57:29 GMT</pubDate></item><item><title>Craft CMS: Arbitrary file read via SplFileObject in non-sandboxed template contexts</title><description>&lt;p&gt;The &lt;code class=&quot;notranslate&quot;&gt;create()&lt;/code&gt; Twig function (introduced in 5.9.0) allows instantiation of arbitrary PHP classes from template code, restricted only by a 5-entry blocklist. &lt;code class=&quot;notranslate&quot;&gt;SplFileObject&lt;/code&gt; is not in the blocklist, enabling arbitrary file read, including &lt;code class=&quot;notranslate&quot;&gt;.env&lt;/code&gt; (security key, DB credentials) and the passwd file from non-sandboxed Twig template contexts, such as entry type title formats and URI formats.&lt;/p&gt;
&lt;p&gt;The sandbox correctly blocks &lt;code class=&quot;notranslate&quot;&gt;create()&lt;/code&gt; in system email templates, so this finding applies only to admin-configured, non-sandboxed contexts that require &lt;code class=&quot;notranslate&quot;&gt;allowAdminChanges=true&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Admin access to the Craft control panel&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;allowAdminChanges&lt;/code&gt; must be &lt;code class=&quot;notranslate&quot;&gt;true&lt;/code&gt; (default in dev/staging, recommended &lt;code class=&quot;notranslate&quot;&gt;false&lt;/code&gt; in production)&lt;/li&gt;
&lt;li&gt;Admin must be able to edit entry type settings (title format, URI format)&lt;/li&gt;
&lt;li&gt;Any user who subsequently creates an entry in the affected section triggers the file read&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Limitations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Requires admin-level access: not exploitable by low-privilege users&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;allowAdminChanges&lt;/code&gt; must be &lt;code class=&quot;notranslate&quot;&gt;true&lt;/code&gt;: production best practices recommend &lt;code class=&quot;notranslate&quot;&gt;false&lt;/code&gt;, which prevents entry type configuration changes&lt;/li&gt;
&lt;li&gt;Per Craft’s own severity guidelines, findings requiring &lt;code class=&quot;notranslate&quot;&gt;allowAdminChanges=true&lt;/code&gt; are rated low&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;notranslate&quot;&gt;create()&lt;/code&gt; function is blocked by the Twig sandbox, so this cannot be exploited via system email templates or any other sandboxed context&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;An admin user (or an attacker who has compromised an admin account) can read arbitrary files from the server filesystem by setting a malicious entry type title format using &lt;code class=&quot;notranslate&quot;&gt;create(&#39;SplFileObject&#39;, [&#39;/path/to/file&#39;])&lt;/code&gt;. In production environments, this exposes &lt;code class=&quot;notranslate&quot;&gt;.env&lt;/code&gt; files containing the &lt;code class=&quot;notranslate&quot;&gt;CRAFT_SECURITY_KEY&lt;/code&gt;, database credentials, API keys, and other secrets. The file contents are rendered as entry titles visible to any user with permission to view entries in the affected section.&lt;/p&gt;
&lt;p&gt;The impact is limited by the requirement for admin access and &lt;code class=&quot;notranslate&quot;&gt;allowAdminChanges=true&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-957r-qf9p-67xw&quot; href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-957r-qf9p-67xw&quot;&gt;GHSA-957r-qf9p-67xw&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/7c96fd73df936a10e8f85ae6ef61a9fc3f277c12/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/7c96fd73df936a10e8f85ae6ef61a9fc3f277c12&quot;&gt;craftcms/cms@&lt;tt&gt;7c96fd7&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/87978f11c8f986c40ef41b941d79547230c4d6d9/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/87978f11c8f986c40ef41b941d79547230c4d6d9&quot;&gt;craftcms/cms@&lt;tt&gt;87978f1&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/4.18.2&quot;&gt;https://github.com/craftcms/cms/releases/tag/4.18.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/5.10.6&quot;&gt;https://github.com/craftcms/cms/releases/tag/5.10.6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-957r-qf9p-67xw</link><guid isPermaLink="false">https://github.com/advisories/GHSA-957r-qf9p-67xw</guid><pubDate>Thu, 06 Aug 2026 21:54:45 GMT</pubDate></item><item><title>Craft CMS: Authenticated leak of secret environment variables</title><description>&lt;p&gt;Environment variables and secrets are interpolated into a Twig template even when the Twig sandbox is enabled, allowing them to be leaked by an authenticated attacker.&lt;/p&gt;
&lt;p&gt;The Craft vulnerability &lt;a href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-fp5j-j7j4-mcxc&quot;&gt;CVE-2026-31857&lt;/a&gt; was only patched by applying sandboxed Twig templating. This theoretically protects Craft CMS against RCE attacks, provided the sandbox is enabled and secure, with no known bypasses.&lt;/p&gt;
&lt;p&gt;However, the same request parameter &lt;code class=&quot;notranslate&quot;&gt;elementId,&lt;/code&gt; which allows for sandboxed Twig templates to be rendered, also includes functionality that interpolates referenced environment variables. If the parameter includes a string of the form &lt;code class=&quot;notranslate&quot;&gt;${ENV_VAR}&lt;/code&gt; then the string is replaced with the environment variable or secret from a secrets file with that name.&lt;/p&gt;
&lt;p&gt;Afterward, the string is rendered as a Twig template. If the sandbox is disabled, Twig templates can already gain RCE or access environment variables using the getenv function. Sandboxed Twig templates should not have this access, but now do thanks to this additional environment-variable replacement behavior.&lt;/p&gt;
&lt;p&gt;The template’s resulting value is not directly reflected in the response. To exfiltrate the value, the sandboxed Twig template cannot use network functions. But it can use a blind error-based approach similar to blind SQL injection. With enough requests, any environment variable or secret can be incrementally leaked. This can be abused to forge a session, escalate privileges with the &lt;code class=&quot;notranslate&quot;&gt;CRAFT_SECURITY_KEY&lt;/code&gt;, and steal credentials for the database, SMTP server, or other connected APIs or blob storage.&lt;/p&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;An authenticated attacker, with permission to access the control panel, can render a malicious Twig template and steal arbitrary environment variables and secrets with a large number of requests, even if the Twig sandbox is enabled through &lt;code class=&quot;notranslate&quot;&gt;enableTwigSandbox()&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-596p-6jv8-775v&quot; href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-596p-6jv8-775v&quot;&gt;GHSA-596p-6jv8-775v&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/4.18.2&quot;&gt;https://github.com/craftcms/cms/releases/tag/4.18.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/5.10.6&quot;&gt;https://github.com/craftcms/cms/releases/tag/5.10.6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-596p-6jv8-775v</link><guid isPermaLink="false">https://github.com/advisories/GHSA-596p-6jv8-775v</guid><pubDate>Thu, 06 Aug 2026 21:53:31 GMT</pubDate></item><item><title>Craft CMS:Authorization bypass: view-only Categories user can modify category structure via structures/move-element</title><description>&lt;p&gt;A control-panel user who holds only the viewCategories permission for a category group (and not saveCategories) can permanently modify that group&#39;s category structure — reordering and re-parenting categories via the structures/move-element action.&lt;/p&gt;
&lt;p&gt;A read-time authorization grant that a write endpoint later trusts. For categories, the structureEditable flag is computed from the view permission (&lt;code class=&quot;notranslate&quot;&gt;src/elements/Category.php:205&lt;/code&gt;) instead of the save permission (entries correctly use saveEntries — &lt;code class=&quot;notranslate&quot;&gt;src/elements/Entry.php:341&lt;/code&gt;). When the read-only category index renders, &lt;code class=&quot;notranslate&quot;&gt;craft\base\Element::indexHtml()&lt;/code&gt; calls &lt;code class=&quot;notranslate&quot;&gt;Craft::$app-&amp;gt;getSession()-&amp;gt;authorize(&#39;editStructure:&amp;lt;structureId&amp;gt;&#39;);&lt;/code&gt; StructuresController then authorizes the structure-mutating action solely on that session grant, with no canSave re-check.&lt;/p&gt;
&lt;p&gt;Verified on Craft CMS 5.10.5. Same class as the moderate-severity authorization bypasses fixed in 5.10.3 and 5.10.5; this is a distinct, unpatched instance.&lt;/p&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;A low-privileged, authenticated user (view-only on a category group) can persistently alter the sibling ordering and parent/child nesting of the category taxonomy. Because a category’s URI is derived from its position in the structure (ancestor slugs), moving a category changes its URL and the URLs of its descendants, and can corrupt any navigation/menus built from the category tree. This is an integrity/broken access-control issue: content that the user has no permission to modify is being modified. No confidentiality impact and no RCE; scope is content/taxonomy integrity.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-xxpx-f366-4xpq&quot; href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-xxpx-f366-4xpq&quot;&gt;GHSA-xxpx-f366-4xpq&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/eb63721b8476ef53f21d7de53d156eef531cb57d/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/eb63721b8476ef53f21d7de53d156eef531cb57d&quot;&gt;craftcms/cms@&lt;tt&gt;eb63721&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/4.18.2&quot;&gt;https://github.com/craftcms/cms/releases/tag/4.18.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/5.10.6&quot;&gt;https://github.com/craftcms/cms/releases/tag/5.10.6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-xxpx-f366-4xpq</link><guid isPermaLink="false">https://github.com/advisories/GHSA-xxpx-f366-4xpq</guid><pubDate>Thu, 06 Aug 2026 21:43:54 GMT</pubDate></item><item><title>Craft CMS: Missing authorization check allows non-admin control panel users access to user registration metrics</title><description>&lt;p&gt;&lt;code class=&quot;notranslate&quot;&gt;ChartsController::actionGetNewUsersData()&lt;/code&gt; at &lt;code class=&quot;notranslate&quot;&gt;/actions/charts/get-new-users-data&lt;/code&gt; is missing a &lt;code class=&quot;notranslate&quot;&gt;requirePermission(&#39;viewUsers&#39;)&lt;/code&gt; authorization check. Any authenticated control panel user, regardless of permissions beyond &lt;code class=&quot;notranslate&quot;&gt;accessCp&lt;/code&gt;, can POST to this endpoint to receive time-series user registration counts for the entire site or for an arbitrary user group ID.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;notranslate&quot;&gt;viewUsers&lt;/code&gt; permission is consistently required throughout the control panel before exposing user-related data, but this action enforces only the base &lt;code class=&quot;notranslate&quot;&gt;accessCp&lt;/code&gt; check inherited from the framework.&lt;/p&gt;
&lt;p&gt;Each call returns the total count of users who joined the specified group in the requested period.&lt;/p&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;Any control panel user with only &lt;code class=&quot;notranslate&quot;&gt;accessCp&lt;/code&gt; permission can obtain the total number of registered users and their registration date distribution across any time window.&lt;/p&gt;
&lt;p&gt;In installations with multiple editor roles, this allows a low-privilege control panel user to infer user group sizes and registration trends that would normally require the &lt;code class=&quot;notranslate&quot;&gt;viewUsers&lt;/code&gt; permission to access.&lt;/p&gt;
&lt;p&gt;No user PII (name, email, password) is disclosed; only aggregate counts and timestamps are returned. Confidentiality impact is low. No integrity or availability impact.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-rvmm-v933-jgxq&quot; href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-rvmm-v933-jgxq&quot;&gt;GHSA-rvmm-v933-jgxq&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/9ee53efc1314e6aba32771c66a13e072a246f4ce/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/9ee53efc1314e6aba32771c66a13e072a246f4ce&quot;&gt;craftcms/cms@&lt;tt&gt;9ee53ef&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/4.18.1&quot;&gt;https://github.com/craftcms/cms/releases/tag/4.18.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/5.10.3&quot;&gt;https://github.com/craftcms/cms/releases/tag/5.10.3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-rvmm-v933-jgxq</link><guid isPermaLink="false">https://github.com/advisories/GHSA-rvmm-v933-jgxq</guid><pubDate>Thu, 06 Aug 2026 21:42:58 GMT</pubDate></item><item><title>Craft CMS: Incorrect path validation could potentially lead to path traversal</title><description>&lt;p&gt;The &lt;code class=&quot;notranslate&quot;&gt;ensurePathIsContained&lt;/code&gt; function of the &lt;code class=&quot;notranslate&quot;&gt;Local&lt;/code&gt; file system class is theoretically vulnerable to path traversal, although no exploitable scenario has been discovered.&lt;/p&gt;
&lt;p&gt;When a file is read, an &lt;code class=&quot;notranslate&quot;&gt;Asset&lt;/code&gt; object uses the &lt;code class=&quot;notranslate&quot;&gt;getFileStream&lt;/code&gt; method of the &lt;code class=&quot;notranslate&quot;&gt;Volume&lt;/code&gt; where the asset file is stored, which in turn uses the &lt;code class=&quot;notranslate&quot;&gt;getFileStream&lt;/code&gt; method of the file system class used by that &lt;code class=&quot;notranslate&quot;&gt;Volume&lt;/code&gt;. For the &lt;code class=&quot;notranslate&quot;&gt;Local&lt;/code&gt; file system, this function returns a stream to a file on the local disk after verifying and creating the correct file path.&lt;/p&gt;
&lt;p&gt;The file path is constructed by first validating the path and then adding a prefix to the validated and normalized path. The prefix is the path to the local directory that houses the particular volume. The order of operations matters here: first, a validation step, afterward a normalization step, and finally the construction of the resulting file path. This opens the possibility of a desanitization-style vulnerability, where the normalization invalidates the assumptions made by the validation or sanitization that preceded it.&lt;/p&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;The issue is not directly exploitable, but for hardening, a fix is recommended regardless.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-7hxc-f267-h5q7&quot; href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-7hxc-f267-h5q7&quot;&gt;GHSA-7hxc-f267-h5q7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/a8425b6c707335e42c35ee2aaf03af50ea4a494d/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/a8425b6c707335e42c35ee2aaf03af50ea4a494d&quot;&gt;craftcms/cms@&lt;tt&gt;a8425b6&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/bd6b9c175b4892e042e8a03760c39b0e94c4c7d6/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/bd6b9c175b4892e042e8a03760c39b0e94c4c7d6&quot;&gt;craftcms/cms@&lt;tt&gt;bd6b9c1&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/4.18.2&quot;&gt;https://github.com/craftcms/cms/releases/tag/4.18.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/5.10.6&quot;&gt;https://github.com/craftcms/cms/releases/tag/5.10.6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-7hxc-f267-h5q7</link><guid isPermaLink="false">https://github.com/advisories/GHSA-7hxc-f267-h5q7</guid><pubDate>Thu, 06 Aug 2026 21:36:11 GMT</pubDate></item><item><title>Craft CMS: Stored XSS in the control panel via unescaped draft name</title><description>&lt;p&gt;The control-panel helper that renders element chip/card labels writes an element&#39;s &lt;code class=&quot;notranslate&quot;&gt;draftName&lt;/code&gt; into the page without HTML-encoding it, while the surrounding path segments are encoded.&lt;/p&gt;
&lt;p&gt;A low-privilege control-panel user who can create a draft of an element (for example, an entry) controls the draft name, so they can store an XSS payload that executes in the browser of any other control-panel user who is shown that element’s chip or card (element indexes with drafts visible, relation and element-selection fields that reference the element, and the drafts list).&lt;/p&gt;
&lt;p&gt;This allows a low-privilege author to run JavaScript in an administrator’s authenticated session and take over the control panel. It is the same output-encoding class as the recently fixed &lt;a title=&quot;GHSA-xrqc-p465-2xvg&quot; data-hovercard-type=&quot;advisory&quot; data-hovercard-url=&quot;/advisories/GHSA-xrqc-p465-2xvg/hovercard&quot; href=&quot;https://github.com/advisories/GHSA-xrqc-p465-2xvg&quot;&gt;GHSA-xrqc-p465-2xvg&lt;/a&gt; (Structure entry title) and &lt;a title=&quot;GHSA-3x4w-mxpf-fhqq&quot; data-hovercard-type=&quot;advisory&quot; data-hovercard-url=&quot;/advisories/GHSA-3x4w-mxpf-fhqq/hovercard&quot; href=&quot;https://github.com/advisories/GHSA-3x4w-mxpf-fhqq&quot;&gt;GHSA-3x4w-mxpf-fhqq&lt;/a&gt; (revision context menu), which encoded other user-controlled titles but not the draft name.&lt;/p&gt;
&lt;h3&gt;Prerequisites&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A control-panel account with permission to edit entries in at least one section and create drafts.&lt;/li&gt;
&lt;li&gt;A higher-privileged user (for example, an administrator) who is later shown the draft’s chip or card (an element index with drafts visible, or a relation/element-selection field referencing the element).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Limitations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Requires the victim to be shown the affected element&#39;s chip/card in the control panel (normal day-to-day activity; element indexes and relation fields are routine).&lt;/li&gt;
&lt;li&gt;The payload runs in the control-panel origin in the victim’s session.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;A low-privilege author can run arbitrary JavaScript in the session of any higher-privileged control-panel user who is shown the element’s chip or card, including administrators. This is a cross-privilege stored XSS, not a self-XSS: the attacker and the victim are different users, and the payload fires during routine browsing of element indexes and relation fields.&lt;/p&gt;
&lt;p&gt;Because the script runs in the victim’s control-panel origin, it can read the CSRF token that Craft embeds in the page JavaScript (&lt;code class=&quot;notranslate&quot;&gt;Craft.csrfTokenValue&lt;/code&gt;, confirmed present on control-panel pages) and issue authenticated control-panel actions as the victim. This was verified end-to-end on Craft Pro: an in-session request to the &lt;code class=&quot;notranslate&quot;&gt;users/save-user&lt;/code&gt; action created a brand new account (&lt;code class=&quot;notranslate&quot;&gt;User saved.&lt;/code&gt;, HTTP 200), an admin-only capability that an author can never perform directly.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-2rp4-x2j7-qmcc&quot; href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-2rp4-x2j7-qmcc&quot;&gt;GHSA-2rp4-x2j7-qmcc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/06c799148537ce960f6bc86e162b499947040eda/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/06c799148537ce960f6bc86e162b499947040eda&quot;&gt;craftcms/cms@&lt;tt&gt;06c7991&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/5.10.8&quot;&gt;https://github.com/craftcms/cms/releases/tag/5.10.8&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-2rp4-x2j7-qmcc</link><guid isPermaLink="false">https://github.com/advisories/GHSA-2rp4-x2j7-qmcc</guid><pubDate>Thu, 06 Aug 2026 21:33:15 GMT</pubDate></item><item><title>PHP_CodeSniffer gitblame report command injection via crafted filename</title><description>&lt;h3&gt;Impact&lt;/h3&gt;
&lt;p&gt;PHP_CodeSniffer versions before v3.13.6 and v4.0.2 contain a command injection vulnerability in the code creating the &lt;code class=&quot;notranslate&quot;&gt;Gitblame&lt;/code&gt;, &lt;code class=&quot;notranslate&quot;&gt;Hgblame&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;Svnblame&lt;/code&gt; report(s).&lt;/p&gt;
&lt;p&gt;As a result, running PHP_CodeSniffer over untrusted files, for example, in a CI pipeline that scans pull requests, or on a developer machine reviewing third-party code, could result in attacker-controlled shell commands being executed when the &lt;code class=&quot;notranslate&quot;&gt;Gitblame&lt;/code&gt;, &lt;code class=&quot;notranslate&quot;&gt;Hgblame&lt;/code&gt; or &lt;code class=&quot;notranslate&quot;&gt;Svnblame&lt;/code&gt; report(s) would process a file whose name contains shell metacharacters.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Users using the default &lt;code class=&quot;notranslate&quot;&gt;Full&lt;/code&gt; report, or any of the other non-*blame reports, are not affected.&lt;/li&gt;
&lt;li&gt;Users on a runtime platform which does not allow filenames to contain shell metacharacters, such as &lt;code class=&quot;notranslate&quot;&gt;&quot;&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;;&lt;/code&gt;, are not affected.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Patched versions&lt;/h3&gt;
&lt;p&gt;The issue has been fixed in PHP_CodeSniffer v3.13.6 and v4.0.2. We recommend all users upgrade to these versions at their earliest convenience.&lt;/p&gt;
&lt;h3&gt;Workaround&lt;/h3&gt;
&lt;p&gt;Users of PHP_CodeSniffer who cannot upgrade immediately should ensure they do not use the &lt;code class=&quot;notranslate&quot;&gt;Gitblame&lt;/code&gt;, &lt;code class=&quot;notranslate&quot;&gt;Hgblame&lt;/code&gt; or the &lt;code class=&quot;notranslate&quot;&gt;Svnblame&lt;/code&gt; reports when scanning untrusted code.&lt;/p&gt;
&lt;p&gt;This is especially relevant for CI jobs, pre-commit or review tooling, automated review services, and any service that scans untrusted repositories or uploaded source trees.&lt;/p&gt;
&lt;h3&gt;Credits&lt;/h3&gt;
&lt;p&gt;Many thanks to both &lt;a href=&quot;https://github.com/Faze-up&quot;&gt;@Faze-up&lt;/a&gt; and &lt;a href=&quot;https://github.com/edorian&quot;&gt;@edorian&lt;/a&gt; for responsibly disclosing this vulnerability.&lt;/p&gt;
&lt;h3&gt;How can I report a security bug?&lt;/h3&gt;
&lt;p&gt;Please report security vulnerabilities privately via &lt;a href=&quot;https://github.com/PHPCSStandards/PHP_CodeSniffer/security&quot;&gt;the &quot;Security and quality&quot; tab on the PHP_CodeSniffer repository&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-hmqg-cxww-wqhq&quot; href=&quot;https://github.com/PHPCSStandards/PHP_CodeSniffer/security/advisories/GHSA-hmqg-cxww-wqhq&quot;&gt;GHSA-hmqg-cxww-wqhq&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;issue-link js-issue-link&quot; data-error-text=&quot;Failed to load title&quot; data-id=&quot;5076015540&quot; data-permission-text=&quot;Title is private&quot; data-url=&quot;https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/1473&quot; data-hovercard-type=&quot;pull_request&quot; data-hovercard-url=&quot;/PHPCSStandards/PHP_CodeSniffer/pull/1473/hovercard&quot; href=&quot;https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1473&quot;&gt;PHPCSStandards/PHP_CodeSniffer#1473&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/PHPCSStandards/PHP_CodeSniffer/commit/7a3a6bbf153a03fa3a9413afc60bded6b764e76b/hovercard&quot; href=&quot;https://github.com/PHPCSStandards/PHP_CodeSniffer/commit/7a3a6bbf153a03fa3a9413afc60bded6b764e76b&quot;&gt;PHPCSStandards/PHP_CodeSniffer@&lt;tt&gt;7a3a6bb&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/PHPCSStandards/PHP_CodeSniffer/commit/f0e1ebb0563f0e5d7f190497a787bcaf8474f3fe/hovercard&quot; href=&quot;https://github.com/PHPCSStandards/PHP_CodeSniffer/commit/f0e1ebb0563f0e5d7f190497a787bcaf8474f3fe&quot;&gt;PHPCSStandards/PHP_CodeSniffer@&lt;tt&gt;f0e1ebb&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FriendsOfPHP/security-advisories/blob/master/squizlabs/php_codesniffer/CVE-2026-67434.yaml&quot;&gt;https://github.com/FriendsOfPHP/security-advisories/blob/master/squizlabs/php_codesniffer/CVE-2026-67434.yaml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/tag/3.13.6&quot;&gt;https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/tag/3.13.6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/tag/4.0.2&quot;&gt;https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/tag/4.0.2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-hmqg-cxww-wqhq</link><guid isPermaLink="false">https://github.com/advisories/GHSA-hmqg-cxww-wqhq</guid><pubDate>Thu, 06 Aug 2026 21:31:34 GMT</pubDate></item><item><title>Craft CMS: Arbitrary user password reset leading to administrator account takeover</title><description>&lt;p&gt;The vulnerability allows any authenticated user to change their own password without providing the current password or having an active elevated session. It also allows the attacker to change other users’ passwords if the attacker’s account has &lt;code class=&quot;notranslate&quot;&gt;edit users&lt;/code&gt; permission (which doesn’t allow changing others’ passwords) and lacks &lt;code class=&quot;notranslate&quot;&gt;Administrate users&lt;/code&gt; permission (which is required to change others’ passwords).&lt;/p&gt;
&lt;p&gt;The vulnerability exists in the &lt;code class=&quot;notranslate&quot;&gt;elements/save&lt;/code&gt; action when saving a User element. The &lt;code class=&quot;notranslate&quot;&gt;UserPasswordValidator&lt;/code&gt; applies only a &lt;code class=&quot;notranslate&quot;&gt;safe&lt;/code&gt; validator to the &lt;code class=&quot;notranslate&quot;&gt;newPassword&lt;/code&gt; field without an &lt;code class=&quot;notranslate&quot;&gt;on&lt;/code&gt; scenario restriction. This makes &lt;code class=&quot;notranslate&quot;&gt;newPassword&lt;/code&gt; mass-assignable during the generic element save flow, completely bypassing the dedicated &lt;code class=&quot;notranslate&quot;&gt;users/set-password&lt;/code&gt; action that enforces elevated session verification.&lt;/p&gt;
&lt;p&gt;An attacker with any authenticated session (whether it’s hijacked or a normal / low-privileged user) can change their own password, and potentially take over administrator accounts.&lt;/p&gt;
&lt;h2&gt;Required Permissions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Access the control panel&lt;/li&gt;
&lt;li&gt;Edit users (needed for the account takeover attack scenario)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Any authenticated user can change their own password without providing their current password.&lt;/li&gt;
&lt;li&gt;Users with Edit users permission can change any user’s password, including administrators.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-p8x7-9vfw-p7vc&quot; href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-p8x7-9vfw-p7vc&quot;&gt;GHSA-p8x7-9vfw-p7vc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/cbdf45fbd3ab548b147d7de375f6f6f580b7c294/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/cbdf45fbd3ab548b147d7de375f6f6f580b7c294&quot;&gt;craftcms/cms@&lt;tt&gt;cbdf45f&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/5.10.8&quot;&gt;https://github.com/craftcms/cms/releases/tag/5.10.8&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-p8x7-9vfw-p7vc</link><guid isPermaLink="false">https://github.com/advisories/GHSA-p8x7-9vfw-p7vc</guid><pubDate>Thu, 06 Aug 2026 21:04:11 GMT</pubDate></item><item><title>Craft CMS: Authenticated RCE through Twig sandbox escape</title><description>&lt;p&gt;The Twig sandbox mechanism in Craft CMS is configured to allow dangerous functionality from the Yii framework, leading to authenticated RCE in a manner similar to previously disclosed vulnerabilities.&lt;/p&gt;
&lt;p&gt;The Twig sandbox in Craft CMS works by implementing Twig&#39;s &lt;code class=&quot;notranslate&quot;&gt;SecurityPolicyInterface&lt;/code&gt;. The resulting &lt;code class=&quot;notranslate&quot;&gt;SecurityPolicy&lt;/code&gt; class implements the &lt;code class=&quot;notranslate&quot;&gt;checkMethodAllowed&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;checkPropertyAllowed&lt;/code&gt; methods of the interface. The implementations compare whether the called method or property is in a configured allowlist or is marked with the &lt;code class=&quot;notranslate&quot;&gt;AllowedInSandbox&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;Additionally, &lt;code class=&quot;notranslate&quot;&gt;SecurityPolicy&lt;/code&gt; allows the allowlisting of whole classes, which is shorthand for allowing all methods and properties of that class to be called. Both the allowlists for tags, filters, variables, methods, properties, and classes, as well as the &lt;code class=&quot;notranslate&quot;&gt;AllowedInSandbox&lt;/code&gt; attribute mechanism, are preconfigured by Craft CMS to allow user-defined templates to use core functionality unimpeded. Additionally, Craft CMS project developers can add more to the allowlists or mark their custom methods and so on as safe with &lt;code class=&quot;notranslate&quot;&gt;AllowedInSandbox&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;notranslate&quot;&gt;SecurityPolicy&lt;/code&gt; class&#39;s allowlisting mechanism is potentially dangerous, as it allows all methods and properties on an object of the allowed class. This means that the checked object can be a subclass and be allowed. And it means that the allowed methods and properties can be defined on any class of the class hierarchy of the object, which does not have to be the allowed class itself.&lt;/p&gt;
&lt;p&gt;Craft CMS uses the &lt;code class=&quot;notranslate&quot;&gt;AllowedInSandbox&lt;/code&gt; attribute to mark the &lt;code class=&quot;notranslate&quot;&gt;ElementInterface&lt;/code&gt; as safe. The &lt;code class=&quot;notranslate&quot;&gt;Element&lt;/code&gt; class implements this interface and is the base class for many relevant model classes in Craft CMS, like &lt;code class=&quot;notranslate&quot;&gt;Entry&lt;/code&gt;, &lt;code class=&quot;notranslate&quot;&gt;User&lt;/code&gt;, &lt;code class=&quot;notranslate&quot;&gt;Asset&lt;/code&gt; and so on. Additionally, &lt;code class=&quot;notranslate&quot;&gt;Element&lt;/code&gt; extends the &lt;code class=&quot;notranslate&quot;&gt;craft\base\Component&lt;/code&gt; class. Going up the class hierarchy of &lt;code class=&quot;notranslate&quot;&gt;craft\base\Component&lt;/code&gt;, eventually the class &lt;code class=&quot;notranslate&quot;&gt;yii\base\Component&lt;/code&gt; is reached, which is located in the Yii framework used by CraftCMS. &lt;code class=&quot;notranslate&quot;&gt;yii\base\Component&lt;/code&gt; is known to contain a dangerous arbitrary function call gadget which leads to previously disclosed RCE vulnerabilities in Craft CMS (&lt;a title=&quot;GHSA-255j-qw47-wjh5&quot; data-hovercard-type=&quot;advisory&quot; data-hovercard-url=&quot;/advisories/GHSA-255j-qw47-wjh5/hovercard&quot; href=&quot;https://github.com/advisories/GHSA-255j-qw47-wjh5&quot;&gt;GHSA-255j-qw47-wjh5&lt;/a&gt;, &lt;a title=&quot;GHSA-2fph-6v5w-89hh&quot; data-hovercard-type=&quot;advisory&quot; data-hovercard-url=&quot;/advisories/GHSA-2fph-6v5w-89hh/hovercard&quot; href=&quot;https://github.com/advisories/GHSA-2fph-6v5w-89hh&quot;&gt;GHSA-2fph-6v5w-89hh&lt;/a&gt;, &lt;a title=&quot;GHSA-7jx7-3846-m7w7&quot; data-hovercard-type=&quot;advisory&quot; data-hovercard-url=&quot;/advisories/GHSA-7jx7-3846-m7w7/hovercard&quot; href=&quot;https://github.com/advisories/GHSA-7jx7-3846-m7w7&quot;&gt;GHSA-7jx7-3846-m7w7&lt;/a&gt;, &lt;a title=&quot;GHSA-qrgm-p9w5-rrfw&quot; data-hovercard-type=&quot;advisory&quot; data-hovercard-url=&quot;/advisories/GHSA-qrgm-p9w5-rrfw/hovercard&quot; href=&quot;https://github.com/advisories/GHSA-qrgm-p9w5-rrfw&quot;&gt;GHSA-qrgm-p9w5-rrfw&lt;/a&gt;). Due to lax class allowlisting, this function-call gadget is allowed in the Twig sandbox. This allows sandboxed Twig templates to use known payloads based on the function-call gadget to achieve RCE.&lt;/p&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;An authenticated attacker with permission to access the control panel can render a malicious Twig template and gain RCE, even if the Twig sandbox is enabled through &lt;code class=&quot;notranslate&quot;&gt;enableTwigSandbox()&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-f5wm-88jv-g5hx&quot; href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-f5wm-88jv-g5hx&quot;&gt;GHSA-f5wm-88jv-g5hx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/0b8be1556be4e030578ec779c3e17ffe2e69d7db/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/0b8be1556be4e030578ec779c3e17ffe2e69d7db&quot;&gt;craftcms/cms@&lt;tt&gt;0b8be15&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/4.18.3&quot;&gt;https://github.com/craftcms/cms/releases/tag/4.18.3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/5.10.7&quot;&gt;https://github.com/craftcms/cms/releases/tag/5.10.7&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-f5wm-88jv-g5hx</link><guid isPermaLink="false">https://github.com/advisories/GHSA-f5wm-88jv-g5hx</guid><pubDate>Thu, 06 Aug 2026 21:02:28 GMT</pubDate></item><item><title>Craft CMS: Missing authorization check allows non-admin control panel users to reorder Global Sets</title><description>&lt;p&gt;The &lt;code class=&quot;notranslate&quot;&gt;reorder-sets&lt;/code&gt; action in Craft CMS’s &lt;code class=&quot;notranslate&quot;&gt;GlobalsController&lt;/code&gt; is missing the &lt;code class=&quot;notranslate&quot;&gt;requireAdmin()&lt;/code&gt; check that the adjacent &lt;code class=&quot;notranslate&quot;&gt;save-set&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;delete-set&lt;/code&gt; actions both enforce. Any authenticated control panel user can POST to &lt;code class=&quot;notranslate&quot;&gt;/actions/globals/reorder-sets&lt;/code&gt; and permanently reorder all global sets in the project config, regardless of whether they have admin access. The reordering is written through to the project config and persists across requests.&lt;/p&gt;
&lt;h2&gt;Description&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;notranslate&quot;&gt;GlobalsController&lt;/code&gt; exposes three administrative actions for managing global set structure. Two of them gate on admin status; the third does not.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A Craft CMS instance with at least two global sets and a non-admin control panel user account.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;A non-admin control panel user can reorder all global sets. While this does not expose or modify content, reordering global sets modifies the project config -- a versioned artifact that is typically committed to source control and deployed across environments. An attacker can create noise in the project config history, trigger config-sync conflicts, or manipulate the display order seen by all editors in the admin panel. The same non-admin user cannot create or delete global sets because those actions correctly enforce &lt;code class=&quot;notranslate&quot;&gt;requireAdmin()&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-9p7c-v5x3-rfx8&quot; href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-9p7c-v5x3-rfx8&quot;&gt;GHSA-9p7c-v5x3-rfx8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2026-14793&quot; rel=&quot;nofollow&quot;&gt;https://nvd.nist.gov/vuln/detail/CVE-2026-14793&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/9bd05c91e6a7e6da5e949ec41a31c220c059aa04/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/9bd05c91e6a7e6da5e949ec41a31c220c059aa04&quot;&gt;craftcms/cms@&lt;tt&gt;9bd05c9&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/4.18.1&quot;&gt;https://github.com/craftcms/cms/releases/tag/4.18.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/5.10.3&quot;&gt;https://github.com/craftcms/cms/releases/tag/5.10.3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vuldb.com/cve/CVE-2026-14793&quot; rel=&quot;nofollow&quot;&gt;https://vuldb.com/cve/CVE-2026-14793&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vuldb.com/submit/850792&quot; rel=&quot;nofollow&quot;&gt;https://vuldb.com/submit/850792&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vuldb.com/vuln/376387&quot; rel=&quot;nofollow&quot;&gt;https://vuldb.com/vuln/376387&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-9p7c-v5x3-rfx8</link><guid isPermaLink="false">https://github.com/advisories/GHSA-9p7c-v5x3-rfx8</guid><pubDate>Thu, 06 Aug 2026 20:55:48 GMT</pubDate></item><item><title>Craft CMS: Authenticated RCE via `condition.config` JSON cleanse bypass</title><description>&lt;p&gt;Craft CMS has an authenticated remote code execution issue in the control panel element-search condition handling.&lt;/p&gt;
&lt;p&gt;Craft cleans the outer request-controlled condition array with &lt;code class=&quot;notranslate&quot;&gt;Component::cleanseConfig()&lt;/code&gt;, but &lt;code class=&quot;notranslate&quot;&gt;Conditions::createCondition()&lt;/code&gt; later decodes and merges the JSON string in &lt;code class=&quot;notranslate&quot;&gt;condition.config&lt;/code&gt; without re-running &lt;code class=&quot;notranslate&quot;&gt;cleanseConfig()&lt;/code&gt; on the decoded/merged configuration.&lt;/p&gt;
&lt;p&gt;Because &lt;code class=&quot;notranslate&quot;&gt;condition.config&lt;/code&gt; is a JSON string during the first cleanse, Yii special config keys such as &lt;code class=&quot;notranslate&quot;&gt;as&lt;/code&gt; ... and &lt;code class=&quot;notranslate&quot;&gt;on&lt;/code&gt; ... can be hidden inside it. After JSON decoding, those keys reach FieldLayout object creation and are interpreted by Yii as behavior/event configuration.&lt;/p&gt;
&lt;p&gt;The RCE is semi-blind: the trigger endpoint returns a normal JSON response, and the command output is verified via a server-side file-write side effect retrieved in a subsequent request.&lt;/p&gt;
&lt;h2&gt;Preconditions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The attacker needs an authenticated Craft control panel session.&lt;/li&gt;
&lt;li&gt;A valid CSRF token is required.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Impact&lt;/h2&gt;
&lt;p&gt;An authenticated control panel user can inject Yii behavior/event configuration after Craft’s intended config cleanse boundary. In the confirmed local lab, this led to command execution as the PHP/web user.&lt;/p&gt;
&lt;p&gt;Potential attacker impact:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Execute operating system commands as the PHP/web user.&lt;/li&gt;
&lt;li&gt;Read Craft secrets, environment variables, and application configuration.&lt;/li&gt;
&lt;li&gt;Access database credentials and stored site content.&lt;/li&gt;
&lt;li&gt;Modify site content, users, and application state.&lt;/li&gt;
&lt;li&gt;Pivot to internal services reachable from the Craft host or container.&lt;/li&gt;
&lt;li&gt;Cause denial of service or establish persistence depending on deployment permissions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-265m-7826-wjqm&quot; href=&quot;https://github.com/craftcms/cms/security/advisories/GHSA-265m-7826-wjqm&quot;&gt;GHSA-265m-7826-wjqm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/353b5d676c88a854c9f6409ad83b837ca0c0e8da/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/353b5d676c88a854c9f6409ad83b837ca0c0e8da&quot;&gt;craftcms/cms@&lt;tt&gt;353b5d6&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/craftcms/cms/commit/789789dc9e2a4e2f2562f51aaf879fb7757d8340/hovercard&quot; href=&quot;https://github.com/craftcms/cms/commit/789789dc9e2a4e2f2562f51aaf879fb7757d8340&quot;&gt;craftcms/cms@&lt;tt&gt;789789d&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/4.18.2&quot;&gt;https://github.com/craftcms/cms/releases/tag/4.18.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/craftcms/cms/releases/tag/5.10.6&quot;&gt;https://github.com/craftcms/cms/releases/tag/5.10.6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-265m-7826-wjqm</link><guid isPermaLink="false">https://github.com/advisories/GHSA-265m-7826-wjqm</guid><pubDate>Thu, 06 Aug 2026 20:45:00 GMT</pubDate></item><item><title>league/commonmark: Denial of service via deeply nested XML output</title><description>&lt;h3&gt;Impact&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;notranslate&quot;&gt;XmlRenderer&lt;/code&gt; pretty-prints XML by emitting depth-proportional indentation whitespace for &lt;strong&gt;every&lt;/strong&gt; opening and closing tag. For a tree of depth n, the indentation alone sums to &lt;strong&gt;O(n²)&lt;/strong&gt; bytes of output (and corresponding memory), reachable through &lt;code class=&quot;notranslate&quot;&gt;MarkdownToXmlConverter&lt;/code&gt; — e.g. &lt;code class=&quot;notranslate&quot;&gt;str_repeat(&#39;&amp;gt; &#39;, $depth) . &quot;x\n&quot;&lt;/code&gt;, a single line of nested blockquotes — or through a direct &lt;code class=&quot;notranslate&quot;&gt;XmlRenderer::renderDocument()&lt;/code&gt; call on an attacker-influenced AST.&lt;/p&gt;
&lt;p&gt;This affects applications that convert untrusted Markdown to XML, which is an &lt;strong&gt;opt-in&lt;/strong&gt; output path. The parser&#39;s &lt;code class=&quot;notranslate&quot;&gt;max_nesting_level&lt;/code&gt; bounds the depth of &lt;em&gt;parser-created&lt;/em&gt; trees, but its default is high enough to reach damaging sizes, can be raised by the host application, and does not constrain custom or programmatically built ASTs handed straight to the renderer. The result is a memory / output-size amplification rather than a hard crash, which is why this issue is rated &lt;strong&gt;Medium&lt;/strong&gt; rather than High. No confidentiality or integrity impact. XML rendering was introduced in 2.0.0 (first shipped in 2.0.0-beta1, June 2021) and has emitted depth-proportional indentation ever since, so all 2.x releases are affected (verified against 2.8.x, clean upstream &lt;code class=&quot;notranslate&quot;&gt;1902f60f&lt;/code&gt;). 1.x has no XML renderer and is not affected.&lt;/p&gt;
&lt;h3&gt;Workarounds&lt;/h3&gt;
&lt;p&gt;Applications converting untrusted Markdown to XML should:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lower &lt;code class=&quot;notranslate&quot;&gt;max_nesting_level&lt;/code&gt;&lt;/strong&gt; to a conservative value appropriate to expected content, so the parser refuses to build extremely deep trees. This is the most direct lever for parser-produced ASTs, but does not protect trees built programmatically and passed straight to &lt;code class=&quot;notranslate&quot;&gt;XmlRenderer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cap input size before conversion&lt;/strong&gt;, since the amplification is driven by input-proportional depth.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Constrain XML consumers&lt;/strong&gt; with memory / output-size limits (and streaming or size caps on any downstream XML parser or storage) so one request cannot allocate unbounded output.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prefer HTML rendering&lt;/strong&gt; for untrusted content where XML is not strictly required — the HTML renderer does not emit depth-proportional indentation and is not subject to this amplification.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-mj63-m3rc-8ppr&quot; href=&quot;https://github.com/thephpleague/commonmark/security/advisories/GHSA-mj63-m3rc-8ppr&quot;&gt;GHSA-mj63-m3rc-8ppr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/thephpleague/commonmark/commit/b5ac8c3947ca81844e85a09c7e0a5b4148bde2e1/hovercard&quot; href=&quot;https://github.com/thephpleague/commonmark/commit/b5ac8c3947ca81844e85a09c7e0a5b4148bde2e1&quot;&gt;thephpleague/commonmark@&lt;tt&gt;b5ac8c3&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&quot;&gt;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-mj63-m3rc-8ppr</link><guid isPermaLink="false">https://github.com/advisories/GHSA-mj63-m3rc-8ppr</guid><pubDate>Thu, 06 Aug 2026 20:42:54 GMT</pubDate></item><item><title>league/commonmark: Denial of service via colliding heading slugs</title><description>&lt;h3&gt;Impact&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;notranslate&quot;&gt;UniqueSlugNormalizer::normalize()&lt;/code&gt; makes each slug document-unique by searching for an unused numeric suffix, but &lt;strong&gt;restarts that search from &lt;code class=&quot;notranslate&quot;&gt;1&lt;/code&gt; on every collision&lt;/strong&gt;. The k-th heading that collapses to the same base slug performs k−1 array lookups, so K colliding slugs cost Σ(k−1) = &lt;strong&gt;O(K²)&lt;/strong&gt;. An attacker can force every heading onto a single base slug trivially — many empty ATX headings, identical heading text, or punctuation-only headings that normalize to the empty string.&lt;/p&gt;
&lt;p&gt;The path is reached whenever the shared slug normalizer runs over attacker-controlled text. That happens when &lt;code class=&quot;notranslate&quot;&gt;HeadingPermalinkExtension&lt;/code&gt; is registered (its &lt;code class=&quot;notranslate&quot;&gt;HeadingPermalinkProcessor&lt;/code&gt; normalizes every heading), independently through &lt;code class=&quot;notranslate&quot;&gt;FootnoteExtension&lt;/code&gt; (its &lt;code class=&quot;notranslate&quot;&gt;AnonymousFootnoteRefParser&lt;/code&gt; normalizes every &lt;code class=&quot;notranslate&quot;&gt;^[label]&lt;/code&gt; reference), and on any &lt;code class=&quot;notranslate&quot;&gt;TableOfContentsExtension&lt;/code&gt; site (which requires &lt;code class=&quot;notranslate&quot;&gt;HeadingPermalinkExtension&lt;/code&gt; to be co-registered). The default &lt;code class=&quot;notranslate&quot;&gt;slug_normalizer/unique&lt;/code&gt; setting (&lt;code class=&quot;notranslate&quot;&gt;UniqueSlugNormalizerInterface::PER_DOCUMENT&lt;/code&gt;) accumulates collisions across the whole document. No authentication is required — a small document body turns into seconds of CPU and denies service. Availability impact only. &lt;strong&gt;&lt;code class=&quot;notranslate&quot;&gt;UniqueSlugNormalizer&lt;/code&gt; was introduced in 2.0.0 (first shipped in 2.0.0-beta1, May 2021); the 1.x heading-permalink slug generator performed no de-duplication and is not affected. All 2.x releases (including 2.8.x) are affected.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Workarounds&lt;/h3&gt;
&lt;p&gt;Integrators who cannot upgrade immediately can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Set &lt;code class=&quot;notranslate&quot;&gt;slug_normalizer/unique&lt;/code&gt; to &lt;code class=&quot;notranslate&quot;&gt;false&lt;/code&gt; / &lt;code class=&quot;notranslate&quot;&gt;UniqueSlugNormalizerInterface::DISABLED&lt;/code&gt;&lt;/strong&gt;, which stops the de-duplication scan entirely — at the cost of losing id uniqueness (colliding headings then share an anchor).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disable &lt;code class=&quot;notranslate&quot;&gt;HeadingPermalinkExtension&lt;/code&gt;&lt;/strong&gt; (and &lt;code class=&quot;notranslate&quot;&gt;TableOfContentsExtension&lt;/code&gt;, which depends on it), and &lt;code class=&quot;notranslate&quot;&gt;FootnoteExtension&lt;/code&gt; where anonymous footnotes reach the same normalizer, for untrusted Markdown.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cap the accepted document size / heading count upstream&lt;/strong&gt; so K cannot reach the quadratic danger zone.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these trades off functionality or correctness; upgrading to the patched release (which removes the quadratic behavior while keeping unique ids and identical output) is the recommended remediation.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-mh25-x5hq-wrqp&quot; href=&quot;https://github.com/thephpleague/commonmark/security/advisories/GHSA-mh25-x5hq-wrqp&quot;&gt;GHSA-mh25-x5hq-wrqp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&quot;&gt;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-mh25-x5hq-wrqp</link><guid isPermaLink="false">https://github.com/advisories/GHSA-mh25-x5hq-wrqp</guid><pubDate>Thu, 06 Aug 2026 20:41:45 GMT</pubDate></item><item><title>league/commonmark: Denial of service via duplicate footnote definitions</title><description>&lt;h3&gt;Impact&lt;/h3&gt;
&lt;p&gt;The Footnote extension records one backref per footnote &lt;em&gt;reference&lt;/em&gt; and then appends the &lt;strong&gt;entire&lt;/strong&gt; backref list for &lt;strong&gt;every&lt;/strong&gt; footnote &lt;em&gt;definition&lt;/em&gt; block in the document, without ever de-duplicating or removing repeated definitions of the same label (&lt;code class=&quot;notranslate&quot;&gt;GatherFootnotesListener&lt;/code&gt;, populated by &lt;code class=&quot;notranslate&quot;&gt;NumberFootnotesListener&lt;/code&gt;). A document that references a single label N times and also supplies N duplicate &lt;code class=&quot;notranslate&quot;&gt;[^a]:&lt;/code&gt; definitions of that label therefore produces &lt;strong&gt;N × N&lt;/strong&gt; &lt;code class=&quot;notranslate&quot;&gt;FootnoteBackref&lt;/code&gt; nodes, so output size, parse time, and peak memory are all &lt;strong&gt;O(N²)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Reaching the vulnerable path requires &lt;code class=&quot;notranslate&quot;&gt;FootnoteExtension&lt;/code&gt; to be registered on the &lt;code class=&quot;notranslate&quot;&gt;Environment&lt;/code&gt;. This is opt-in, but is a commonly enabled GFM-style feature; no other non-default configuration is required. An unauthenticated attacker can expand a &lt;strong&gt;~10 KB&lt;/strong&gt; request into a &lt;strong&gt;~62 MB&lt;/strong&gt; HTML response, &lt;strong&gt;~3 s&lt;/strong&gt; of CPU, and &lt;strong&gt;~440 MB&lt;/strong&gt; of peak memory — enough to OOM-kill a default 128 MB PHP worker and deny service. Availability impact only; no confidentiality or integrity effect. &lt;strong&gt;The Footnote extension was introduced in 1.5.0 (May 2020) with this backref logic present from the first commit, so all releases from 1.5.0 onward (including every 2.x through 2.8.x) are affected.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Workarounds&lt;/h3&gt;
&lt;p&gt;There is no library-level option to cap the number of footnotes, references, or definitions, so no configuration switch prevents the amplification. Integrators who cannot upgrade should:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Disable the Footnote extension&lt;/strong&gt; for untrusted input, or&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enforce a strict input-size limit before conversion&lt;/strong&gt; — but note this is a weak control here, since the ~10 KB payload that already triggers the 62 MB / ~440 MB blowup is well within typical request-body limits, so any cap must be aggressively small to help.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Upgrading to the patched release is the recommended remediation.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-jfm3-95jq-q3rf&quot; href=&quot;https://github.com/thephpleague/commonmark/security/advisories/GHSA-jfm3-95jq-q3rf&quot;&gt;GHSA-jfm3-95jq-q3rf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/thephpleague/commonmark/commit/66028124a17ba193da7b11cc3dfda92df21bfbf4/hovercard&quot; href=&quot;https://github.com/thephpleague/commonmark/commit/66028124a17ba193da7b11cc3dfda92df21bfbf4&quot;&gt;thephpleague/commonmark@&lt;tt&gt;6602812&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&quot;&gt;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-jfm3-95jq-q3rf</link><guid isPermaLink="false">https://github.com/advisories/GHSA-jfm3-95jq-q3rf</guid><pubDate>Thu, 06 Aug 2026 20:40:53 GMT</pubDate></item><item><title>league/commonmark: Denial of service via adjacent inline attribute blocks</title><description>&lt;h3&gt;Impact&lt;/h3&gt;
&lt;p&gt;With the Attributes extension enabled, &lt;code class=&quot;notranslate&quot;&gt;AttributesListener::findTargetAndDirection()&lt;/code&gt; resolves each attribute node&#39;s target by walking outward through its siblings. For a run of N adjacent inline attribute blocks placed at the start of a block (with nothing to their left), each node scans the &lt;strong&gt;entire&lt;/strong&gt; sibling list to the far-right end before giving up and falling back to the parent. Each resolution is therefore Θ(N) and the whole run is &lt;strong&gt;Θ(N²)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Reaching the path requires &lt;code class=&quot;notranslate&quot;&gt;AttributesExtension&lt;/code&gt; (opt-in, but first-party: &lt;code class=&quot;notranslate&quot;&gt;League\CommonMark\Extension\Attributes\AttributesExtension&lt;/code&gt;). No other configuration matters — the quadratic walk runs unconditionally during parsing and is &lt;strong&gt;not&lt;/strong&gt; gated by the &lt;code class=&quot;notranslate&quot;&gt;attributes/allow&lt;/code&gt; allow-list, the &lt;code class=&quot;notranslate&quot;&gt;on*&lt;/code&gt; hardening added in 2.7.0, or &lt;code class=&quot;notranslate&quot;&gt;allow_unsafe_links&lt;/code&gt;. An unauthenticated attacker can submit a &lt;strong&gt;~32 KB&lt;/strong&gt; input (&lt;code class=&quot;notranslate&quot;&gt;{#a}&lt;/code&gt; repeated 8,000 times) that takes &lt;strong&gt;over 5 seconds&lt;/strong&gt; to convert, with time growing quadratically in input length — a cheap denial of service. Availability impact only. &lt;strong&gt;The Attributes extension was introduced in 1.5.0 (May 2020) with this outward-walk resolver present from the first commit, so all releases from 1.5.0 onward (including every 2.x) are affected.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Workarounds&lt;/h3&gt;
&lt;p&gt;There is no library-level configuration that gates the quadratic walk. Integrators who cannot upgrade can only reduce exposure indirectly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Disable the Attributes extension&lt;/strong&gt; for untrusted input, or&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Impose a strict maximum input length before conversion&lt;/strong&gt; — noting that because the cost is quadratic, even a modest cap must be small to meaningfully bound worst-case CPU.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Upgrading to a release containing the fix is recommended.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-g2gp-3wwq-f4ph&quot; href=&quot;https://github.com/thephpleague/commonmark/security/advisories/GHSA-g2gp-3wwq-f4ph&quot;&gt;GHSA-g2gp-3wwq-f4ph&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/thephpleague/commonmark/commit/2d4c0fafa62501be919262064cffa6d71687430b/hovercard&quot; href=&quot;https://github.com/thephpleague/commonmark/commit/2d4c0fafa62501be919262064cffa6d71687430b&quot;&gt;thephpleague/commonmark@&lt;tt&gt;2d4c0fa&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&quot;&gt;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-g2gp-3wwq-f4ph</link><guid isPermaLink="false">https://github.com/advisories/GHSA-g2gp-3wwq-f4ph</guid><pubDate>Thu, 06 Aug 2026 20:39:52 GMT</pubDate></item><item><title>league/commonmark: Quadratic-time denial of service when parsing crafted Markdown</title><description>&lt;h3&gt;Impact&lt;/h3&gt;
&lt;p&gt;Affected versions of &lt;code class=&quot;notranslate&quot;&gt;league/commonmark&lt;/code&gt; can have quadratic time complexity when parsing specially crafted Markdown lines. In practical terms, doubling the length of an affected line can make the parser perform roughly four times as much work. The parser identifies locations using character positions, but regular-expression matches report byte positions. These positions differ when a UTF-8 character uses more than one byte. Several parsing paths repeatedly rescan growing portions of the line to translate between the two positions. The Autolink extension can also copy and validate the remaining line at every URL-like prefix.&lt;/p&gt;
&lt;p&gt;In current 2.x releases, a single non-ASCII character anywhere on a line can place that whole line on the slower multibyte path. An attacker can combine it with a long run of leading whitespace or repeated Markdown punctuation, causing increasingly large rescans. When the Autolink extension is enabled, repeated URL-like prefixes provide another trigger, even on ASCII-only lines. Each trigger fits within one long line, so complex Markdown structure is unnecessary.&lt;/p&gt;
&lt;p&gt;An attacker who can submit Markdown for conversion can use a comparatively small request to consume disproportionate CPU time and allocation activity. Repeated or concurrent requests can occupy all available PHP workers and prevent legitimate requests from completing. The core paths affect &lt;code class=&quot;notranslate&quot;&gt;CommonMarkConverter&lt;/code&gt;, &lt;code class=&quot;notranslate&quot;&gt;GithubFlavoredMarkdownConverter&lt;/code&gt;, and custom environments. The autolink-specific path affects applications using &lt;code class=&quot;notranslate&quot;&gt;AutolinkExtension&lt;/code&gt; or &lt;code class=&quot;notranslate&quot;&gt;GithubFlavoredMarkdownExtension&lt;/code&gt;. Applications that process only trusted Markdown are not remotely exploitable. The impact is limited to availability: it does not disclose data, change rendered output, or bypass rendering restrictions. Settings such as &lt;code class=&quot;notranslate&quot;&gt;html_input&lt;/code&gt; and &lt;code class=&quot;notranslate&quot;&gt;allow_unsafe_links&lt;/code&gt; do not mitigate the issue because the expensive work occurs before rendering.&lt;/p&gt;
&lt;h3&gt;Patches&lt;/h3&gt;
&lt;p&gt;The issue is patched in &lt;code class=&quot;notranslate&quot;&gt;2.9.0&lt;/code&gt; and later. Starting in that release, the parser records UTF-8 character-to-byte positions incrementally, converts ordered regular-expression match positions without restarting from the beginning of the line, and matches autolinks against the original line instead of copying every remaining suffix. The affected work then grows in direct proportion to the input size while preserving existing Markdown output and configuration behavior. Versions from &lt;code class=&quot;notranslate&quot;&gt;0.6.0&lt;/code&gt; through &lt;code class=&quot;notranslate&quot;&gt;2.8.3&lt;/code&gt; are affected. The 0.x and 1.x release lines are no longer supported, so their users must upgrade to &lt;code class=&quot;notranslate&quot;&gt;2.9.0&lt;/code&gt; or later.&lt;/p&gt;
&lt;h3&gt;Workarounds&lt;/h3&gt;
&lt;p&gt;If you cannot upgrade immediately, reject or truncate inputs with excessively long individual lines before passing them to the converter. A total request-size limit is also useful, but a per-line limit is important because every demonstrated trigger fits on one line. Choose limits appropriate for the application and enforce them before Markdown parsing begins. Restricting conversion to trusted users, applying strict execution-time limits, rate-limiting requests, and limiting concurrent conversions can further reduce exposure, but these measures are not complete substitutes for upgrading.&lt;/p&gt;
&lt;p&gt;Disabling &lt;code class=&quot;notranslate&quot;&gt;AutolinkExtension&lt;/code&gt; and avoiding &lt;code class=&quot;notranslate&quot;&gt;GithubFlavoredMarkdownExtension&lt;/code&gt; removes the autolink-specific trigger, but the core multibyte parsing paths remain reachable in the standard parser. Existing nesting, delimiter, raw-HTML, and unsafe-link configuration options do not eliminate all affected paths. Applications that must continue processing untrusted Markdown should therefore enforce input limits even when autolinking is disabled.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-2q4p-g7hv-5rgv&quot; href=&quot;https://github.com/thephpleague/commonmark/security/advisories/GHSA-2q4p-g7hv-5rgv&quot;&gt;GHSA-2q4p-g7hv-5rgv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/thephpleague/commonmark/commit/a6ef6cdc308dfa39a34239c35818e75892a0e6a8/hovercard&quot; href=&quot;https://github.com/thephpleague/commonmark/commit/a6ef6cdc308dfa39a34239c35818e75892a0e6a8&quot;&gt;thephpleague/commonmark@&lt;tt&gt;a6ef6cd&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/thephpleague/commonmark/commit/a70979ea0d7d3377bd7127536748454a922bf5eb/hovercard&quot; href=&quot;https://github.com/thephpleague/commonmark/commit/a70979ea0d7d3377bd7127536748454a922bf5eb&quot;&gt;thephpleague/commonmark@&lt;tt&gt;a70979e&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/thephpleague/commonmark/commit/c97b02e5e652b992033b93ba5d6182f706343fc6/hovercard&quot; href=&quot;https://github.com/thephpleague/commonmark/commit/c97b02e5e652b992033b93ba5d6182f706343fc6&quot;&gt;thephpleague/commonmark@&lt;tt&gt;c97b02e&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&quot;&gt;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-2q4p-g7hv-5rgv</link><guid isPermaLink="false">https://github.com/advisories/GHSA-2q4p-g7hv-5rgv</guid><pubDate>Thu, 06 Aug 2026 20:37:20 GMT</pubDate></item><item><title>league/commonmark: AttributesExtension href/src unsafe-link filter bypass via embedded control bytes</title><description>&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;The &lt;code class=&quot;notranslate&quot;&gt;AttributesExtension&lt;/code&gt;&#39;s &lt;code class=&quot;notranslate&quot;&gt;href&lt;/code&gt;/&lt;code class=&quot;notranslate&quot;&gt;src&lt;/code&gt; unsafe-link filter (&lt;code class=&quot;notranslate&quot;&gt;AttributesHelper::filterAttributes()&lt;/code&gt;) can be bypassed by embedding control bytes in a &lt;code class=&quot;notranslate&quot;&gt;javascript:&lt;/code&gt; URL that browsers discard before parsing the scheme. Two variants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tab/newline inside the scheme&lt;/strong&gt; — a literal ASCII TAB (0x09), CR (0x0D), or LF (0x0A), e.g. &lt;code class=&quot;notranslate&quot;&gt;java&amp;lt;TAB&amp;gt;script:alert(1)&lt;/code&gt;. Per the WHATWG URL Standard&#39;s &quot;basic URL parser&quot; step 3, browsers &quot;remove all ASCII tab or newline from input&quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leading C0 controls&lt;/strong&gt; — e.g. &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;0x01&amp;gt;javascript:alert(1)&lt;/code&gt;. Per step 1 of the same algorithm, browsers remove any leading or trailing C0 control or space. (A leading &lt;em&gt;space&lt;/em&gt; alone does not bypass, because &lt;code class=&quot;notranslate&quot;&gt;parseAttributes()&lt;/code&gt; already &lt;code class=&quot;notranslate&quot;&gt;trim()&lt;/code&gt;s the value; other C0 bytes are not trimmed.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The filter is a literal anchored-prefix regex (&lt;code class=&quot;notranslate&quot;&gt;RegexHelper::isLinkPotentiallyUnsafe()&lt;/code&gt; / &lt;code class=&quot;notranslate&quot;&gt;REGEX_UNSAFE_PROTOCOL&lt;/code&gt;) that matches neither obfuscated form, so in both cases the browser still executes &lt;code class=&quot;notranslate&quot;&gt;javascript:alert(1)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is confirmed reproducible even with &lt;code class=&quot;notranslate&quot;&gt;allow_unsafe_links =&amp;gt; false&lt;/code&gt; set&lt;/strong&gt; — i.e. even applications that have followed the library&#39;s own documented hardening guidance for untrusted input remain exploitable.&lt;/p&gt;
&lt;p&gt;This is a &lt;em&gt;sibling gap&lt;/em&gt; in the same defense that &lt;a title=&quot;CVE-2025-46734&quot; data-hovercard-type=&quot;advisory&quot; data-hovercard-url=&quot;/advisories/GHSA-3527-qv2q-pfvx/hovercard&quot; href=&quot;https://github.com/advisories/GHSA-3527-qv2q-pfvx&quot;&gt;CVE-2025-46734&lt;/a&gt; (&lt;a title=&quot;GHSA-3527-qv2q-pfvx&quot; data-hovercard-type=&quot;advisory&quot; data-hovercard-url=&quot;/advisories/GHSA-3527-qv2q-pfvx/hovercard&quot; href=&quot;https://github.com/advisories/GHSA-3527-qv2q-pfvx&quot;&gt;GHSA-3527-qv2q-pfvx&lt;/a&gt;) fixed in v2.7.0 — that fix made &lt;code class=&quot;notranslate&quot;&gt;href&lt;/code&gt;/&lt;code class=&quot;notranslate&quot;&gt;src&lt;/code&gt; respect &lt;code class=&quot;notranslate&quot;&gt;allow_unsafe_links&lt;/code&gt;, but did not normalize control bytes before checking, so these obfuscation techniques were never covered.&lt;/p&gt;
&lt;h2&gt;Vulnerability&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Files&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;src/Util/RegexHelper.php:69&lt;/code&gt; (&lt;code class=&quot;notranslate&quot;&gt;REGEX_UNSAFE_PROTOCOL&lt;/code&gt;), &lt;code class=&quot;notranslate&quot;&gt;:239-242&lt;/code&gt; (&lt;code class=&quot;notranslate&quot;&gt;isLinkPotentiallyUnsafe()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;src/Extension/Attributes/Util/AttributesHelper.php:149-179&lt;/code&gt; (&lt;code class=&quot;notranslate&quot;&gt;filterAttributes()&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;CWE&lt;/strong&gt;: CWE-79 (Improper Neutralization of Input During Web Page Generation / XSS) — primary&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CWE-692 (Incomplete Denylist to Cross-Site Scripting) — the anchored-prefix denylist in &lt;code class=&quot;notranslate&quot;&gt;REGEX_UNSAFE_PROTOCOL&lt;/code&gt; is incomplete. This is a composite of CWE-184 and CWE-79, so it captures the full &quot;incomplete denylist → XSS&quot; chain on its own.&lt;/li&gt;
&lt;li&gt;CWE-86 (Improper Neutralization of Invalid Characters in Identifiers in Web Pages) — the specific evasion technique: control bytes embedded within the URI scheme identifier, which the browser strips before resolving it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Root Cause&lt;/h3&gt;
&lt;div class=&quot;highlight highlight-text-html-php&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// src/Util/RegexHelper.php&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;REGEX_UNSAFE_PROTOCOL&lt;/span&gt; = &lt;span class=&quot;pl-s&quot;&gt;&#39;&lt;span class=&quot;pl-s&quot;&gt;/^(?:javascript|vbscript|file|data):/i&lt;/span&gt;&#39;&lt;/span&gt;;

&lt;span class=&quot;pl-k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;isLinkPotentiallyUnsafe&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;url&lt;/span&gt;): &lt;span class=&quot;pl-smi&quot;&gt;bool&lt;/span&gt;
{
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;\preg_match&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;self&lt;/span&gt;::&lt;span class=&quot;pl-c1&quot;&gt;REGEX_UNSAFE_PROTOCOL&lt;/span&gt;, &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;url&lt;/span&gt;) !== &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class=&quot;pl-en&quot;&gt;\preg_match&lt;/span&gt;(&lt;span class=&quot;pl-smi&quot;&gt;self&lt;/span&gt;::&lt;span class=&quot;pl-c1&quot;&gt;REGEX_SAFE_DATA_PROTOCOL&lt;/span&gt;, &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;url&lt;/span&gt;) === &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;;
}

&lt;span class=&quot;pl-c&quot;&gt;// src/Extension/Attributes/Util/AttributesHelper.php&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;attributes&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;value&lt;/span&gt;) {
    &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;attrNameLower&lt;/span&gt; = &lt;span class=&quot;pl-en&quot;&gt;\strtolower&lt;/span&gt;(&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;name&lt;/span&gt;);
    &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; (! &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;allowUnsafeLinks&lt;/span&gt; &amp;amp;&amp;amp; (&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;attrNameLower&lt;/span&gt; === &lt;span class=&quot;pl-s&quot;&gt;&#39;&lt;span class=&quot;pl-s&quot;&gt;href&lt;/span&gt;&#39;&lt;/span&gt; || &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;attrNameLower&lt;/span&gt; === &lt;span class=&quot;pl-s&quot;&gt;&#39;&lt;span class=&quot;pl-s&quot;&gt;src&lt;/span&gt;&#39;&lt;/span&gt;) &amp;amp;&amp;amp; &lt;span class=&quot;pl-en&quot;&gt;\is_string&lt;/span&gt;(&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;value&lt;/span&gt;) &amp;amp;&amp;amp; RegexHelper::&lt;span class=&quot;pl-en&quot;&gt;isLinkPotentiallyUnsafe&lt;/span&gt;(&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;value&lt;/span&gt;)) {
        unset(&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;attributes&lt;/span&gt;[&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;$&lt;/span&gt;name&lt;/span&gt;]);
        &lt;span class=&quot;pl-k&quot;&gt;continue&lt;/span&gt;;
    }
    &lt;span class=&quot;pl-c1&quot;&gt;.&lt;/span&gt;.&lt;span class=&quot;pl-c1&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Attributes extension&#39;s own quote-value grammar (&lt;code class=&quot;notranslate&quot;&gt;PARTIAL_DOUBLEQUOTEDVALUE = &#39;&quot;[^&quot;]*&quot;&#39;&lt;/code&gt;) accepts any byte except &lt;code class=&quot;notranslate&quot;&gt;&quot;&lt;/code&gt; inside quotes, including raw tab/CR/LF and other C0 controls, and &lt;code class=&quot;notranslate&quot;&gt;parseAttributes()&lt;/code&gt; only &lt;code class=&quot;notranslate&quot;&gt;trim()&lt;/code&gt;s (leading/trailing, and only the default charlist &lt;code class=&quot;notranslate&quot;&gt;&quot; \t\n\r\0\x0B&quot;&lt;/code&gt; — so a leading &lt;code class=&quot;notranslate&quot;&gt;\x01&lt;/code&gt; survives). Critically, &lt;strong&gt;the core Markdown link-destination path (&lt;code class=&quot;notranslate&quot;&gt;LinkParserHelper&lt;/code&gt; → &lt;code class=&quot;notranslate&quot;&gt;UrlEncoder::unescapeAndEncode()&lt;/code&gt;) percent-encodes every control byte before this same safety check ever runs — but the Attributes extension&#39;s &lt;code class=&quot;notranslate&quot;&gt;href&lt;/code&gt;/&lt;code class=&quot;notranslate&quot;&gt;src&lt;/code&gt; handling has no equivalent normalization step&lt;/strong&gt;, so the raw control byte reaches both the check and the final HTML output (&lt;code class=&quot;notranslate&quot;&gt;Xml::escape()&lt;/code&gt; only escapes &lt;code class=&quot;notranslate&quot;&gt;&amp;amp; &amp;lt; &amp;gt; &quot; &#39;&lt;/code&gt;, not tab/CR/LF, since they&#39;re legal bytes inside an HTML attribute).&lt;/p&gt;
&lt;h3&gt;Attack Scenario&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;An application enables the (commonly-used) &lt;code class=&quot;notranslate&quot;&gt;AttributesExtension&lt;/code&gt; and sets &lt;code class=&quot;notranslate&quot;&gt;allow_unsafe_links =&amp;gt; false&lt;/code&gt; — the project&#39;s own documented hardening step for untrusted input.&lt;/li&gt;
&lt;li&gt;An attacker submits Markdown: &lt;code class=&quot;notranslate&quot;&gt;[Click me](javascript:alert(0)){href=&quot;java&amp;lt;TAB&amp;gt;script:alert(document.cookie)&quot;}&lt;/code&gt; (TAB is one literal 0x09 byte).&lt;/li&gt;
&lt;li&gt;The library emits &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;a href=&quot;java&amp;lt;TAB&amp;gt;script:alert(document.cookie)&quot;&amp;gt;Click me&amp;lt;/a&amp;gt;&lt;/code&gt; — &lt;code class=&quot;notranslate&quot;&gt;isLinkPotentiallyUnsafe()&lt;/code&gt; doesn&#39;t match the tab-split scheme, so the filter takes no action.&lt;/li&gt;
&lt;li&gt;A victim viewing/clicking the link has the browser strip the embedded TAB and execute &lt;code class=&quot;notranslate&quot;&gt;javascript:alert(document.cookie)&lt;/code&gt; in the victim&#39;s session — stored XSS, cookie theft, account takeover potential.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Why the payload needs an unsafe core destination.&lt;/strong&gt; Step 2 above deliberately uses &lt;code class=&quot;notranslate&quot;&gt;[Click me](javascript:alert(0))&lt;/code&gt; rather than a normal link. &lt;code class=&quot;notranslate&quot;&gt;LinkRenderer&lt;/code&gt; overwrites &lt;code class=&quot;notranslate&quot;&gt;attrs[&#39;href&#39;]&lt;/code&gt; with the node&#39;s own URL &lt;em&gt;unless&lt;/em&gt; that URL is itself judged unsafe — so &lt;code class=&quot;notranslate&quot;&gt;[x](https://example.com){href=&quot;java&amp;lt;TAB&amp;gt;script:...&quot;}&lt;/code&gt; renders the harmless &lt;code class=&quot;notranslate&quot;&gt;href=&quot;https://example.com&quot;&lt;/code&gt;, and an empty destination &lt;code class=&quot;notranslate&quot;&gt;[x](){href=&quot;...&quot;}&lt;/code&gt; renders &lt;code class=&quot;notranslate&quot;&gt;href=&quot;&quot;&lt;/code&gt;. The attacker therefore supplies a core destination that the filter &lt;em&gt;does&lt;/em&gt; catch, which suppresses the overwrite and lets the attribute-supplied &lt;code class=&quot;notranslate&quot;&gt;href&lt;/code&gt; reach the final tag. This is no obstacle in practice — the attacker writes the entire Markdown document.&lt;/p&gt;
&lt;p&gt;Two related forms that are &lt;strong&gt;not&lt;/strong&gt; exploitable, noted so the fix isn&#39;t over-scoped:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attaching the attribute to a non-link block — &lt;code class=&quot;notranslate&quot;&gt;hi {href=&quot;java&amp;lt;TAB&amp;gt;script:alert(1)&quot;}&lt;/code&gt; — does bypass the filter and emits &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;p href=&quot;java&amp;lt;TAB&amp;gt;script:alert(1)&quot;&amp;gt;&lt;/code&gt;, but &lt;code class=&quot;notranslate&quot;&gt;href&lt;/code&gt; on a &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;p&amp;gt;&lt;/code&gt; is inert: there is nothing to navigate. (An earlier draft of this report described this as a &quot;simpler, unconditional variant&quot; of the attack; it is a filter bypass, not an XSS.)&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;&amp;lt;img src&amp;gt;&lt;/code&gt; is unaffected, since &lt;code class=&quot;notranslate&quot;&gt;ImageRenderer&lt;/code&gt; unconditionally overwrites &lt;code class=&quot;notranslate&quot;&gt;src&lt;/code&gt; from the core URL regardless of the safety verdict.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Recommended Fix&lt;/h3&gt;
&lt;p&gt;Normalize inside &lt;code class=&quot;notranslate&quot;&gt;RegexHelper::isLinkPotentiallyUnsafe()&lt;/code&gt; before testing, mirroring the WHATWG URL parser&#39;s own normalization. This covers both variants, fixes every call site at once (&lt;code class=&quot;notranslate&quot;&gt;LinkRenderer&lt;/code&gt;, &lt;code class=&quot;notranslate&quot;&gt;ImageRenderer&lt;/code&gt;, and any third-party callers), and needs no changes in the Attributes extension.&lt;/p&gt;
&lt;h2&gt;Affected Versions&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;notranslate&quot;&gt;&amp;gt;= 1.5.0, &amp;lt;= 2.8.3&lt;/code&gt;&lt;/strong&gt; - every release that ships the &lt;code class=&quot;notranslate&quot;&gt;AttributesExtension&lt;/code&gt;. Verified by installing each version and rendering the payloads with &lt;code class=&quot;notranslate&quot;&gt;allow_unsafe_links =&amp;gt; false&lt;/code&gt;. The attribute-value grammar (&lt;code class=&quot;notranslate&quot;&gt;PARTIAL_DOUBLEQUOTEDVALUE = &#39;&quot;[^&quot;]*&quot;&#39;&lt;/code&gt;) has accepted raw control bytes since the extension was introduced, and none of the intervening parser rewrites narrowed it.&lt;/p&gt;
&lt;h2&gt;Prior Related Advisories&lt;/h2&gt;
&lt;p&gt;&lt;a title=&quot;GHSA-3527-qv2q-pfvx&quot; data-hovercard-type=&quot;advisory&quot; data-hovercard-url=&quot;/advisories/GHSA-3527-qv2q-pfvx/hovercard&quot; href=&quot;https://github.com/advisories/GHSA-3527-qv2q-pfvx&quot;&gt;GHSA-3527-qv2q-pfvx&lt;/a&gt; / &lt;a title=&quot;CVE-2025-46734&quot; data-hovercard-type=&quot;advisory&quot; data-hovercard-url=&quot;/advisories/GHSA-3527-qv2q-pfvx/hovercard&quot; href=&quot;https://github.com/advisories/GHSA-3527-qv2q-pfvx&quot;&gt;CVE-2025-46734&lt;/a&gt; fixed a different Attributes-extension XSS (unallowlisted &lt;code class=&quot;notranslate&quot;&gt;on*&lt;/code&gt; handlers, &lt;code class=&quot;notranslate&quot;&gt;href&lt;/code&gt;/&lt;code class=&quot;notranslate&quot;&gt;src&lt;/code&gt; not respecting &lt;code class=&quot;notranslate&quot;&gt;allow_unsafe_links&lt;/code&gt; at all) in v2.7.0. This issue bypasses the specific &lt;code class=&quot;notranslate&quot;&gt;href&lt;/code&gt;/&lt;code class=&quot;notranslate&quot;&gt;src&lt;/code&gt; protection that fix introduced (the control-byte normalization gap was not part of that fix) - but the obfuscated inputs also work on older versions.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;GHSA-29pj-957v-52mc&quot; href=&quot;https://github.com/thephpleague/commonmark/security/advisories/GHSA-29pj-957v-52mc&quot;&gt;GHSA-29pj-957v-52mc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;commit-link&quot; data-hovercard-type=&quot;commit&quot; data-hovercard-url=&quot;https://github.com/thephpleague/commonmark/commit/493a5aa7d65754b73846006eaff9c2c4431a8e2c/hovercard&quot; href=&quot;https://github.com/thephpleague/commonmark/commit/493a5aa7d65754b73846006eaff9c2c4431a8e2c&quot;&gt;thephpleague/commonmark@&lt;tt&gt;493a5aa&lt;/tt&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&quot;&gt;https://github.com/thephpleague/commonmark/releases/tag/2.9.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
  </description><link>https://github.com/advisories/GHSA-29pj-957v-52mc</link><guid isPermaLink="false">https://github.com/advisories/GHSA-29pj-957v-52mc</guid><pubDate>Thu, 06 Aug 2026 20:30:39 GMT</pubDate></item></channel></rss>