VYPR
Moderate severityNVD Advisory· Published Aug 26, 2009· Updated Apr 23, 2026

CVE-2009-2967

CVE-2009-2967

Description

Multiple cross-site scripting (XSS) vulnerabilities in Buildbot 0.7.6 through 0.7.11p2 allow remote attackers to inject arbitrary web script or HTML via unspecified vectors, different vulnerabilities than CVE-2009-2959.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
buildbotPyPI
>= 0.7.6, < 0.7.11p30.7.11p3

Affected products

9
  • Buildbot/Buildbot9 versions
    cpe:2.3:a:buildbot:buildbot:0.7.10:*:*:*:*:*:*:*+ 8 more
    • cpe:2.3:a:buildbot:buildbot:0.7.10:*:*:*:*:*:*:*
    • cpe:2.3:a:buildbot:buildbot:0.7.10p1:*:*:*:*:*:*:*
    • cpe:2.3:a:buildbot:buildbot:0.7.11:*:*:*:*:*:*:*
    • cpe:2.3:a:buildbot:buildbot:0.7.11p1:*:*:*:*:*:*:*
    • cpe:2.3:a:buildbot:buildbot:0.7.11p2:*:*:*:*:*:*:*
    • cpe:2.3:a:buildbot:buildbot:0.7.6:*:*:*:*:*:*:*
    • cpe:2.3:a:buildbot:buildbot:0.7.7:*:*:*:*:*:*:*
    • cpe:2.3:a:buildbot:buildbot:0.7.8:*:*:*:*:*:*:*
    • cpe:2.3:a:buildbot:buildbot:0.7.9:*:*:*:*:*:*:*

Patches

1
78f7942b5056

fix a few dozen additional XSS vulnerabilities

