Help Validating the content of file during File Upload

Hi All,

Our application has pages where file upload facility is available. During the test it was noted that arbitrary files of different content-type and size could be uploaded.
In one instance, testers could insert benign EICAR Test Virus file and also a binary(notepad.exe) file. It was uploaded and acknowledged as successful.

Multiple attack scenarios could be possible with the above vulnerability as attackers could upload malicious files or files with huge size there by forcing system to malfunction or exhaust system resources.

However we have a file size validation where it allows the file size up to the value entered in site_config.json i.e “max_file_size”.
But we also need to validate the content.

Hearing from anyone who has given a though on this before, would be of a great help.

Thanks in advance.

What version of Frappe are you using?

Frappe validates the filetype when you use the attach option:

Any Solution?

In hooks.py of your customp application

override_doctype_class = {
# “File”: “custom_app.overrides.doctype.file.CustomFile”,
}

And in file.py add the below code:

import mimetypes
import frappe
from frappe import _
from frappe.core.doctype.file.exceptions import MaxFileSizeReachedError
from frappe.core.doctype.file.file import File

class CustomFile(File):
def check_max_file_size(self):

    # Predefined file size limits by category (in bytes)
    file_type_limits = {
        "image": 5 * 1024 * 1024,   # 5 MB for image files
        "document": 10 * 1024 * 1024,  # 10 MB for document files
        "video": 30 * 1024 * 1024,   # 30 MB for video files
    }

    # Guess the MIME type of the file
    file_type = mimetypes.guess_type(self.file_name)[0]
    if not file_type:
        # If MIME type is undetectable, raise an error
        frappe.throw(_("Could not determine file type from MIME type."))

    # Determine the file's category based on MIME type
    if file_type.startswith("image"):
        file_category = "image"
    elif file_type.startswith("application"):
        # Check for common document types
        if any(file_type.startswith(prefix) for prefix in [
            "application/pdf", 
            "application/msword", 
            "application/vnd.ms-excel",]):
            file_category = "document"
    elif file_type.startswith("video"):
        file_category = "video"
    else:
        # If file type is unsupported, raise an error
        frappe.throw(_("Unsupported file type detected: {0}").format(file_type))

    # Get the file content size in bytes
    file_size = len(self.get("content") or b"")  # Default to empty byte string if no content

    # Check if the file size exceeds the maximum allowed limit for the detected category
    if file_category and file_size > file_type_limits.get(file_category, 0):
        # Raise error if file exceeds limit
        max_size_mb = file_type_limits[file_category] / (1024 * 1024)  # Convert bytes to MB
        msg = _("File size exceeds the maximum allowed limit of {0} MB").format(max_size_mb)
        frappe.throw(msg, exc=MaxFileSizeReachedError)

    return file_size  # Return the file size if it's within limits