CVE-2024-31451: Insufficient Information (NVD-CWE-noinfo)
value: DocsGPT is a GPT-powered chat for documentation. DocsGPT is vulnerable to unauthenticated limited file write in routes.py. This vulnerability is fixed in 0.8.1.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-04-16T15:15Z
Repository: https://github.com/arc53/DocsGPT
Language: Python
Files changed: application/api/user/routes.py
Commit date: 2024-04-08 12:56:27 +0100
Commit message: advisory-fix

Diff: diff --git a/application/api/user/routes.py b/application/api/user/routes.py
index b1ec69e..ec75554 100644
--- a/application/api/user/routes.py
+++ b/application/api/user/routes.py
@@ -1,8 +1,9 @@
 import os
 import uuid
 from flask import Blueprint, request, jsonify
+from urllib.parse import urlparse
 import requests
 from pymongo import MongoClient
 from bson.objectid import ObjectId
 from werkzeug.utils import secure_filename
 
@@ -250,24 +251,30 @@ def check_docs():
     vectorstore = "vectors/" + data["docs"]
     base_path = "https://raw.githubusercontent.com/arc53/DocsHUB/main/"
     if os.path.exists(vectorstore) or data["docs"] == "default":
         return {"status": "exists"}
     else:
-        r = requests.get(base_path + vectorstore + "index.faiss")
-
-        if r.status_code != 200:
-            return {"status": "null"}
+        file_url = urlparse(base_path + vectorstore + "index.faiss")
+        
+        if file_url.scheme in ['https'] and file_url.netloc == 'raw.githubusercontent.com' and file_url.path.startswith('/arc53/DocsHUB/main/'):
+            
+            r = requests.get(file_url.geturl())
+
+            if r.status_code != 200:
+                return {"status": "null"}
+            else:
+                if not os.path.exists(vectorstore):
+                    os.makedirs(vectorstore)
+                with open(vectorstore + "index.faiss", "wb") as f:
+                    f.write(r.content)
+
+                # download the store
+                r = requests.get(base_path + vectorstore + "index.pkl")
+                with open(vectorstore + "index.pkl", "wb") as f:
+                    f.write(r.content)
         else:
-            if not os.path.exists(vectorstore):
-                os.makedirs(vectorstore)
-            with open(vectorstore + "index.faiss", "wb") as f:
-                f.write(r.content)
-
-            # download the store
-            r = requests.get(base_path + vectorstore + "index.pkl")
-            with open(vectorstore + "index.pkl", "wb") as f:
-                f.write(r.content)
+            return {"status": "null"}
 
         return {"status": "loaded"}
 
 @user.route("/api/create_prompt", methods=["POST"])
 def create_prompt():

Vulnerable code:         r = requests.get(base_path + vectorstore + "index.faiss")

        if r.status_code != 200:
            return {"status": "null"}
            if not os.path.exists(vectorstore):
                os.makedirs(vectorstore)
            with open(vectorstore + "index.faiss", "wb") as f:
                f.write(r.content)

            # download the store
            r = requests.get(base_path + vectorstore + "index.pkl")
            with open(vectorstore + "index.pkl", "wb") as f:
                f.write(r.content)
Fixed code: from urllib.parse import urlparse
        file_url = urlparse(base_path + vectorstore + "index.faiss")
        
        if file_url.scheme in ['https'] and file_url.netloc == 'raw.githubusercontent.com' and file_url.path.startswith('/arc53/DocsHUB/main/'):
            
            r = requests.get(file_url.geturl())

            if r.status_code != 200:
                return {"status": "null"}
            else:
                if not os.path.exists(vectorstore):
                    os.makedirs(vectorstore)
                with open(vectorstore + "index.faiss", "wb") as f:
                    f.write(r.content)

                # download the store
                r = requests.get(base_path + vectorstore + "index.pkl")
                with open(vectorstore + "index.pkl", "wb") as f:
                    f.write(r.content)
            return {"status": "null"}