CVE-2019-11565: Server-Side Request Forgery (SSRF) (CWE-918)
value: Server Side Request Forgery (SSRF) exists in the Print My Blog plugin before 1.6.7 for WordPress via the site parameter.
CWE description: The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
CVSS v3 base score: 9.8
Published: 2019-04-27T14:29Z
Repository: https://github.com/mnelson4/printmyblog
Language: PHP
Files changed: includes/vendor/mnelson4/RestApiDetector/RestApiDetector.php
Commit date: 2019-04-26 20:40:30 -0700
Commit message: do a little more sanitizing of the site param when REST PRoxy enabled

Diff: diff --git a/includes/vendor/mnelson4/RestApiDetector/RestApiDetector.php b/includes/vendor/mnelson4/RestApiDetector/RestApiDetector.php
index d422fbd..1d57635 100644
--- a/includes/vendor/mnelson4/RestApiDetector/RestApiDetector.php
+++ b/includes/vendor/mnelson4/RestApiDetector/RestApiDetector.php
@@ -28,15 +28,11 @@ class RestApiDetector
      * @param $site
      * @throws RestApiDetectorError
      */
     public function __construct($site)
     {
-        // If the REST API Proxy Plugin isn't active, always use the current site.
-        if(! PMB_REST_PROXY_EXISTS){
-            $site = '';
-        }
-        $this->setSite($site);
+        $this->setSite($this->sanitizeSite($site));
         $this->getSiteInfo();
     }
 
     /**
      * Gets the site name and URL (works if they provide the "site" query param too,
@@ -53,18 +49,11 @@ class RestApiDetector
             $this->setRestApiUrl(get_rest_url());
             $this->setSite(get_bloginfo('url'));
             $this->setLocal(true);
             return;
         }
-        // If they forgot to add http(s), add it for them.
-        if(strpos($this->getSite(), 'http://') === false && strpos($this->getSite(), 'https://') === false) {
-            $this->setSite( 'http://' . $this->getSite());
-        }
-        // if there is one, check if it exists in wordpress.com, eg "retirementreflections.com"
-        $site = trailingslashit(sanitize_text_field($this->getSite()));
-
-
+        $site = $this->getSite();
         // Let's see if it's self-hosted...
         $data = $this->getSelfHostedSiteInfo($site);
 //        if($data === false){
 //            // Alright, there was no link to the REST API index. But maybe it's a WordPress.com site...
 //            $data = $this->guessSelfHostedSiteInfo($site);
@@ -75,10 +64,36 @@ class RestApiDetector
         }
 
         return $data;
     }
 
+    /**
+     * Avoid SSRF by sanitizing the site received.
+     * @since $VID:$
+     * @param $site
+     * @return mixed|string
+     */
+    protected function sanitizeSite($site)
+    {
+        // If the REST API Proxy Plugin isn't active, always use the current site.
+        if(! PMB_REST_PROXY_EXISTS){
+            return '';
+        }
+        // If they forgot to add http(s), add it for them.
+        if(strpos($site, 'http://') === false && strpos($site, 'https://') === false) {
+            $site = 'http://' . $site;
+        }
+        // if there is one, check if it exists in wordpress.com, eg "retirementreflections.com"
+
+        $file_info = pathinfo($site);
+        if( isset($file_info['extension'])){
+            $site = str_replace($file_info['filename'] . "." . $file_info['extension'], "", $site);
+        }
+        $site = trailingslashit(sanitize_text_field($site));
+        return $site;
+    }
+
     /**
      * Tries to get the site's name, description, and URL, assuming it's self-hosted.
      * Returns a true on success, false if the site works but wasn't a self-hosted WordPress site, or
      * throws an exception if the site is self-hosted WordPress but had an error.
      * @since $VID:$

Vulnerable code:         // If the REST API Proxy Plugin isn't active, always use the current site.
        if(! PMB_REST_PROXY_EXISTS){
            $site = '';
        }
        $this->setSite($site);
        // If they forgot to add http(s), add it for them.
        if(strpos($this->getSite(), 'http://') === false && strpos($this->getSite(), 'https://') === false) {
            $this->setSite( 'http://' . $this->getSite());
        }
        // if there is one, check if it exists in wordpress.com, eg "retirementreflections.com"
        $site = trailingslashit(sanitize_text_field($this->getSite()));


Fixed code:         $this->setSite($this->sanitizeSite($site));
        $site = $this->getSite();
    /**
     * Avoid SSRF by sanitizing the site received.
     * @since $VID:$
     * @param $site
     * @return mixed|string
     */
    protected function sanitizeSite($site)
    {
        // If the REST API Proxy Plugin isn't active, always use the current site.
        if(! PMB_REST_PROXY_EXISTS){
            return '';
        }
        // If they forgot to add http(s), add it for them.
        if(strpos($site, 'http://') === false && strpos($site, 'https://') === false) {
            $site = 'http://' . $site;
        }
        // if there is one, check if it exists in wordpress.com, eg "retirementreflections.com"

        $file_info = pathinfo($site);
        if( isset($file_info['extension'])){
            $site = str_replace($file_info['filename'] . "." . $file_info['extension'], "", $site);
        }
        $site = trailingslashit(sanitize_text_field($site));
        return $site;
    }