VYPR
High severity8.4NVD Advisory· Published Apr 29, 2026· Updated May 6, 2026

CVE-2026-7111

CVE-2026-7111

Description

Text::CSV_XS versions before 1.62 for Perl have a use-after-free when registered callbacks extend the Perl argument stack, which may enable type confusion or memory corruption.

The Parse, print, getline, and getline_all methods invoke registered callbacks (for example after_parse, before_print, or on_error) and cache the Perl argument stack pointer across the call. If a callback extends the argument stack enough to trigger a reallocation, the return value is written through the stale pointer into the freed buffer, and the caller reads the original $self argument as the return value instead.

Calling code that expects parsed data from getline_all receives the Text::CSV_XS object in its place, leading to logic errors or crashes. Text::CSV_XS objects used without any registered callbacks are not affected.

Affected products

2

Patches

1
c17f31a5f2bf

Fix possible stack corruption (thanks leont) (issue 67)

https://github.com/cpan-authors/Text-CSV_XSH.Merijn Brand - TuxApr 25, 2026via nvd-ref
4 files changed · +58 22
  • ChangeLog+1 0 modified
    @@ -1,5 +1,6 @@
     1.62	- 2026-04-25, H.Merijn Brand
         * It is 2026
    +    * Fix possible stack corruption (thanks leont) (issue 67)
     
     1.61	- 2025-07-26, H.Merijn Brand
         * Add love letter to CSV from xan project with reference
    
  • cpanfile+1 1 modified
    @@ -6,7 +6,7 @@ recommends "Encode"                   => "3.21";
     on "configure" => sub {
         requires   "ExtUtils::MakeMaker";
     
    -    recommends "ExtUtils::MakeMaker"      => "7.76";
    +    recommends "ExtUtils::MakeMaker"      => "7.78";
         };
     
     on "build" => sub {
    
  • CSV_XS.xs+18 18 modified
    @@ -122,6 +122,12 @@ static unsigned char ec, ebcdic2ascii[256] = {
     	croak ("self is not a hash ref");		\
         hv = (HV *)SvRV (self)
     
    +#define undef &PL_sv_undef
    +#define PUT_RETURN(x)	\
    +    SPAGAIN;		\
    +    ST (0) = x;		\
    +    XSRETURN (1)
    +
     /* Keep in sync with .pm! */
     #define CACHE_ID_quote_char		0
     #define CACHE_ID_escape_char		1
    @@ -2603,7 +2609,7 @@ BOOT:
         Perl_load_module (aTHX_ PERL_LOADMOD_NOIMPORT, newSVpvs ("IO::Handle"), NULL, NULL, NULL);
     
     void
    -SetDiag (SV *self, int xse, ...)
    +SetDiag (SV *self, int xse, SV *line = undef)
     
       PPCODE:
         HV		*hv;
    @@ -2619,8 +2625,8 @@ SetDiag (SV *self, int xse, ...)
     	ST (0) = sv_2mortal (SvDiag (xse));
     	}
     
    -    if (xse && items > 2 && SvPOK (ST (2))) {
    -	sv_setpvn (ST (0),  SvPVX (ST (2)), SvCUR (ST (2)));
    +    if (xse && SvPOK (line)) {
    +	sv_setpvn (ST (0),  SvPVX (line), SvCUR (line));
     	SvIOK_on  (ST (0));
     	}
     
    @@ -2670,8 +2676,8 @@ Parse (SV *self, SV *src, SV *fields, SV *fflags)
         av  = (AV *)SvRV (fields);
         avf = (AV *)SvRV (fflags);
     
    -    ST (0) = xsParse (self, hv, av, avf, src, 0) ? &PL_sv_yes : &PL_sv_no;
    -    XSRETURN (1);
    +    int x = xsParse (self, hv, av, avf, src, 0);
    +    PUT_RETURN (x ? &PL_sv_yes : &PL_sv_no);
         /* XS Parse */
     
     void
    @@ -2691,8 +2697,8 @@ print (SV *self, SV *io, SV *fields)
     	av = (AV *)SvRV (fields);
     	}
     
    -    ST (0) = xsCombine (self, hv, av, io, 1) ? &PL_sv_yes : &PL_sv_no;
    -    XSRETURN (1);
    +    int x = xsCombine (self, hv, av, io, 1);
    +    PUT_RETURN (x ? &PL_sv_yes : &PL_sv_no);
         /* XS print */
     
     void
    @@ -2706,26 +2712,20 @@ getline (SV *self, SV *io)
         CSV_XS_SELF;
         av  = newAV ();
         avf = newAV ();
    -    ST (0) = xsParse (self, hv, av, avf, io, 1)
    -	? sv_2mortal (newRV_noinc ((SV *)av))
    -	: &PL_sv_undef;
    -    XSRETURN (1);
    +    int x = xsParse (self, hv, av, avf, io, 1);
    +    PUT_RETURN (x ? sv_2mortal (newRV_noinc ((SV *)av)) : undef);
         /* XS getline */
     
     void
    -getline_all (SV *self, SV *io, ...)
    +getline_all (SV *self, SV *io, SV *offset = undef, SV *length = undef)
     
       PPCODE:
         HV	*hv;
    -    SV  *offset, *length;
     
         CSV_XS_SELF;
     
    -    offset = items > 2 ? ST (2) : &PL_sv_undef;
    -    length = items > 3 ? ST (3) : &PL_sv_undef;
    -
    -    ST (0) = xsParse_all (self, hv, io, offset, length);
    -    XSRETURN (1);
    +    SV *x  = xsParse_all (self, hv, io, offset, length);
    +    PUT_RETURN (x);
         /* XS getline_all */
     
     void
    
  • sandbox/issue-65.pl+38 3 modified
    @@ -6,7 +6,7 @@
     use 5.014002;
     use warnings;
     
    -our $VERSION = "0.02 - 20251124";
    +our $VERSION = "0.03 - 20260425";
     our $CMD = $0 =~ s{.*/}{}r;
     
     sub usage {
    @@ -25,8 +25,10 @@ sub usage {
         "v|verbose:1"	=> \(my $opt_v = 0),
         ) or usage (1);
     
    +my $x  = @ARGV ?
    +    $ARGV[-1] =~ m/^[0-9]+/ ? pop   @ARGV :
    +    $ARGV[ 0] =~ m/^[0-9]+/ ? shift @ARGV : 0 : 0;
     my $fn = shift // (-d "t" ? "sandbox/issue-65.csv" : "issue-65.csv");
    -my $x  = shift;
     
     say "Index";
     {   my $aoa = csv (
    @@ -35,18 +37,51 @@ sub usage {
     	);
         }
     
    -if ($x) {
    +if ($x == 1) {			# fix
         say "AP City";
         my $aoh = csv (
     	in      => $fn,
     	headers => "auto",
     	after_parse => sub { $_{Rndrng_Prvdr_City} eq "Chicago" or return \"skip" },
     	);
         }
    +elsif ($x == 2) {		# fix
    +    say "AP 1";
    +    my $aoh = csv (
    +	in      => $fn,
    +	headers => "auto",
    +	after_parse => sub { 1; },
    +	);
    +    }
    +elsif ($x == 3) {		# fix
    +    say "AP undef";
    +    my $aoh = csv (
    +	in      => $fn,
    +	headers => "auto",
    +	after_parse => sub { undef; },
    +	);
    +    }
    +elsif ($x == 4) {		# No fix
    +    say "BP undef";
    +    my $aoh = csv (
    +	in      => $fn,
    +	headers => "auto",
    +	before_print => sub { undef; },
    +	);
    +    }
    +elsif ($x == 5) {		# fix
    +    say "AI undef";
    +    my $aoh = csv (
    +	in      => $fn,
    +	headers => "auto",
    +	after_in => sub { undef; },
    +	);
    +    }
     
     say "Name NPI";
     {   my $aoh = csv (
     	in      => $fn,
    +#	headers => "auto", # -- does not fix the issue
     	filter  => { Rndrng_NPI        => sub { $_ > 1 }, },
     	);
         }
    

Vulnerability mechanics

AI mechanics synthesis has not run for this CVE yet.

References

3

News mentions

0

No linked articles in our index yet.