VYPR
Moderate severityNVD Advisory· Published Aug 25, 2015· Updated May 6, 2026

CVE-2015-5161

CVE-2015-5161

Description

The Zend_Xml_Security::scan in ZendXml before 1.0.1 and Zend Framework before 1.12.14, 2.x before 2.4.6, and 2.5.x before 2.5.2, when running under PHP-FPM in a threaded environment, allows remote attackers to bypass security checks and conduct XML external entity (XXE) and XML entity expansion (XEE) attacks via multibyte encoded characters.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
zendframework/zendframeworkPackagist
>= 2.0.0, < 2.4.62.4.6
zendframework/zendframeworkPackagist
>= 2.5.0, < 2.5.22.5.2
zendframework/zendframework1Packagist
>= 1.12.0, < 1.12.141.12.14
zendframework/zendxmlPackagist
>= 1.0.0, < 1.0.11.0.1
zendframework/zendframeworkPackagist
>= 1.12.0, < 1.12.141.12.14

Affected products

154
  • Zend/Framework154 versions
    cpe:2.3:a:zend:zend_framework:1.0.0:*:*:*:*:*:*:*+ 153 more
    • cpe:2.3:a:zend:zend_framework:1.0.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.0.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.0.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.0.0:rc2a:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.0.0:rc3:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.0.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.0.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.0.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.0.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.0:alpha1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.0:beta1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.5:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.6:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.7:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.8:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.10.9:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.0:b1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.10:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.11:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.12:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.13:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.5:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.6:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.7:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.8:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.11.9:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.0:rc3:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.0:rc4:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.10:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.11:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.12:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.13:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.5:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.6:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.7:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.8:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.12.9:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.5.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.5.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.5.0:rc3:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.5.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.5.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.5.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.6.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.6.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.6.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.6.0:rc3:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.6.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.6.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.0:pl1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.0:pr:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.3:pl1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.5:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.6:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.7:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.8:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.7.9:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.8.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.8.0:a1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.8.0:b1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.8.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.8.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.8.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.8.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.8.4:pl1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.8.5:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.0:a1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.0:b1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.3:pl1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.5:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.6:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.7:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:1.9.8:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.0:rc3:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.0:rc4:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.0:rc5:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.0:rc6:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.0:rc7:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.5:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.6:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.0.7:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.1.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.1.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.1.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.1.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.1.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.1.5:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.1.6:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.2.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.2.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.2.10:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.2.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.2.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.2.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.2.5:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.2.6:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.2.7:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.2.8:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.2.9:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.3.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.3.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.3.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.3.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.3.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.3.5:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.3.6:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.3.7:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.3.8:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.3.9:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.4.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.4.1:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.4.2:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.4.3:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.4.4:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.4.5:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.5.0:*:*:*:*:*:*:*
    • cpe:2.3:a:zend:zend_framework:2.5.1:*:*:*:*:*:*:*

Patches

2
79f478fa2af8

[ZF2015-06] Fix potential XXE vector via BOM detection

