Moderate severityNVD Advisory· Published Nov 6, 2010· Updated Apr 29, 2026
CVE-2010-2477
CVE-2010-2477
Description
Multiple cross-site scripting (XSS) vulnerabilities in the paste.httpexceptions implementation in Paste before 1.7.4 allow remote attackers to inject arbitrary web script or HTML via vectors involving a 404 status code, related to (1) paste.urlparser.StaticURLParser, (2) paste.urlparser.PkgResourcesParser, (3) paste.urlmap.URLMap, and (4) HTTPNotFound.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
pastePyPI | < 1.7.4 | 1.7.4 |
Affected products
22cpe:2.3:a:pythonpaste:paste:*:*:*:*:*:*:*:*+ 21 more
- cpe:2.3:a:pythonpaste:paste:*:*:*:*:*:*:*:*range: <=1.7.3.1
- cpe:2.3:a:pythonpaste:paste:0.1.0:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:0.3:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:0.4.1:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:0.5:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:0.9.1:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:0.9.2:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:0.9.3:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:0.9.4:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.0.1:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.1:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.1.1:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.2:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.3:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.4:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.4.2:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.5:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.6:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.7:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.7.1:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.7.2:*:*:*:*:*:*:*
- cpe:2.3:a:pythonpaste:paste:1.7.3:*:*:*:*:*:*:*
Patches
14910493c62f3Fix XSS attacks as reported by Tim Wintle
6 files changed · +44 −18
docs/news.txt+9 −0 modified@@ -3,6 +3,15 @@ News .. contents:: +1.7.4 +----- + +* Fix XSS bug (security issue) with not found handlers for + :class:`paste.urlparser.StaticURLParser` and + :class:`paste.urlmap.URLMap`. If you ask for a path with + ``/--><script>...`` that will be inserted in the error page and can + execute Javascript. Reported by Tim Wintle. + 1.7.3.1 -------
paste/httpexceptions.py+5 −6 modified@@ -77,7 +77,7 @@ from paste.wsgilib import catch_errors_app from paste.response import has_header, header_value, replace_header from paste.request import resolve_relative_url -from paste.util.quoting import strip_html, html_quote, no_quote +from paste.util.quoting import strip_html, html_quote, no_quote, comment_quote SERVER_NAME = 'WSGI Server' TEMPLATE = """\ @@ -212,12 +212,12 @@ def make_body(self, environ, template, escfunc, comment_escfunc=None): def plain(self, environ): """ text/plain representation of the exception """ - body = self.make_body(environ, strip_html(self.template), no_quote) + body = self.make_body(environ, strip_html(self.template), comment_quote) return ('%s %s\r\n%s\r\n' % (self.code, self.title, body)) def html(self, environ): """ text/html representation of the exception """ - body = self.make_body(environ, self.template, html_quote, no_quote) + body = self.make_body(environ, self.template, html_quote, comment_quote) return TEMPLATE % { 'title': self.title, 'code': self.code, @@ -334,14 +334,14 @@ def __init__(self, detail=None, headers=None, comment=None): def relative_redirect(cls, dest_uri, environ, detail=None, headers=None, comment=None): """ - Create a redirect object with the dest_uri, which may be relative, + Create a redirect object with the dest_uri, which may be relative, considering it relative to the uri implied by the given environ. """ location = resolve_relative_url(dest_uri, environ) headers = headers or [] headers.append(('Location', location)) return cls(detail=detail, headers=headers, comment=comment) - + relative_redirect = classmethod(relative_redirect) def location(self): @@ -658,4 +658,3 @@ def make_middleware(app, global_conf=None, warning_level=None): return HTTPExceptionHandler(app, warning_level=warning_level) __all__.extend(['HTTPExceptionHandler', 'get_exception']) -
paste/urlmap.py+10 −11 modified@@ -7,6 +7,7 @@ from UserDict import DictMixin import re import os +import cgi from paste import httpexceptions __all__ = ['URLMap', 'PathProxyURLMap'] @@ -77,12 +78,12 @@ class URLMap(DictMixin): dispatch to. URLs are matched most-specific-first, i.e., longest URL first. The ``SCRIPT_NAME`` and ``PATH_INFO`` environmental variables are adjusted to indicate the new context. - + URLs can also include domains, like ``http://blah.com/foo``, or as tuples ``('blah.com', '/foo')``. This will match domain names; without the ``http://domain`` or with a domain of ``None`` any domain will be matched (so long as no other explicit domain matches). """ - + def __init__(self, not_found_app=None): self.applications = [] if not not_found_app: @@ -105,15 +106,15 @@ def not_found_app(self, environ, start_response): extra += '\nHTTP_HOST: %r' % environ.get('HTTP_HOST') app = httpexceptions.HTTPNotFound( environ['PATH_INFO'], - comment=extra).wsgi_application + comment=cgi.escape(extra)).wsgi_application return app(environ, start_response) def normalize_url(self, url, trim=True): if isinstance(url, (list, tuple)): domain = url[0] url = self.normalize_url(url[1])[1] return domain, url - assert (not url or url.startswith('/') + assert (not url or url.startswith('/') or self.domain_url_re.search(url)), ( "URL fragments must start with / or http:// (you gave %r)" % url) match = self.domain_url_re.search(url) @@ -165,7 +166,7 @@ def __getitem__(self, url): if app_url == dom_url: return app raise KeyError( - "No application with the url %r (domain: %r; existing: %s)" + "No application with the url %r (domain: %r; existing: %s)" % (url[1], url[0] or '*', self.applications)) def __delitem__(self, url): @@ -202,8 +203,8 @@ def __call__(self, environ, start_response): return app(environ, start_response) environ['paste.urlmap_object'] = self return self.not_found_application(environ, start_response) - - + + class PathProxyURLMap(object): """ @@ -225,15 +226,15 @@ def __init__(self, map, base_paste_url, base_path, builder): self.base_paste_url = self.map.normalize_url(base_paste_url) self.base_path = base_path self.builder = builder - + def __setitem__(self, url, app): if isinstance(app, (str, unicode)): app_fn = os.path.join(self.base_path, app) app = self.builder(app_fn) url = self.map.normalize_url(url) # @@: This means http://foo.com/bar will potentially # match foo.com, but /base_paste_url/bar, which is unintuitive - url = (url[0] or self.base_paste_url[0], + url = (url[0] or self.base_paste_url[0], self.base_paste_url[1] + url[1]) self.map[url] = app @@ -247,5 +248,3 @@ def not_found_application__set(self, value): self.map.not_found_application = value not_found_application = property(not_found_application__get, not_found_application__set) - -
paste/util/quoting.py+7 −0 modified@@ -76,6 +76,13 @@ def no_quote(s): """ return s +_comment_quote_re = re.compile(r'\-\s*\>') +def comment_quote(s): + """ + Quote that makes sure text can't escape a comment + """ + return _comment_quote_re.sub('->', str(s)) + url_quote = urllib.quote url_unquote = urllib.unquote
tests/test_urlmap.py+6 −1 modified@@ -39,4 +39,9 @@ def test_map(): res.mustcontain('script_name="/f"') res.mustcontain('path_info="/z/y"') res.mustcontain('f-only') - + +def test_404(): + mapper = URLMap({}) + app = TestApp(mapper, extra_environ={'HTTP_ACCEPT': 'text/html'}) + res = app.get("/-->%0D<script>alert('xss')</script>", status=404) + assert '--><script' not in res.body
tests/test_urlparser.py+7 −0 modified@@ -106,6 +106,13 @@ def test_relative_path_in_static_parser(): app = StaticURLParser(relative_path('find_file')) assert '..' not in app.root_directory +def test_xss(): + app = TestApp(StaticURLParser(relative_path('find_file')), + extra_environ={'HTTP_ACCEPT': 'text/html'}) + res = app.get("/-->%0D<script>alert('xss')</script>", status=404) + print res + assert 0 + def test_static_parser(): app = StaticURLParser(path('find_file')) testapp = TestApp(app)
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
14- marc.infonvdPatchWEB
- marc.infonvdPatchWEB
- github.com/advisories/GHSA-7gfc-2v6g-6w9fghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2010-2477ghsaADVISORY
- groups.google.com/group/paste-users/browse_thread/thread/3b3fff3dadd0b1e5nvdWEB
- groups.google.com/group/pylons-discuss/msg/8c256dc076a408d8nvdWEB
- pylonshq.com/articles/archives/2010/6/paste_174_released_addresses_xss_security_holenvdWEB
- www.ubuntu.com/usn/USN-1026-1nvdWEB
- github.com/cdent/paste/commit/4910493c62f369a3222357af09450930e4c93f5eghsaWEB
- github.com/pypa/advisory-database/tree/main/vulns/paste/PYSEC-2010-29.yamlghsaWEB
- web.archive.org/web/20111227133546/http://secunia.com/advisories/42500ghsaWEB
- web.archive.org/web/20120527154041/http://www.securityfocus.com/bid/41160ghsaWEB
- secunia.com/advisories/42500nvd
- www.securityfocus.com/bid/41160nvd
News mentions
0No linked articles in our index yet.