CVE-2022-23071 (Python, published 2022-06-19T11:15Z)
Description: value: In Recipes, versions 0.9.1 through 1.2.5 are vulnerable to Server Side Request Forgery (SSRF), in the “Import Recipe” functionality. When an attacker enters the localhost URL, a low privileged attacker can access/read the internal file system to access sensitive information.
Severity: MEDIUM (CVSS v3 base score: 6.5)
Weakness: CWE-918 \u2014 Server-Side Request Forgery (SSRF)
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.
Repository: https://github.com/TandoorRecipes/recipes
Files changed:
cookbook/integration/cookbookapp.py
cookbook/integration/cookmate.py
cookbook/integration/recettetek.py
cookbook/integration/recipesage.py
cookbook/provider/dropbox.py
cookbook/provider/nextcloud.py
cookbook/views/api.py
requirements.txt
Commit message: added url validation to all server requests


Vulnerable code:
                response = requests.get(images[0])
                self.import_recipe_image(recipe, BytesIO(response.content))
                response = requests.get(recipe_xml.find('imageurl').text.strip())
                    response = requests.get(file['originalPicture'])
                    if imghdr.what(BytesIO(response.content)) is not None:
                        self.import_recipe_image(recipe, BytesIO(response.content), filetype=get_filetype(file['originalPicture']))
                    else:
                        raise Exception("Original image failed to download.")
                response = requests.get(file['image'][0])
                self.import_recipe_image(recipe, BytesIO(response.content))
        response = requests.get(recipe.link.replace('www.dropbox.', 'dl.dropboxusercontent.'))
        return io.BytesIO(response.content)
        r = requests.get(
            url,
            headers=headers,
            auth=HTTPBasicAuth(
                recipe.storage.username, recipe.storage.password
        )
        response_json = r.json()
        for element in response_json['ocs']['data']:
            if element['share_type'] == '3':
                return element['url']
        return Nextcloud.create_share_link(recipe)
from django.db.models import (Case, Count, Exists, F, IntegerField, OuterRef, ProtectedError, Q,
from recipe_scrapers import NoSchemaFoundInWildMode, WebsiteNotImplementedError, scrape_me
from cookbook.helper.recipe_url_import import get_from_scraper
            filetype = ".jpeg" # fall-back to .jpeg, even if wrong, at least users will know it's an image and most image viewers can open it correctly anyways
                    response = requests.get(serializer.validated_data['image_url'])
                    image = File(io.BytesIO(response.content))
                    filetype = mimetypes.guess_extension(response.headers['content-type']) or filetype
            data = requests.get(url, headers=external_request_headers).content

Fixed code:
import validators
                url = images[0]
                if validators.url(url, public=True):
                    response = requests.get(url)
                    self.import_recipe_image(recipe, BytesIO(response.content))
import validators
                url = recipe_xml.find('imageurl').text.strip()
                if validators.url(url, public=True):
                    response = requests.get(url)
import validators
                    url = file['originalPicture']
                    if validators.url(url, public=True):
                        response = requests.get(url)
                        if imghdr.what(BytesIO(response.content)) is not None:
                            self.import_recipe_image(recipe, BytesIO(response.content), filetype=get_filetype(file['originalPicture']))
                        else:
                            raise Exception("Original image failed to download.")
import validators
                url = file['image'][0]
                if validators.url(url, public=True):
                    response = requests.get(url)
                    self.import_recipe_image(recipe, BytesIO(response.content))
import validators

        url = recipe.link.replace('www.dropbox.', 'dl.dropboxusercontent.')
        if validators.url(url, public=True):
            response = requests.get(url)
            return io.BytesIO(response.content)
import validators
        if validators.url(url, public=True):
            r = requests.get(
                url,
                headers=headers,
                auth=HTTPBasicAuth(
                    recipe.storage.username, recipe.storage.password
                )
            response_json = r.json()
            for element in response_json['ocs']['data']:
                if element['share_type'] == '3':
                    return element['url']
            return Nextcloud.create_share_link(recipe)
import validators
from django.db.models import (Case, Count, Exists, OuterRef, ProtectedError, Q,
from validators import ValidationFailure
            filetype = ".jpeg"  # fall-back to .jpeg, even if wrong, at least users will know it's an image and most image viewers can open it correctly anyways
                    url = serializer.validated_data['image_url']
                    if validators.url(url, public=True):
                        response = requests.get(url)
                        image = File(io.BytesIO(response.content))
                        filetype = mimetypes.guess_extension(response.headers['content-type']) or filetype
            if validators.url(url, public=True):
                data = requests.get(url, headers=external_request_headers).content
            else:
                return JsonResponse({
                    'error': True,
                    'msg': _('Invalid Url')
                }, status=400)

validators==0.19.0