https://github.com/buildbot/buildbotDustin J. MitchellAug 13, 2009via ghsa
6 files changed · +27 17
  • buildbot/status/web/baseweb.py+7 3 modified
    @@ -123,10 +123,12 @@ def body(self, req):
             data = ""
     
             # really this is "up to %d builds"
    +        html_branches = map(html.escape, branches)
             data += "<h1>Last %d finished builds: %s</h1>\n" % \
    -                (numbuilds, ", ".join(branches))
    +                (numbuilds, ", ".join(html_branches))
             if builders:
    -            data += ("<p>of builders: %s</p>\n" % (", ".join(builders)))
    +            html_builders = map(html.escape, builders)
    +            data += ("<p>of builders: %s</p>\n" % (", ".join(html_builders)))
             data += "<ul>\n"
             got = 0
             building = False
    @@ -179,8 +181,9 @@ def body(self, req):
                                                     numbuilds)
     
             data = ""
    +        html_branches = map(html.escape, branches)
             data += ("<h1>Last %d builds of builder %s: %s</h1>\n" %
    -                 (numbuilds, self.builder_name, ", ".join(branches)))
    +                 (numbuilds, self.builder_name, ", ".join(html_branches)))
             data += "<ul>\n"
             got = 0
             for build in g:
    @@ -215,6 +218,7 @@ def body(self, req):
     
             data = ""
     
    +        html_branches = map(html.escape, branches)
             data += "<h2>Latest builds: %s</h2>\n" % ", ".join(branches)
             data += "<table>\n"
     
    
  • buildbot/status/web/builder.py+2 2 modified
    @@ -129,7 +129,7 @@ def body(self, req):
             data += "<h2>Recent Builds:</h2>\n"
             data += "(<a href=\"%s\">view in waterfall</a>)\n" % (self.path_to_root(req)+"waterfall?show="+html.escape(b.getName()))
             data += "<ul>\n"
    -        numbuilds = req.args.get('numbuilds', ['5'])[0]
    +        numbuilds = int(req.args.get('numbuilds', ['5'])[0])
             for i,build in enumerate(b.generateFinishedBuilds(num_builds=int(numbuilds))):
                 data += " <li>" + self.make_line(req, build, False) + "</li>\n"
                 if i == 0:
    @@ -194,7 +194,7 @@ def force(self, req):
             revision = req.args.get("revision", [""])[0]
     
             r = "The web-page 'force build' button was pressed by '%s': %s\n" \
    -            % (name, reason)
    +            % (html.escape(name), html.escape(reason))
             log.msg("web forcebuild of builder '%s', branch='%s', revision='%s'"
                     " by user '%s'" % (self.builder_status.getName(), branch,
                                        revision, name))
    
  • buildbot/status/web/build.py+4 4 modified
    @@ -239,14 +239,14 @@ def stop(self, req):
                     (b.getBuilder().getName(), b.getNumber()))
             name = req.args.get("username", ["<unknown>"])[0]
             comments = req.args.get("comments", ["<no reason specified>"])[0]
    +        # html-quote both the username and comments, just to be safe
             reason = ("The web-page 'stop build' button was pressed by "
    -                  "'%s': %s\n" % (name, comments))
    +                  "'%s': %s\n" % (html.escape(name), html.escape(comments)))
             if c:
                 c.stopBuild(reason)
             # we're at http://localhost:8080/svn-hello/builds/5/stop?[args] and
             # we want to go to: http://localhost:8080/svn-hello
    -        url = req.args.get('url', ['../..'])[0]
    -        r = Redirect(url)
    +        r = Redirect("../..")
             d = defer.Deferred()
             reactor.callLater(1, d.callback, r)
             return DeferredResource(d)
    @@ -262,7 +262,7 @@ def rebuild(self, req):
             name = req.args.get("username", ["<unknown>"])[0]
             comments = req.args.get("comments", ["<no reason specified>"])[0]
             reason = ("The web-page 'rebuild' button was pressed by "
    -                  "'%s': %s\n" % (name, comments))
    +                  "'%s': %s\n" % (html.escape(name), html.escape(comments)))
             if not bc or not b.isFinished():
                 log.msg("could not rebuild: bc=%s, isFinished=%s"
                         % (bc, b.isFinished()))
    
  • buildbot/status/web/buildstatus.py+2 0 modified
    @@ -1,3 +1,4 @@
    +from twisted.web import html, resource
     from buildbot.status.web.base import Box
     from buildbot.status.web.base import HtmlResource
     from buildbot.status.web.base import IBox
    @@ -22,6 +23,7 @@ def body(self, request):
             number = request.args.get("number", [None])[0]
             if not name or not number:
                 return "builder and number parameter missing"
    +        number = int(number)
     
             # Main table for the build status.
             data += '<table>\n'
    
  • buildbot/status/web/grid.py+10 6 modified
    @@ -3,6 +3,8 @@
     import sys, time, os.path
     import urllib
     
    +from twisted.web import html, resource
    +
     from buildbot import util
     from buildbot import version
     from buildbot.status.web.base import HtmlResource
    @@ -194,12 +196,13 @@ def body(self, request):
             data += '<tr>\n'
             data += '<td class="title"><a href="%s">%s</a>' % (projectURL, projectName)
             if categories:
    +            html_categories = map(html.escape(categories))
                 if len(categories) > 1:
    -                data += '\n<br /><b>Categories:</b><br/>%s' % ('<br/>'.join(categories))
    +                data += '\n<br /><b>Categories:</b><br/>%s' % ('<br/>'.join(html_categories))
                 else:
    -                data += '\n<br /><b>Category:</b> %s' % categories[0]
    +                data += '\n<br /><b>Category:</b> %s' % html_categories[0]
             if branch != ANYBRANCH:
    -            data += '\n<br /><b>Branch:</b> %s' % (branch or 'trunk')
    +            data += '\n<br /><b>Branch:</b> %s' % (html.escape(branch) or 'trunk')
             data += '</td>\n'
             for stamp in stamps:
                 data += self.stamp_td(stamp)
    @@ -289,12 +292,13 @@ def body(self, request):
             data += '<tr>\n'
             data += '<td class="title"><a href="%s">%s</a>' % (projectURL, projectName)
             if categories:
    +            html_categories = map(html.escape(categories))
                 if len(categories) > 1:
    -                data += '\n<br /><b>Categories:</b><br/>%s' % ('<br/>'.join(categories))
    +                data += '\n<br /><b>Categories:</b><br/>%s' % ('<br/>'.join(html_categories))
                 else:
    -                data += '\n<br /><b>Category:</b> %s' % categories[0]
    +                data += '\n<br /><b>Category:</b> %s' % html_categories[0]
             if branch != ANYBRANCH:
    -            data += '\n<br /><b>Branch:</b> %s' % (branch or 'trunk')
    +            data += '\n<br /><b>Branch:</b> %s' % (html.escape(branch) or 'trunk')
             data += '</td>\n'
     
             sortedBuilderNames = status.getBuilderNames()[:]
    
  • buildbot/status/web/waterfall.py+2 2 modified
    @@ -356,7 +356,7 @@ def body(self, request):
                                         '<input type="text" name="branch" '
                                         'value="%s">'
                                         '</td></tr>\n'
    -                                    ) % (b,)
    +                                    ) % (html.escape(b),)
             show_branches_input += '</table>\n'
     
             # this has a set of toggle-buttons to let the user choose the
    @@ -584,7 +584,7 @@ def with_args(req, remove_args=[], new_args=[], new_path=None):
                         newargs[k].append(v)
                     else:
                         newargs[k] = [v]
    -            newquery = "&".join(["%s=%s" % (k, urllib.quote(v))
    +            newquery = "&".join(["%s=%s" % (urllib.quote(k), urllib.quote(v))
                                      for k in newargs
                                      for v in newargs[k]
                                      ])
    

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

13

News mentions

0

No linked articles in our index yet.