CVE-2026-43891
changedetection.io: Arbitrary Local File Read via crafted backup restore
changedetection.io is a free open source web page change detection tool. Prior to 0.55.1, the vulnerability is caused by trusting attacker-controlled snapshot paths restored from backup files. The vulnerable flow starts in the backup restore logic. When a backup ZIP is restored, the application extracts the archive and copies each restored watch UUID directory directly into the live datastore using shutil.copytree(entry.path, dst_dir). This preserves attacker-controlled files inside the restored watch directory, including history.txt. After restore, the application parses history.txt in the watch history property and returns the contents of the targeted local file. This vulnerability is fixed in 0.55.1.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
7.5
changedetection.io: Arbitrary Local File Read via crafted backup restore
changedetection.io is a free open source web page change detection tool. Prior to 0.55.1, the vulnerability is caused by trusting attacker-controlled snapshot paths restored from backup files. The vulnerable flow starts in the backup restore logic. When a backup ZIP is restored, the application extracts the archive and copies each restored watch UUID directory directly into the live datastore using shutil.copytree(entry.path, dst_dir). This preserves attacker-controlled files inside the restored watch directory, including history.txt. After restore, the application parses history.txt in the watch history property and returns the contents of the targeted local file. This vulnerability is fixed in 0.55.1.
- Record
CVE-2026-43891- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-73
- Updated
- 2026-11-02
EUVDEUVD-2026-29720
7.5
changedetection.io is a free open source web page change detection tool. Prior to 0.55.1, the vulnerability is caused by trusting attacker-controlled snapshot paths restored from backup files. The vulnerable flow starts in the backup restore logic. When a backup ZIP is restored, the application extracts the archive and copies each restored watch UUID directory directly into the live datastore using shutil.copytree(entry.path, dst_dir). This preserves attacker-controlled files inside the restored watch directory, including history.txt. After restore, the application parses history.txt in the watch history property and returns the contents of the targeted local file. This vulnerability is fixed in 0.55.1.
- Record
EUVD-2026-29720- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-8757-69j2-hx56
7.5
changedetection.io has an Arbitrary Local File Read via a crafted backup restore
Details
The vulnerability is caused by trusting attacker-controlled snapshot paths restored from backup files.
The vulnerable flow starts in the backup restore logic. When a backup ZIP is restored, the application extracts the archive and copies each restored watch UUID directory directly into the live datastore using shutil.copytree(entry.path, dst_dir). This preserves attacker-controlled files inside the restored watch directory, including history.txt.
Relevant code:
After restore, the application parses history.txt in the watch history property. This is the core trust-boundary issue.
Relevant code:
The relevant logic is effectively:
if os.sep not in v and '/' not in v and '\\' not in v:
v = os.path.join(self.data_dir, v)
else:
snapshot_fname = os.path.basename(v)
proposed_new_path = os.path.join(self.data_dir, snapshot_fname)
if not os.path.exists(v) and os.path.exists(proposed_new_path):
v = proposed_new_path
This has the following security consequence:
- If the
history.txtvalue is only a filename, it is resolved safely underself.data_dir. - If the value contains path separators, it is treated as a path reference rather than a watch-local snapshot name.
- If that external path already exists, it is preserved unchanged.
As a result, a malicious restored history.txt entry such as:
1776969105,/etc/passwd
will be accepted if the referenced file exists and is readable by the application process.
The second vulnerable step is in get_history_snapshot(). Once the untrusted path has been accepted into the watch history, the application reads the resolved path directly without enforcing that it remains inside the watch directory.
Relevant code:
That function eventually performs direct file reads such as:
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
return f.read()
The third step is reachability. The trusted history entry is consumed by both the Preview UI and the watch history API.
Relevant code:
In the Preview flow, the application selects the latest history timestamp and calls:
content = watch.get_history_snapshot(timestamp=timestamp)
In the API flow, the application also calls:
content = watch.get_history_snapshot(timestamp=timestamp)
This creates the following end-to-end exploit chain:
- An attacker supplies a crafted backup ZIP.
- The restore process preserves attacker-controlled
history.txt. - The
history.txtparser accepts an absolute or out-of-directory path if that path exists. - Preview or the history API dereferences the stored path directly.
- The application returns the contents of the targeted local file.
The root cause is that imported history entries are treated as trusted filesystem paths instead of being restricted to safe…
- Record
GHSA-8757-69j2-hx56- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-73
- Updated
- 2026-11-02
NVD
7.5
changedetection.io is a free open source web page change detection tool. Prior to 0.55.1, the vulnerability is caused by trusting attacker-controlled snapshot paths restored from backup files. The vulnerable flow starts in the backup restore logic. When a backup ZIP is restored, the application extracts the archive and copies each restored watch UUID directory directly into the live datastore using shutil.copytree(entry.path, dst_dir). This preserves attacker-controlled files inside the restored watch directory, including history.txt. After restore, the application parses history.txt in the watch history property and returns the contents of the targeted local file. This vulnerability is fixed in 0.55.1.
- Record
CVE-2026-43891- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-73
- Updated
- 2026-11-02
OSV
7.5
changedetection.io: Arbitrary Local File Read via crafted backup restore
changedetection.io is a free open source web page change detection tool. Prior to 0.55.1, the vulnerability is caused by trusting attacker-controlled snapshot paths restored from backup files. The vulnerable flow starts in the backup restore logic. When a backup ZIP is restored, the application extracts the archive and copies each restored watch UUID directory directly into the live datastore using shutil.copytree(entry.path, dst_dir). This preserves attacker-controlled files inside the restored watch directory, including history.txt. After restore, the application parses history.txt in the watch history property and returns the contents of the targeted local file. This vulnerability is fixed in 0.55.1.
- Record
CVE-2026-43891- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-73
- Updated
- 2026-11-02
OSVGHSA-8757-69j2-hx56
7.5
changedetection.io has an Arbitrary Local File Read via a crafted backup restore
Details
The vulnerability is caused by trusting attacker-controlled snapshot paths restored from backup files.
The vulnerable flow starts in the backup restore logic. When a backup ZIP is restored, the application extracts the archive and copies each restored watch UUID directory directly into the live datastore using shutil.copytree(entry.path, dst_dir). This preserves attacker-controlled files inside the restored watch directory, including history.txt.
Relevant code:
After restore, the application parses history.txt in the watch history property. This is the core trust-boundary issue.
Relevant code:
The relevant logic is effectively:
if os.sep not in v and '/' not in v and '\\' not in v:
v = os.path.join(self.data_dir, v)
else:
snapshot_fname = os.path.basename(v)
proposed_new_path = os.path.join(self.data_dir, snapshot_fname)
if not os.path.exists(v) and os.path.exists(proposed_new_path):
v = proposed_new_path
This has the following security consequence:
- If the
history.txtvalue is only a filename, it is resolved safely underself.data_dir. - If the value contains path separators, it is treated as a path reference rather than a watch-local snapshot name.
- If that external path already exists, it is preserved unchanged.
As a result, a malicious restored history.txt entry such as:
1776969105,/etc/passwd
will be accepted if the referenced file exists and is readable by the application process.
The second vulnerable step is in get_history_snapshot(). Once the untrusted path has been accepted into the watch history, the application reads the resolved path directly without enforcing that it remains inside the watch directory.
Relevant code:
That function eventually performs direct file reads such as:
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
return f.read()
The third step is reachability. The trusted history entry is consumed by both the Preview UI and the watch history API.
Relevant code:
In the Preview flow, the application selects the latest history timestamp and calls:
content = watch.get_history_snapshot(timestamp=timestamp)
In the API flow, the application also calls:
content = watch.get_history_snapshot(timestamp=timestamp)
This creates the following end-to-end exploit chain:
- An attacker supplies a crafted backup ZIP.
- The restore process preserves attacker-controlled
history.txt. - The
history.txtparser accepts an absolute or out-of-directory path if that path exists. - Preview or the history API dereferences the stored path directly.
- The application returns the contents of the targeted local file.
The root cause is that imported history entries are treated as trusted filesystem paths instead of being restricted to safe…
- Record
GHSA-8757-69j2-hx56- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-73
- Updated
- 2026-11-02
OSVPYSEC-2026-30
7.5
changedetection.io is a free open source web page change detection tool. Prior to 0.55.1, the vulnerability is caused by trusting attacker-controlled snapshot paths restored from backup files. The vulnerable flow starts in the backup restore logic. When a backup ZIP is restored, the application extracts the archive and copies each restored watch UUID directory directly into the live datastore using shutil.copytree(entry.path, dst_dir). This preserves attacker-controlled files inside the restored watch directory, including history.txt. After restore, the application parses history.txt in the watch history property and returns the contents of the targeted local file. This vulnerability is fixed in 0.55.1.
- Record
PYSEC-2026-30- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
changedetection-ioPyPI |
through 0.54.10 | 0.55.1 |
changedetection-ioPyPI |
before 0.55.1, plus listed versions 0.38.20.390.39.10.39.100.39.10.post1 Show 45 moreShow less0.39.10.post20.39.110.39.120.39.130.39.13.10.39.140.39.14.10.39.150.39.160.39.170.39.17.10.39.17.20.39.180.39.190.39.19.10.39.20.39.200.39.20.10.39.20.20.39.20.30.39.20.40.39.210.39.21.10.39.220.39.22.10.39.30.39.40.39.50.39.60.39.70.39.80.39.90.40.00.40.0.10.40.0.20.40.0.30.40.0.40.40.1.00.40.1.10.40.20.40.30.410.41.10.420.42.1 |
0.55.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-43891 is a high vulnerability (CVSS 7.5) in Dgtlmoon Changedetection.io, published May 5, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.35%, the 29th percentile. Fixed in changedetection-io 0.55.1.
References
github.com/dgtlmoon/changedetection.io/security/advisories/GHSA-8757-69j2-hx56
github.com/pocket-id/pocket-id/security/advisories/GHSA-w6p7-2fxx-4f44
nvd.nist.gov/vuln/detail/CVE-2026-43891
github.com/pypa/advisory-database/tree/main/vulns/changedetection-io/PYSEC-2026-30.yaml
github.com/advisories/GHSA-8757-69j2-hx56
github.com/CVEProject/cvelistV5/tree/main/cves/2026/43xxx/CVE-2026-43891.json
github.com/dgtlmoon/changedetection.io
Left out here: 146 versions and the rest of 2 source descriptions. The JSON record has them.