https://github.com/zendframework/ZendXmlMatthew Weier O'PhinneyJul 27, 2015via ghsa
2 files changed · +380 11
  • library/ZendXml/Security.php+255 11 modified
    @@ -3,7 +3,7 @@
      * Zend Framework (http://framework.zend.com/)
      *
      * @link      http://github.com/zendframework/zf2 for the canonical source repository
    - * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
    + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
      * @license   http://framework.zend.com/license/new-bsd New BSD License
      */
     namespace ZendXml;
    @@ -19,12 +19,14 @@ class Security
          * Heuristic scan to detect entity in XML
          *
          * @param  string $xml
    -     * @throws Exception\RuntimeException
    +     * @throws Exception\RuntimeException If entity expansion or external entity declaration was discovered.
          */
         protected static function heuristicScan($xml)
         {
    -        if (strpos($xml, '<!ENTITY') !== false) {
    -            throw new Exception\RuntimeException(self::ENTITY_DETECT);
    +        foreach (self::getEntityComparison($xml) as $compare) {
    +            if (strpos($xml, $compare) !== false) {
    +                throw new Exception\RuntimeException(self::ENTITY_DETECT);
    +            }
             }
         }
     
    @@ -66,13 +68,12 @@ public static function scan($xml, DOMDocument $dom = null)
             $result = $dom->loadXml($xml, LIBXML_NONET);
             restore_error_handler();
     
    -        // Entity load to previous setting
    -        if (!self::isPhpFpm()) {
    -            libxml_disable_entity_loader($loadEntities);
    -            libxml_use_internal_errors($useInternalXmlErrors);
    -        }
    -
             if (!$result) {
    +            // Entity load to previous setting
    +            if (!self::isPhpFpm()) {
    +                libxml_disable_entity_loader($loadEntities);
    +                libxml_use_internal_errors($useInternalXmlErrors);
    +            }
                 return false;
             }
     
    @@ -87,6 +88,12 @@ public static function scan($xml, DOMDocument $dom = null)
                 }
             }
     
    +        // Entity load to previous setting
    +        if (!self::isPhpFpm()) {
    +            libxml_disable_entity_loader($loadEntities);
    +            libxml_use_internal_errors($useInternalXmlErrors);
    +        }
    +
             if (isset($simpleXml)) {
                 $result = simplexml_import_dom($dom);
                 if (!$result instanceof SimpleXMLElement) {
    @@ -118,13 +125,250 @@ public static function scanFile($file, DOMDocument $dom = null)
         /**
          * Return true if PHP is running with PHP-FPM
          *
    +     * This method is mainly used to determine whether or not heuristic checks
    +     * (vs libxml checks) should be made, due to threading issues in libxml;
    +     * under php-fpm, threading becomes a concern.
    +     *
    +     * However, PHP versions 5.5.22+ and 5.6.6+ contain a patch to the
    +     * libxml support in PHP that makes the libxml checks viable; in such
    +     * versions, this method will return false to enforce those checks, which
    +     * are more strict and accurate than the heuristic checks.
    +     *
          * @return boolean
          */
         public static function isPhpFpm()
         {
    -        if (substr(php_sapi_name(), 0, 3) === 'fpm') {
    +        $isVulnerableVersion = (
    +            version_compare(PHP_VERSION, '5.5.22', 'lt')
    +            || (
    +                version_compare(PHP_VERSION, '5.6', 'gte')
    +                && version_compare(PHP_VERSION, '5.6.6', 'lt')
    +            )
    +        );
    +
    +        if (substr(php_sapi_name(), 0, 3) === 'fpm' && $isVulnerableVersion) {
                 return true;
             }
             return false;
         }
    +
    +    /**
    +     * Determine and return the string(s) to use for the <!ENTITY comparison.
    +     *
    +     * @param string $xml
    +     * @return string[]
    +     */
    +    protected static function getEntityComparison($xml)
    +    {
    +        $encodingMap = self::getAsciiEncodingMap();
    +        return array_map(function ($encoding) use ($encodingMap) {
    +            $generator   = isset($encodingMap[$encoding]) ? $encodingMap[$encoding] : $encodingMap['UTF-8'];
    +            return $generator('<!ENTITY');
    +        }, self::detectXmlEncoding($xml, self::detectStringEncoding($xml)));
    +    }
    +
    +    /**
    +     * Determine the string encoding.
    +     *
    +     * Determines string encoding from either a detected BOM or a
    +     * heuristic.
    +     *
    +     * @param string $xml
    +     * @return string File encoding
    +     */
    +    protected static function detectStringEncoding($xml)
    +    {
    +        return self::detectBom($xml) ?: self::detectXmlStringEncoding($xml);
    +    }
    +
    +    /**
    +     * Attempt to match a known BOM.
    +     *
    +     * Iterates through the return of getBomMap(), comparing the initial bytes
    +     * of the provided string to the BOM of each; if a match is determined,
    +     * it returns the encoding.
    +     *
    +     * @param string $string
    +     * @return false|string Returns encoding on success.
    +     */
    +    protected static function detectBom($string)
    +    {
    +        foreach (self::getBomMap() as $criteria) {
    +            if (0 === strncmp($string, $criteria['bom'], $criteria['length'])) {
    +                return $criteria['encoding'];
    +            }
    +        }
    +        return false;
    +    }
    +
    +    /**
    +     * Attempt to detect the string encoding of an XML string.
    +     *
    +     * @param string $xml
    +     * @return string Encoding
    +     */
    +    protected static function detectXmlStringEncoding($xml)
    +    {
    +        foreach (self::getAsciiEncodingMap() as $encoding => $generator) {
    +            $prefix = $generator('<' . '?xml');
    +            if (0 === strncmp($xml, $prefix, strlen($prefix))) {
    +                return $encoding;
    +            }
    +        }
    +
    +        // Fallback
    +        return 'UTF-8';
    +    }
    +
    +    /**
    +     * Attempt to detect the specified XML encoding.
    +     *
    +     * Using the file's encoding, determines if an "encoding" attribute is
    +     * present and well-formed in the XML declaration; if so, it returns a
    +     * list with both the ASCII representation of that declaration and the
    +     * original file encoding.
    +     *
    +     * If not, a list containing only the provided file encoding is returned.
    +     *
    +     * @param string $xml
    +     * @param string $fileEncoding
    +     * @return string[] Potential XML encodings
    +     */
    +    protected static function detectXmlEncoding($xml, $fileEncoding)
    +    {
    +        $encodingMap = self::getAsciiEncodingMap();
    +        $generator   = $encodingMap[$fileEncoding];
    +        $encAttr     = $generator('encoding="');
    +        $quote       = $generator('"');
    +        $close       = $generator('>');
    +
    +        $closePos    = strpos($xml, $close);
    +        if (false === $closePos) {
    +            return array($fileEncoding);
    +        }
    +
    +        $encPos = strpos($xml, $encAttr);
    +        if (false === $encPos
    +            || $encPos > $closePos
    +        ) {
    +            return array($fileEncoding);
    +        }
    +
    +        $encPos   += strlen($encAttr);
    +        $quotePos = strpos($xml, $quote, $encPos);
    +        if (false === $quotePos) {
    +            return array($fileEncoding);
    +        }
    +
    +        $encoding = self::substr($xml, $encPos, $quotePos);
    +        return array(
    +            // Following line works because we're only supporting 8-bit safe encodings at this time.
    +            str_replace('\0', '', $encoding), // detected encoding
    +            $fileEncoding,                    // file encoding
    +        );
    +    }
    +
    +    /**
    +     * Return a list of BOM maps.
    +     *
    +     * Returns a list of common encoding -> BOM maps, along with the character
    +     * length to compare against.
    +     *
    +     * @link https://en.wikipedia.org/wiki/Byte_order_mark
    +     * @return array
    +     */
    +    protected static function getBomMap()
    +    {
    +        return array(
    +            array(
    +                'encoding' => 'UTF-32BE',
    +                'bom'      => pack('CCCC', 0x00, 0x00, 0xfe, 0xff),
    +                'length'   => 4,
    +            ),
    +            array(
    +                'encoding' => 'UTF-32LE',
    +                'bom'      => pack('CCCC', 0xff, 0xfe, 0x00, 0x00),
    +                'length'   => 4,
    +            ),
    +            array(
    +                'encoding' => 'GB-18030',
    +                'bom'      => pack('CCCC', 0x84, 0x31, 0x95, 0x33),
    +                'length'   => 4,
    +            ),
    +            array(
    +                'encoding' => 'UTF-16BE',
    +                'bom'      => pack('CC', 0xfe, 0xff),
    +                'length'   => 2,
    +            ),
    +            array(
    +                'encoding' => 'UTF-16LE',
    +                'bom'      => pack('CC', 0xff, 0xfe),
    +                'length'   => 2,
    +            ),
    +            array(
    +                'encoding' => 'UTF-8',
    +                'bom'      => pack('CCC', 0xef, 0xbb, 0xbf),
    +                'length'   => 3,
    +            ),
    +        );
    +    }
    +
    +    /**
    +     * Return a map of encoding => generator pairs.
    +     *
    +     * Returns a map of encoding => generator pairs, where the generator is a
    +     * callable that accepts a string and returns the appropriate byte order
    +     * sequence of that string for the encoding.
    +     *
    +     * @return array
    +     */
    +    protected static function getAsciiEncodingMap()
    +    {
    +        return array(
    +            'UTF-32BE'   => function ($ascii) {
    +                return preg_replace('/(.)/', "\0\0\0\\1", $ascii);
    +            },
    +            'UTF-32LE'   => function ($ascii) {
    +                return preg_replace('/(.)/', "\\1\0\0\0", $ascii);
    +            },
    +            'UTF-32odd1' => function ($ascii) {
    +                return preg_replace('/(.)/', "\0\\1\0\0", $ascii);
    +            },
    +            'UTF-32odd2' => function ($ascii) {
    +                return preg_replace('/(.)/', "\0\0\\1\0", $ascii);
    +            },
    +            'UTF-16BE'   => function ($ascii) {
    +                return preg_replace('/(.)/', "\0\\1", $ascii);
    +            },
    +            'UTF-16LE'   => function ($ascii) {
    +                return preg_replace('/(.)/', "\\1\0", $ascii);
    +            },
    +            'UTF-8'      => function ($ascii) {
    +                return $ascii;
    +            },
    +            'GB-18030'   => function ($ascii) {
    +                return $ascii;
    +            },
    +        );
    +    }
    +
    +    /**
    +     * Binary-safe substr.
    +     *
    +     * substr() is not binary-safe; this method loops by character to ensure
    +     * multi-byte characters are aggregated correctly.
    +     *
    +     * @param string $string
    +     * @param int $start
    +     * @param int $end
    +     * @return string
    +     */
    +    protected static function substr($string, $start, $end)
    +    {
    +        $substr = '';
    +        for ($i = $start; $i < $end; $i += 1) {
    +            $substr .= $string[$i];
    +        }
    +        return $substr;
    +    }
     }
    
  • tests/ZendXmlTest/MultibyteTest.php+125 0 added
    @@ -0,0 +1,125 @@
    +<?php
    +/**
    + * Zend Framework (http://framework.zend.com/)
    + *
    + * @link      http://github.com/zendframework/zf2 for the canonical source repository
    + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
    + * @license   http://framework.zend.com/license/new-bsd New BSD License
    + */
    +namespace ZendTest\Xml;
    +
    +use ZendXml\Security as XmlSecurity;
    +use ZendXml\Exception;
    +use DOMDocument;
    +use ReflectionMethod;
    +use SimpleXMLElement;
    +
    +/**
    + * @group ZF2015-06
    + */
    +class MultibyteTest extends \PHPUnit_Framework_TestCase
    +{
    +    public function multibyteEncodings()
    +    {
    +        return array(
    +            'UTF-16LE' => array('UTF-16LE', pack('CC', 0xff, 0xfe), 3),
    +            'UTF-16BE' => array('UTF-16BE', pack('CC', 0xfe, 0xff), 3),
    +            'UTF-32LE' => array('UTF-32LE', pack('CCCC', 0xff, 0xfe, 0x00, 0x00), 4),
    +            'UTF-32BE' => array('UTF-32BE', pack('CCCC', 0x00, 0x00, 0xfe, 0xff), 4),
    +        );
    +    }
    +
    +    public function getXmlWithXXE()
    +    {
    +        return <<<XML
    +<?xml version="1.0" encoding="{ENCODING}"?>
    +<!DOCTYPE methodCall [
    +  <!ENTITY pocdata SYSTEM "file:///etc/passwd">
    +]>
    +<methodCall>
    +    <methodName>retrieved: &pocdata;</methodName>
    +</methodCall>
    +XML;
    +    }
    +
    +    /**
    +     * Invoke ZendXml\Security::heuristicScan with the provided XML.
    +     *
    +     * @param string $xml
    +     * @return void
    +     * @throws Exception\RuntimeException
    +     */
    +    public function invokeHeuristicScan($xml)
    +    {
    +        $r = new ReflectionMethod('ZendXml\Security', 'heuristicScan');
    +        $r->setAccessible(true);
    +        return $r->invoke(null, $xml);
    +    }
    +
    +    /**
    +     * @dataProvider multibyteEncodings
    +     * @group heuristicDetection
    +     */
    +    public function testDetectsMultibyteXXEVectorsUnderFPMWithEncodedStringMissingBOM($encoding, $bom, $bomLength)
    +    {
    +        $xml = $this->getXmlWithXXE();
    +        $xml = str_replace('{ENCODING}', $encoding, $xml);
    +        $xml = iconv('UTF-8', $encoding, $xml);
    +        $this->assertNotSame(0, strncmp($xml, $bom, $bomLength));
    +        $this->setExpectedException('ZendXml\Exception\RuntimeException', 'ENTITY');
    +        $this->invokeHeuristicScan($xml);
    +    }
    +
    +    /**
    +     * @dataProvider multibyteEncodings
    +     */
    +    public function testDetectsMultibyteXXEVectorsUnderFPMWithEncodedStringUsingBOM($encoding, $bom)
    +    {
    +        $xml  = $this->getXmlWithXXE();
    +        $xml  = str_replace('{ENCODING}', $encoding, $xml);
    +        $orig = iconv('UTF-8', $encoding, $xml);
    +        $xml  = $bom . $orig;
    +        $this->setExpectedException('ZendXml\Exception\RuntimeException', 'ENTITY');
    +        $this->invokeHeuristicScan($xml);
    +    }
    +
    +    public function getXmlWithoutXXE()
    +    {
    +        return <<<XML
    +<?xml version="1.0" encoding="{ENCODING}"?>
    +<methodCall>
    +    <methodName>retrieved: &pocdata;</methodName>
    +</methodCall>
    +XML;
    +    }
    +
    +    /**
    +     * @dataProvider multibyteEncodings
    +     */
    +    public function testDoesNotFlagValidMultibyteXmlAsInvalidUnderFPM($encoding)
    +    {
    +        $xml = $this->getXmlWithoutXXE();
    +        $xml = str_replace('{ENCODING}', $encoding, $xml);
    +        $xml = iconv('UTF-8', $encoding, $xml);
    +        try {
    +            $result = $this->invokeHeuristicScan($xml);
    +            $this->assertNull($result);
    +        } catch (\Exception $e) {
    +            $this->fail('Security scan raised exception when it should not have');
    +        }
    +    }
    +
    +    /**
    +     * @dataProvider multibyteEncodings
    +     * @group mixedEncoding
    +     */
    +    public function testDetectsXXEWhenXMLDocumentEncodingDiffersFromFileEncoding($encoding, $bom)
    +    {
    +        $xml = $this->getXmlWithXXE();
    +        $xml = str_replace('{ENCODING}', 'UTF-8', $xml);
    +        $xml = iconv('UTF-8', $encoding, $xml);
    +        $xml = $bom . $xml;
    +        $this->setExpectedException('ZendXml\Exception\RuntimeException', 'ENTITY');
    +        $this->invokeHeuristicScan($xml);
    +    }
    +}
    
ff7edddf1410

Fix for XML XXE/XEE potential attacks

https://github.com/zendframework/zf1Enrico ZimuelFeb 25, 2014via ghsa
58 files changed · +717 225
  • library/Zend/Amf/Adobe/Auth.php+4 1 modified
    @@ -28,6 +28,9 @@
     /** @see Zend_Auth_Result */
     require_once 'Zend/Auth/Result.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * This class implements authentication against XML file with roles for Flex Builder.
      *
    @@ -61,7 +64,7 @@ class Zend_Amf_Adobe_Auth extends Zend_Amf_Auth_Abstract
         public function __construct($rolefile)
         {
             $this->_acl = new Zend_Acl();
    -        $xml = simplexml_load_file($rolefile);
    +        $xml = Zend_Xml_Security::scanFile($rolefile);
     /*
     Roles file format:
      <roles>
    
  • library/Zend/Amf/Parse/Amf0/Deserializer.php+4 1 modified
    @@ -23,6 +23,9 @@
     /** Zend_Amf_Constants */
     require_once 'Zend/Amf/Constants.php';
     
    +/** Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /** @see Zend_Amf_Parse_Deserializer */
     require_once 'Zend/Amf/Parse/Deserializer.php';
     
    @@ -248,7 +251,7 @@ public function readDate()
         public function readXmlString()
         {
             $string = $this->_stream->readLongUTF();
    -        return simplexml_load_string($string);
    +        return Zend_Xml_Security::scan($string); //simplexml_load_string($string);
         }
     
         /**
    
  • library/Zend/Amf/Parse/Amf3/Deserializer.php+4 1 modified
    @@ -23,6 +23,9 @@
     /** Zend_Amf_Parse_Deserializer */
     require_once 'Zend/Amf/Parse/Deserializer.php';
     
    +/** Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /** Zend_Amf_Parse_TypeLoader */
     require_once 'Zend/Amf/Parse/TypeLoader.php';
     
    @@ -417,6 +420,6 @@ public function readXmlString()
             $xmlReference = $this->readInteger();
             $length = $xmlReference >> 1;
             $string = $this->_stream->readBytes($length);
    -        return simplexml_load_string($string);
    +        return Zend_Xml_Security::scan($string); 
         }
     }
    
  • library/Zend/Config.php+1 1 modified
    @@ -444,7 +444,7 @@ protected function _assertValidExtend($extendingSection, $extendedSection)
          * @param string $errfile
          * @param integer $errline
          */
    -    protected function _loadFileErrorHandler($errno, $errstr, $errfile, $errline)
    +    public function _loadFileErrorHandler($errno, $errstr, $errfile, $errline)
         {
             if ($this->_loadFileErrorStr === null) {
                 $this->_loadFileErrorStr = $errstr;
    
  • library/Zend/Config/Xml.php+20 2 modified
    @@ -24,6 +24,12 @@
      */
     require_once 'Zend/Config.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @see Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
    +
     /**
      * XML Adapter for Zend_Config
      *
    @@ -96,9 +102,21 @@ public function __construct($xml, $section = null, $options = false)
     
             set_error_handler(array($this, '_loadFileErrorHandler')); // Warnings and errors are suppressed
             if (strstr($xml, '<?xml')) {
    -            $config = simplexml_load_string($xml);
    +            $config = Zend_Xml_Security::scan($xml);
             } else {
    -            $config = simplexml_load_file($xml);
    +            try {
    +                if (!$config = Zend_Xml_Security::scanFile($xml)) {
    +                    require_once 'Zend/Config/Exception.php';
    +                    throw new Zend_Config_Exception(
    +                        "Error failed to load $xml file"
    +                    );
    +                }
    +            } catch (Zend_Xml_Exception $e) {
    +                require_once 'Zend/Config/Exception.php';
    +                throw new Zend_Config_Exception(
    +                    $e->getMessage()
    +                );
    +            }
             }
     
             restore_error_handler();
    
  • library/Zend/Dom/Query.php+15 11 modified
    @@ -29,6 +29,12 @@
      */
     require_once 'Zend/Dom/Query/Result.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @see Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
    +
     /**
      * Query DOM structures based on CSS selectors and/or XPath
      *
    @@ -245,7 +251,6 @@ public function queryXpath($xpathQuery, $query = null)
     
             $encoding = $this->getEncoding();
             libxml_use_internal_errors(true);
    -        libxml_disable_entity_loader(true);
             if (null === $encoding) {
                 $domDoc = new DOMDocument('1.0');
             } else {
    @@ -254,14 +259,14 @@ public function queryXpath($xpathQuery, $query = null)
             $type   = $this->getDocumentType();
             switch ($type) {
                 case self::DOC_XML:
    -                $success = $domDoc->loadXML($document);
    -                foreach ($domDoc->childNodes as $child) {
    -                    if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
    -                        require_once 'Zend/Dom/Exception.php';
    -                        throw new Zend_Dom_Exception(
    -                            'Invalid XML: Detected use of illegal DOCTYPE'
    -                        );
    -                    }
    +                try {
    +                    $domDoc = Zend_Xml_Security::scan($document, $domDoc);
    +                    $success = ($domDoc !== false);
    +                } catch (Zend_Xml_Exception $e) {
    +                    require_once 'Zend/Dom/Exception.php';
    +                    throw new Zend_Dom_Exception(
    +                        $e->getMessage()
    +                    );
                     }
                     break;
                 case self::DOC_HTML:
    @@ -275,15 +280,14 @@ public function queryXpath($xpathQuery, $query = null)
                 $this->_documentErrors = $errors;
                 libxml_clear_errors();
             }
    -        libxml_disable_entity_loader(false);
             libxml_use_internal_errors(false);
     
             if (!$success) {
                 require_once 'Zend/Dom/Exception.php';
                 throw new Zend_Dom_Exception(sprintf('Error parsing document (type == %s)', $type));
             }
     
    -        $nodeList   = $this->_getNodeList($domDoc, $xpathQuery);
    +        $nodeList = $this->_getNodeList($domDoc, $xpathQuery);
             return new Zend_Dom_Query_Result($query, $xpathQuery, $domDoc, $nodeList);
         }
     
    
  • library/Zend/Feed/Abstract.php+7 10 modified
    @@ -26,6 +26,8 @@
      */
     require_once 'Zend/Feed/Element.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * The Zend_Feed_Abstract class is an abstract class representing feeds.
    @@ -111,10 +113,10 @@ public function __wakeup()
         {
             @ini_set('track_errors', 1);
             $doc = new DOMDocument;
    -        $status = @$doc->loadXML($this->_element);
    +        $doc = @Zend_Xml_Security::scan($this->_element, $doc);
             @ini_restore('track_errors');
     
    -        if (!$status) {
    +        if (!$doc) {
                 // prevent the class to generate an undefined variable notice (ZF-2590)
                 if (!isset($php_errormsg)) {
                     if (function_exists('xdebug_is_enabled')) {
    @@ -268,20 +270,15 @@ abstract public function send();
          */
         protected function _importFeedFromString($feed)
         {
    -        // Load the feed as an XML DOMDocument object
    -        $libxml_errflag       = libxml_use_internal_errors(true);
    -        $libxml_entity_loader = libxml_disable_entity_loader(true);
    -        $doc = new DOMDocument;
             if (trim($feed) == '') {
                 require_once 'Zend/Feed/Exception.php';
                 throw new Zend_Feed_Exception('Remote feed being imported'
                 . ' is an Empty string or comes from an empty HTTP response');
             }
    -        $status = $doc->loadXML($feed);
    -        libxml_disable_entity_loader($libxml_entity_loader);
    -        libxml_use_internal_errors($libxml_errflag);
    +        $doc = new DOMDocument;
    +        $doc = Zend_Xml_Security::scan($feed, $doc);
     
    -        if (!$status) {
    +        if (!$doc) {
                 // prevent the class to generate an undefined variable notice (ZF-2590)
                 // Build error message
                 $error = libxml_get_last_error();
    
  • library/Zend/Feed/Entry/Abstract.php+4 2 modified
    @@ -31,6 +31,8 @@
      */
     require_once 'Zend/Feed/Element.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * Zend_Feed_Entry_Abstract represents a single entry in an Atom or RSS
    @@ -80,10 +82,10 @@ public function __construct($uri = null, $element = null)
                     // Load the feed as an XML DOMDocument object
                     @ini_set('track_errors', 1);
                     $doc = new DOMDocument();
    -                $status = @$doc->loadXML($element);
    +                $doc = @Zend_Xml_Security::scan($element, $doc);
                     @ini_restore('track_errors');
     
    -                if (!$status) {
    +                if (!$doc) {
                         // prevent the class to generate an undefined variable notice (ZF-2590)
                         if (!isset($php_errormsg)) {
                             if (function_exists('xdebug_is_enabled')) {
    
  • library/Zend/Feed/Entry/Atom.php+4 2 modified
    @@ -26,6 +26,8 @@
      */
     require_once 'Zend/Feed/Entry/Abstract.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * Concrete class for working with Atom entries.
    @@ -194,10 +196,10 @@ public function save($postUri = null)
             // Update internal properties using $client->responseBody;
             @ini_set('track_errors', 1);
             $newEntry = new DOMDocument;
    -        $status = @$newEntry->loadXML($response->getBody());
    +        $newEntry = @Zend_Xml_Security::scan($response->getBody(), $newEntry);
             @ini_restore('track_errors');
     
    -        if (!$status) {
    +        if (!$newEntry) {
                 // prevent the class to generate an undefined variable notice (ZF-2590)
                 if (!isset($php_errormsg)) {
                     if (function_exists('xdebug_is_enabled')) {
    
  • library/Zend/Feed.php+6 9 modified
    @@ -20,6 +20,8 @@
      * @version    $Id$
      */
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * Feed utility class
    @@ -190,20 +192,15 @@ public static function import($uri)
          */
         public static function importString($string)
         {
    -        // Load the feed as an XML DOMDocument object
    -        $libxml_errflag       = libxml_use_internal_errors(true);
    -        $libxml_entity_loader = libxml_disable_entity_loader(true);
    -        $doc = new DOMDocument;
             if (trim($string) == '') {
                 require_once 'Zend/Feed/Exception.php';
                 throw new Zend_Feed_Exception('Document/string being imported'
                 . ' is an Empty string or comes from an empty HTTP response');
             }
    -        $status = $doc->loadXML($string);
    -        libxml_disable_entity_loader($libxml_entity_loader);
    -        libxml_use_internal_errors($libxml_errflag);
    +        $doc = new DOMDocument;
    +        $doc = Zend_Xml_Security::scan($string, $doc);
     
    -        if (!$status) {
    +        if (!$doc) {
                 // prevent the class to generate an undefined variable notice (ZF-2590)
                 // Build error message
                 $error = libxml_get_last_error();
    @@ -320,7 +317,7 @@ public static function findFeeds($uri)
                     if (!mb_check_encoding($link, 'UTF-8')) {
                         $link = mb_convert_encoding($link, 'UTF-8');
                     }
    -                $xml = @simplexml_load_string(rtrim($link, ' /') . ' />');
    +                $xml = @Zend_Xml_Security::scan(rtrim($link, ' /') . ' />');
                     if ($xml === false) {
                         continue;
                     }
    
  • library/Zend/Feed/Reader.php+25 26 modified
    @@ -39,6 +39,12 @@
      */
     require_once 'Zend/Feed/Reader/FeedSet.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @see Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
    +
     /**
      * @category   Zend
      * @package    Zend_Feed_Reader
    @@ -326,29 +332,23 @@ public static function importFeed(Zend_Feed_Abstract $feed)
         }
     
         /**
    -     * Import a feed froma string
    +     * Import a feed from a string
          *
          * @param  string $string
          * @return Zend_Feed_Reader_FeedInterface
          */
         public static function importString($string)
         {
    -        $libxml_errflag = libxml_use_internal_errors(true);
    -        $oldValue = libxml_disable_entity_loader(true);
             $dom = new DOMDocument;
    -        $status = $dom->loadXML($string);
    -        foreach ($dom->childNodes as $child) {
    -            if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
    -                require_once 'Zend/Feed/Exception.php';
    -                throw new Zend_Feed_Exception(
    -                    'Invalid XML: Detected use of illegal DOCTYPE'
    -                );
    -            }
    +        try {
    +            $dom = Zend_Xml_Security::scan($string, $dom);        
    +        } catch (Zend_Xml_Exception $e) {    
    +            require_once 'Zend/Feed/Exception.php';
    +            throw new Zend_Feed_Exception(
    +                $e->getMessage()
    +            );
             }
    -        libxml_disable_entity_loader($oldValue);
    -        libxml_use_internal_errors($libxml_errflag);
    -
    -        if (!$status) {
    +        if (!$dom) {
                 // Build error message
                 $error = libxml_get_last_error();
                 if ($error && $error->message) {
    @@ -455,20 +455,19 @@ public static function detectType($feed, $specOnly = false)
                 $dom = $feed;
             } elseif(is_string($feed) && !empty($feed)) {
                 @ini_set('track_errors', 1);
    -            $oldValue = libxml_disable_entity_loader(true);
    +            //$oldValue = libxml_disable_entity_loader(true);
                 $dom = new DOMDocument;
    -            $status = @$dom->loadXML($feed);
    -            foreach ($dom->childNodes as $child) {
    -                if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
    -                    require_once 'Zend/Feed/Exception.php';
    -                    throw new Zend_Feed_Exception(
    -                        'Invalid XML: Detected use of illegal DOCTYPE'
    -                    );
    -                }
    +            try {
    +                $dom = Zend_Xml_Security::scan($feed, $dom);
    +            } catch (Zend_Xml_Exception $e) {
    +                require_once 'Zend/Feed/Exception.php';
    +                throw new Zend_Feed_Exception(
    +                    $e->getMessage()
    +                );
                 }
    -            libxml_disable_entity_loader($oldValue);
    +            //libxml_disable_entity_loader($oldValue);
                 @ini_restore('track_errors');
    -            if (!$status) {
    +            if (!$dom) {
                     if (!isset($php_errormsg)) {
                         if (function_exists('xdebug_is_enabled')) {
                             $php_errormsg = '(error message not available, when XDebug is running)';
    
  • library/Zend/Feed/Writer/Renderer/Entry/Atom.php+6 2 modified
    @@ -26,6 +26,9 @@
     
     require_once 'Zend/Feed/Writer/Renderer/Feed/Atom/Source.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * @category   Zend
      * @package    Zend_Feed_Writer
    @@ -389,8 +392,9 @@ protected function _loadXhtml($content)
                 "/(<[\/]?)([a-zA-Z]+)/"
             ), '$1xhtml:$2', $xhtml);
             $dom = new DOMDocument('1.0', $this->getEncoding());
    -        $dom->loadXML('<xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml">'
    -            . $xhtml . '</xhtml:div>');
    +
    +        $dom = Zend_Xml_Security::scan('<xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml">'
    +            . $xhtml . '</xhtml:div>', $dom);
             return $dom->documentElement;
         }
     
    
  • library/Zend/Gdata/App/Base.php+5 2 modified
    @@ -26,6 +26,9 @@
      */
     require_once 'Zend/Gdata/App/Util.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * Abstract class for all XML elements
      *
    @@ -301,9 +304,9 @@ public function transferFromXML($xml)
                 // Load the feed as an XML DOMDocument object
                 @ini_set('track_errors', 1);
                 $doc = new DOMDocument();
    -            $success = @$doc->loadXML($xml);
    +            $doc = @Zend_Xml_Security::scan($xml, $doc);
                 @ini_restore('track_errors');
    -            if (!$success) {
    +            if (!$doc) {
                     require_once 'Zend/Gdata/App/Exception.php';
                     throw new Zend_Gdata_App_Exception("DOMDocument cannot parse XML: $php_errormsg");
                 }
    
  • library/Zend/Gdata/App.php+5 2 modified
    @@ -46,6 +46,9 @@
      */
     require_once 'Zend/Uri/Http.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * Provides Atom Publishing Protocol (APP) functionality.  This class and all
      * other components of Zend_Gdata_App are designed to work independently from
    @@ -822,10 +825,10 @@ public static function importString($string,
             // Load the feed as an XML DOMDocument object
             @ini_set('track_errors', 1);
             $doc = new DOMDocument();
    -        $success = @$doc->loadXML($string);
    +        $doc = @Zend_Xml_Security::scan($string, $doc);
             @ini_restore('track_errors');
     
    -        if (!$success) {
    +        if (!$doc) {
                 require_once 'Zend/Gdata/App/Exception.php';
                 throw new Zend_Gdata_App_Exception(
                     "DOMDocument cannot parse XML: $php_errormsg");
    
  • library/Zend/Gdata/Gapps/ServiceException.php+5 2 modified
    @@ -32,6 +32,9 @@
      */
     require_once 'Zend/Gdata/Gapps/Error.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * Gdata Gapps Exception class. This is thrown when an
      * AppsForYourDomainErrors message is received from the Google Apps
    @@ -160,10 +163,10 @@ public function importFromString($string) {
                 // exception by referencing $php_errormsg
                 @ini_set('track_errors', 1);
                 $doc = new DOMDocument();
    -            $success = @$doc->loadXML($string);
    +            $doc = @Zend_Xml_Security::scan($string, $doc);
                 @ini_restore('track_errors');
     
    -            if (!$success) {
    +            if (!$doc) {
                     require_once 'Zend/Gdata/App/Exception.php';
                     // $php_errormsg is automatically generated by PHP if
                     // an error occurs while calling loadXML(), above.
    
  • library/Zend/Gdata/YouTube.php+4 2 modified
    @@ -71,6 +71,8 @@
      */
     require_once 'Zend/Gdata/YouTube/InboxFeed.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * Service class for interacting with the YouTube Data API.
    @@ -652,10 +654,10 @@ public static function parseFormUploadTokenResponse($response)
             // Load the feed as an XML DOMDocument object
             @ini_set('track_errors', 1);
             $doc = new DOMDocument();
    -        $success = @$doc->loadXML($response);
    +        $doc = @Zend_Xml_Security::scan($response, $doc);
             @ini_restore('track_errors');
     
    -        if (!$success) {
    +        if (!$doc) {
                 require_once 'Zend/Gdata/App/Exception.php';
                 throw new Zend_Gdata_App_Exception(
                     "Zend_Gdata_YouTube::parseFormUploadTokenResponse - " .
    
  • library/Zend/Json.php+3 1 modified
    @@ -26,6 +26,8 @@
      */
     require_once 'Zend/Json/Expr.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * Class for encoding to and decoding from JSON.
    @@ -343,7 +345,7 @@ protected static function _processXml($simpleXmlElementObject, $ignoreXmlAttribu
         public static function fromXml($xmlStringContents, $ignoreXmlAttributes=true)
         {
             // Load the XML formatted string into a Simple XML Element object.
    -        $simpleXmlElementObject = simplexml_load_string($xmlStringContents);
    +        $simpleXmlElementObject = Zend_Xml_Security::scan($xmlStringContents);
     
             // If it is not a valid XML content, throw an exception.
             if ($simpleXmlElementObject == null) {
    
  • library/Zend/Locale/Data.php+4 1 modified
    @@ -25,6 +25,9 @@
      */
     require_once 'Zend/Locale.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * Locale data reader, handles the CLDR
      *
    @@ -158,7 +161,7 @@ private static function _findRoute($locale, $path, $attribute, $value, &$temp)
                     throw new Zend_Locale_Exception("Missing locale file '$filename' for '$locale' locale.");
                 }
     
    -            self::$_ldml[(string) $locale] = simplexml_load_file($filename);
    +            self::$_ldml[(string) $locale] = Zend_Xml_Security::scanFile($filename);
             }
     
             // search for 'alias' tag in the search path for redirection
    
  • library/Zend/Mobile/Push/Message/Mpns/Raw.php+4 1 modified
    @@ -22,6 +22,9 @@
     /** Zend_Mobile_Push_Message_Mpns **/
     require_once 'Zend/Mobile/Push/Message/Mpns.php';
     
    +/** Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * Mpns Raw Message
      *
    @@ -94,7 +97,7 @@ public function setMessage($msg)
             if (!is_string($msg)) {
                 throw new Zend_Mobile_Push_Message_Exception('$msg is not a string');
             }
    -        if (!simplexml_load_string($msg)) {
    +        if (!Zend_Xml_Security::scan($msg)) {
                 throw new Zend_Mobile_Push_Message_Exception('$msg is not valid xml');
             }
             $this->_msg = $msg;
    
  • library/Zend/Rest/Client/Result.php+3 1 modified
    @@ -20,6 +20,8 @@
      * @version    $Id$
      */
     
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * @category   Zend
      * @package    Zend_Rest
    @@ -48,7 +50,7 @@ class Zend_Rest_Client_Result implements IteratorAggregate {
         public function __construct($data)
         {
             set_error_handler(array($this, 'handleXmlErrors'));
    -        $this->_sxml = simplexml_load_string($data);
    +        $this->_sxml = Zend_Xml_Security::scan($data); 
             restore_error_handler();
             if($this->_sxml === false) {
                 if ($this->_errstr === null) {
    
  • library/Zend/Search/Lucene/Document/Docx.php+5 2 modified
    @@ -23,6 +23,9 @@
     /** Zend_Search_Lucene_Document_OpenXml */
     require_once 'Zend/Search/Lucene/Document/OpenXml.php';
     
    +/** Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * Docx document.
      *
    @@ -67,11 +70,11 @@ private function __construct($fileName, $storeContent) {
                 require_once 'Zend/Search/Lucene/Exception.php';
                 throw new Zend_Search_Lucene_Exception('Invalid archive or corrupted .docx file.');
             }
    -        $relations = simplexml_load_string($relationsXml);
    +        $relations = Zend_Xml_Security::scan($relationsXml);
             foreach($relations->Relationship as $rel) {
                 if ($rel ["Type"] == Zend_Search_Lucene_Document_OpenXml::SCHEMA_OFFICEDOCUMENT) {
                     // Found office document! Read in contents...
    -                $contents = simplexml_load_string($package->getFromName(
    +                $contents = Zend_Xml_Security::scan($package->getFromName(
                                                                     $this->absoluteZipPath(dirname($rel['Target'])
                                                                   . '/'
                                                                   . basename($rel['Target']))
    
  • library/Zend/Search/Lucene/Document/OpenXml.php+4 2 modified
    @@ -24,6 +24,8 @@
     /** Zend_Search_Lucene_Document */
     require_once 'Zend/Search/Lucene/Document.php';
     
    +/** Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * OpenXML document.
    @@ -83,11 +85,11 @@ protected function extractMetaData(ZipArchive $package)
             $coreProperties = array();
     
             // Read relations and search for core properties
    -        $relations = simplexml_load_string($package->getFromName("_rels/.rels"));
    +        $relations = Zend_Xml_Security::scan($package->getFromName("_rels/.rels"));
             foreach ($relations->Relationship as $rel) {
                 if ($rel["Type"] == Zend_Search_Lucene_Document_OpenXml::SCHEMA_COREPROPERTIES) {
                     // Found core properties! Read in contents...
    -                $contents = simplexml_load_string(
    +                $contents = Zend_Xml_Security::scan(
                         $package->getFromName(dirname($rel["Target"]) . "/" . basename($rel["Target"]))
                     );
     
    
  • library/Zend/Search/Lucene/Document/Pptx.php+7 5 modified
    @@ -20,6 +20,8 @@
      * @version    $Id$
      */
     
    +/** Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /** Zend_Search_Lucene_Document_OpenXml */
     require_once 'Zend/Search/Lucene/Document/OpenXml.php';
    @@ -93,24 +95,24 @@ private function __construct($fileName, $storeContent)
                 require_once 'Zend/Search/Lucene/Exception.php';
                 throw new Zend_Search_Lucene_Exception('Invalid archive or corrupted .pptx file.');
             }
    -        $relations = simplexml_load_string($relationsXml);
    +        $relations = Zend_Xml_Security::scan($relationsXml);
             foreach ($relations->Relationship as $rel) {
                 if ($rel["Type"] == Zend_Search_Lucene_Document_OpenXml::SCHEMA_OFFICEDOCUMENT) {
                     // Found office document! Search for slides...
    -                $slideRelations = simplexml_load_string($package->getFromName( $this->absoluteZipPath(dirname($rel["Target"]) . "/_rels/" . basename($rel["Target"]) . ".rels")) );
    +                $slideRelations = Zend_Xml_Security::scan($package->getFromName( $this->absoluteZipPath(dirname($rel["Target"]) . "/_rels/" . basename($rel["Target"]) . ".rels")) );
                     foreach ($slideRelations->Relationship as $slideRel) {
                         if ($slideRel["Type"] == Zend_Search_Lucene_Document_Pptx::SCHEMA_SLIDERELATION) {
                             // Found slide!
    -                        $slides[ str_replace( 'rId', '', (string)$slideRel["Id"] ) ] = simplexml_load_string(
    +                        $slides[ str_replace( 'rId', '', (string)$slideRel["Id"] ) ] = Zend_Xml_Security::scan(
                                 $package->getFromName( $this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($slideRel["Target"]) . "/" . basename($slideRel["Target"])) )
                             );
     
                             // Search for slide notes
    -                        $slideNotesRelations = simplexml_load_string($package->getFromName( $this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($slideRel["Target"]) . "/_rels/" . basename($slideRel["Target"]) . ".rels")) );
    +                        $slideNotesRelations = Zend_Xml_Security::scan($package->getFromName( $this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($slideRel["Target"]) . "/_rels/" . basename($slideRel["Target"]) . ".rels")) );
                             foreach ($slideNotesRelations->Relationship as $slideNoteRel) {
                                 if ($slideNoteRel["Type"] == Zend_Search_Lucene_Document_Pptx::SCHEMA_SLIDENOTESRELATION) {
                                     // Found slide notes!
    -                                $slideNotes[ str_replace( 'rId', '', (string)$slideRel["Id"] ) ] = simplexml_load_string(
    +                                $slideNotes[ str_replace( 'rId', '', (string)$slideRel["Id"] ) ] = Zend_Xml_Security::scan(
                                         $package->getFromName( $this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($slideRel["Target"]) . "/" . dirname($slideNoteRel["Target"]) . "/" . basename($slideNoteRel["Target"])) )
                                     );
     
    
  • library/Zend/Search/Lucene/Document/Xlsx.php+7 4 modified
    @@ -24,6 +24,9 @@
     /** Zend_Search_Lucene_Document_OpenXml */
     require_once 'Zend/Search/Lucene/Document/OpenXml.php';
     
    +/** Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * Xlsx document.
      *
    @@ -100,17 +103,17 @@ private function __construct($fileName, $storeContent)
                 require_once 'Zend/Search/Lucene/Exception.php';
                 throw new Zend_Search_Lucene_Exception('Invalid archive or corrupted .xlsx file.');
             }
    -        $relations = simplexml_load_string($relationsXml);
    +        $relations = Zend_Xml_Security::scan($relationsXml);
             foreach ($relations->Relationship as $rel) {
                 if ($rel["Type"] == Zend_Search_Lucene_Document_OpenXml::SCHEMA_OFFICEDOCUMENT) {
                     // Found office document! Read relations for workbook...
    -                $workbookRelations = simplexml_load_string($package->getFromName( $this->absoluteZipPath(dirname($rel["Target"]) . "/_rels/" . basename($rel["Target"]) . ".rels")) );
    +                $workbookRelations = Zend_Xml_Security::scan($package->getFromName( $this->absoluteZipPath(dirname($rel["Target"]) . "/_rels/" . basename($rel["Target"]) . ".rels")) );
                     $workbookRelations->registerXPathNamespace("rel", Zend_Search_Lucene_Document_OpenXml::SCHEMA_RELATIONSHIP);
     
                     // Read shared strings
                     $sharedStringsPath = $workbookRelations->xpath("rel:Relationship[@Type='" . Zend_Search_Lucene_Document_Xlsx::SCHEMA_SHAREDSTRINGS . "']");
                     $sharedStringsPath = (string)$sharedStringsPath[0]['Target'];
    -                $xmlStrings = simplexml_load_string($package->getFromName( $this->absoluteZipPath(dirname($rel["Target"]) . "/" . $sharedStringsPath)) );
    +                $xmlStrings = Zend_Xml_Security::scan($package->getFromName( $this->absoluteZipPath(dirname($rel["Target"]) . "/" . $sharedStringsPath)) );
                     if (isset($xmlStrings) && isset($xmlStrings->si)) {
                         foreach ($xmlStrings->si as $val) {
                             if (isset($val->t)) {
    @@ -124,7 +127,7 @@ private function __construct($fileName, $storeContent)
                     // Loop relations for workbook and extract worksheets...
                     foreach ($workbookRelations->Relationship as $workbookRelation) {
                         if ($workbookRelation["Type"] == Zend_Search_Lucene_Document_Xlsx::SCHEMA_WORKSHEETRELATION) {
    -                        $worksheets[ str_replace( 'rId', '', (string)$workbookRelation["Id"]) ] = simplexml_load_string(
    +                        $worksheets[ str_replace( 'rId', '', (string)$workbookRelation["Id"]) ] = Zend_Xml_Security::scan(
                                 $package->getFromName( $this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($workbookRelation["Target"]) . "/" . basename($workbookRelation["Target"])) )
                             );
                         }
    
  • library/Zend/Serializer/Adapter/Wddx.php+8 14 modified
    @@ -23,6 +23,12 @@
     /** @see Zend_Serializer_Adapter_AdapterAbstract */
     require_once 'Zend/Serializer/Adapter/AdapterAbstract.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @see Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
    +
     /**
      * @link       http://www.infoloom.com/gcaconfs/WEB/chicago98/simeonov.HTM
      * @link       http://en.wikipedia.org/wiki/WDDX
    @@ -100,24 +106,12 @@ public function unserialize($wddx, array $opts = array())
                 // check if the returned NULL is valid
                 // or based on an invalid wddx string
                 try {
    -                $oldLibxmlDisableEntityLoader = libxml_disable_entity_loader(true);
    -                $dom = new DOMDocument;
    -                $dom->loadXML($wddx);
    -                foreach ($dom->childNodes as $child) {
    -                    if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
    -                        require_once 'Zend/Serializer/Exception.php';
    -                        throw new Zend_Serializer_Exception(
    -                            'Invalid XML: Detected use of illegal DOCTYPE'
    -                        );
    -                    }
    -                }
    -                $simpleXml = simplexml_import_dom($dom);
    -                libxml_disable_entity_loader($oldLibxmlDisableEntityLoader);
    +                $simpleXml = Zend_Xml_Security::scan($wddx);
                     if (isset($simpleXml->data[0]->null[0])) {
                         return null; // valid null
                     }
                     $errMsg = 'Can\'t unserialize wddx string';
    -            } catch (Exception $e) {
    +            } catch (Zend_Xml_Exception $e) {
                     $errMsg = $e->getMessage();
                 }
     
    
  • library/Zend/Service/Amazon/Ec2/Response.php+4 3 modified
    @@ -25,6 +25,9 @@
      */
     require_once 'Zend/Http/Response.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * @category   Zend
      * @package    Zend_Service_Amazon
    @@ -125,9 +128,7 @@ public function getDocument()
                     $errors = libxml_use_internal_errors();
     
                     $this->_document = new DOMDocument();
    -                if (!$this->_document->loadXML($body)) {
    -                    $this->_document = false;
    -                }
    +                $this->_document = Zend_Xml_Security::scan($body, $this->_document);
     
                     // reset libxml error handling
                     libxml_clear_errors();
    
  • library/Zend/Service/Amazon.php+5 2 modified
    @@ -26,6 +26,9 @@
      */
     require_once 'Zend/Rest/Client.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * @category   Zend
      * @package    Zend_Service
    @@ -126,7 +129,7 @@ public function itemSearch(array $options)
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
     
             /**
    @@ -168,7 +171,7 @@ public function itemLookup($asin, array $options = array())
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
             $xpath = new DOMXPath($dom);
             $xpath->registerNamespace('az', 'http://webservices.amazon.com/AWSECommerceService/2011-08-01');
    
  • library/Zend/Service/Amazon/SimpleDb/Response.php+5 5 modified
    @@ -24,6 +24,9 @@
      */
     require_once 'Zend/Http/Response.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * @category   Zend
      * @package    Zend_Service_Amazon
    @@ -120,8 +123,7 @@ public function getSimpleXMLDocument()
                 $body = false;
             }
     
    -
    -        return simplexml_load_string($body);
    +        return Zend_Xml_Security::scan($body);
         }
     
         /**
    @@ -153,9 +155,7 @@ public function getDocument()
                     $errors = libxml_use_internal_errors();
     
                     $this->_document = new DOMDocument();
    -                if (!$this->_document->loadXML($body)) {
    -                    $this->_document = false;
    -                }
    +                $this->_document = Zend_Xml_Security::scan($body, $this->_document);
     
                     // reset libxml error handling
                     libxml_clear_errors();
    
  • library/Zend/Service/Audioscrobbler.php+4 2 modified
    @@ -27,6 +27,8 @@
      */
     require_once 'Zend/Http/Client.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * @category   Zend
    @@ -182,7 +184,7 @@ protected function _getInfo($service, $params = null)
     
             set_error_handler(array($this, '_errorHandler'));
     
    -        if (!$simpleXmlElementResponse = simplexml_load_string($responseBody)) {
    +        if (!$simpleXmlElementResponse = Zend_Xml_Security::scan($responseBody)) {
                 restore_error_handler();
                 /**
                  * @see Zend_Service_Exception
    @@ -640,7 +642,7 @@ public function groupGetWeeklyAlbumChartList($from = NULL, $to = NULL)
          * @param  array   $errcontext
          * @return void
          */
    -    protected function _errorHandler($errno, $errstr, $errfile, $errline, array $errcontext)
    +    public function _errorHandler($errno, $errstr, $errfile, $errline, array $errcontext)
         {
             $this->_error = array(
                 'errno'      => $errno,
    
  • library/Zend/Service/Delicious.php+4 2 modified
    @@ -47,6 +47,8 @@
      */
     require_once 'Zend/Service/Delicious/PostList.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * Zend_Service_Delicious is a concrete implementation of the del.icio.us web service
    @@ -506,8 +508,8 @@ public function makeRequest($path, array $parms = array(), $type = 'xml')
             switch ($type) {
                 case 'xml':
                     $dom = new DOMDocument() ;
    -
    -                if (!@$dom->loadXML($responseBody)) {
    +    
    +                if (!$dom = @Zend_Xml_Security::scan($responseBody, $dom)) {
                         /**
                          * @see Zend_Service_Delicious_Exception
                          */
    
  • library/Zend/Service/Ebay/Finding.php+4 1 modified
    @@ -25,6 +25,9 @@
      */
     require_once 'Zend/Service/Ebay/Abstract.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * @category   Zend
      * @package    Zend_Service
    @@ -367,7 +370,7 @@ protected function _parseResponse(Zend_Http_Response $response)
     
             // first trying, loading XML
             $dom = new DOMDocument();
    -        if (!@$dom->loadXML($response->getBody())) {
    +        if (!$dom = @Zend_Xml_Security::scan($response->getBody(), $dom)) {
                 $message = 'It was not possible to load XML returned.';
             }
     
    
  • library/Zend/Service/Flickr.php+8 9 modified
    @@ -21,6 +21,8 @@
      * @version    $Id$
      */
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * @category   Zend
    @@ -114,8 +116,7 @@ public function tagSearch($query, array $options = array())
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    -
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
     
             /**
    @@ -178,8 +179,7 @@ public function userSearch($query, array $options = null)
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    -
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
     
             /**
    @@ -233,8 +233,7 @@ public function groupPoolGetPhotos($query, array $options = array())
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    -
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
     
             /**
    @@ -283,7 +282,7 @@ public function getIdByUsername($username)
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
             $xpath = new DOMXPath($dom);
             return (string) $xpath->query('//user')->item(0)->getAttribute('id');
    @@ -327,7 +326,7 @@ public function getIdByEmail($email)
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
             $xpath = new DOMXPath($dom);
             return (string) $xpath->query('//user')->item(0)->getAttribute('id');
    @@ -360,7 +359,7 @@ public function getImageDetails($id)
             $response = $restClient->restGet('/services/rest/', $options);
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             $xpath = new DOMXPath($dom);
             self::_checkErrors($dom);
             $retval = array();
    
  • library/Zend/Service/SlideShare.php+6 3 modified
    @@ -35,6 +35,9 @@
      */
     require_once 'Zend/Service/SlideShare/SlideShow.php';
     
    +/** Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * The Zend_Service_SlideShare component is used to interface with the
      * slideshare.net web server to retrieve slide shows hosted on the web site for
    @@ -376,7 +379,7 @@ public function uploadSlideShow(
                 );
             }
     
    -        $sxe = simplexml_load_string($response->getBody());
    +        $sxe = Zend_Xml_Security::scan($response->getBody());
     
             if ($sxe->getName() == "SlideShareServiceError") {
                 $message = (string)$sxe->Message[0];
    @@ -437,7 +440,7 @@ public function getSlideShow($ss_id)
                     );
                 }
     
    -            $sxe = simplexml_load_string($response->getBody());
    +            $sxe = Zend_Xml_Security::scan($response->getBody());
     
                 if ($sxe->getName() == "SlideShareServiceError") {
                     $message = (string)$sxe->Message[0];
    @@ -585,7 +588,7 @@ protected function _getSlideShowsByType($key, $value, $offset = null, $limit = n
                     );
                 }
     
    -            $sxe = simplexml_load_string($response->getBody());
    +            $sxe = Zend_Xml_Security::scan($response->getBody());
     
                 if ($sxe->getName() == "SlideShareServiceError") {
                     $message = (string)$sxe->Message[0];
    
  • library/Zend/Service/SqlAzure/Management/Client.php+5 2 modified
    @@ -39,7 +39,10 @@
      * @see Zend_Service_SqlAzure_Management_FirewallRuleInstance
      */
      require_once 'Zend/Service/SqlAzure/Management/FirewallRuleInstance.php';
    - 
    +
    + /** @see Zend_Xml_Security */
    + require_once 'Zend/Xml/Security.php';
    +
     /**
      * @category   Zend
      * @package    Zend_Service_SqlAzure
    @@ -279,7 +282,7 @@ protected function _parseResponse(Zend_Http_Response $response = null)
     			throw new Zend_Service_SqlAzure_Exception('Response should not be null.');
     		}
     		
    -        $xml = @simplexml_load_string($response->getBody());
    +        $xml = @Zend_Xml_Security::scan($response->getBody());
             
             if ($xml !== false) {
                 // Fetch all namespaces 
    
  • library/Zend/Service/Technorati.php+3 1 modified
    @@ -21,6 +21,8 @@
      * @version    $Id$
      */
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * Zend_Service_Technorati provides an easy, intuitive and object-oriented interface
    @@ -961,7 +963,7 @@ protected static function _checkErrors(DomDocument $dom)
         protected function _convertResponseAndCheckContent(Zend_Http_Response $response)
         {
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
             return $dom;
         }
    
  • library/Zend/Service/WindowsAzure/CommandLine/Package.php+3 1 modified
    @@ -20,6 +20,8 @@
      * @license    http://framework.zend.com/license/new-bsd     New BSD License
      */
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * Package commands
    @@ -125,7 +127,7 @@ public function createPackageCommand($path, $runDevFabric, $outputPath)
     			require_once 'Zend/Service/Console/Exception.php';
     			throw new Zend_Service_Console_Exception('Could not locate ServiceDefinition.csdef at ' . $serviceDefinitionFile . '.');
     		}
    -		$serviceDefinition = simplexml_load_file($serviceDefinitionFile);
    +		$serviceDefinition = Zend_Xml_Security::scanFile($serviceDefinitionFile);
     		$xmlRoles = array();
     		if ($serviceDefinition->WebRole) {
     			if (count($serviceDefinition->WebRole) > 1) {
    
  • library/Zend/Service/WindowsAzure/Diagnostics/ConfigurationInstance.php+4 1 modified
    @@ -30,6 +30,9 @@
      */
     require_once 'Zend/Service/WindowsAzure/Diagnostics/ConfigurationDataSources.php';
     
    +/** Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * @category   Zend
      * @package    Zend_Service_WindowsAzure
    @@ -60,7 +63,7 @@ public function __construct()
     	public function loadXml($configurationXml)
     	{
     		// Convert to SimpleXMLElement
    -		$configurationXml = simplexml_load_string($configurationXml);
    +		$configurationXml = Zend_Xml_Security::scan($configurationXml);
     	
     		// Assign general settings
     		$this->DataSources->OverallQuotaInMB = (int)$configurationXml->DataSources->OverallQuotaInMB;
    
  • library/Zend/Service/WindowsAzure/Management/Client.php+5 2 modified
    @@ -75,6 +75,9 @@
      */
     require_once 'Zend/Service/WindowsAzure/Management/OperatingSystemFamilyInstance.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * @category   Zend
      * @package    Zend_Service_WindowsAzure
    @@ -318,7 +321,7 @@ protected function _parseResponse(Zend_Http_Response $response = null)
     			throw new Zend_Service_WindowsAzure_Exception('Response should not be null.');
     		}
     		
    -        $xml = @simplexml_load_string($response->getBody());
    +        $xml = Zend_Xml_Security::scan($response->getBody());
             
             if ($xml !== false) {
                 // Fetch all namespaces 
    @@ -1428,7 +1431,7 @@ protected function _updateInstanceCountInConfiguration($roleName, $instanceCount
     		$configuration = preg_replace('/(<\?xml[^?]+?)utf-16/i', '$1utf-8', $configuration);
     		//$configuration = '<?xml version="1.0">' . substr($configuration, strpos($configuration, '>') + 2);
     
    -		$xml = simplexml_load_string($configuration); 
    +		$xml = Zend_Xml_Security::scan($configuration); 
     		
     		// http://www.php.net/manual/en/simplexmlelement.xpath.php#97818
     		$namespaces = $xml->getDocNamespaces();
    
  • library/Zend/Service/WindowsAzure/Storage.php+5 1 modified
    @@ -34,6 +34,10 @@
      * @see Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract
      */
     require_once 'Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php';
    +
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
     /**
      * @category   Zend
      * @package    Zend_Service_WindowsAzure
    @@ -410,7 +414,7 @@ protected function _parseResponse(Zend_Http_Response $response = null)
     			throw new Zend_Service_WindowsAzure_Exception('Response should not be null.');
     		}
     		
    -        $xml = @simplexml_load_string($response->getBody());
    +        $xml = Zend_Xml_Security::scan($response->getBody());
             
             if ($xml !== false) {
                 // Fetch all namespaces 
    
  • library/Zend/Service/Yahoo.php+9 14 modified
    @@ -21,6 +21,8 @@
      * @version    $Id$
      */
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
     
     /**
      * @category   Zend
    @@ -99,8 +101,7 @@ public function inlinkDataSearch($query, array $options = array())
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    -
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
     
             /**
    @@ -155,8 +156,7 @@ public function imageSearch($query, array $options = array())
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    -
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
     
             /**
    @@ -219,8 +219,7 @@ public function localSearch($query, array $options = array())
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    -
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
     
             /**
    @@ -273,8 +272,7 @@ public function newsSearch($query, array $options = array())
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    -
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
     
             /**
    @@ -320,8 +318,7 @@ public function pageDataSearch($query, array $options = array())
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    -
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
     
             /**
    @@ -374,8 +371,7 @@ public function videoSearch($query, array $options = array())
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    -
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
     
             /**
    @@ -431,8 +427,7 @@ public function webSearch($query, array $options = array())
             }
     
             $dom = new DOMDocument();
    -        $dom->loadXML($response->getBody());
    -
    +        $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
             self::_checkErrors($dom);
     
             /**
    
  • library/Zend/Soap/Server.php+14 11 modified
    @@ -24,6 +24,12 @@
      */
     require_once 'Zend/Server/Interface.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @see Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
    +
     /**
      * Zend_Soap_Server
      *
    @@ -729,21 +735,18 @@ protected function _setRequest($request)
                     $xml = $request;
                 }
     
    -            libxml_disable_entity_loader(true);
                 $dom = new DOMDocument();
    -            if(strlen($xml) == 0 || !$dom->loadXML($xml)) {
    -                require_once 'Zend/Soap/Server/Exception.php';
    -                throw new Zend_Soap_Server_Exception('Invalid XML');
    -            }
    -            foreach ($dom->childNodes as $child) {
    -                if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
    +            try {
    +                if(strlen($xml) == 0 || (!$dom = Zend_Xml_Security::scan($xml, $dom))) {
                         require_once 'Zend/Soap/Server/Exception.php';
    -                    throw new Zend_Soap_Server_Exception(
    -                        'Invalid XML: Detected use of illegal DOCTYPE'
    -                    );
    +                    throw new Zend_Soap_Server_Exception('Invalid XML');
                     }
    +            } catch (Zend_Xml_Exception $e) {
    +                require_once 'Zend/Soap/Server/Exception.php';
    +                throw new Zend_Soap_Server_Exception(
    +                    $e->getMessage()
    +                );
                 }
    -            libxml_disable_entity_loader(false);
             }
             $this->_request = $xml;
             return $this;
    
  • library/Zend/Soap/Wsdl.php+7 17 modified
    @@ -29,6 +29,9 @@
      */
     require_once "Zend/Soap/Wsdl/Strategy/Abstract.php";
     
    +/** @see Zend_Xml_Security */
    +require_once "Zend/Xml/Security.php";
    +
     /**
      * Zend_Soap_Wsdl
      *
    @@ -96,23 +99,12 @@ public function __construct($name, $uri, $strategy = true)
                         xmlns:xsd='http://www.w3.org/2001/XMLSchema'
                         xmlns:soap-enc='http://schemas.xmlsoap.org/soap/encoding/'
                         xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'></definitions>";
    -        libxml_disable_entity_loader(true);
             $this->_dom = new DOMDocument();
    -        if (!$this->_dom->loadXML($wsdl)) {
    +        if (!$this->_dom = Zend_Xml_Security::scan($wsdl, $this->_dom)) {
                 require_once 'Zend/Server/Exception.php';
                 throw new Zend_Server_Exception('Unable to create DomDocument');
    -        } else {
    -            foreach ($this->_dom->childNodes as $child) {
    -                if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
    -                    require_once 'Zend/Server/Exception.php';
    -                    throw new Zend_Server_Exception(
    -                        'Invalid XML: Detected use of illegal DOCTYPE'
    -                    );
    -                }
    -            }
    -            $this->_wsdl = $this->_dom->documentElement;
    -        }
    -        libxml_disable_entity_loader(false);
    +        } 
    +        $this->_wsdl = $this->_dom->documentElement;
     
             $this->setComplexTypeStrategy($strategy);
         }
    @@ -135,10 +127,8 @@ public function setUri($uri)
                 // @todo: This is the worst hack ever, but its needed due to design and non BC issues of WSDL generation
                 $xml = $this->_dom->saveXML();
                 $xml = str_replace($oldUri, $uri, $xml);
    -            libxml_disable_entity_loader(true);
                 $this->_dom = new DOMDocument();
    -            $this->_dom->loadXML($xml);
    -            libxml_disable_entity_loader(false);
    +            $this->_dom = Zend_Xml_Security::scan($xml, $this->_dom);
             }
     
             return $this;
    
  • library/Zend/Translate/Adapter/Qt.php+14 0 modified
    @@ -26,6 +26,11 @@
     /** Zend_Translate_Adapter */
     require_once 'Zend/Translate/Adapter.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @See Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
     
     /**
      * @category   Zend
    @@ -72,6 +77,15 @@ protected function _loadTranslationData($filename, $locale, array $options = arr
             xml_parser_set_option($this->_file, XML_OPTION_CASE_FOLDING, 0);
             xml_set_element_handler($this->_file, "_startElement", "_endElement");
             xml_set_character_data_handler($this->_file, "_contentElement");
    +        
    +        try {
    +            Zend_Xml_Security::scanFile($filename);
    +        } catch (Zend_Xml_Exception $e) {
    +            require_once 'Zend/Translate/Exception.php';
    +            throw new Zend_Translate_Exception(
    +                $e->getMessage()
    +            );
    +        }
     
             if (!xml_parse($this->_file, file_get_contents($filename))) {
                 $ex = sprintf('XML error: %s at line %d of file %s',
    
  • library/Zend/Translate/Adapter/Tbx.php+14 0 modified
    @@ -26,6 +26,11 @@
     /** Zend_Translate_Adapter */
     require_once 'Zend/Translate/Adapter.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @see Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
     
     /**
      * @category   Zend
    @@ -68,6 +73,15 @@ protected function _loadTranslationData($filename, $locale, array $options = arr
             xml_set_element_handler($this->_file, "_startElement", "_endElement");
             xml_set_character_data_handler($this->_file, "_contentElement");
     
    +        try {
    +            Zend_Xml_Security::scanFile($filename);
    +        } catch (Zend_Xml_Exception $e) {
    +            require_once 'Zend/Translate/Exception.php';
    +            throw new Zend_Translate_Exception(
    +                $e->getMessage()
    +            );
    +        }
    +
             if (!xml_parse($this->_file, file_get_contents($filename))) {
                 $ex = sprintf('XML error: %s at line %d of file %s',
                               xml_error_string(xml_get_error_code($this->_file)),
    
  • library/Zend/Translate/Adapter/Tmx.php+14 0 modified
    @@ -26,6 +26,11 @@
     /** Zend_Translate_Adapter */
     require_once 'Zend/Translate/Adapter.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @See Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
     
     /**
      * @category   Zend
    @@ -73,6 +78,15 @@ protected function _loadTranslationData($filename, $locale, array $options = arr
             xml_set_element_handler($this->_file, "_startElement", "_endElement");
             xml_set_character_data_handler($this->_file, "_contentElement");
     
    +        try {
    +            Zend_Xml_Security::scanFile($filename);
    +        } catch (Zend_Xml_Exception $e) {
    +            require_once 'Zend/Translate/Exception.php';
    +            throw new Zend_Translate_Exception(
    +                $e->getMessage()
    +            );
    +        }
    + 
             if (!xml_parse($this->_file, file_get_contents($filename))) {
                 $ex = sprintf('XML error: %s at line %d of file %s',
                               xml_error_string(xml_get_error_code($this->_file)),
    
  • library/Zend/Translate/Adapter/Xliff.php+14 0 modified
    @@ -26,6 +26,11 @@
     /** Zend_Translate_Adapter */
     require_once 'Zend/Translate/Adapter.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @See Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
     
     /**
      * @category   Zend
    @@ -80,6 +85,15 @@ protected function _loadTranslationData($filename, $locale, array $options = arr
             xml_set_element_handler($this->_file, "_startElement", "_endElement");
             xml_set_character_data_handler($this->_file, "_contentElement");
     
    +        try {
    +            Zend_Xml_Security::scanFile($filename);
    +        } catch (Zend_Xml_Exception $e) {
    +            require_once 'Zend/Translate/Exception.php';
    +            throw new Zend_Translate_Exception(
    +                $e->getMessage()
    +            );
    +        }
    +
             if (!xml_parse($this->_file, file_get_contents($filename))) {
                 $ex = sprintf('XML error: %s at line %d of file %s',
                               xml_error_string(xml_get_error_code($this->_file)),
    
  • library/Zend/Translate/Adapter/XmlTm.php+14 0 modified
    @@ -26,6 +26,11 @@
     /** Zend_Translate_Adapter */
     require_once 'Zend/Translate/Adapter.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @See Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
     
     /**
      * @category   Zend
    @@ -68,6 +73,15 @@ protected function _loadTranslationData($filename, $locale, array $options = arr
             xml_set_element_handler($this->_file, "_startElement", "_endElement");
             xml_set_character_data_handler($this->_file, "_contentElement");
     
    +        try {
    +            Zend_Xml_Security::scanFile($filename);
    +        } catch (Zend_Xml_Exception $e) {
    +            require_once 'Zend/Translate/Exception.php';
    +            throw new Zend_Translate_Exception(
    +                $e->getMessage()
    +            );
    +        }
    +
             if (!xml_parse($this->_file, file_get_contents($filename))) {
                 $ex = sprintf('XML error: %s at line %d of file %s',
                               xml_error_string(xml_get_error_code($this->_file)),
    
  • library/Zend/Xml/Exception.php+36 0 added
    @@ -0,0 +1,36 @@
    +<?php
    +/**
    + * Zend Framework
    + *
    + * LICENSE
    + *
    + * This source file is subject to the new BSD license that is bundled
    + * with this package in the file LICENSE.txt.
    + * It is also available through the world-wide-web at this URL:
    + * http://framework.zend.com/license/new-bsd
    + * If you did not receive a copy of the license and are unable to
    + * obtain it through the world-wide-web, please send an email
    + * to license@zend.com so we can send you a copy immediately.
    + *
    + * @category   Zend
    + * @package    Zend_Xml
    + * @copyright  Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
    + * @license    http://framework.zend.com/license/new-bsd     New BSD License
    + * @version    $Id$
    + */
    +
    +
    +/**
    + * @see Zend_Exception
    + */
    +require_once 'Zend/Exception.php';
    +
    +
    +/**
    + * @category   Zend
    + * @package    Zend_Xml
    + * @copyright  Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
    + * @license    http://framework.zend.com/license/new-bsd     New BSD License
    + */
    +class Zend_Xml_Exception extends Zend_Exception
    +{}
    
  • library/Zend/XmlRpc/Request.php+8 16 modified
    @@ -28,6 +28,12 @@
      */
     require_once 'Zend/XmlRpc/Fault.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @see Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
    +
     /**
      * XmlRpc Request object
      *
    @@ -303,26 +309,12 @@ public function loadXml($request)
                 return false;
             }
     
    -        // @see ZF-12293 - disable external entities for security purposes
    -        $loadEntities = libxml_disable_entity_loader(true);
             try {
    -            $dom = new DOMDocument;
    -            $dom->loadXML($request);
    -            foreach ($dom->childNodes as $child) {
    -                if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
    -                    require_once 'Zend/XmlRpc/Exception.php';
    -                    throw new Zend_XmlRpc_Exception(
    -                        'Invalid XML: Detected use of illegal DOCTYPE'
    -                    );
    -                }
    -            }
    -            $xml = simplexml_import_dom($dom);
    -            libxml_disable_entity_loader($loadEntities);
    -        } catch (Exception $e) {
    +            $xml = Zend_Xml_Security::scan($request);
    +        } catch (Zend_Xml_Exception $e) {
                 // Not valid XML
                 $this->_fault = new Zend_XmlRpc_Fault(631);
                 $this->_fault->setEncoding($this->getEncoding());
    -            libxml_disable_entity_loader($loadEntities);
                 return false;
             }
     
    
  • library/Zend/XmlRpc/Response.php+8 21 modified
    @@ -28,6 +28,12 @@
      */
     require_once 'Zend/XmlRpc/Fault.php';
     
    +/** @see Zend_Xml_Security */
    +require_once 'Zend/Xml/Security.php';
    +
    +/** @see Zend_Xml_Exception */
    +require_once 'Zend/Xml/Exception.php';
    +
     /**
      * XmlRpc Response
      *
    @@ -176,28 +182,9 @@ public function loadXml($response)
                 return false;
             }
     
    -        // @see ZF-12293 - disable external entities for security purposes
    -        $loadEntities         = libxml_disable_entity_loader(true);
    -        $useInternalXmlErrors = libxml_use_internal_errors(true);
             try {
    -            $dom = new DOMDocument;
    -            $dom->loadXML($response);
    -            foreach ($dom->childNodes as $child) {
    -                if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
    -                    require_once 'Zend/XmlRpc/Exception.php';
    -                    throw new Zend_XmlRpc_Exception(
    -                        'Invalid XML: Detected use of illegal DOCTYPE'
    -                    );
    -                }
    -            }
    -            // TODO: Locate why this passes tests but a simplexml import doesn't
    -            // $xml = simplexml_import_dom($dom);
    -            $xml = new SimpleXMLElement($response);
    -            libxml_disable_entity_loader($loadEntities);
    -            libxml_use_internal_errors($useInternalXmlErrors);
    -        } catch (Exception $e) {
    -            libxml_disable_entity_loader($loadEntities);
    -            libxml_use_internal_errors($useInternalXmlErrors);
    +            $xml = Zend_Xml_Security::scan($response);
    +        } catch (Zend_Xml_Exception $e) {    
                 // Not valid XML
                 $this->_fault = new Zend_XmlRpc_Fault(651);
                 $this->_fault->setEncoding($this->getEncoding());
    
  • library/Zend/Xml/Security.php+101 0 added
    @@ -0,0 +1,101 @@
    +<?php
    +/**
    + * Zend Framework
    + *
    + * LICENSE
    + *
    + * This source file is subject to the new BSD license that is bundled
    + * with this package in the file LICENSE.txt.
    + * It is also available through the world-wide-web at this URL:
    + * http://framework.zend.com/license/new-bsd
    + * If you did not receive a copy of the license and are unable to
    + * obtain it through the world-wide-web, please send an email
    + * to license@zend.com so we can send you a copy immediately.
    + *
    + * @category   Zend
    + * @package    Zend_Xml
    + * @copyright  Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
    + * @license    http://framework.zend.com/license/new-bsd     New BSD License
    + * @version    $Id$
    + */
    +
    + 
    +/**
    + * @category   Zend
    + * @package    Zend_Xml_SecurityScan
    + * @copyright  Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
    + * @license    http://framework.zend.com/license/new-bsd     New BSD License
    + */
    +class Zend_Xml_Security
    +{
    +    /**
    +     * Scan XML string for potential XXE and XEE attacks 
    +     *
    +     * @param   string $xml
    +     * @param   DomDocument $dom
    +     * @throws  Zend_Xml_Exception
    +     * @return  SimpleXMLElement|DomDocument|boolean
    +     */
    +    public static function scan($xml, DOMDocument $dom = null)
    +    {
    +        if (null === $dom) {
    +            $simpleXml = true;
    +            $dom = new DOMDocument();
    +        } 
    +
    +        // Disable entity load
    +        $loadEntities = libxml_disable_entity_loader(true);
    +        $useInternalXmlErrors = libxml_use_internal_errors(true);
    +
    +        if (!$dom->loadXml($xml)) {
    +            // Entity load to previous setting
    +            libxml_disable_entity_loader($loadEntities);
    +            libxml_use_internal_errors($useInternalXmlErrors);
    +            return false;
    +        }
    +
    +        // Scan for potential XEE attacks using Entity
    +        foreach ($dom->childNodes as $child) {
    +            if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
    +                if ($child->entities->length > 0) {
    +                    require_once 'Exception.php';
    +                    throw new Zend_Xml_Exception(
    +                        'Detected use of ENTITY_NODE in XML, disabled to prevent XEE attacks'
    +                    );
    +                }
    +            }
    +        }
    +
    +        // Entity load to previous setting
    +        libxml_disable_entity_loader($loadEntities);
    +        libxml_use_internal_errors($useInternalXmlErrors);
    +
    +        if (isset($simpleXml)) {
    +            $result = simplexml_import_dom($dom); 
    +            if (!$result instanceof SimpleXMLElement) {
    +                return false;
    +            }
    +            return $result;
    +        }
    +        return $dom;
    +    }
    +
    +    /**
    +     * Scan XML file for potential XXE/XEE attacks
    +     *
    +     * @param  string $file
    +     * @param  DOMDocument $dom
    +     * @throws Zend_Xml_Exception
    +     * @return SimpleXMLElement|DomDocument
    +     */
    +    public static function scanFile($file, DOMDocument $dom = null)
    +    {
    +        if (!file_exists($file)) {
    +            require_once 'Exception.php';
    +            throw new Zend_Xml_Exception(
    +                "The file $file specified doesn't exist"
    +            );
    +        }
    +        return self::scan(file_get_contents($file), $dom);
    +    }
    +}
    
  • tests/Zend/Config/XmlTest.php+2 2 modified
    @@ -204,13 +204,13 @@ public function testZF3578_InvalidOrMissingfXmlFile()
                 $config = new Zend_Config_Xml($this->_xmlFileInvalid);
                 $this->fail('An expected Zend_Config_Exception has not been raised');
             } catch (Zend_Config_Exception $expected) {
    -            $this->assertContains('parser error', $expected->getMessage());
    +            $this->assertContains('failed to load', $expected->getMessage());
             }
             try {
                 $config = new Zend_Config_Xml('I/dont/exist');
                 $this->fail('An expected Zend_Config_Exception has not been raised');
             } catch (Zend_Config_Exception $expected) {
    -            $this->assertContains('failed to load', $expected->getMessage());
    +            $this->assertContains('doesn\'t exist', $expected->getMessage());
             }
         }
     
    
  • tests/Zend/Feed/Reader/Integration/PodcastRss2Test.php+4 0 modified
    @@ -74,6 +74,7 @@ public function testGetsOwner()
             $this->assertEquals('john.doe@example.com (John Doe)', $feed->getOwner());
         }
     
    +    /*
         public function testGetsCategories()
         {
             $feed = Zend_Feed_Reader::importString(
    @@ -86,6 +87,7 @@ public function testGetsCategories()
                 'TV & Film' => null
             ), $feed->getCategories());
         }
    +    */
     
         public function testGetsTitle()
         {
    @@ -170,13 +172,15 @@ public function testGetsEntryCount()
             $this->assertEquals(3, $feed->count());
         }
     
    +    /*
         public function testGetsImage()
         {
             $feed = Zend_Feed_Reader::importString(
                 file_get_contents($this->_feedSamplePath)
             );
             $this->assertEquals('http://example.com/podcasts/everything/AllAboutEverything.jpg', $feed->getImage());
         }
    +    */
     
         /**
          * Entry level testing
    
  • tests/Zend/Mobile/Push/Message/Mpns/RawTest.php+1 1 modified
    @@ -88,7 +88,7 @@ public function testSetMessageThrowsExceptionOnNonString()
         }
     
         /**
    -     * @expectedException PHPUnit_Framework_Error
    +     * @expectedException Zend_Mobile_Push_Message_Exception 
          */
         public function testSetMessageThrowsExceptionOnNonXml()
         {
    
  • tests/Zend/Serializer/Adapter/WddxTest.php+1 1 modified
    @@ -230,7 +230,7 @@ public function testUnserializeInvalidXml()
             $value = 'not a serialized string';
             $this->setExpectedException(
                 'Zend_Serializer_Exception',
    -            'DOMDocument::loadXML(): Start tag expected'
    +            'Can\'t unserialize wddx string'
             );
             $this->_adapter->unserialize($value);
         }
    
  • tests/Zend/Xml/AllTests.php+56 0 added
    @@ -0,0 +1,56 @@
    +<?php
    +/**
    + * Zend Framework
    + *
    + * LICENSE
    + *
    + * This source file is subject to the new BSD license that is bundled
    + * with this package in the file LICENSE.txt.
    + * It is also available through the world-wide-web at this URL:
    + * http://framework.zend.com/license/new-bsd
    + * If you did not receive a copy of the license and are unable to
    + * obtain it through the world-wide-web, please send an email
    + * to license@zend.com so we can send you a copy immediately.
    + *
    + * @category   Zend
    + * @package    Zend_Xml
    + * @subpackage UnitTests
    + * @copyright  Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
    + * @license    http://framework.zend.com/license/new-bsd     New BSD License
    + * @version    $Id$
    + */
    +
    +if (!defined('PHPUnit_MAIN_METHOD')) {
    +    define('PHPUnit_MAIN_METHOD', 'Zend_Xml_AllTests::main');
    +}
    +
    +require_once 'Zend/Xml/SecurityTest.php';
    +
    +/**
    + * @category   Zend
    + * @package    Zend_Xml
    + * @subpackage UnitTests
    + * @copyright  Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
    + * @license    http://framework.zend.com/license/new-bsd     New BSD License
    + * @group      Zend_Xml
    + */
    +class Zend_Xml_AllTests
    +{
    +    public static function main()
    +    {
    +        PHPUnit_TextUI_TestRunner::run(self::suite());
    +    }
    +
    +    public static function suite()
    +    {
    +        $suite = new PHPUnit_Framework_TestSuite('Zend Framework - Zend_Xml');
    +
    +        $suite->addTestSuite('Zend_Xml_SecurityTest');
    +
    +        return $suite;
    +    }
    +}
    +
    +if (PHPUnit_MAIN_METHOD == 'Zend_Xml_AllTests::main') {
    +    Zend_Xml_AllTests::main();
    +}
    
  • tests/Zend/XmlRpc/Server/FaultTest.php+1 0 modified
    @@ -28,6 +28,7 @@
     
     require_once 'Zend/XmlRpc/Server.php';
     require_once 'Zend/XmlRpc/Server/Fault.php';
    +require_once 'Zend/XmlRpc/Server/Exception.php';
     
     /**
      * Test case for Zend_XmlRpc_Server_Fault
    
  • tests/Zend/Xml/SecurityTest.php+170 0 added
    @@ -0,0 +1,170 @@
    +<?php
    +/**
    + * Zend Framework
    + *
    + * LICENSE
    + *
    + * This source file is subject to the new BSD license that is bundled
    + * with this package in the file LICENSE.txt.
    + * It is also available through the world-wide-web at this URL:
    + * http://framework.zend.com/license/new-bsd
    + * If you did not receive a copy of the license and are unable to
    + * obtain it through the world-wide-web, please send an email
    + * to license@zend.com so we can send you a copy immediately.
    + *
    + * @category   Zend
    + * @package    Zend_Xml_Security
    + * @subpackage UnitTests
    + * @copyright  Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
    + * @license    http://framework.zend.com/license/new-bsd     New BSD License
    + * @version    $Id$
    + */
    +
    +if (!defined('PHPUnit_MAIN_METHOD')) {
    +    define('PHPUnit_MAIN_METHOD', 'Zend_Xml_SecurityTest::main');
    +}
    +
    +/**
    + * @see Zend_Xml_Security
    + */
    +require_once 'Zend/Xml/Security.php';
    +
    +require_once 'Zend/Xml/Exception.php';
    +
    +/**
    + * @category   Zend
    + * @package    Zend_Xml_Security
    + * @subpackage UnitTests
    + * @copyright  Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
    + * @license    http://framework.zend.com/license/new-bsd     New BSD License
    + * @group      Zend_Xml
    + */
    +class Zend_Xml_SecurityTest extends PHPUnit_Framework_TestCase
    +{
    +    public static function main()
    +    {
    +        $suite  = new PHPUnit_Framework_TestSuite(__CLASS__);
    +        $result = PHPUnit_TextUI_TestRunner::run($suite);
    +    }
    + 
    +    public function testScanForXEE()
    +    {
    +        $xml = <<<XML
    +<?xml version="1.0"?>
    +<!DOCTYPE results [<!ENTITY harmless "completely harmless">]>
    +<results>
    +    <result>This result is &harmless;</result>
    +</results>
    +XML;
    +
    +        $this->setExpectedException('Zend_Xml_Exception');
    +        $result = Zend_Xml_Security::scan($xml);
    +    }
    +
    +    public function testScanForXXE()
    +    {
    +        $file = tempnam(sys_get_temp_dir(), 'Zend_XML_Security');
    +        file_put_contents($file, 'This is a remote content!');
    +        $xml = <<<XML
    +<?xml version="1.0"?>
    +<!DOCTYPE root
    +[
    +<!ENTITY foo SYSTEM "file://$file">
    +]>
    +<results>
    +    <result>&foo;</result>
    +</results>
    +XML;
    +
    +        try {
    +            $result = Zend_Xml_Security::scan($xml);
    +        } catch (Zend_Xml_Exception $e) {
    +            unlink($file);
    +            return;
    +        }
    +
    +        $this->fail('An expected exception has not been raised.');
    +    }
    +
    +    public function testScanSimpleXmlResult()
    +    {
    +        $result = Zend_Xml_Security::scan($this->_getXml());
    +        $this->assertTrue($result instanceof SimpleXMLElement);
    +        $this->assertEquals($result->result, 'test');
    +    }
    +
    +    public function testScanDom()
    +    {
    +        $dom = new DOMDocument('1.0');
    +        $result = Zend_Xml_Security::scan($this->_getXml(), $dom);
    +        $this->assertTrue($result instanceof DOMDocument);
    +        $node = $result->getElementsByTagName('result')->item(0);
    +        $this->assertEquals($node->nodeValue, 'test');
    +    }
    +
    +    public function testScanInvalidXml()
    +    {
    +        $xml = <<<XML
    +<foo>test</bar>
    +XML;
    +
    +        $result = Zend_XML_Security::scan($xml);
    +        $this->assertFalse($result);
    +    }
    +
    +    public function testScanInvalidXmlDom()
    +    {
    +        $xml = <<<XML
    +<foo>test</bar>
    +XML;
    +
    +        $dom = new DOMDocument('1.0');
    +        $result = Zend_XML_Security::scan($xml, $dom);
    +        $this->assertFalse($result);
    +    }
    +
    +    public function testScanFile()
    +    {
    +        $file = tempnam(sys_get_temp_dir(), 'Zend_XML_Security');
    +        file_put_contents($file, $this->_getXml());
    +
    +        $result = Zend_Xml_Security::scanFile($file);
    +        $this->assertTrue($result instanceof SimpleXMLElement);
    +        $this->assertEquals($result->result, 'test');
    +        unlink($file);
    +    }
    +
    +    public function testScanXmlWithDTD()
    +    {
    +        $xml = <<<XML
    +<?xml version="1.0"?>
    +<!DOCTYPE results [
    +<!ELEMENT results (result+)>
    +<!ELEMENT result (#PCDATA)>
    +]>
    +<results>
    +    <result>test</result>
    +</results>
    +XML;
    +
    +        $dom = new DOMDocument('1.0');
    +        $result = Zend_Xml_Security::scan($xml, $dom);
    +        $this->assertTrue($result instanceof DOMDocument);
    +        $this->assertTrue($result->validate());
    +    }
    +
    +    protected function _getXml()
    +    {
    +        return <<<XML
    +<?xml version="1.0"?>
    +<results>
    +    <result>test</result>
    +</results>
    +XML;
    +
    +    }
    +}
    +
    +if (PHPUnit_MAIN_METHOD == "Zend_Xml_SecurityTest::main") {
    +    Zend_Xml_SecurityTest::main();
    +}
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

21

News mentions

0

No linked articles in our index yet.