changeset 8553:ee17f62c8341

bug: improve security of eval'ed of session database data. (hexora) Hexora flagged: eval(res[0]) where res[0] is a stored repr of a dictionary. Change these to safe_eval(s) s=res[0] using: eval(s, {'__builtins__': {}}, {}) to wipe all functions and variable references inside the eval. This may be breakable however it's better than it was. There is one place where a username (set by user) is stored as a value, but the username rules prohibit ' or " from being present. Also a repr("us'er") is properly quoted and safe_eval(repr({'user': 'us\'r'})) is properly round tripped.
author John Rouillard <rouilj@ieee.org>
date Sun, 05 Apr 2026 17:44:02 -0400
parents dbe30d5032b8
children 92aecf6c5c09
files CHANGES.txt roundup/backends/sessions_rdbms.py
diffstat 2 files changed, 6 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES.txt	Thu Apr 02 12:26:13 2026 -0400
+++ b/CHANGES.txt	Sun Apr 05 17:44:02 2026 -0400
@@ -68,6 +68,7 @@
 - refactor mime detection/handling in the rest interface. Better
   supports some mime types, ads default mime type for files without a
   mime type (e.g. message contents). Cleaner code. (John Rouillard)
+- run hexora and mitigate/fix some medium sev and above. (John Rouillard)
 
 Features:
 
--- a/roundup/backends/sessions_rdbms.py	Thu Apr 02 12:26:13 2026 -0400
+++ b/roundup/backends/sessions_rdbms.py	Sun Apr 05 17:44:02 2026 -0400
@@ -10,6 +10,8 @@
 from roundup.anypy.html import html_escape as escape
 from roundup.backends.sessions_common import SessionCommon
 
+def safe_eval(s):
+    return eval(s, {"__builtins__": {}}, {})
 
 class BasicDatabase(SessionCommon):
     ''' Provide a nice encapsulation of an RDBMS table.
@@ -42,7 +44,7 @@
             if default != self._marker:
                 return default
             raise KeyError('No such %s "%s"' % (self.name, escape(infoid)))
-        values = eval(res[0])
+        values = safe_eval(res[0])
         return values.get(value, None)
 
     def getall(self, infoid):
@@ -52,7 +54,7 @@
         res = self.cursor.fetchone()
         if not res:
             raise KeyError('No such %s "%s"' % (self.name, escape(infoid)))
-        return eval(res[0])
+        return safe_eval(res[0])
 
     def set(self, infoid, **newvalues):
         """ Store all newvalues under key infoid with a timestamp in database.
@@ -70,7 +72,7 @@
 
         timestamp = time.time()
         if res:
-            values = eval(res[0])
+            values = safe_eval(res[0])
         else:
             values = {}
 

Roundup Issue Tracker: http://roundup-tracker.org/