VAITP Dataset

← Back to the dataset

CVE-2026-32275

Unsanitized JSONP callback in Tautulli allows for XSS and API key theft.

  • CVSS 7.4
  • CWE-79
  • Input Validation and Sanitization
  • Remote

Tautulli is a Python based monitoring and tracking tool for Plex Media Server. From version 1.3.10 to before version 2.17.0, an unsanitized JSONP callback parameter allows cross-origin script injection and API key theft. This issue has been patched in version 2.17.0.

CVSS base score
7.4
Published
2026-03-30
OWASP
A03 Injection
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Input Validation and Sanitization
Subcategory
Cross-Site Scripting (XSS)
Accessibility scope
Remote
Impact
Data Theft
Affected component
Tautulli
Fixed by upgrading
Yes

Solution

Upgrade to version 2.17.0 or later.

Vulnerable code sample

from flask import Flask, request, Response, jsonify
import json

app = Flask(__name__)

@app.route('/api/v2', methods=['GET'])
def vulnerable_api_endpoint():
    # This endpoint returns sensitive data, including a mock API key.
    data = {
        'response': {
            'result': 'success',
            'message': None,
            'data': {
                'api_key': 'a_very_secret_api_key_12345',
                'other_data': 'some_value'
            }
        }
    }

    # The 'callback' parameter is retrieved from the request arguments.
    callback = request.args.get('callback')

    if callback:
        # VULNERABILITY: The unsanitized 'callback' value is directly
        # embedded into the response body.
        # An attacker can provide malicious JavaScript in the 'callback' parameter.
        # Example malicious request: /api/v2?callback=alert(1)//
        json_data = json.dumps(data)
        response_body = f"{callback}({json_data});"
        return Response(response_body, mimetype='application/javascript')
    else:
        # Default behavior for a non-JSONP request.
        return jsonify(data)

Patched code sample

import re
import json
from flask import Flask, request, Response

# This is a minimal Flask application to represent the server-side logic.
# It demonstrates how to fix a JSONP callback vulnerability.
app = Flask(__name__)

# A whitelist regex for what is considered a valid JSONP callback function name.
# It allows alphanumeric characters, underscores, dots, and dollar signs.
# This pattern strictly prevents the inclusion of characters like parentheses,
# semicolons, angle brackets, or spaces that an attacker would use to inject
# arbitrary scripts.
VALID_CALLBACK_REGEX = re.compile(r'^[a-zA-Z0-9_$.]+$')


@app.route('/api/example_endpoint')
def example_endpoint():
    """
    An example API endpoint that supports JSONP and demonstrates the fix for
    an unsanitized callback parameter.
    """
    callback_name = request.args.get('callback')
    api_data = {"status": "success", "data": "some_value"}
    json_response = json.dumps(api_data)

    # If a 'callback' parameter is present in the request URL.
    if callback_name:
        # THE FIX:
        # Before using the callback name, it is validated against the strict
        # regular expression.
        if VALID_CALLBACK_REGEX.match(callback_name):
            # If the name is valid and safe, wrap the JSON response in the
            # requested function call.
            padded_response = f"{callback_name}({json_response})"
            return Response(padded_response, mimetype='application/javascript')
        else:
            # If the callback name is invalid (e.g., contains malicious characters
            # like 'alert(1);'), it is rejected. The server falls back to
            # returning a standard, unpadded JSON response. This prevents the
            # malicious script from being injected into the response.
            return Response(json_response, mimetype='application/json')

    # If no callback parameter is provided, return a standard JSON response.
    return Response(json_response, mimetype='application/json')

Payload

alert(document.cookie);/*

Cite this entry

@misc{vaitp:cve202632275,
  title        = {{Unsanitized JSONP callback in Tautulli allows for XSS and API key theft.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-32275},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-32275/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::