Średnia

changedetection.io has Reflected XSS in its RSS Tag Error Response

  • Ujawniono: 04.03.2026
  • Aktualizacja: 11.10.2026 14:17

A reflected cross-site scripting (XSS) vulnerability was identified in the /rss/tag/ endpoint of changedetection.io. The tag_uuid path parameter is reflected directly in the HTTP response body without HTML escaping. Since Flask returns text/html by default for plain string responses, the browser parses and executes injected JavaScript.

This vulnerability persists in version 0.54.1, which patched the related XSS in /rss/watch/ (CVE-2026-27645 / GHSA-mw8m-398g-h89w) but did not address the identical pattern in the tag RSS endpoint.

Package

  • Ecosystem: pip
  • Package: changedetection.io
  • Affected versions: <= 0.54.1
  • Patched versions: (none yet)

Severity

Moderate - CVSS 6.1 CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

Details

File: changedetectionio/blueprint/rss/tag.py Line: 36 Source: tag.py @ 1d72716

The tag_uuid parameter from the URL path is interpolated into the response body using an f-string with no escaping:

python
tag = datastore.data['settings']['application'].get('tags', {}).get(tag_uuid)
if not tag:
    return f"Tag with UUID {tag_uuid} not found", 404  # ← No escaping, Content-Type: text/html

Flask's default Content-Type for plain string responses is text/html; charset=utf-8, so any HTML/JavaScript injected via {tag_uuid} is rendered and executed by the browser.

Relationship to CVE-2026-27645

CVE-2026-27645 (GHSA-mw8m-398g-h89w) addressed the identical vulnerability pattern in /rss/watch/ (single_watch.py). The fix applied in v0.54.1 patched that endpoint but did not fix the same pattern in /rss/tag/ (tag.py). Testing confirms:

  • /rss/watch/ on v0.54.1 — Returns generic 404 page, XSS no longer triggers ✅
  • /rss/tag/ on v0.54.1 — XSS payload still fires, vulnerability confirmed ❌

Attack Vector

The attack requires a valid RSS access token, which is a 32-character hex string exposed in the <link> HTML tag on the homepage without authentication:

  1. Attacker visits the target's homepage (if unauthenticated) and extracts the RSS token from the <link> tag

  2. Crafts a malicious URL:

    http://target:5000/rss/tag/<img src=x onerror=alert(document.cookie)>?token=EXTRACTED_TOKEN
  3. Sends the link to a victim who has an active session on the changedetection.io instance

  4. When the victim clicks the link, the server responds with:

    Tag with UUID <img src=x onerror=alert(document.cookie)> not found
  5. The browser renders the <img> tag, the onerror fires, and JavaScript executes in the victim's session context

Proof of Concept

Request

http
GET /rss/tag/%3Cimg%20src%3Dx%20onerror%3Dalert(document.domain)%3E?token=60b83b06df98b24c66367bc3d233105b HTTP/1.1
Host: localhost:5000

Response

http
HTTP/1.1 404 NOT FOUND
Content-Type: text/html; charset=utf-8

Tag with UUID <img src=x onerror=alert(document.domain)> not found

The XSS payload is reflected unescaped in an HTML response. The browser executes alert(document.domain) and displays "localhost", confirming JavaScript execution.

Tested on: changedetection.io v0.54.1 (Docker, localhost, Feb 25, 2026)

https://github.com/user-attachments/assets/6db07f6a-6df8-48a7-a597-9f39dfa1bb29

Impact

  • Session cookie theft via document.cookie exfiltration
  • Account takeover if session cookies lack the HttpOnly flag
  • Phishing via crafted links that appear to originate from a trusted changedetection.io instance
  • Low exploitation barrier - the RSS token is obtainable without authentication from the homepage <link> tag
  • Widespread exposure - prior scanning of internet-facing instances (during CVE-2026-27645 research) identified 500+ publicly accessible deployments

Suggested Fix

Escape the tag_uuid parameter before reflecting it in the response, or set the Content-Type to text/plain:

Option A: HTML Escape (Recommended)

python
from markupsafe import escape

if not tag:
    return f"Tag with UUID {escape(tag_uuid)} not found", 404

Option B: Set Content-Type to text/plain

python
from flask import make_response

if not tag:
    resp = make_response(f"Tag with UUID {tag_uuid} not found", 404)
    resp.headers['Content-Type'] = 'text/plain; charset=utf-8'
    return resp

Credits

References

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Python (PyPI) changedetection-io < 0.54.4 0.54.4

Odnośniki

Ocena CVSS 6.1/10
Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Słabość (CWE)
CWE-79
Platforma
Python (PyPI)
Paczka
changedetection-io
Ujawniono
04.03.2026
Aktualizacja
11.10.2026 14:17

Źródła i licencje

OSV / GitHub Advisory Database - PYSEC-2026-2127 - PyPA Advisory Database; CC BY 4.0

OSV / GitHub Advisory Database - GHSA-8whx-v8qq-pq64 - CC BY 4.0

Historia podatności: changedetection-io

Wszystkie opisane podatności tej paczki (Python (PyPI)), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (20) w archiwum
Wszystkich wpisów
20
Pierwsza → ostatnia
02.2023 05.2026
Bez poprawki
1
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 2
  • Wysoka 9
  • Średnia 6
  • Niska 2
  • Nieoceniona 1

Ujawnienia w latach

  1. 2023: 1
  2. 2024: 6
  3. 2025: 2
  4. 2026: 11
Istotność:
  1. Wysoka · 7.5 CVE-2026-41895 <= 0.54.9 brak poprawki
  2. changedetection.io has Reflected XSS in its RSS Tag Error Response ten wpis
    Średnia · 6.1 CVE-2026-29038 < 0.54.4 0.54.4
  3. Wysoka · 8.6 CVE-2026-27696 < 0.54.1 0.54.1
  4. Wysoka CVE-2025-52558 < 0.50.4 0.50.4

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.