Moderate severityNVD Advisory· Published Oct 31, 2014· Updated May 6, 2026
CVE-2014-3473
CVE-2014-3473
Description
Cross-site scripting (XSS) vulnerability in the Orchestration/Stack section in the Horizon Orchestration dashboard in OpenStack Dashboard (Horizon) before 2013.2.4, 2014.1 before 2014.1.2, and Juno before Juno-2, when used with Heat, allows remote Orchestration template owners or catalogs to inject arbitrary web script or HTML via a crafted template.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
horizonPyPI | < 8.0.0a0 | 8.0.0a0 |
Affected products
3Patches
2c844bd692894Fix multiple Cross-Site Scripting (XSS) vulnerabilities
6 files changed · +29 −6
horizon/static/horizon/js/horizon.instances.js+8 −1 modified@@ -51,8 +51,15 @@ horizon.instances = { $(this.get_network_element("")).each(function(){ var $this = $(this); var $input = $this.children("input"); + var name = $this.text().replace(/^\s+/,"") + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(/\//g, '/'); var network_property = { - name:$this.text().replace(/^\s+/,""), + name:name, id:$input.attr("id"), value:$input.attr("value") };
horizon/tables/base.py+3 −1 modified@@ -585,7 +585,9 @@ def value(self): link_classes = ' '.join(self.column.link_classes) # Escape the data inside while allowing our HTML to render data = mark_safe('<a href="%s" class="%s">%s</a>' % - (self.url, link_classes, escape(data))) + (escape(self.url), + escape(link_classes), + escape(data))) return data @property
openstack_dashboard/dashboards/admin/groups/tables.py+2 −1 modified@@ -161,7 +161,8 @@ def get_link_url(self, datum=None): class UsersTable(tables.DataTable): name = tables.Column('name', verbose_name=_('User Name')) email = tables.Column('email', verbose_name=_('Email'), - filters=[defaultfilters.urlize]) + filters=[defaultfilters.escape, + defaultfilters.urlize]) id = tables.Column('id', verbose_name=_('User ID')) enabled = tables.Column('enabled', verbose_name=_('Enabled'), status=True,
openstack_dashboard/dashboards/admin/users/tables.py+2 −1 modified@@ -117,7 +117,8 @@ class UsersTable(tables.DataTable): ) name = tables.Column('name', verbose_name=_('User Name')) email = tables.Column('email', verbose_name=_('Email'), - filters=[defaultfilters.urlize]) + filters=[defaultfilters.escape, + defaultfilters.urlize]) # Default tenant is not returned from Keystone currently. #default_tenant = tables.Column('default_tenant', # verbose_name=_('Default Project'))
openstack_dashboard/dashboards/project/stacks/tables.py+8 −2 modified@@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. +from django.core import urlresolvers from django.http import Http404 # noqa from django.template.defaultfilters import timesince # noqa from django.template.defaultfilters import title # noqa @@ -94,11 +95,16 @@ class Meta: row_actions = (DeleteStack, ) +def get_resource_url(obj): + return urlresolvers.reverse('horizon:project:stacks:resource', + args=(obj.stack_id, obj.resource_name)) + + class EventsTable(tables.DataTable): logical_resource = tables.Column('resource_name', verbose_name=_("Stack Resource"), - link=lambda d: d.resource_name,) + link=get_resource_url) physical_resource = tables.Column('physical_resource_id', verbose_name=_("Resource"), link=mappings.resource_to_url) @@ -142,7 +148,7 @@ class ResourcesTable(tables.DataTable): logical_resource = tables.Column('resource_name', verbose_name=_("Stack Resource"), - link=lambda d: d.resource_name) + link=get_resource_url) physical_resource = tables.Column('physical_resource_id', verbose_name=_("Resource"), link=mappings.resource_to_url)
openstack_dashboard/dashboards/project/stacks/tabs.py+6 −0 modified@@ -75,6 +75,9 @@ def get_context_data(self, request): stack_identifier = '%s/%s' % (stack.stack_name, stack.id) events = api.heat.events_list(self.request, stack_identifier) LOG.debug('got events %s' % events) + # The stack id is needed to generate the resource URL. + for event in events: + event.stack_id = stack.id except Exception: events = [] messages.error(request, _( @@ -95,6 +98,9 @@ def get_context_data(self, request): stack_identifier = '%s/%s' % (stack.stack_name, stack.id) resources = api.heat.resources_list(self.request, stack_identifier) LOG.debug('got resources %s' % resources) + # The stack id is needed to generate the resource URL. + for r in resources: + r.stack_id = stack.id except Exception: resources = [] messages.error(request, _(
de4466d88b81Fix multiple Cross-Site Scripting (XSS) vulnerabilities.
6 files changed · +29 −6
horizon/static/horizon/js/horizon.instances.js+8 −1 modified@@ -51,8 +51,15 @@ horizon.instances = { $(this.get_network_element("")).each(function(){ var $this = $(this); var $input = $this.children("input"); + var name = $this.text().replace(/^\s+/,"") + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(/\//g, '/'); var network_property = { - name:$this.text().replace(/^\s+/,""), + name:name, id:$input.attr("id"), value:$input.attr("value") };
horizon/tables/base.py+3 −1 modified@@ -692,7 +692,9 @@ def value(self): self.column.link_attrs.items()]) # Escape the data inside while allowing our HTML to render data = mark_safe('<a href="%s" %s>%s</a>' % ( - self.url, link_attrs, escape(unicode(data)))) + (escape(self.url), + link_attrs, + escape(unicode(data))))) return data @property
openstack_dashboard/dashboards/admin/groups/tables.py+2 −1 modified@@ -159,7 +159,8 @@ def get_link_url(self, datum=None): class UsersTable(tables.DataTable): name = tables.Column('name', verbose_name=_('User Name')) email = tables.Column('email', verbose_name=_('Email'), - filters=[defaultfilters.urlize]) + filters=[defaultfilters.escape, + defaultfilters.urlize]) id = tables.Column('id', verbose_name=_('User ID')) enabled = tables.Column('enabled', verbose_name=_('Enabled'), status=True,
openstack_dashboard/dashboards/admin/users/tables.py+3 −1 modified@@ -131,7 +131,9 @@ class UsersTable(tables.DataTable): email = tables.Column('email', verbose_name=_('Email'), filters=(lambda v: defaultfilters .default_if_none(v, ""), - defaultfilters.urlize)) + defaultfilters.escape, + defaultfilters.urlize) + ) # Default tenant is not returned from Keystone currently. #default_tenant = tables.Column('default_tenant', # verbose_name=_('Default Project'))
openstack_dashboard/dashboards/project/stacks/tables.py+7 −2 modified@@ -115,11 +115,16 @@ class Meta: ChangeStackTemplate) +def get_resource_url(obj): + return urlresolvers.reverse('horizon:project:stacks:resource', + args=(obj.stack_id, obj.resource_name)) + + class EventsTable(tables.DataTable): logical_resource = tables.Column('resource_name', verbose_name=_("Stack Resource"), - link=lambda d: d.resource_name,) + link=get_resource_url) physical_resource = tables.Column('physical_resource_id', verbose_name=_("Resource"), link=mappings.resource_to_url) @@ -164,7 +169,7 @@ class ResourcesTable(tables.DataTable): logical_resource = tables.Column('resource_name', verbose_name=_("Stack Resource"), - link=lambda d: d.resource_name) + link=get_resource_url) physical_resource = tables.Column('physical_resource_id', verbose_name=_("Resource"), link=mappings.resource_to_url)
openstack_dashboard/dashboards/project/stacks/tabs.py+6 −0 modified@@ -99,6 +99,9 @@ def get_context_data(self, request): stack_identifier = '%s/%s' % (stack.stack_name, stack.id) events = api.heat.events_list(self.request, stack_identifier) LOG.debug('got events %s' % events) + # The stack id is needed to generate the resource URL. + for event in events: + event.stack_id = stack.id except Exception: events = [] messages.error(request, _( @@ -124,6 +127,9 @@ def get_context_data(self, request): stack_identifier = '%s/%s' % (stack.stack_name, stack.id) resources = api.heat.resources_list(self.request, stack_identifier) LOG.debug('got resources %s' % resources) + # The stack id is needed to generate the resource URL. + for r in resources: + r.stack_id = stack.id except Exception: resources = [] messages.error(request, _(
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- www.openwall.com/lists/oss-security/2014/07/08/6nvdMailing ListPatchWEB
- lists.opensuse.org/opensuse-updates/2015-01/msg00040.htmlnvdMailing ListThird Party AdvisoryWEB
- www.securityfocus.com/bid/68459nvdThird Party AdvisoryVDB EntryWEB
- bugs.launchpad.net/horizon/+bug/1308727nvdIssue TrackingThird Party AdvisoryWEB
- github.com/advisories/GHSA-8vwv-2v7v-jmgrghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2014-3473ghsaADVISORY
- access.redhat.com/errata/RHSA-2014:0939ghsaWEB
- access.redhat.com/errata/RHSA-2014:1188ghsaWEB
- access.redhat.com/security/cve/CVE-2014-3473ghsaWEB
- bugzilla.redhat.com/show_bug.cgighsaWEB
- github.com/openstack/horizon/commit/c844bd692894353c60b320005b804970605e910fghsaWEB
- github.com/openstack/horizon/commit/de4466d88b816437fb29eff5ab23b9b964cd3985ghsaWEB
- opendev.org/openstack/horizonghsaPACKAGE
News mentions
0No linked articles in our index yet.