=== 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 = [ + '