CVE-2020-36827 (published 2024-03-24T01:15Z)

The XAO::Web module before 1.84 for Perl mishandles < and > characters in JSON output during use of json-embed in Web::Action.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/amaltsev/XAO-Web
commit_details: repo_url: https://github.com/amaltsev/XAO-Web
author: Andrew Maltsev
author_date: 2020-09-17 20:22:22-07:00
msg: 1.84 Security fix for json-embed in Web::Action

Encoding <> characters in json output
repository: repo_url: https://github.com/amaltsev/XAO-Web
repo_name: amaltsev/XAO-Web
repo_language: Perl
owner: amaltsev
file_changes: filename: Makefile.PL
change_type: ModificationType.MODIFY
diff: @@ -90,11 +90,11 @@ WriteMakefile(
     'MIN_PERL_VERSION'  => '5.10.1',
     'LICENSE'           => 'artistic',
     'CONFIGURE_REQUIRES'=> {
-        'XAO::Base'                 => 1.27,
+        'XAO::Base'                 => 1.28,
         'ExtUtils::MakeMaker'       => 6.64,
     },
     'TEST_REQUIRES'     => {
-        'XAO::Base'                 => 1.27,
+        'XAO::Base'                 => 1.28,
     },
     'PREREQ_PM'     => {
         'Authen::SASL::SASLprep'    => 1.1,
@@ -119,7 +119,7 @@ WriteMakefile(
         'Text::FormatTable'         => 0.01,
         'Time::HiRes'               => 1.9719,
         'Unicode::Normalize'        => 1.18,
-        'XAO::Base'                 => 1.27,
+        'XAO::Base'                 => 1.28,
         'XAO::FS'                   => 1.21,
     },
     META_MERGE => {

programming_language: Perl
filename: Web.pm
change_type: ModificationType.MODIFY
diff: @@ -15,7 +15,7 @@ use XAO::Errors qw(XAO::Web);
 # XAO::Web version number. Hand changed with every release!
 #
 use vars qw($VERSION);
-$VERSION='1.83';
+$VERSION='1.84';
 
 ###############################################################################
 

programming_language: Perl
filename: Action.pm
change_type: ModificationType.MODIFY
diff: @@ -316,7 +316,16 @@ sub display_data ($@) {
         # are then encoded into bytes of the page final encoding.
         # JSON's to_json() call is exactly that, character output.
         #
-        $self->textout(to_json($data));
+        my $json=to_json($data);
+
+        # The data is typically embedded in a <script>...</script> set
+        # of tags, so if the content of a data field has </script> then
+        # that would close the outer script tag allowing that content to
+        # execute in the page context. Bad bad bad.
+        #
+        $json =~ s/([<>])/'\\u' . sprintf('%04x',ord($1))/esg;
+
+        $self->textout($json);
     }
     elsif($format eq 'xml' || $format eq 'xml-embed') {
         my $xml_sub=$self->get_mode_sub('xml',$args->{'xmlmode'} || $args->{'mode'},$args->{'mode'});

programming_language: Perl
filename: Page.pm
change_type: ModificationType.MODIFY
diff: @@ -723,6 +723,8 @@ sub test_unicode_transparency {
     use utf8;
     binmode STDERR, ':utf8';
 
+    my $byte2122=Encode::encode('utf8',"\x{2122}");
+
     # By default, mainly for backwards compatibility, the template
     # engine operates on bytes, not characters. Thus we expect bytes
     # back even when we supply unicode.
@@ -854,18 +856,23 @@ sub test_unicode_transparency {
         },
         c15c => {
             template    => qq(<%Page template='&#8482;'%>),
-            expect      => Encode::encode_utf8('™'),
+            expect      => $byte2122,
         },
         #
         d1a => {
-            template    => qq(<script><%MyAction datamode='test-alt' arg='Foo\x{2122}' format='json-embed'%></script>),
-            expect      => qr/Foo\x{2122}/,
+            objname     => 'Web::MyAction',
+            args        => { datamode => 'test-alt', format => 'json-embed', arg => qq(Foo\x{2122}) },
+            expect      => qr/Foo$byte2122/,
         },
         d1b => {
             charmode    => 1,
             template    => qq(<script><%MyAction datamode='test-alt' arg='Foo\x{2122}' format='json-embed'%></script>),
             expect      => qr/Foo\x{2122}/,
         },
+        d1c => {
+            template    => qq(<script><%MyAction datamode='test-alt' arg='</script><script>alert(1);' format='json-embed'%></script>),
+            expect      => qr/\\u003c\/script\\u003e\\u003cscript\\u003ealert/,
+        },
         #
         e1 => {
             template    => "<\$FOO\$>\x00\x01\x02",
@@ -928,7 +935,7 @@ sub test_unicode_transparency {
 
         $self->siteconfig->put('/xao/page/character_mode' => $test->{'charmode'});
 
-        my $page=XAO::Objects->new(objname => 'Web::Page');
+        my $page=XAO::Objects->new(objname => $test->{'objname'} || 'Web::Page');
 
         my $template=$test->{'template'};
         my $got=$page->expand({template => $template},$test->{'args'});
@@ -950,7 +957,7 @@ sub test_unicode_transparency {
         }
 
         if(ref $expect eq 'Regexp') {
-            $self->assert($got =~ $expect,
+            $self->assert($got =~ $expect ? 1 : 0,
                 "Test $tname - expected to match '$expect', got '$got'");
         }
         else {
@@ -976,7 +983,7 @@ sub test_expand {
         '<$TEST/f$>'    => '\'&quot;!@#$%^&amp;*()_-=[]\\&lt;&gt;? ',
         '<$TEST/q$>'    => '\'%22!@%23$%25^%26*()_-%3d[]\\%3c%3e%3f%20',
         '<$TEST/u$>'    => '\'%22!@%23$%25^%26*()_-%3d[]\\%3c%3e%3f%20',
-        '<$TEST/j$>'    => '\\u0027\\"!@#$%^&*()_-=[]\\\\<>? ',
+        '<$TEST/j$>'    => '\\u0027\\"!@#$%^&*()_-=[]\\\\\\u003c\\u003e? ',
     );
     foreach my $template (keys %ttt) {
         my $got=$page->expand(template => $template,

programming_language: Perl