VYPR
High severityNVD Advisory· Published May 14, 2025· Updated May 15, 2025

label-studio vulnerable to Cross-Site Scripting (Reflected) via the label_config parameter.

CVE-2025-47783

Description

Label Studio is a multi-type data labeling and annotation tool. A vulnerability in versions prior to 1.18.0 allows an attacker to inject a malicious script into the context of a web page, which can lead to data theft, session hijacking, unauthorized actions on behalf of the user, and other attacks. The vulnerability is reproducible when sending a properly formatted request to the POST /projects/upload-example/ endpoint. In the source code, the vulnerability is located at label_studio/projects/views.py. Version 1.18.0 contains a patch for the issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
label-studioPyPI
< 1.18.01.18.0

Affected products

1

Patches

1
97db9e7b1678

fix: LEAP-2058: delete unused upload-example endpoint (#7440)

4 files changed · +0 143
  • label_studio/core/all_urls.json+0 6 modified
    @@ -131,12 +131,6 @@
             "name": "projects:project-settings-anything",
             "decorators": ""
         },
    -    {
    -        "url": "/projects/upload-example/",
    -        "module": "projects.views.upload_example_using_config",
    -        "name": "projects:project-upload-example-using-config",
    -        "decorators": ""
    -    },
         {
             "url": "/api/projects/",
             "module": "projects.api.ProjectListAPI",
    
  • label_studio/projects/urls.py+0 1 modified
    @@ -11,7 +11,6 @@
         path('', views.project_list, name='project-index'),
         path('<int:pk>/settings/', views.project_settings, name='project-settings', kwargs={'sub_path': ''}),
         path('<int:pk>/settings/<sub_path>', views.project_settings, name='project-settings-anything'),
    -    path('upload-example/', views.upload_example_using_config, name='project-upload-example-using-config'),
     ]
     
     # reverse for projects:api:name
    
  • label_studio/projects/views.py+0 40 modified
    @@ -1,19 +1,9 @@
     """This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
     """
    -import json
     import logging
     
    -import lxml.etree
    -from core.label_config import get_sample_task
    -from core.utils.common import get_organization_from_request
     from django.contrib.auth.decorators import login_required
    -from django.http import HttpResponse
     from django.shortcuts import render
    -from django.views.decorators.http import require_http_methods
    -from organizations.models import Organization
    -from projects.models import Project
    -from rest_framework import generics, status
    -from rest_framework.exceptions import ValidationError
     
     logger = logging.getLogger(__name__)
     
    @@ -26,33 +16,3 @@ def project_list(request):
     @login_required
     def project_settings(request, pk, sub_path):
         return render(request, 'projects/settings.html')
    -
    -
    -def playground_replacements(request, task_data):
    -    if request.GET.get('playground', '0') == '1':
    -        for key in task_data:
    -            if '/samples/time-series.csv' in task_data[key]:
    -                task_data[key] = 'https://app.heartex.ai' + task_data[key]
    -    return task_data
    -
    -
    -@require_http_methods(['POST'])
    -def upload_example_using_config(request):
    -    """Generate upload data example by config only"""
    -    config = request.POST.get('label_config', '')
    -
    -    org_pk = get_organization_from_request(request)
    -    secure_mode = False
    -    if org_pk is not None:
    -        org = generics.get_object_or_404(Organization, pk=org_pk)
    -        secure_mode = org.secure_mode
    -
    -    try:
    -        Project.validate_label_config(config)
    -        task_data, _, _ = get_sample_task(config, secure_mode)
    -        task_data = playground_replacements(request, task_data)
    -    except (ValueError, ValidationError, lxml.etree.Error):
    -        response = HttpResponse('error while example generating', status=status.HTTP_400_BAD_REQUEST)
    -    else:
    -        response = HttpResponse(json.dumps(task_data))
    -    return response
    
  • label_studio/tests/sample_tasks.tavern.yml+0 96 removed
    @@ -1,96 +0,0 @@
    ----
    -test_name: get_paragraphs_sample_task
    -strict: false
    -marks:
    -- usefixtures:
    -  - django_live_url
    -stages:
    -- id: signup
    -  type: ref
    -- name: stage
    -  request:
    -    data:
    -      label_config: "<View>\n  <ParagraphLabels name=\"actions\" toName=\"dialogue\"\
    -        >\n      <Label value=\"Inform\"></Label>\n      <Label value=\"Request\"\
    -        ></Label>\n      <Label value=\"Negate\"></Label>\n      <Label value=\"Affirm\"\
    -        ></Label>\n  </ParagraphLabels>\n\n  <Paragraphs\n          audioUrl=\"$audio\"\
    -        \n          name=\"dialogue\"\n          value=\"$dialogue\"\n          layout=\"\
    -        dialogue\"\n          savetextresult=\"yes\"\n          nameKey=\"speaker\"\
    -        \n          textKey=\"phrase\"\n  />\n</View>\n"
    -    headers:
    -      content-type: application/x-www-form-urlencoded
    -    method: POST
    -    url: '{django_live_url}/projects/upload-example'
    -  response:
    -    json:
    -      dialogue:
    -      - phrase: 'Sample: Text #1'
    -        speaker: Alice
    -      - phrase: 'Sample: Text #2'
    -        speaker: Bob
    -      - phrase: 'Sample: Text #3'
    -        speaker: Alice
    -      - phrase: 'Sample: Text #4'
    -        speaker: Bob
    -      - phrase: 'Sample: Text #5'
    -        speaker: Alice
    -    status_code: 200
    -
    ----
    -test_name: get_paragraphs_sample_task_value_type_url
    -strict: false
    -marks:
    -- usefixtures:
    -  - django_live_url
    -stages:
    -- id: signup
    -  type: ref
    -- name: stage
    -  request:
    -    data:
    -      label_config: "<View>\n  <ParagraphLabels name=\"actions\" toName=\"dialogue\"\
    -        >\n      <Label value=\"Inform\"></Label>\n      <Label value=\"Request\"\
    -        ></Label>\n      <Label value=\"Negate\"></Label>\n      <Label value=\"Affirm\"\
    -        ></Label>\n  </ParagraphLabels>\n\n  <Paragraphs\n          audioUrl=\"$audio\"\
    -        \n          name=\"dialogue\"\n          value=\"$dialogue\"\n          layout=\"\
    -        dialogue\"\n          savetextresult=\"yes\"\n          nameKey=\"speaker\"\
    -        \n          textKey=\"phrase\"\n valueType=\"url\"  />\n</View>\n"
    -    headers:
    -      content-type: application/x-www-form-urlencoded
    -    method: POST
    -    url: '{django_live_url}/projects/upload-example'
    -  response:
    -    json:
    -      dialogue: /samples/paragraphs.json?nameKey=speaker&textKey=phrase
    -    status_code: 200
    -
    ----
    -test_name: get_image_sample_task_with_value_list
    -strict: false
    -marks:
    -  - usefixtures:
    -      - django_live_url
    -stages:
    -  - id: signup
    -    type: ref
    -  - name: stage
    -    request:
    -      data:
    -        label_config: |
    -          <View>
    -            <Image name="image" valueList="$images"/>
    -            <RectangleLabels name="labels" toName="image">
    -                <Label value="Label1"/>
    -                <Label value="Label2"/>
    -                <Label value="Label3"/>
    -            </RectangleLabels>
    -          </View>
    -      headers:
    -        content-type: application/x-www-form-urlencoded
    -      method: POST
    -      url: '{django_live_url}/projects/upload-example'
    -    response:
    -      json:
    -        images:
    -          - "/static/samples/sample.jpg"
    -      status_code: 200
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.