CVE-2023-0300 (Java, published 2023-01-14T18:15Z)
Description: value: Cross-site Scripting (XSS) - Reflected in GitHub repository alfio-event/alf.io prior to 2.0-M4-2301.
Severity: nan (CVSS v3 base score: 5.4)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Repository: https://github.com/alfio-event/alf.io
Files changed:
src/main/java/alfio/manager/GroupManager.java
src/main/java/alfio/repository/GroupRepository.java
src/main/webapp/resources/js/admin/service/service.js
src/test/java/alfio/manager/GroupManagerIntegrationTest.java
Commit message: escape HTML in group name and description (#1155)



Vulnerable code:
        AffectedRowCountAndKey<Integer> insert = groupRepository.insert(name, description, organizationId);
        groupRepository.update(listId, modification.getName(), modification.getDescription());
            .map(i -> new MapSqlParameterSource("groupId", groupId).addValue("value", i.getValue().toLowerCase()).addValue("description", i.getDescription()))
    baseServices.service("NotificationHandler", ["growl", function (growl) {
                return growl.success(message, config);
                return growl.warning(message, config);
                return growl.info(message, config);
                return growl.error(message, config);

Fixed code:
import org.apache.commons.text.StringEscapeUtils;
import static org.apache.commons.text.StringEscapeUtils.escapeHtml4;
        AffectedRowCountAndKey<Integer> insert = groupRepository.insert(escapeHtml4(name), escapeHtml4(description), organizationId);
        groupRepository.update(listId, escapeHtml4(modification.getName()), escapeHtml4(modification.getDescription()));
import static org.apache.commons.text.StringEscapeUtils.escapeHtml4;

            .map(i -> new MapSqlParameterSource("groupId", groupId)
                .addValue("value", i.getValue().toLowerCase())
                .addValue("description", escapeHtml4(i.getDescription())))
    baseServices.service("NotificationHandler", ["growl", "$sanitize", function (growl, $sanitize) {
        var sanitize = function(message) {
            var sanitized = $sanitize(message);
            return sanitized.split(' ').map(function(part) {
                return encodeURIComponent(part);
            }).join(' ');
        };
                return growl.success(sanitize(message), config);
                return growl.warning(sanitize(message), config);
                return growl.info(sanitize(message), config);
                return growl.error(sanitize(message), config);

    @Test
    void testEscape() {
        List<TicketCategoryModification> categories = Collections.singletonList(
            new TicketCategoryModification(null, "default", TicketCategory.TicketAccessType.INHERIT, 10,
                new DateTimeModification(LocalDate.now(ClockProvider.clock()).plusDays(1), LocalTime.now(ClockProvider.clock())),
                new DateTimeModification(LocalDate.now(ClockProvider.clock()).plusDays(2), LocalTime.now(ClockProvider.clock())),
                DESCRIPTION, BigDecimal.TEN, false, "", false, null, null, null, null, null, 0, null, null, AlfioMetadata.empty()));
        Pair<Event, String> pair = initEvent(categories, organizationRepository, userManager, eventManager, eventRepository);
        Event event = pair.getKey();
        Group group = groupManager.createNew("test > 1", "This is a test < 1", event.getOrganizationId());
        assertNotNull(group);
        assertEquals("This is a test &lt; 1", group.getDescription());
        assertEquals("test &gt; 1", group.getName());
        LinkedGroupModification modification = new LinkedGroupModification(null, group.getId(), event.getId(), null, LinkedGroup.Type.ONCE_PER_VALUE, LinkedGroup.MatchType.FULL, null);
        LinkedGroup configuration = groupManager.createLink(group.getId(), event.getId(), modification);
        assertNotNull(configuration);
        Result<Integer> items = groupManager.insertMembers(group.getId(), List.of(new GroupMemberModification(null,"test@test.ch", "description <>")));
        assertTrue(items.isSuccess());
        var persistedGroup = groupManager.loadComplete(group.getId()).orElseThrow();
        assertEquals("description &lt;&gt;", persistedGroup.getItems().get(0).getDescription());
        groupManager.update(group.getId(), new GroupModification(group.getId(), "test > 1", "This is a test < 1", event.getOrganizationId(), List.of(new GroupMemberModification(null,"test@test.ch", "description <>"))));
        persistedGroup = groupManager.loadComplete(group.getId()).orElseThrow();
        assertEquals("This is a test &lt; 1", persistedGroup.getDescription());
        assertEquals("test &gt; 1", persistedGroup.getName());
    }