=== modified file 'Mailman/Cgi/edithtml.py'
--- Mailman/Cgi/edithtml.py 2006-08-30 14:54:22 +0000
+++ Mailman/Cgi/edithtml.py 2007-12-04 19:52:18 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2007 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -159,7 +159,20 @@
doc.AddItem('
')
return
code = cgi_info['html_code'].value
- code = re.sub(r'<([/]?script.*?)>', r'<\1>', code)
+ if Utils.suspiciousHTML(code):
+ doc.AddItem(Header(3,
+ _("""The page you saved contains suspicious HTML that could
+potentially expose your users to cross-site scripting attacks. This change
+has therefore been rejected. If you still want to make these changes, you
+must have shell access to your Mailman server.
+ """)))
+ doc.AddItem(_('See '))
+ doc.AddItem(Link(
+'http://www.python.org/cgi-bin/faqw-mm.py?req=show&file=faq04.048.htp',
+ _('FAQ 4.48.')))
+ doc.AddItem(Header(3,_("Page Unchanged.")))
+ doc.AddItem('
')
+ return
langdir = os.path.join(mlist.fullpath(), mlist.preferred_language)
# Make sure the directory exists
omask = os.umask(0)
=== modified file 'Mailman/Gui/General.py'
--- Mailman/Gui/General.py 2006-08-30 14:54:22 +0000
+++ Mailman/Gui/General.py 2007-12-04 19:52:18 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2007 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -436,17 +442,21 @@
# Convert any html entities to Unicode
mlist.subject_prefix = Utils.canonstr(
val, mlist.preferred_language)
+ elif property == 'info':
+ if val <> mlist.info:
+ if Utils.suspiciousHTML(val):
+ doc.addError(_("""The info attribute you saved
+contains suspicious HTML that could potentially expose your users to cross-site
+scripting attacks. This change has therefore been rejected. If you still want
+to make these changes, you must have shell access to your Mailman server.
+This change can be made with bin/withlist or with bin/config_list by setting
+mlist.info.
+ """))
+ else:
+ mlist.info = val
else:
GUIBase._setValue(self, mlist, property, val, doc)
- def _escape(self, property, value):
- # The 'info' property allows HTML, but let's sanitize it to avoid XSS
- # exploits. Everything else should be fully escaped.
- if property <> 'info':
- return GUIBase._escape(self, property, value)
- # Sanitize tags but nothing else. Not the best
- # solution, but expedient.
- return re.sub(r'(?i)<([/]?script.*?)>', r'<\1>', value)
def _postValidate(self, mlist, doc):
if not mlist.reply_to_address.strip() and \
=== modified file 'Mailman/Gui/GUIBase.py'
--- Mailman/Gui/GUIBase.py 2005-08-27 01:40:17 +0000
+++ Mailman/Gui/GUIBase.py 2007-11-18 20:01:26 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2004 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-2007 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -12,7 +12,8 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
"""Base class for all web GUI components."""
@@ -122,10 +127,6 @@
# Validate all the attributes for this category
pass
- def _escape(self, property, value):
- value = value.replace('<', '<')
- return value
-
def handleForm(self, mlist, category, subcat, cgidata, doc):
for item in self.GetConfigInfo(mlist, category, subcat):
# Skip descriptions and legacy non-attributes
@@ -144,10 +145,9 @@
elif not cgidata.has_key(property):
continue
elif isinstance(cgidata[property], ListType):
- val = [self._escape(property, x.value)
- for x in cgidata[property]]
+ val = [x.value for x in cgidata[property]]
else:
- val = self._escape(property, cgidata[property].value)
+ val = cgidata[property].value
# Coerce the value to the expected type, raising exceptions if the
# value is invalid.
try:
=== modified file 'Mailman/Utils.py'
--- Mailman/Utils.py 2007-11-25 08:04:30 +0000
+++ Mailman/Utils.py 2007-12-04 19:52:18 +0000
@@ -876,3 +876,154 @@
except (LookupError, UnicodeError, ValueError, HeaderParseError):
# possibly charset problem. return with undecoded string in one line.
return EMPTYSTRING.join(s.splitlines())
+
+
+# Patterns and functions to flag possible XSS attacks in HTML.
+# This list is compiled from information at http://ha.ckers.org/xss.html,
+# http://www.quirksmode.org/js/events_compinfo.html,
+# http://www.htmlref.com/reference/appa/events1.htm,
+# http://lxr.mozilla.org/mozilla/source/content/events/src/nsDOMEvent.cpp#59,
+# http://www.w3.org/TR/DOM-Level-2-Events/events.html and
+# http://www.xulplanet.com/references/elemref/ref_EventHandlers.html
+# Many thanks are due to Moritz Naumann for his assistance with this.
+_badwords = [
+ '