XXS Vulnerability in Segment Description Fields - BloomReach Experience - Open Source CMS

XXS Vulnerability in Segment Description Fields 

Issue date: 01-07-2019
Affects 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.