From 419877967c22b6793f2f5fbc2bb73d232948fa70 Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Mon, 16 Feb 2026 16:01:30 +0100 Subject: [PATCH] UI/ Security - Fixing over-zealous filename cleaner --- changedetectionio/flask_app.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/changedetectionio/flask_app.py b/changedetectionio/flask_app.py index 2b2cc356c..8246b0d01 100644 --- a/changedetectionio/flask_app.py +++ b/changedetectionio/flask_app.py @@ -712,9 +712,25 @@ def changedetection_app(config=None, datastore_o=None): def static_content(group, filename): from flask import make_response import re + def sanitize_filename(filename): + filename = filename.lower() + + # Split extension + name, ext = os.path.splitext(filename) + + # Remove unwanted chars from name and extension + name = re.sub(r'[^a-z0-9_]+', '', name) + ext = re.sub(r'[^a-z0-9]+', '', ext.lstrip('.')) + + if not name: + raise ValueError("Invalid filename") + + # Rebuild with at most one dot + return f"{name}.{ext}" if ext else name + # Strict sanitization: only allow a-z, 0-9, and underscore (blocks .. and other traversal) group = re.sub(r'[^a-z0-9_]+', '', group.lower()) - filename = re.sub(r'[^a-z0-9_]+', '', filename.lower()) + filename = sanitize_filename(filename) # Additional safety: reject if sanitization resulted in empty strings if not group or not filename: