VYPR
Medium severityNVD Advisory· Published Jan 5, 2026· Updated Apr 15, 2026

CVE-2025-15022

CVE-2025-15022

Description

Action captions in Vaadin accept HTML by default but were not sanitized, potentially allowing Cross-site Scripting (XSS) if caption content is derived from user input.

In Vaadin Framework 7 and 8, the Action class is a general-purpose class that may be used by multiple components. The fixed versions sanitize captions by default and provide an API to explicitly enable HTML content mode for backwards compatibility.

In Vaadin 23 and newer, the Action class is only used by the Spreadsheet component. The fixed versions sanitize HTML using Jsoup with a relaxed safelist.

Vaadin 14 is not affected as Spreadsheet component was not supported.

Users of affected versions should apply the following mitigation or upgrade. Releases that have fixed this issue include:

Product version Vaadin 7.0.0 - 7.7.49 Vaadin 8.0.0 - 8.29.1 Vaadin 23.1.0 - 23.6.5 Vaadin 24.0.0 - 24.8.13 Vaadin 24.9.0 - 24.9.6

Mitigation Upgrade to 7.7.50 Upgrade to 8.30.0 Upgrade to 23.6.6 Upgrade to 24.8.14 or 24.9.7 Upgrade to 25.0.0 or newer

Artifacts     Maven coordinatesVulnerable versionsFixed versioncom.vaadin:vaadin-server 7.0.0 - 7.7.49 ≥7.7.50 com.vaadin:vaadin-server 8.0.0 - 8.29.1 ≥8.30.0 com.vaadin:vaadin 23.1.0 - 23.6.5 ≥23.6.6 com.vaadin:vaadin24.0.0 - 24.8.13 ≥24.8.14 com.vaadin:vaadin24.9.0 - 24.9.6 ≥24.9.7 com.vaadin:vaadin-spreadsheet-flow 23.1.0 - 23.6.5 ≥23.6.6 com.vaadin:vaadin-spreadsheet-flow 24.0.0 - 24.8.13 ≥24.8.14 com.vaadin:vaadin-spreadsheet-flow 24.9.0 - 24.9.6 ≥24.9.7

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
com.vaadin:vaadin-serverMaven
>= 7.0.0, < 7.7.507.7.50
com.vaadin:vaadin-serverMaven
>= 8.0.0, < 8.30.08.30.0
com.vaadin:vaadinMaven
>= 23.1.0, < 23.6.623.6.6
com.vaadin:vaadinMaven
>= 24.0.0, < 24.8.1424.8.14
com.vaadin:vaadinMaven
>= 24.9.0, < 24.9.724.9.7
com.vaadin:vaadin-spreadsheet-flowMaven
>= 23.1.0, < 23.6.623.6.6
com.vaadin:vaadin-spreadsheet-flowMaven
>= 24.0.0, < 24.8.1424.8.14
com.vaadin:vaadin-spreadsheet-flowMaven
>= 24.9.0, < 24.9.724.9.7

Affected products

1

Patches

1
71046aa3dd08

