From 57fe5ee1ea085c838c42368f7ec439dde066cc5f Mon Sep 17 00:00:00 2001 From: Jason Novinger Date: Fri, 13 Feb 2026 06:53:28 -0600 Subject: [PATCH] Fixes #20442: Mark template-accessible methods with alters_data=True Add alters_data=True to methods that modify database or filesystem state and are accessible from Jinja2 sandbox template contexts: - UserConfig.set(), clear(): Persist preference changes when commit=True - ManagedFile.sync_data(): Writes files to scripts/reports storage - ScriptModule.sync_classes(), sync_data(): Creates/deletes Script objects - Job.start(), terminate(): Updates job status, creates notifications Methods intentionally not protected: - DataFile.refresh_from_disk(): Only modifies instance attributes in memory - Overridden save()/delete(): Django's AltersData mixin auto-propagates - Properties like Script.python_class: Not callable in template context Ref: #20356 for exploit details demonstrating the vulnerability --- netbox/core/models/files.py | 1 + netbox/core/models/jobs.py | 2 ++ netbox/extras/models/scripts.py | 2 ++ netbox/users/models/preferences.py | 2 ++ 4 files changed, 7 insertions(+) diff --git a/netbox/core/models/files.py b/netbox/core/models/files.py index 819f68779..f51d12cfa 100644 --- a/netbox/core/models/files.py +++ b/netbox/core/models/files.py @@ -89,6 +89,7 @@ class ManagedFile(SyncedDataMixin, models.Model): with storage.open(self.full_path, 'wb+') as new_file: new_file.write(self.data_file.data) + sync_data.alters_data = True @cached_property def storage(self): diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index 4427bb7ff..f48947883 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -216,6 +216,7 @@ class Job(models.Model): # Send signal job_start.send(self) + start.alters_data = True def terminate(self, status=JobStatusChoices.STATUS_COMPLETED, error=None): """ @@ -245,6 +246,7 @@ class Job(models.Model): # Send signal job_end.send(self) + terminate.alters_data = True def log(self, record: logging.LogRecord): """ diff --git a/netbox/extras/models/scripts.py b/netbox/extras/models/scripts.py index 3d71d8308..f2b15b0cf 100644 --- a/netbox/extras/models/scripts.py +++ b/netbox/extras/models/scripts.py @@ -178,9 +178,11 @@ class ScriptModule(PythonModuleMixin, JobsMixin, ManagedFile): name=name, is_executable=True, ) + sync_classes.alters_data = True def sync_data(self): super().sync_data() + sync_data.alters_data = True def save(self, *args, **kwargs): self.file_root = ManagedFileRootPathChoices.SCRIPTS diff --git a/netbox/users/models/preferences.py b/netbox/users/models/preferences.py index 75a5e99b5..84a8eacf4 100644 --- a/netbox/users/models/preferences.py +++ b/netbox/users/models/preferences.py @@ -113,6 +113,7 @@ class UserConfig(models.Model): if commit: self.save() + set.alters_data = True def clear(self, path, commit=False): """ @@ -140,3 +141,4 @@ class UserConfig(models.Model): if commit: self.save() + clear.alters_data = True