Cross-site Scripting Vulnerability on Data Import
Medium4.7CVE-2024-23633 · Published Jan 24, 2024 · updated Sep 10, 2026
# Introduction This write-up describes a vulnerability found in [Label Studio](https://github.com/HumanSignal/label-studio), a popular open source data labeling tool. The vulnerability affects all versions of Label Studio prior to `1.10.1` and was tested on version `1.9.2.post0`. # Overview [Label Studio](https://github.com/HumanSignal/label-studio) had a remote import feature allowed users to import data from a remote web source, that was downloaded and could be viewed on the website. This feature could had been abused to download a HTML file that executed malicious JavaScript code in the context of the Label Studio website. # Description The following [code snippet in Label Studio](https://github.com/HumanSignal/label-studio/blob/1.9.2.post0/label_studio/data_import/uploader.py#L125C5-L146) showed that is a URL passed the SSRF verification checks, the contents of the file would be downloaded using the filename in the URL. ```python def tasks_from_url(file_upload_ids, project, user, url, could_be_tasks_list): """Download file using URL and read tasks from it""" # process URL with tasks try: filename = url.rsplit('/', 1)[-1] <1> response = ssrf_sa...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| label-studio PyPI | < 1.10.1 | 1.10.1 |
Details and references
# Introduction This write-up describes a vulnerability found in [Label Studio](https://github.com/HumanSignal/label-studio), a popular open source data labeling tool. The vulnerability affects all versions of Label Studio prior to `1.10.1` and was tested on version `1.9.2.post0`. # Overview [Label Studio](https://github.com/HumanSignal/label-studio) had a remote import feature allowed users to import data from a remote web source, that was downloaded and could be viewed on the website. This feature could had been abused to download a HTML file that executed malicious JavaScript code in the context of the Label Studio website. # Description The following [code snippet in Label Studio](https://github.com/HumanSignal/label-studio/blob/1.9.2.post0/label_studio/data_import/uploader.py#L125C5-L146) showed that is a URL passed the SSRF verification checks, the contents of the file would be downloaded using the filename in the URL. ```python def tasks_from_url(file_upload_ids, project, user, url, could_be_tasks_list): """Download file using URL and read tasks from it""" # process URL with tasks try: filename = url.rsplit('/', 1)[-1] <1> response = ssrf_safe_get( url, verify=project.organization.should_verify_ssl_certs(), stream=True, headers={'Accept-Encoding': None} ) file_content = response.content check_tasks_max_file_size(int(response.headers['content-length'])) file_upload = create_file_upload(user, project, SimpleUploadedFile(filename, file_content)) if file_upload.format_could_be_tasks_list: could_be_tasks_list = True file_upload_ids.append(file_upload.id) tasks, found_formats, data_keys = FileUpload.load_tasks_from_uploaded_files(project, file_upload_ids) except ValidationError as e: raise e except Exception as e: raise ValidationError(str(e)) return data_keys, found_formats, tasks, file_upload_ids, could_be_tasks_list ``` 1. The file name that was set was retrieved from the URL. The downloaded file path could then be retrieved by sending a request to `/api/projects/{project_id}/file-uploads?ids=[{download_id}]` where `{project_id}` was the ID of the project and `{download_id}` was the ID of the downloaded file. Once the downloaded file path was retrieved by the previous API endpoint, the [following code snippet](https://github.com/HumanSignal/label-studio/blob/1.9.2.post0/label_studio/data_import/api.py#L595C1-L616C62) demonstrated that the `Content-Type` of the response was determined by the file extension, since `mimetypes.guess_type` guesses the `Content-Type` based on the file extension. ```python class UploadedFileResponse(generics.RetrieveAPIView): permission_classes = (IsAuthenticated,) @swagger_auto_schema(auto_schema=None) def get(self, *args, **kwargs): request = self.request filename = kwargs['filename'] # XXX needed, on windows os.path.join generates '\' which breaks FileUpload file = settings.UPLOAD_DIR + ('/' if not settings.UPLOAD_DIR.endswith('/') else '') + filename logger.debug(f'Fetch uploaded file by user {request.user} => {file}') file_upload = FileUpload.objects.filter(file=file).last() if not file_upload.has_permission(request.user): return Response(status=status.HTTP_403_FORBIDDEN) file = file_upload.file if file.storage.exists(file.name): content_type, encoding = mimetypes.guess_type(str(file.name)) <1> content_type = content_type or 'application/octet-stream' return RangedFileResponse(request, file.open(mode='rb'), content_type=content_type) else: return Response(status=status.HTTP_404_NOT_FOUND) ``` 1. Determines the `Content-Type` based on the extension of the uploaded file by using `mimetypes.guess_type`. Since the `Content-Type` was determined by the file extension of the downloaded file, an attacker
- CVSS 3.1
- CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N
- Severity from
- GitHub (reviewed advisory)
- Weakness
- CWE-79
- Also known as
- CVE-2024-23633, PYSEC-2024-128
- github.com/HumanSignal/label-studio/security/advisories/GHSA-fq23-g58m-799r
- nvd.nist.gov/vuln/detail/CVE-2024-23633
- developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox
- github.com/HumanSignal/label-studio
- github.com/HumanSignal/label-studio/blob/1.9.2.post0/label_studio/data_import/api.py#L595C1-L616C62
- github.com/HumanSignal/label-studio/blob/1.9.2.post0/label_studio/data_import/uploader.py#L125C5-L146
- github.com/pypa/advisory-database/tree/main/vulns/label-studio/PYSEC-2024-128.yaml
More Label Studio advisories
All Label Studio| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| Feb 222024 | Label Studio vulnerable to Cross-site Scripting if `<Choices>` or `<Labels>` are used in labeling config | Medium4.7 | 1.11.0 |
| Jan 312024 | Label Studio SSRF on Import Bypassing `SSRF_PROTECTION_ENABLED` Protections | Medium5.3 | 1.11.0 |
| Jan 242024 | Cross-site Scripting Vulnerability on Avatar Upload | High7.1 | 1.9.2 |
| Nov 142023 | Label Studio Object Relational Mapper Leak Vulnerability in Filtering Task | High7.5 | 1.9.2.post0 |
| Nov 92023 | Label Studio has Hardcoded Django `SECRET_KEY` that can be Abused to Forge Session Tokens | Critical9.8 | 1.8.2 |
| Mar 242023 | Nginx alias path traversal allows unauthenticated attackers to read all files on /label_studio/core/ | High7.5 | 1.7.2 |