XXS Vulnerability in Segment Description Fields
Issue date: 01-07-2019Affects versions: 13.1, 13.0, 12.6, 11.2
Announce Date and Security Issue ID
(date this issue is published and the jira Security issue number, just plain - no link)
Affected Product Version(s)
13.1.1, 13.0.2, 12.6.3, 11.2.13
Severity
Normal.
Description
A Relevance Segment has two description fields that contain content in HTML markup. It can contain JavaScript that can be executed in the browser. Editors that have a login in BrXM can edit these fields.
This fix improves the HTML cleaning of these fields on save and eliminates the vulnerability.
Instructions
Upgrade the version of the project to a version later than the affected versions. Fields that are affected will be cleaned by opening the Segment in edit mode and save it.
To make sure existing content is free from this, customers are strongly recommended to have an administrator run the check/report script below with the Updater Editor, after upgrading to the latest maintenance release!
Update Script
The following Groovy script can be executed by an administrator in the CMS Updater Editor after the maintenance upgrade (the script depends on some of the fixes and improvements) using the following settings:
Name: PersonaAndSegmentDescriptionCheck Select node using: Updater
Script content:
package org.hippoecm.frontend.plugins.cms.admin.updater import org.onehippo.cms7.services.HippoServiceRegistry import org.onehippo.cms7.services.htmlprocessor.HtmlProcessor import org.onehippo.cms7.services.htmlprocessor.HtmlProcessorService import org.onehippo.repository.update.BaseNodeUpdateVisitor import javax.jcr.Node import javax.jcr.NodeIterator import javax.jcr.RepositoryException import javax.jcr.Session import javax.jcr.query.Query import javax.jcr.query.QueryManager class PersonaAndSegmentDescriptionCheck extends BaseNodeUpdateVisitor { private NodeIterator nodeIterator; private HtmlProcessor htmlProcessor; @Override void initialize(final Session session) throws RepositoryException { super.initialize(session) final HtmlProcessorService htmlProcessorService = HippoServiceRegistry.getService(HtmlProcessorService.class); htmlProcessor = htmlProcessorService.getHtmlProcessor("audience-description"); if (htmlProcessor == null) { log.debug("No processor!"); throw new RepositoryException("Cannot find html processor."); } } Node firstNode(final Session session) throws RepositoryException { final QueryManager queryManager = session.getWorkspace().getQueryManager(); final Query jcrQuery = queryManager.createQuery("//element(*, targeting:persona)", "xpath"); nodeIterator = jcrQuery.execute().getNodes(); return nextNode(); } Node nextNode() throws RepositoryException { return nodeIterator.hasNext() ? nodeIterator.next() : null; } boolean doUpdate(Node node) throws RepositoryException { boolean changed1 = updateProperty(node, "targeting:description"); boolean changed2 = updateProperty(node, "targeting:segmentDescription"); return changed1 || changed2; } boolean updateProperty(Node node, String propertyName) { if (node.hasProperty(propertyName)) { def before = node.getProperty(propertyName).getString(); def after = htmlProcessor.write(before, Collections.emptyList()); if (before != after) { log.info("Updating node ${node.path}, property '${propertyName}'" ); log.info("before: ${before}"); log.info("after: ${after}"); node.setProperty(propertyName, after); return true; } } return false; } boolean logSkippedNodePaths() { return false; } boolean skipCheckoutNodes() { return true } boolean undoUpdate(Node node) { throw new UnsupportedOperationException(); } }
The script can be run in DryRun mode first. It reports which nodes are updated and shows the before and after content in the script log. The script can be run multiple times without causing problems in the content of the two description fields. After a DryRun the script can be Executed.