| Gói / sản phẩm | Phiên bản bị ảnh hưởng | Phiên bản đã vá |
|---|---|---|
| changedetection-io | < 0.53.7< 0.54.1 | 0.53.70.54.1 |
| changedetection | < 0.54.1 | 0.54.1 |
Three security vulnerabilities were identified in changedetection.io through source code review and live validation against a locally deployed Docker instance. All vulnerabilities were confirmed exploitable on the latest version (0.53.6) it was additionally validated at scale against 500 internet-facing instances discovered via FOFA search engine, producing 5K+ confirmed detections using a custom Nuclei template, demonstrating widespread real-world impact. The RSS single-watch endpoint reflects the UUID path parameter 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.
File: changedetectionio/blueprint/rss/single_watch.py (lines ~45 and ~50)
The UUID parameter from the URL path is interpolated into the response body using an f-string with no escaping:
watch = datastore.data['watching'].get(uuid)
if not watch:
return f"Watch with UUID {uuid} not found", 404 # ← No escaping, Content-Type: text/html
if len(dates) < 2:
return f"Watch {uuid} does not have enough history snapshots...", 400 # ← Same issue
Flask's default Content-Type for plain string responses is text/html; charset=utf-8, so any HTML/JavaScript in {uuid} is rendered by the browser.
The attack requires a valid RSS access token, which is a 32-character hex string exposed in the HTML <link> tag on the homepage without authentication:
<!-- Visible in page source of any unauthenticated instance --> <link rel="alternate" type="application/rss+xml" href="/rss?token=f2bb14e20ff01bad83a743cf21b5df95">Attacker visits the target's homepage if it unauthenticathed and extracts the RSS token from the <link> tag Crafts a malicious URL:
The browser renders the <img> tag, the onerror fires, and JavaScript executes in the victim's session context
Request:
GET /rss/watch/%3Cimg%20src%3Dx%20onerror%3Dalert(document.cookie)%3E?token=223e7edbbfee2268f5abb5344919054e HTTP/1.1
Host: [127.0.0.1:5000](http://127.0.0.1:5000/)
<img width="1918" height="1032" alt="image" src="https://github.com/user-attachments/assets/1633b167-e4ec-4705-a110-18fad7826fc9" />
Bạn đang dùng một trong các sản phẩm này? Quét site để biết có đang lộ phiên bản có lỗ hổng không.
Quét site miễn phíResponse:
HTTP/1.1 404 NOT FOUND
Content-Type: text/html; charset=utf-8
Watch with UUID not found
The XSS payload is reflected unescaped in an HTML response. The browser executes alert(document.cookie).
Lots of intances over internet affected to this. <img width="1465" height="721" alt="image" src="https://github.com/user-attachments/assets/f54160d4-abd1-4e8d-b845-f85e53e79325" />
changedetection.io can work with developer teams to validate and address these issues. Please confirm receipt of this report and inform changedetection.io of the preferred timeline for coordinating the fix.
Roberto Nunes