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.
| Package | Affected versions | Patched versions |
|---|---|---|
buildbotPyPI | >= 0.7.6, < 0.7.11p3 | 0.7.11p3 |
Affected products
9cpe: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
178f7942b5056fix a few dozen additional XSS vulnerabilities
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- buildbot.net/tracnvdPatchVendor AdvisoryWEB
- www.vupen.com/english/advisories/2009/2352nvdPatchVendor AdvisoryWEB
- secunia.com/advisories/36352nvdVendor AdvisoryWEB
- secunia.com/advisories/36418nvdVendor AdvisoryWEB
- github.com/advisories/GHSA-mj3x-wprp-mvj9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2009-2967ghsaADVISORY
- sourceforge.net/mailarchive/message.phpnvdWEB
- www.securityfocus.com/bid/36100nvdWEB
- exchange.xforce.ibmcloud.com/vulnerabilities/52896nvdWEB
- github.com/buildbot/buildbot/commit/78f7942b5056ab75c27f491b6fd6f266699c15e3ghsaWEB
- github.com/pypa/advisory-database/tree/main/vulns/buildbot/PYSEC-2009-2.yamlghsaWEB
- www.redhat.com/archives/fedora-package-announce/2009-August/msg00978.htmlnvdWEB
- www.redhat.com/archives/fedora-package-announce/2009-August/msg00985.htmlnvdWEB
News mentions
0No linked articles in our index yet.