
PoC: asignación masiva por fusión ciega en la configuración de changedetection.io (CVE-2026-71204, Media 6.3)
Producto: dgtlmoon/changedetection.io — v0.55.7
Archivos: changedetectionio/blueprint/settings/__init__.py, changedetectionio/forms.py
CWE: CWE-284 — Control de acceso inadecuado
CVSS 3.1: AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:L — 6.3 (Media)
CNA: Turan Security · registro de CVE
El manejador de guardado de /settings de changedetection.io construye un dict de actualización a partir de form.data['application'] y lo fusiona a ciegas en la configuración almacenada de la aplicación mediante .update(). Debido a que las casillas de verificación HTML solo aparecen en los datos del formulario enviado cuando están marcadas, un POST manipulado que simplemente omite un campo de casilla relevante para la seguridad (como el que exige el requisito de clave API) es indistinguible, a nivel del manejador, de que el usuario la haya desmarcado en la interfaz — el .update() ciego desactiva silenciosamente esa configuración.
Una solicitud que nunca establece explícitamente api_access_token_enabled (o equivalente) a false — simplemente deja el campo fuera del cuerpo del POST — da como resultado que la configuración de la aplicación se fusione con esa protección efectivamente deshabilitada, sin ningún paso de confirmación explícito ni señal de auditoría que distinga «el usuario desmarcó esto» de «el campo no se envió».
/settings normalmente./settings con el campo api_access_token_enabled (o cualquier otra configuración booleana protegida que se esté probando) omitido por completo del cuerpo, incluyendo solo campos no relacionados:
POST /settings HTTP/1.1
Content-Type: application/x-www-form-urlencoded
application-some_other_field=value
form.data['application'] → .update() en el manejador de guardado de la configuración trata el campo ausente igual que un «desactivado» explícito, deshabilitando silenciosamente la protección sin que el usuario (o un auditor que revise la solicitud) vea una señal explícita de desactivación.Usar un .update() ciego de dict a partir de datos de formulario sin procesar confunde «campo ausente del POST» con «campo establecido explícitamente a false» para configuraciones basadas en casillas de verificación — los formularios HTML nunca envían casillas desmarcadas, por lo que este patrón no es seguro para ningún campo de configuración con implicaciones de seguridad.
Enumera explícitamente los campos booleanos de configuración esperados y establece por defecto los ausentes a su valor almacenado actual (no False), o usa una biblioteca de formularios que distinga «no enviado» de «enviado como desmarcado» y valide explícitamente los interruptores relevantes para la seguridad en lugar de hacerlo mediante una fusión ciega de dict.