The vulnerability is a path traversal issue in changedetection.io (GHSA-8757-69j2-hx56) that leads to arbitrary file disclosure. The exploit is initiated when an administrator restores a malicious backup ZIP file. An attacker can craft a history.txt file within this backup to contain a path to a sensitive file on the server, such as /etc/passwd.
The root cause of the vulnerability is located in the Watch.history property within changedetectionio/model/Watch.py. When parsing the history.txt file, the vulnerable version of this function failed to properly sanitize file paths. If a path contained a separator character (/ or \), it was trusted and stored as-is. This allowed an attacker to inject absolute or directory traversal paths into the application's history data.
This malicious path is subsequently used by the Watch.get_history_snapshot function in the same file. This function would receive the unsafe path and proceed to read the file at that location without any validation to ensure it was within the watch's designated data directory. The contents of the arbitrary file could then be exfiltrated through the application's UI via the "Preview" page or through the API, as both functionalities call get_history_snapshot.
The patch addresses this vulnerability by implementing two key changes. First, in the Watch.history property, it now uses os.path.basename to strip any directory information from the path and then resolves the path's real location to ensure it resides within the watch's data directory. Second, as a defense-in-depth measure, the Watch.get_history_snapshot function was updated to include a check that validates the filepath before any read operation is performed.
During an exploit, a runtime profiler would show Watch.history being called to process the malicious history.txt, followed by a call to Watch.get_history_snapshot to perform the arbitrary file read.