refactor: remove duplication code in ContextMenuManager (#8285)

https://github.com/vaadin/flow-componentsDiego CardosoNov 25, 2025via ghsa
3 files changed · +461 26
  • vaadin-spreadsheet-flow-parent/vaadin-spreadsheet-flow/src/main/java/com/vaadin/flow/component/spreadsheet/client/SpreadsheetActionDetails.java+4 1 modified
    @@ -14,6 +14,9 @@
     public class SpreadsheetActionDetails implements Serializable {
         public String caption;
         public String key;
    -    /** 0 = cell, 1 = row, 2 = column TODO replace with enum type */
    +    /**
    +     * 0 = cell, 1 = row, 2 = column - kept as int for client-server
    +     * compatibility
    +     */
         public int type;
     }
    
  • vaadin-spreadsheet-flow-parent/vaadin-spreadsheet-flow/src/main/java/com/vaadin/flow/component/spreadsheet/ContextMenuManager.java+55 25 modified
    @@ -13,6 +13,8 @@
     import java.util.LinkedList;
     
     import org.apache.poi.ss.util.CellRangeAddress;
    +import org.jsoup.Jsoup;
    +import org.jsoup.safety.Safelist;
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     
    @@ -42,6 +44,23 @@ public class ContextMenuManager implements Serializable {
     
         private int contextMenuHeaderIndex = -1;
     
    +    /**
    +     * Enum for spreadsheet action types.
    +     */
    +    enum ActionType {
    +        CELL(0), ROW(1), COLUMN(2);
    +
    +        private final int value;
    +
    +        ActionType(int value) {
    +            this.value = value;
    +        }
    +
    +        public int getValue() {
    +            return value;
    +        }
    +    }
    +
         /**
          * Constructs a new ContextMenuManager and ties it to the given Spreadsheet.
          *
    @@ -216,19 +235,11 @@ public void onActionOnColumnHeader(String actionKey) {
         protected ArrayList<SpreadsheetActionDetails> createActionsListForSelection() {
             ArrayList<SpreadsheetActionDetails> actions = new ArrayList<SpreadsheetActionDetails>();
             for (Handler handler : actionHandlers) {
    -            Action[] actions2 = handler.getActions(spreadsheet
    +            Action[] handlerActions = handler.getActions(spreadsheet
                         .getCellSelectionManager().getLatestSelectionEvent(),
                         spreadsheet);
    -            if (actions2 != null) {
    -                for (Action action : actions2) {
    -                    String key = actionMapper.key(action);
    -                    SpreadsheetActionDetails spreadsheetActionDetails = new SpreadsheetActionDetails();
    -                    spreadsheetActionDetails.caption = action.getCaption();
    -                    spreadsheetActionDetails.key = key;
    -                    spreadsheetActionDetails.type = 0;
    -                    actions.add(spreadsheetActionDetails);
    -                }
    -            }
    +            actions.addAll(
    +                    createActionDetailsList(handlerActions, ActionType.CELL));
             }
             return actions;
         }
    @@ -246,14 +257,9 @@ protected ArrayList<SpreadsheetActionDetails> createActionsListForColumn(
             final CellRangeAddress column = new CellRangeAddress(-1, -1,
                     columnIndex - 1, columnIndex - 1);
             for (Handler handler : actionHandlers) {
    -            for (Action action : handler.getActions(column, spreadsheet)) {
    -                String key = actionMapper.key(action);
    -                SpreadsheetActionDetails spreadsheetActionDetails = new SpreadsheetActionDetails();
    -                spreadsheetActionDetails.caption = action.getCaption();
    -                spreadsheetActionDetails.key = key;
    -                spreadsheetActionDetails.type = 2;
    -                actions.add(spreadsheetActionDetails);
    -            }
    +            Action[] handlerActions = handler.getActions(column, spreadsheet);
    +            actions.addAll(
    +                    createActionDetailsList(handlerActions, ActionType.COLUMN));
             }
             return actions;
         }
    @@ -271,16 +277,40 @@ protected ArrayList<SpreadsheetActionDetails> createActionsListForRow(
             final CellRangeAddress row = new CellRangeAddress(rowIndex - 1,
                     rowIndex - 1, -1, -1);
             for (Handler handler : actionHandlers) {
    -            for (Action action : handler.getActions(row, spreadsheet)) {
    +            Action[] handlerActions = handler.getActions(row, spreadsheet);
    +            actions.addAll(
    +                    createActionDetailsList(handlerActions, ActionType.ROW));
    +        }
    +        return actions;
    +    }
    +
    +    /**
    +     * Helper method to create SpreadsheetActionDetails from actions.
    +     *
    +     * @param actions
    +     *            Array of actions to convert
    +     * @param actionType
    +     *            Type of the action (cell, row, or column)
    +     * @return List of SpreadsheetActionDetails
    +     */
    +    private ArrayList<SpreadsheetActionDetails> createActionDetailsList(
    +            Action[] actions, ActionType actionType) {
    +        ArrayList<SpreadsheetActionDetails> actionDetailsList = new ArrayList<SpreadsheetActionDetails>();
    +        if (actions != null) {
    +            for (Action action : actions) {
                     String key = actionMapper.key(action);
                     SpreadsheetActionDetails spreadsheetActionDetails = new SpreadsheetActionDetails();
    -                spreadsheetActionDetails.caption = action.getCaption();
    +                String caption = action.getCaption();
    +                if (caption == null) {
    +                    caption = "";
    +                }
    +                spreadsheetActionDetails.caption = Jsoup.clean(caption,
    +                        Safelist.relaxed());
                     spreadsheetActionDetails.key = key;
    -                spreadsheetActionDetails.type = 1;
    -                actions.add(spreadsheetActionDetails);
    +                spreadsheetActionDetails.type = actionType.getValue();
    +                actionDetailsList.add(spreadsheetActionDetails);
                 }
             }
    -        return actions;
    +        return actionDetailsList;
         }
    -
     }
    
  • vaadin-spreadsheet-flow-parent/vaadin-spreadsheet-flow/src/test/java/com/vaadin/flow/component/spreadsheet/tests/ContextMenuManagerTest.java+402 0 added
    @@ -0,0 +1,402 @@
    +/**
    + * Copyright 2000-2025 Vaadin Ltd.
    + *
    + * This program is available under Vaadin Commercial License and Service Terms.
    + *
    + * See {@literal <https://vaadin.com/commercial-license-and-service-terms>} for the full
    + * license.
    + */
    +package com.vaadin.flow.component.spreadsheet.tests;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertFalse;
    +import static org.junit.Assert.assertNotNull;
    +import static org.junit.Assert.assertTrue;
    +
    +import java.lang.reflect.Method;
    +import java.util.ArrayList;
    +import java.util.Collections;
    +
    +import org.apache.poi.ss.util.CellRangeAddress;
    +import org.apache.poi.ss.util.CellReference;
    +import org.junit.Before;
    +import org.junit.Test;
    +import org.mockito.Mock;
    +import org.mockito.Mockito;
    +import org.mockito.MockitoAnnotations;
    +
    +import com.vaadin.flow.component.spreadsheet.CellSelectionManager;
    +import com.vaadin.flow.component.spreadsheet.ContextMenuManager;
    +import com.vaadin.flow.component.spreadsheet.Spreadsheet;
    +import com.vaadin.flow.component.spreadsheet.Spreadsheet.SelectionChangeEvent;
    +import com.vaadin.flow.component.spreadsheet.client.SpreadsheetActionDetails;
    +import com.vaadin.flow.component.spreadsheet.framework.Action;
    +import com.vaadin.flow.component.spreadsheet.framework.Action.Handler;
    +
    +public class ContextMenuManagerTest {
    +
    +    private ContextMenuManager contextMenuManager;
    +
    +    @Mock
    +    private Spreadsheet mockSpreadsheet;
    +
    +    @Mock
    +    private Handler mockHandler;
    +
    +    @Mock
    +    private CellSelectionManager mockSelectionManager;
    +
    +    private SelectionChangeEvent mockSelectionEvent;
    +
    +    @Before
    +    public void setUp() {
    +        MockitoAnnotations.openMocks(this);
    +        contextMenuManager = new ContextMenuManager(mockSpreadsheet);
    +
    +        // Create a mock selection event
    +        CellReference cellRef = new CellReference("Sheet1", 0, 0, false, false);
    +        mockSelectionEvent = new SelectionChangeEvent(mockSpreadsheet, cellRef,
    +                Collections.emptyList(), null, Collections.emptyList());
    +
    +        Mockito.when(mockSpreadsheet.getCellSelectionManager())
    +                .thenReturn(mockSelectionManager);
    +        Mockito.when(mockSelectionManager.getLatestSelectionEvent())
    +                .thenReturn(mockSelectionEvent);
    +    }
    +
    +    @Test
    +    public void hasActionHandlers_withNoHandlers_shouldReturnFalse() {
    +        assertFalse(contextMenuManager.hasActionHandlers());
    +    }
    +
    +    @Test
    +    public void hasActionHandlers_withHandler_shouldReturnTrue() {
    +        contextMenuManager.addActionHandler(mockHandler);
    +        assertTrue(contextMenuManager.hasActionHandlers());
    +    }
    +
    +    @Test
    +    public void addActionHandler_nullHandler_shouldNotAddHandler() {
    +        contextMenuManager.addActionHandler(null);
    +        assertFalse(contextMenuManager.hasActionHandlers());
    +    }
    +
    +    @Test
    +    public void addActionHandler_sameHandlerTwice_shouldAddOnlyOnce() {
    +        contextMenuManager.addActionHandler(mockHandler);
    +        contextMenuManager.addActionHandler(mockHandler);
    +
    +        // Verify only one handler is added by checking removal behavior
    +        contextMenuManager.removeActionHandler(mockHandler);
    +        assertFalse(contextMenuManager.hasActionHandlers());
    +    }
    +
    +    @Test
    +    public void removeActionHandler_existingHandler_shouldRemoveHandler() {
    +        contextMenuManager.addActionHandler(mockHandler);
    +        assertTrue(contextMenuManager.hasActionHandlers());
    +
    +        contextMenuManager.removeActionHandler(mockHandler);
    +        assertFalse(contextMenuManager.hasActionHandlers());
    +    }
    +
    +    @Test
    +    public void createActionsListForSelection_withValidCaption_shouldCreateActionDetails()
    +            throws Exception {
    +        String caption = "Test Action";
    +        Action action = new Action(caption);
    +        Action[] actions = { action };
    +
    +        contextMenuManager.addActionHandler(mockHandler);
    +        Mockito.when(
    +                mockHandler.getActions(Mockito.any(SelectionChangeEvent.class),
    +                        Mockito.eq(mockSpreadsheet)))
    +                .thenReturn(actions);
    +
    +        // Use reflection to access protected method
    +        Method method = ContextMenuManager.class
    +                .getDeclaredMethod("createActionsListForSelection");
    +        method.setAccessible(true);
    +        @SuppressWarnings("unchecked")
    +        ArrayList<SpreadsheetActionDetails> result = (ArrayList<SpreadsheetActionDetails>) method
    +                .invoke(contextMenuManager);
    +
    +        assertEquals(1, result.size());
    +        SpreadsheetActionDetails details = result.get(0);
    +        assertEquals(caption, details.caption);
    +        assertEquals(0, details.type); // CELL type
    +        assertNotNull(details.key);
    +    }
    +
    +    @Test
    +    public void createActionsListForSelection_withNullCaption_shouldUseSanitizedEmptyString()
    +            throws Exception {
    +        Action action = new Action(null);
    +        Action[] actions = { action };
    +
    +        contextMenuManager.addActionHandler(mockHandler);
    +        Mockito.when(
    +                mockHandler.getActions(Mockito.any(SelectionChangeEvent.class),
    +                        Mockito.eq(mockSpreadsheet)))
    +                .thenReturn(actions);
    +
    +        // Use reflection to access protected method
    +        Method method = ContextMenuManager.class
    +                .getDeclaredMethod("createActionsListForSelection");
    +        method.setAccessible(true);
    +        @SuppressWarnings("unchecked")
    +        ArrayList<SpreadsheetActionDetails> result = (ArrayList<SpreadsheetActionDetails>) method
    +                .invoke(contextMenuManager);
    +
    +        assertEquals(1, result.size());
    +        SpreadsheetActionDetails details = result.get(0);
    +        assertEquals("", details.caption);
    +        assertEquals(0, details.type); // CELL type
    +    }
    +
    +    @Test
    +    public void createActionsListForSelection_withHTMLCaption_shouldSanitizeHTML()
    +            throws Exception {
    +        String htmlCaption = "<script>alert('xss')</script><b>Bold Text</b><p>Paragraph</p>";
    +        Action action = new Action(htmlCaption);
    +        Action[] actions = { action };
    +
    +        contextMenuManager.addActionHandler(mockHandler);
    +        Mockito.when(
    +                mockHandler.getActions(Mockito.any(SelectionChangeEvent.class),
    +                        Mockito.eq(mockSpreadsheet)))
    +                .thenReturn(actions);
    +
    +        // Use reflection to access protected method
    +        Method method = ContextMenuManager.class
    +                .getDeclaredMethod("createActionsListForSelection");
    +        method.setAccessible(true);
    +        @SuppressWarnings("unchecked")
    +        ArrayList<SpreadsheetActionDetails> result = (ArrayList<SpreadsheetActionDetails>) method
    +                .invoke(contextMenuManager);
    +
    +        assertEquals(1, result.size());
    +        SpreadsheetActionDetails details = result.get(0);
    +
    +        // Normalize whitespace for comparison
    +        String normalizedCaption = details.caption.replaceAll("\\s+", " ")
    +                .trim();
    +        String expectedNormalized = "<b>Bold Text</b> <p>Paragraph</p>"; // Normalized
    +                                                                         // expected
    +
    +        assertEquals(expectedNormalized, normalizedCaption);
    +        assertFalse("Should not contain script tags",
    +                details.caption.contains("script"));
    +        assertEquals(0, details.type); // CELL type
    +    }
    +
    +    @Test
    +    public void createActionsListForSelection_withMaliciousHTML_shouldRemoveDangerousContent()
    +            throws Exception {
    +        String maliciousCaption = "<script>document.cookie='stolen'</script>"
    +                + "<img src='x' onerror='alert(1)'>"
    +                + "<a href='javascript:void(0)'>Link</a>" + "Safe text";
    +        Action action = new Action(maliciousCaption);
    +        Action[] actions = { action };
    +
    +        contextMenuManager.addActionHandler(mockHandler);
    +        Mockito.when(
    +                mockHandler.getActions(Mockito.any(SelectionChangeEvent.class),
    +                        Mockito.eq(mockSpreadsheet)))
    +                .thenReturn(actions);
    +
    +        // Use reflection to access protected method
    +        Method method = ContextMenuManager.class
    +                .getDeclaredMethod("createActionsListForSelection");
    +        method.setAccessible(true);
    +        @SuppressWarnings("unchecked")
    +        ArrayList<SpreadsheetActionDetails> result = (ArrayList<SpreadsheetActionDetails>) method
    +                .invoke(contextMenuManager);
    +
    +        assertEquals(1, result.size());
    +        SpreadsheetActionDetails details = result.get(0);
    +        // Should contain only safe content, no scripts or dangerous attributes
    +        assertTrue(details.caption.contains("Safe text"));
    +        assertFalse(details.caption.contains("script"));
    +        assertFalse(details.caption.contains("onerror"));
    +        assertFalse(details.caption.contains("javascript:"));
    +    }
    +
    +    @Test
    +    public void createActionsListForRow_shouldCreateCorrectActionType()
    +            throws Exception {
    +        String caption = "Row Action";
    +        Action action = new Action(caption);
    +        Action[] actions = { action };
    +        int rowIndex = 5;
    +
    +        contextMenuManager.addActionHandler(mockHandler);
    +        Mockito.when(mockHandler.getActions(Mockito.any(CellRangeAddress.class),
    +                Mockito.eq(mockSpreadsheet))).thenReturn(actions);
    +
    +        // Use reflection to access protected method
    +        Method method = ContextMenuManager.class
    +                .getDeclaredMethod("createActionsListForRow", int.class);
    +        method.setAccessible(true);
    +        @SuppressWarnings("unchecked")
    +        ArrayList<SpreadsheetActionDetails> result = (ArrayList<SpreadsheetActionDetails>) method
    +                .invoke(contextMenuManager, rowIndex);
    +
    +        assertEquals(1, result.size());
    +        SpreadsheetActionDetails details = result.get(0);
    +        assertEquals(caption, details.caption);
    +        assertEquals(1, details.type); // ROW type
    +    }
    +
    +    @Test
    +    public void createActionsListForColumn_shouldCreateCorrectActionType()
    +            throws Exception {
    +        String caption = "Column Action";
    +        Action action = new Action(caption);
    +        Action[] actions = { action };
    +        int columnIndex = 3;
    +
    +        contextMenuManager.addActionHandler(mockHandler);
    +        Mockito.when(mockHandler.getActions(Mockito.any(CellRangeAddress.class),
    +                Mockito.eq(mockSpreadsheet))).thenReturn(actions);
    +
    +        // Use reflection to access protected method
    +        Method method = ContextMenuManager.class
    +                .getDeclaredMethod("createActionsListForColumn", int.class);
    +        method.setAccessible(true);
    +        @SuppressWarnings("unchecked")
    +        ArrayList<SpreadsheetActionDetails> result = (ArrayList<SpreadsheetActionDetails>) method
    +                .invoke(contextMenuManager, columnIndex);
    +
    +        assertEquals(1, result.size());
    +        SpreadsheetActionDetails details = result.get(0);
    +        assertEquals(caption, details.caption);
    +        assertEquals(2, details.type); // COLUMN type
    +    }
    +
    +    @Test
    +    public void createActionsListForColumn_withHTMLCaption_shouldSanitizeHTML()
    +            throws Exception {
    +        String htmlCaption = "<em>Emphasized</em><script>alert('bad')</script>";
    +        String expectedSanitized = "<em>Emphasized</em>"; // Script removed, em
    +                                                          // tag kept
    +        Action action = new Action(htmlCaption);
    +        Action[] actions = { action };
    +        int columnIndex = 1;
    +
    +        contextMenuManager.addActionHandler(mockHandler);
    +        Mockito.when(mockHandler.getActions(Mockito.any(CellRangeAddress.class),
    +                Mockito.eq(mockSpreadsheet))).thenReturn(actions);
    +
    +        // Use reflection to access protected method
    +        Method method = ContextMenuManager.class
    +                .getDeclaredMethod("createActionsListForColumn", int.class);
    +        method.setAccessible(true);
    +        @SuppressWarnings("unchecked")
    +        ArrayList<SpreadsheetActionDetails> result = (ArrayList<SpreadsheetActionDetails>) method
    +                .invoke(contextMenuManager, columnIndex);
    +
    +        assertEquals(1, result.size());
    +        SpreadsheetActionDetails details = result.get(0);
    +        assertEquals(expectedSanitized, details.caption);
    +        assertEquals(2, details.type); // COLUMN type
    +    }
    +
    +    @Test
    +    public void createActionsListForRow_withHTMLCaption_shouldSanitizeHTML()
    +            throws Exception {
    +        String htmlCaption = "<strong>Strong</strong><iframe src='evil.com'></iframe>";
    +        String expectedSanitized = "<strong>Strong</strong>"; // iframe removed,
    +                                                              // strong kept
    +        Action action = new Action(htmlCaption);
    +        Action[] actions = { action };
    +        int rowIndex = 2;
    +
    +        contextMenuManager.addActionHandler(mockHandler);
    +        Mockito.when(mockHandler.getActions(Mockito.any(CellRangeAddress.class),
    +                Mockito.eq(mockSpreadsheet))).thenReturn(actions);
    +
    +        // Use reflection to access protected method
    +        Method method = ContextMenuManager.class
    +                .getDeclaredMethod("createActionsListForRow", int.class);
    +        method.setAccessible(true);
    +        @SuppressWarnings("unchecked")
    +        ArrayList<SpreadsheetActionDetails> result = (ArrayList<SpreadsheetActionDetails>) method
    +                .invoke(contextMenuManager, rowIndex);
    +
    +        assertEquals(1, result.size());
    +        SpreadsheetActionDetails details = result.get(0);
    +        assertEquals(expectedSanitized, details.caption);
    +        assertEquals(1, details.type); // ROW type
    +    }
    +
    +    @Test
    +    public void createActionsListForSelection_withNullActions_shouldReturnEmptyList()
    +            throws Exception {
    +        contextMenuManager.addActionHandler(mockHandler);
    +        Mockito.when(
    +                mockHandler.getActions(Mockito.any(SelectionChangeEvent.class),
    +                        Mockito.eq(mockSpreadsheet)))
    +                .thenReturn(null);
    +
    +        // Use reflection to access protected method
    +        Method method = ContextMenuManager.class
    +                .getDeclaredMethod("createActionsListForSelection");
    +        method.setAccessible(true);
    +        @SuppressWarnings("unchecked")
    +        ArrayList<SpreadsheetActionDetails> result = (ArrayList<SpreadsheetActionDetails>) method
    +                .invoke(contextMenuManager);
    +
    +        assertEquals(0, result.size());
    +    }
    +
    +    @Test
    +    public void createActionsListForSelection_withEmptyActions_shouldReturnEmptyList()
    +            throws Exception {
    +        Action[] emptyActions = {};
    +
    +        contextMenuManager.addActionHandler(mockHandler);
    +        Mockito.when(
    +                mockHandler.getActions(Mockito.any(SelectionChangeEvent.class),
    +                        Mockito.eq(mockSpreadsheet)))
    +                .thenReturn(emptyActions);
    +
    +        // Use reflection to access protected method
    +        Method method = ContextMenuManager.class
    +                .getDeclaredMethod("createActionsListForSelection");
    +        method.setAccessible(true);
    +        @SuppressWarnings("unchecked")
    +        ArrayList<SpreadsheetActionDetails> result = (ArrayList<SpreadsheetActionDetails>) method
    +                .invoke(contextMenuManager);
    +
    +        assertEquals(0, result.size());
    +    }
    +
    +    @Test
    +    public void createActionsListForSelection_withMultipleActions_shouldCreateMultipleDetails()
    +            throws Exception {
    +        Action action1 = new Action("Action 1");
    +        Action action2 = new Action("<b>Action 2</b>");
    +        Action[] actions = { action1, action2 };
    +
    +        contextMenuManager.addActionHandler(mockHandler);
    +        Mockito.when(
    +                mockHandler.getActions(Mockito.any(SelectionChangeEvent.class),
    +                        Mockito.eq(mockSpreadsheet)))
    +                .thenReturn(actions);
    +
    +        // Use reflection to access protected method
    +        Method method = ContextMenuManager.class
    +                .getDeclaredMethod("createActionsListForSelection");
    +        method.setAccessible(true);
    +        @SuppressWarnings("unchecked")
    +        ArrayList<SpreadsheetActionDetails> result = (ArrayList<SpreadsheetActionDetails>) method
    +                .invoke(contextMenuManager);
    +
    +        assertEquals(2, result.size());
    +        assertEquals("Action 1", result.get(0).caption);
    +        assertEquals("<b>Action 2</b>", result.get(1).caption);
    +        assertEquals(0, result.get(0).type); // Both should be CELL type
    +        assertEquals(0, result.get(1).type);
    +    }
    +}
    

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

5

News mentions

0

No linked articles in our index yet.