<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="/static/style.xsl" type="text/xsl"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  <channel>
    <title>Most recent entries from all</title>
    <link>https://vulnerability.circl.lu</link>
    <description>Contains only the most 10 recent entries.</description>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>python-feedgen</generator>
    <language>en</language>
    <lastBuildDate>Tue, 29 Sep 2026 05:38:55 +0000</lastBuildDate>
    <item>
      <title>CVE-2026-81722 — nltk PorterStemmer before 3.10.3 Quadratic-time DoS</title>
      <link>https://vulnerability.circl.lu/vuln/cve-2026-81722</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; nltk&lt;/p&gt;
&lt;p&gt;nltk PorterStemmer in versions &amp;lt;= 3.10.2 (fixed in 3.10.3) contains an inefficient-algorithmic-complexity denial of service in PorterStemmer.stem(). The _is_consonant() helper walks backward over the entire run of trailing &amp;#39;y&amp;#39; characters on every call, and _measure() invokes it for each stem position, causing O(n^2) behavior. A single ~20-50 KB untrusted token consisting of a long run of the letter &amp;#39;y&amp;#39; followed by a matching suffix (e.g., &amp;#39;ness&amp;#39;) can pin a CPU core for seconds to minutes, causing availability impact.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; nltk&lt;/p&gt;
&lt;p&gt;nltk PorterStemmer in versions &amp;lt;= 3.10.2 (fixed in 3.10.3) contains an inefficient-algorithmic-complexity denial of service in PorterStemmer.stem(). The _is_consonant() helper walks backward over the entire run of trailing &amp;#39;y&amp;#39; characters on every call, and _measure() invokes it for each stem position, causing O(n^2) behavior. A single ~20-50 KB untrusted token consisting of a long run of the letter &amp;#39;y&amp;#39; followed by a matching suffix (e.g., &amp;#39;ness&amp;#39;) can pin a CPU core for seconds to minutes, causing availability impact.&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://vulnerability.circl.lu/vuln/cve-2026-81722</guid>
    </item>
    <item>
      <title>GHSA-ww6m-cw3f-q94g — NLTK: Quadratic-time DoS in PorterStemmer via long runs of 'y'</title>
      <link>https://vulnerability.circl.lu/vuln/ghsa-ww6m-cw3f-q94g</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; PyPI: nltk&lt;/p&gt;
