From: CPANSec Security Scanner Bot Subject: [PATCH] HTML::Bare 0.04: bounds truncated fixed-advance lookahead (heap OOB read) Heap-buffer-overflow READ (CWE-125) in the hand-rolled C parser (parser.c), reached by the default HTML::Bare->new(text=>$html)->parse on untrusted markup. This is the 0.04 (upstream git, nanoscopic/perl-HTML-Bare) port of the same fix carried by CVE-2026-57073-r1.patch against the 0.02 CPAN release. The defect is unchanged between 0.02 and 0.04. parser.c only grew (self-close now consults the tag lookup and an outside_all exit), which shifts the line numbers so the 0.02 patch does not apply. Several transitions advance `cpos` by a fixed amount past a recognised token without checking the buffer end, then dereference the new position: - the `` follows the `/`, so a truncated tail such as `

` when `*(cpos+1)` is non-NUL. Both changes are behaviour-preserving for well-formed input — real CDATA always carries the `[`, and a non-truncated self-close always has a byte after the `/`; they differ only on the truncated-tail case that previously overran the allocation. Only the default `parserc_parse` is patched; the opt-in `parserc_parse_unsafely` is left as-is by design. --- a/parser.c +++ b/parser.c @@ -281,7 +281,8 @@ int parserc_parse( struct parserc *self, char *htmlin ) { *(cpos+4) == 'D' && *(cpos+5) == 'A' && *(cpos+6) == 'T' && - *(cpos+7) == 'A' ) { + *(cpos+7) == 'A' && + *(cpos+8) == '[' ) { // require full "type = 1; goto cdata; @@ -477,7 +478,7 @@ int parserc_parse( struct parserc *self, char *htmlin ) { temp = nodec_addchildr( curnode, tagname, tagname_len ); temp->z = cpos +1 - htmlin; tagname_len = 0; - cpos+=2; + if( *(cpos+1) ) cpos += 2; else cpos++; // skip assumed '>' only if not the NUL terminator if( curnode == root ) goto outside_all; goto val_1; } @@ -514,7 +515,7 @@ int parserc_parse( struct parserc *self, char *htmlin ) { curname = del_namec( curname ); curnode = curnode->parent; if( !curnode ) goto done; - cpos+=2; // am assuming next char is > + if( *(cpos+1) ) cpos += 2; else cpos++; // was: assume next char is > (skip past NUL on truncated tail) if( curnode == root ) goto outside_all; goto val_1; case '=': @@ -573,7 +574,7 @@ int parserc_parse( struct parserc *self, char *htmlin ) { curname = del_namec( curname ); curnode = curnode->parent; if( !curnode ) goto done; - cpos += 2; + if( *(cpos+1) ) cpos += 2; else cpos++; // "/> assumed" — skip '>' only if present, not the NUL if( curnode == root ) goto outside_all; goto val_1; case ' ':