&lt;p&gt;`nltk.stem.PorterStemmer.stem()` -- a ubiquitous public API applied to arbitrary, often untrusted, tokens -- runs in O(n^2) time on a token containing a long run of the letter &amp;#39;y&amp;#39;, letting a single ~20-50 KB token pin a CPU core (CWE-407).&lt;/p&gt;
&lt;p&gt;## Root cause&lt;/p&gt;
&lt;p&gt;`_is_consonant(word, i)` was made *iterative* (commit for #3633, GHSA/CWE-674) to fix an earlier unbounded-recursion `RecursionError` on `&amp;#39;y&amp;#39;*10000`. The iterative form walks *backward* over the whole run of &amp;#39;y&amp;#39;s on every call:&lt;/p&gt;
&lt;p&gt;```python
while i &amp;gt; 0 and word[i] == &amp;#39;y&amp;#39;:
    negate = not negate
    i -= 1
```&lt;/p&gt;
&lt;p&gt;`_measure()` then calls `_is_consonant(stem, i)` once for **every** position `i` of the stem. For a run of n &amp;#39;y&amp;#39;s that is sum_{i} O(i) = O(n^2). The recursion fix therefore traded a CWE-674 RecursionError for a CWE-407 quadratic-time DoS.&lt;/p&gt;
&lt;p&gt;## Proof of concept&lt;/p&gt;
&lt;p&gt;Measured (Python 3.13): `stem(&amp;#39;y&amp;#39;*5000 + &amp;#39;ness&amp;#39;)` = 2.6s, `stem(&amp;#39;y&amp;#39;*10000 + &amp;#39;ness&amp;#39;)` = 11.3s (2x input -&amp;gt; ~4.3x time = quadratic), `stem(&amp;#39;y&amp;#39;*20000 + &amp;#39;ness&amp;#39;)` &amp;gt; 20s. A pure run of &amp;#39;y&amp;#39; with no matching suffix is fast because the stemmer rules that call `_measure` do not fire; a real suffix such as &amp;#39;ness&amp;#39; triggers `_measure` on the long stem.&lt;/p&gt;
&lt;p&gt;```python
from nltk.stem import PorterStemmer
PorterStemmer().stem(&amp;#39;y&amp;#39; * 20000 + &amp;#39;ness&amp;#39;)   # &amp;gt;20s of CPU
```&lt;/p&gt;
&lt;p&gt;## Impact&lt;/p&gt;
&lt;p&gt;Stemming is routinely applied to untrusted text (search, indexing, NLP pipelines). A single unbroken ~20-50 KB token of &amp;#39;y&amp;#39; characters (no whitespace, so it survives tokenization) causes multi-second-to-minu…&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; PyPI: nltk&lt;/p&gt;
&lt;p&gt;`nltk.stem.PorterStemmer.stem()` -- a ubiquitous public API applied to arbitrary, often untrusted, tokens -- runs in O(n^2) time on a token containing a long run of the letter &amp;#39;y&amp;#39;, letting a single ~20-50 KB token pin a CPU core (CWE-407).&lt;/p&gt;
&lt;p&gt;## Root cause&lt;/p&gt;
&lt;p&gt;`_is_consonant(word, i)` was made *iterative* (commit for #3633, GHSA/CWE-674) to fix an earlier unbounded-recursion `RecursionError` on `&amp;#39;y&amp;#39;*10000`. The iterative form walks *backward* over the whole run of &amp;#39;y&amp;#39;s on every call:&lt;/p&gt;
&lt;p&gt;```python
while i &amp;gt; 0 and word[i] == &amp;#39;y&amp;#39;:
    negate = not negate
    i -= 1
```&lt;/p&gt;
&lt;p&gt;`_measure()` then calls `_is_consonant(stem, i)` once for **every** position `i` of the stem. For a run of n &amp;#39;y&amp;#39;s that is sum_{i} O(i) = O(n^2). The recursion fix therefore traded a CWE-674 RecursionError for a CWE-407 quadratic-time DoS.&lt;/p&gt;
&lt;p&gt;## Proof of concept&lt;/p&gt;
&lt;p&gt;Measured (Python 3.13): `stem(&amp;#39;y&amp;#39;*5000 + &amp;#39;ness&amp;#39;)` = 2.6s, `stem(&amp;#39;y&amp;#39;*10000 + &amp;#39;ness&amp;#39;)` = 11.3s (2x input -&amp;gt; ~4.3x time = quadratic), `stem(&amp;#39;y&amp;#39;*20000 + &amp;#39;ness&amp;#39;)` &amp;gt; 20s. A pure run of &amp;#39;y&amp;#39; with no matching suffix is fast because the stemmer rules that call `_measure` do not fire; a real suffix such as &amp;#39;ness&amp;#39; triggers `_measure` on the long stem.&lt;/p&gt;
&lt;p&gt;```python
from nltk.stem import PorterStemmer
PorterStemmer().stem(&amp;#39;y&amp;#39; * 20000 + &amp;#39;ness&amp;#39;)   # &amp;gt;20s of CPU
```&lt;/p&gt;
&lt;p&gt;## Impact&lt;/p&gt;
&lt;p&gt;Stemming is routinely applied to untrusted text (search, indexing, NLP pipelines). A single unbroken ~20-50 KB token of &amp;#39;y&amp;#39; characters (no whitespace, so it survives tokenization) causes multi-second-to-minu…&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://vulnerability.circl.lu/vuln/ghsa-ww6m-cw3f-q94g</guid>
    </item>
    <item>
      <title>PYSEC-2026-3738</title>
      <link>https://vulnerability.circl.lu/vuln/pysec-2026-3738</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; PyPI: nltk&lt;/p&gt;
&lt;p&gt;nltk PorterStemmer in versions &amp;lt;= 3.10.2 (fixed in 3.10.3) contains an inefficient-algorithmic-complexity denial of service in PorterStemmer.stem(). The _is_consonant() helper walks backward over the entire run of trailing &amp;#39;y&amp;#39; characters on every call, and _measure() invokes it for each stem position, causing O(n^2) behavior. A single ~20-50 KB untrusted token consisting of a long run of the letter &amp;#39;y&amp;#39; followed by a matching suffix (e.g., &amp;#39;ness&amp;#39;) can pin a CPU core for seconds to minutes, causing availability impact.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; PyPI: nltk&lt;/p&gt;
&lt;p&gt;nltk PorterStemmer in versions &amp;lt;= 3.10.2 (fixed in 3.10.3) contains an inefficient-algorithmic-complexity denial of service in PorterStemmer.stem(). The _is_consonant() helper walks backward over the entire run of trailing &amp;#39;y&amp;#39; characters on every call, and _measure() invokes it for each stem position, causing O(n^2) behavior. A single ~20-50 KB untrusted token consisting of a long run of the letter &amp;#39;y&amp;#39; followed by a matching suffix (e.g., &amp;#39;ness&amp;#39;) can pin a CPU core for seconds to minutes, causing availability impact.&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://vulnerability.circl.lu/vuln/pysec-2026-3738</guid>
    </item>
  </channel>
</rss>
