VYPR
Moderate severityNVD Advisory· Published Dec 13, 2023· Updated Aug 2, 2024

CVE-2023-47324

CVE-2023-47324

Description

Silverpeas Core 6.3.1 contains a stored XSS vulnerability in the message/notification feature that can lead to full account takeover.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Silverpeas Core 6.3.1 contains a stored XSS vulnerability in the message/notification feature that can lead to full account takeover.

Vulnerability

Analysis

Silverpeas Core 6.3.1 is vulnerable to stored cross-site scripting (XSS) via its message/notification feature [3]. The vulnerability allows an attacker to inject malicious scripts into messages or notifications that are stored on the server and later rendered to other users without proper sanitization.

Attack

Vector

To exploit this vulnerability, an attacker must have an account on the Silverpeas platform and send a crafted message or notification containing malicious JavaScript [1]. The attacker does not need special privileges beyond being able to send messages. The stored script executes when the victim views the notification or message, bypassing the same-origin policy in the victim's browser.

Impact

Successful exploitation can lead to complete compromise of the victim's session, enabling the attacker to perform arbitrary actions on behalf of the victim user. According to the commit message, this stored XSS can lead to full account takeover [2][4]. The impact is especially severe in collaborative environments where users share documents and manage projects, as the attacker could access sensitive data or escalate privileges.

Mitigation

The Silverpeas team has fixed the issue in commit 9cb2941 as part of bug #13811 [2][4]. Users are strongly advised to update their Silverpeas Core installation to a version containing this patch. No workarounds have been published.

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.silverpeas.core:silverpeas-core-webMaven
< 6.3.26.3.2
org.silverpeas.core:silverpeas-core-apiMaven
< 6.3.26.3.2
org.silverpeas.core:silverpeas-core-warMaven
< 6.3.26.3.2
org.silverpeas.core:silverpeas-core-configurationMaven
< 6.3.26.3.2

Affected products

5

Patches

1
9cb2941e9242

Bug #13811: fixing stored XSS leading to full account takeover

https://github.com/Silverpeas/Silverpeas-CoreSilverYoChaOct 25, 2023via ghsa
21 files changed · +197 63
  • core-api/src/main/java/org/silverpeas/core/security/html/HtmlSanitizer.java+7 0 modified
    @@ -39,6 +39,13 @@ static HtmlSanitizer get() {
         return ServiceProvider.getSingleton(HtmlSanitizer.class);
       }
     
    +  /**
    +   * @see #sanitize(String)
    +   */
    +  static String ofHtml(final String html) {
    +    return HtmlSanitizer.get().sanitize(html);
    +  }
    +
       /**
        * Sanitizing the given content by keeping:
        * <ul>
    
  • core-configuration/src/main/config/resources/StringTemplates/core/token/tokenSetting_js.st+1 1 modified
    @@ -36,7 +36,7 @@ function __stampURL(url, tokenName, tokenValue) {
     
     function setTokens(targetContainerSelector) {
       function hasProtectedWord(hrefLowerCase) {
    -    var actions = ['delete','update','create','block','unblock'];
    +    var actions = ['delete','update','creat','save','block'];
         for (var i = 0; i < actions.length; i++) {
           if (hrefLowerCase.indexOf(actions[i]) >= 0) {
             return true;
    
  • core-library/src/test/java/org/silverpeas/core/security/html/HtmlSanitizerTest.java+98 0 added
    @@ -0,0 +1,98 @@
    +/*
    + * Copyright (C) 2000 - 2023 Silverpeas
    + *
    + * This program is free software: you can redistribute it and/or modify
    + * it under the terms of the GNU Affero General Public License as
    + * published by the Free Software Foundation, either version 3 of the
    + * License, or (at your option) any later version.
    + *
    + * As a special exception to the terms and conditions of version 3.0 of
    + * the GPL, you may redistribute this Program in connection with Free/Libre
    + * Open Source Software ("FLOSS") applications as described in Silverpeas's
    + * FLOSS exception.  You should have received a copy of the text describing
    + * the FLOSS exception, and it is also available here:
    + * "https://www.silverpeas.org/legal/floss_exception.html"
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    + * GNU Affero General Public License for more details.
    + *
    + * You should have received a copy of the GNU Affero General Public License
    + * along with this program.  If not, see <https://www.gnu.org/licenses/>.
    + */
    +
    +package org.silverpeas.core.security.html;
    +
    +import org.junit.jupiter.api.Test;
    +import org.silverpeas.core.test.extention.EnableSilverTestEnv;
    +import org.silverpeas.core.test.extention.TestedBean;
    +
    +import static org.hamcrest.MatcherAssert.assertThat;
    +import static org.hamcrest.Matchers.emptyString;
    +import static org.hamcrest.Matchers.is;
    +import static org.silverpeas.core.util.StringUtil.EMPTY;
    +
    +/**
    + * @author silveryocha
    + */
    +@EnableSilverTestEnv
    +class HtmlSanitizerTest {
    +
    +  @TestedBean
    +  private DefaultHtmlSanitizer service;
    +
    +  @Test
    +  void sanitizeNotDefined() {
    +    assertThat(service.sanitize(null), emptyString());
    +    assertThat(service.sanitize(EMPTY), emptyString());
    +  }
    +
    +  @Test
    +  void sanitizeText() {
    +    String payload = "BEFORE<iframe>INSIDE</iframe>AFTER";
    +    assertThat(service.sanitize(payload), is("BEFOREAFTER"));
    +    payload = "BEFORE< iframe  >INSIDE</ iframe >AFTER";
    +    assertThat(service.sanitize(payload),
    +        is("BEFORE&lt; iframe  &gt;INSIDE&lt;/ iframe &gt;AFTER"));
    +    payload = "BEFORE< \t iframe>INSIDE</\t iframe\n>AFTER";
    +    assertThat(service.sanitize(payload),
    +        is("BEFORE&lt; \t iframe&gt;INSIDE&lt;/\t iframe\n&gt;AFTER"));
    +  }
    +
    +  @Test
    +  void sanitizeIFrame() {
    +    String iframe = "BEFORE<iframe>INSIDE</iframe>AFTER";
    +    assertThat(service.sanitize(iframe), is("BEFOREAFTER"));
    +    iframe = "BEFORE< iframe  >INSIDE</ iframe >AFTER";
    +    assertThat(service.sanitize(iframe), is("BEFORE&lt; iframe  &gt;INSIDE&lt;/ iframe &gt;AFTER"));
    +    iframe = "BEFORE< \t iframe>INSIDE</\t iframe\n>AFTER";
    +    assertThat(service.sanitize(iframe),
    +        is("BEFORE&lt; \t iframe&gt;INSIDE&lt;/\t iframe\n&gt;AFTER"));
    +  }
    +
    +  @Test
    +  void sanitizeScript() {
    +    String script =
    +        "BEFORE<script type=\"text/javascript\">window.alert('Silverpeas')" + "</script>AFTER";
    +    assertThat(service.sanitize(script), is("BEFOREAFTER"));
    +    script =
    +        "BEFORE< script type=\"text/javascript\">window.alert('Silverpeas')" + "</ script >AFTER";
    +    assertThat(service.sanitize(script),
    +        is("BEFORE&lt; script type&#61;&#34;text/javascript&#34;&gt;window.alert(&#39;" +
    +            "Silverpeas&#39;)&lt;/ script &gt;AFTER"));
    +  }
    +
    +  @Test
    +  void sanitizePayloadExploit() {
    +    final String payload = "<html><body onload=\"document.forms0.submit();\"><form " +
    +        "action=\"http://server/users/1/update\" method=\"GET\"><input type=\"hidden\" " +
    +        "name=\"userId\" value=\"2\" /><input type=\"hidden\" name=\"userLastName\" " +
    +        "value=\"Toto\" /><input type=\"hidden\" name=\"userAccessLevel\" value=\"ADMINISTRATOR\"" +
    +        " /><input type=\"hidden\" name=\"X-STKN\" value=\"ZKWXYZ\" /></form><span>test</span><a " +
    +        "href=\"http://server/users/1\"></a></body></html>";
    +    assertThat(service.sanitize(payload),
    +        is("test<a href=\"http://server/users/1\" rel=\"noopener noreferrer nofollow\" " +
    +            "target=\"_blank\"></a>"));
    +  }
    +}
    \ No newline at end of file
    
  • core-rs/src/main/java/org/silverpeas/core/web/token/SynchronizerTokenService.java+41 26 modified
    @@ -24,8 +24,7 @@
     package org.silverpeas.core.web.token;
     
     import org.silverpeas.core.admin.user.model.User;
    -import org.silverpeas.core.annotation.Bean;
    -import org.silverpeas.core.annotation.Technical;
    +import org.silverpeas.core.annotation.Service;
     import org.silverpeas.core.date.TemporalFormatter;
     import org.silverpeas.core.security.session.SessionInfo;
     import org.silverpeas.core.security.session.SessionManagement;
    @@ -51,25 +50,27 @@
     /**
      * A service to manage the synchronizer tokens used in Silverpeas to protect the user sessions or
      * the web resources published by Silverpeas.
    - *
    + * <p>
      * Each resource in Silverpeas and accessible through the Web can be protected by one or more
      * security tokens. These tokens are named synchronizer token as they are transmitted within each
      * request and must match the ones expected by Silverpeas to access the asked resource. This service
      * provides the functions to generate, to validate and to set such tokens for the Web resource in
      * Silverpeas to protect (not all resources require to be protected in Silverpeas).
    - *
    + * </p>
      * @author mmoquillon
      */
    -@Technical
    -@Bean
    +@Service
     public class SynchronizerTokenService {
     
       public static final String SESSION_TOKEN_KEY = "X-STKN";
       public static final String NAVIGATION_TOKEN_KEY = "X-NTKN";
       private static final String UNPROTECTED_URI_RULE =
           "(?i)(?!.*(/qaptcha|rpdcsearch/|rclipboard/|rselectionpeaswrapper/|rusernotification/|services/usernotifications/|blockingNews|services/password/)).*";
    -  private static final String DEFAULT_GET_RULE
    -      = "(?i)^/\\w+[\\w/]*/jsp/.*(delete|update|creat|block|unblock).*$";
    +  private static final String DEFAULT_GET_RULE_KEYWORDS = "(delete|update|creat|save|block)";
    +  private static final String DEFAULT_GET_RULE_ON_KEYWORD =
    +      "(?i)^.*" + DEFAULT_GET_RULE_KEYWORDS + ".*$";
    +  private static final String DEFAULT_GET_RULE =
    +      "(?i)^/\\w+[\\w/]*/jsp/.*" + DEFAULT_GET_RULE_KEYWORDS + ".*$";
       private static final SilverLogger logger = SilverLogger.getLogger("silverpeas.core.security");
       private static final List<String> DEFAULT_PROTECTED_METHODS = Arrays.asList("POST", "PUT",
           "DELETE");
    @@ -87,11 +88,11 @@ protected SynchronizerTokenService() {
        * Sets up a session token for the specified Silverpeas session. It creates a synchronizer token
        * to protect the specified opened user session. If a token is already protecting the session, the
        * token is then renewed.
    -   *
    +   * <p>
        * A session token is a token used to validate that any requests to a protected web resource are
        * correctly sent within an opened and valid user session. The setting occurs only if the security
        * mechanism by token is enabled.
    -   *
    +   * </p>
        * @param session the user session to protect with a synchronizer token.
        */
       public void setUpSessionTokens(SessionInfo session) {
    @@ -136,23 +137,27 @@ public void setUpNavigationTokens(HttpServletRequest request) {
        * Validates the request to a Silverpeas web resource can be trusted. The request is validated
        * only if both the security mechanism by token is enabled and the request targets a protected web
        * resource.
    -   *
    +   * <p>
        * The access to a protected web resource is considered as trusted if and only if it is stamped
        * with the expected security tokens for the requested resource. Otherwise, the request isn't
        * considered as trusted and should be rejected. A request is stamped at least with the session
        * token, that is to say with the token that is set with the user session.
    -   *
    +   * </p>
        * @param request the HTTP request to check.
    +   * @param onKeywordsOnly true to verify the request URI against predefined keywords without
    +   * taking care of the entire request URI. false to verify the keywords into request URI structure.
        * @throws TokenValidationException if the specified request cannot be trusted.
        */
    -  public void validate(HttpServletRequest request) throws TokenValidationException {
    -    if (SecuritySettings.isWebSecurityByTokensEnabled() && isAProtectedResource(request)) {
    +  public void validate(HttpServletRequest request, final boolean onKeywordsOnly)
    +      throws TokenValidationException {
    +    if (SecuritySettings.isWebSecurityByTokensEnabled() &&
    +        isAProtectedResource(request, onKeywordsOnly)) {
           logger.debug("Validate the request for path {0}", getRequestPath(request));
           Token expectedToken = getSessionToken(request);
           // is there a user session opened?
           if (expectedToken.isDefined()) {
             String actualToken = getTokenInRequest(SESSION_TOKEN_KEY, request);
    -        validate(actualToken, expectedToken);
    +        validate(request, actualToken, expectedToken);
           }
     
           // is the navigation protected by a token?
    @@ -161,28 +166,32 @@ public void validate(HttpServletRequest request) throws TokenValidationException
           if (expectedToken.isDefined()) {
             logger.debug("Validate the request origin for path {0}", getRequestPath(request));
             String actualToken = getTokenInRequest(NAVIGATION_TOKEN_KEY, request);
    -        validate(actualToken, expectedToken);
    +        validate(request, actualToken, expectedToken);
           }
         }
       }
     
       /**
        * Is the resource targeted by the specified request must be protected by a synchronizer token?
    -   *
    +   * <p>
        * A resource is protected if either the request is a POST, PUT or a DELETE HTTP method or if the
        * requested URI is declared as to be protected.
    -   *
    +   * </p>
        * @param request the request to a possibly protected resource.
    +   * @param onKeywordsOnly true to verify the request URI against predefined keywords without
    +   * taking care of the entire request URI. false to verify the keywords into request URI structure.
        * @return true if the requested resource is a protected one and then the request should be
    -   * validate.
    +   * validated.
        */
    -  public boolean isAProtectedResource(HttpServletRequest request) {
    +  public boolean isAProtectedResource(HttpServletRequest request, final boolean onKeywordsOnly) {
         boolean isProtected = false;
         if (request.getRequestURI().matches(UNPROTECTED_URI_RULE)) {
           isProtected = DEFAULT_PROTECTED_METHODS.contains(request.getMethod());
    -      if (!isProtected && request.getMethod().equals("GET")) {
    +      if (!isProtected && "GET".equals(request.getMethod())) {
             String path = getRequestPath(request);
    -        isProtected = path.matches(DEFAULT_GET_RULE);
    +        isProtected = onKeywordsOnly ?
    +            path.matches(DEFAULT_GET_RULE_ON_KEYWORD) :
    +            path.matches(DEFAULT_GET_RULE);
           }
         }
         return isProtected;
    @@ -231,16 +240,22 @@ private String getRequestPath(HttpServletRequest request) {
         return path;
       }
     
    -  private void validate(String actualToken, Token expectedToken) throws TokenValidationException {
    +  private void validate(final HttpServletRequest request, String actualToken, Token expectedToken)
    +      throws TokenValidationException {
         if (!(StringUtil.isDefined(actualToken) && expectedToken.isDefined()
             && expectedToken.getValue().equals(actualToken))) {
    -      throwTokenInvalidException();
    +      throwTokenInvalidException(request);
         }
       }
     
    -  private void throwTokenInvalidException() throws TokenValidationException {
    +  private void throwTokenInvalidException(final HttpServletRequest request)
    +      throws TokenValidationException {
         String now = TemporalFormatter.toBaseIso8601(OffsetDateTime.now(), true);
    -    throw new TokenValidationException("Attempt of a CSRF attack detected at " + now);
    +    final TokenValidationException exception = new TokenValidationException(
    +        "Attempt of a CSRF attack detected at " + now);
    +    logger.error("The request for path {0} isn''t valid: {1}", request.getRequestURI(),
    +        exception.getMessage());
    +    throw exception;
       }
     
       private Token getTokenInSession(String tokenId, HttpServletRequest request, boolean pop) {
    
  • core-war/src/main/java/org/silverpeas/web/jobdomain/servlets/JobDomainPeasRequestRouter.java+6 6 modified
    @@ -258,7 +258,7 @@ public String getDestination(String function, JobDomainPeasSessionController job
               }
     
               destination = DOMAIN_CONTENT_DEST;
    -        } else if (function.startsWith("userModify")) {
    +        } else if (function.startsWith("userUpdate")) {
               UserRequestData userRequestData =
                   RequestParameterDecoder.decode(request, UserRequestData.class);
     
    @@ -430,7 +430,7 @@ public String getDestination(String function, JobDomainPeasSessionController job
                   WebEncodeHelper.htmlStringToJavaString(request.getParameter(GROUP_NAME_PARAM)),
                   WebEncodeHelper.htmlStringToJavaString(request.getParameter("groupDescription")),
                   request.getParameter("groupRule"));
    -        } else if (function.startsWith("groupModify")) {
    +        } else if (function.startsWith("groupUpdate")) {
               bHaveToRefreshDomain = jobDomainSC.modifyGroup(request.getParameter(IDGROUP_PARAM),
                   WebEncodeHelper.htmlStringToJavaString(request.getParameter(GROUP_NAME_PARAM)),
                   WebEncodeHelper.htmlStringToJavaString(request.getParameter("groupDescription")),
    @@ -634,9 +634,9 @@ public String getDestination(String function, JobDomainPeasSessionController job
                   .getPath((String) request.getAttribute(MY_COMPONENT_URL_ATTR),
                       jobDomainSC.getString("JDP.groupAdd") + "..."));
               destination = "groupCreate.jsp";
    -        } else if (function.startsWith("displayGroupModify")) {
    +        } else if (function.startsWith("displayGroupUpdate")) {
               request.setAttribute(GROUP_OBJECT_ATTR, jobDomainSC.getTargetGroup());
    -          request.setAttribute(ACTION_ATTR, "groupModify");
    +          request.setAttribute(ACTION_ATTR, "groupUpdate");
               request.setAttribute(GROUPS_PATH_ATTR, jobDomainSC
                   .getPath((String) request.getAttribute(MY_COMPONENT_URL_ATTR),
                       jobDomainSC.getString("JDP.groupUpdate") + "..."));
    @@ -679,9 +679,9 @@ public String getDestination(String function, JobDomainPeasSessionController job
                       jobDomainSC.getString("JDP.csvImport") + "..."));
               request.setAttribute("FieldLabelsToImport", jobDomainSC.getFieldLabelsOfCSVToImport());
               destination = "usersCsvImport.jsp";
    -        } else if (function.startsWith("displayUserModify")) {
    +        } else if (function.startsWith("displayUserUpdate")) {
               request.setAttribute(USER_OBJECT_ATTR, jobDomainSC.getTargetUserFull());
    -          request.setAttribute(ACTION_ATTR, "userModify");
    +          request.setAttribute(ACTION_ATTR, "userUpdate");
               request.setAttribute(GROUPS_PATH_ATTR, jobDomainSC
                   .getPath((String) request.getAttribute(MY_COMPONENT_URL_ATTR),
                       jobDomainSC.getString("JDP.userUpdate") + "..."));
    
  • core-war/src/main/java/org/silverpeas/web/notificationuser/servlets/UserNotificationRequestRouter.java+3 1 modified
    @@ -25,6 +25,7 @@
     
     import org.silverpeas.core.notification.user.NotificationContext;
     import org.silverpeas.core.notification.user.UserNotification;
    +import org.silverpeas.core.security.html.HtmlSanitizer;
     import org.silverpeas.core.util.ResourceLocator;
     import org.silverpeas.core.util.SettingBundle;
     import org.silverpeas.core.util.StringUtil;
    @@ -125,9 +126,10 @@ public String getDestination(String function, UserNotificationSessionController
       private NotificationContext getNotificationContext(final HttpRequest request) {
         final NotificationContext context = new NotificationContext(getCurrentRequester());
         Enumeration<String> parameters = request.getParameterNames();
    +    final HtmlSanitizer htmlSanitizer = HtmlSanitizer.get();
         while (parameters.hasMoreElements()) {
           final String name = parameters.nextElement();
    -      context.put(name, request.getParameter(name));
    +      context.put(name, htmlSanitizer.sanitize(request.getParameter(name)));
         }
         return context;
       }
    
  • core-war/src/main/java/org/silverpeas/web/token/SessionSynchronizerTokenValidator.java+3 11 modified
    @@ -85,19 +85,17 @@ public class SessionSynchronizerTokenValidator implements Filter {
       @Override
       public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
           throws IOException, ServletException {
    -
         HttpServletRequest httpRequest = (HttpServletRequest) request;
         if (SecuritySettings.isWebSecurityByTokensEnabled() && isProtectedResource(httpRequest)) {
           try {
             checkAuthenticatedRequest(httpRequest);
    -        tokenService.validate(httpRequest);
    +        tokenService.validate(httpRequest, false);
             chain.doFilter(request, response);
           } catch (TokenValidationException ex) {
    -        logger.error("The request for path {0} isn''t valid: {1}", pathOf(request), ex.getMessage());
             ((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN);
           } catch (UnauthenticatedRequestException ex) {
             logger.error("The request for path {0} isn''t sent within an opened session",
    -            pathOf(request));
    +            ((HttpServletRequest) request).getRequestURI());
             redirectToAuthenticationPage(request, response);
           }
         } else {
    @@ -162,7 +160,7 @@ private boolean isCredentialManagement(HttpServletRequest request) {
       }
     
       private boolean isProtectedResource(HttpServletRequest request) {
    -    return tokenService.isAProtectedResource(request) && !isFileDragAndDrop(request) &&
    +    return tokenService.isAProtectedResource(request, false) && !isFileDragAndDrop(request) &&
             !isCredentialManagement(request) && !isSsoAuthentication(request) &&
             !isWebServiceRequested(request) &&
             !isWebBrowserEditionResource(request) && !isCMISResource(request) &&
    @@ -198,13 +196,7 @@ private boolean isDragAndDropWebEditionResource(HttpServletRequest request) {
         return request.getRequestURI().contains(getApplicationURL() + "/Rddwe/");
       }
     
    -  private String pathOf(ServletRequest request) {
    -    return ((HttpServletRequest) request).getRequestURI();
    -  }
    -
       private static class UnauthenticatedRequestException extends Exception {
    -
         private static final long serialVersionUID = 9173126171348369053L;
    -
       }
     }
    
  • core-war/src/main/webapp/jobDomainPeas/jsp/groupContent.jsp+2 2 modified
    @@ -81,7 +81,7 @@
           showTabs = true;
           // Group operations
           operationPane.addOperationOfCreation(resource.getIcon("JDP.groupAdd"), resource.getString("JDP.groupAdd"), "displayGroupCreate?Idgroup=" + thisGroupId);
    -      operationPane.addOperation(resource.getIcon("JDP.groupUpdate"), resource.getString("GML.modify"), "displayGroupModify?Idgroup=" + thisGroupId);
    +      operationPane.addOperation(resource.getIcon("JDP.groupUpdate"), resource.getString("GML.modify"), "displayGroupUpdate?Idgroup=" + thisGroupId);
           operationPane.addOperation(resource.getIcon("JDP.groupDel"), resource.getString("GML.remove"), "javascript:removeGroup()");
           // User operations
           operationPane.addLine();
    @@ -103,7 +103,7 @@
           } else {
             //Group operations
             operationPane.addOperationOfCreation(resource.getIcon("JDP.groupAdd"), resource.getString("JDP.groupAdd"), "displayGroupCreate?Idgroup=" + thisGroupId);
    -        operationPane.addOperation(resource.getIcon("JDP.groupUpdate"), resource.getString("GML.modify"), "displayGroupModify?Idgroup=" + thisGroupId);
    +        operationPane.addOperation(resource.getIcon("JDP.groupUpdate"), resource.getString("GML.modify"), "displayGroupUpdate?Idgroup=" + thisGroupId);
             if (!isGroupManagerDirectly) {
               operationPane.addOperation(resource.getIcon("JDP.groupDel"), resource.getString("GML.remove"), "javascript:removeGroup()");
             }
    
  • core-war/src/main/webapp/jobDomainPeas/jsp/userContent.jsp+1 1 modified
    @@ -116,7 +116,7 @@
         if (isUserFull) {
           operationPane
               .addOperation(resource.getIcon("JDP.userUpdate"), resource.getString("GML.modify"),
    -              "displayUserModify?Iduser=" + thisUserId);
    +              "displayUserUpdate?Iduser=" + thisUserId);
         }
         updatableUser = true;
         if (userObject.isBlockedState()) {
    
  • core-war/src/main/webapp/jobDomainPeas/jsp/userCreate.jsp+4 4 modified
    @@ -90,7 +90,7 @@
       List<Group> groups = (List<Group>) request.getAttribute("GroupsManagedByCurrentUser");
     
       boolean userCreation = "userCreate".equals(action);
    -  boolean extraInfosUpdatable = userCreation || "userModify".equals(action);
    +  boolean extraInfosUpdatable = userCreation || "userUpdate".equals(action);
     
       browseBar.setComponentName(getDomainLabel(domObject, resource),
           "domainContent?Iddomain=" + domObject.getId());
    @@ -165,8 +165,8 @@ function ifCorrectBasicFormExecute(callback) {
       <% if (userObject.isPasswordAvailable()) { %>
       if ($('#userPasswordValid:checked').val()) {
         var $pwdInput = $('#userPasswordId');
    -    <% if (userCreation || "userModify".equals(action)) { %>
    -    <% if ("userModify".equals(action)) { %>
    +    <% if (userCreation || "userUpdate".equals(action)) { %>
    +    <% if ("userUpdate".equals(action)) { %>
         if ($pwdInput.val()) {
           <% } %>
           var passwordDeferred = sp.promise.deferred();
    @@ -183,7 +183,7 @@ function ifCorrectBasicFormExecute(callback) {
           if ($pwdInput.val() != $('#userPasswordAgainId').val()) {
             SilverpeasError.add("<fmt:message key='JDP.confirmPwdError'/>");
           }
    -      <% if ("userModify".equals(action)) { %>
    +      <% if ("userUpdate".equals(action)) { %>
         }
         <% } %>
         <% } %>
    
  • core-war/src/main/webapp/POPUP/jsp/readMessage.jsp+1 1 modified
    @@ -53,7 +53,7 @@
         <c:set var="popupMsgId" value="${popupMsg.id}"/>
         <c:set var="popupMsgDate" value="${popupMsg.date}"/>
         <c:set var="popupMsgTime" value="${popupMsg.time}"/>
    -    <c:set var="popupMsgBody" value="${popupMsg.body}"/>
    +    <c:set var="popupMsgBody" value="${silfn:sanitizeHtml(popupMsg.body)}"/>
         <c:set var="popupMsgUrl" value="${popupMsg.url}"/>
         <c:set var="senderId" value="${popupMsg.senderId}"/>
         <c:set var="senderName" value="${silfn:defaultEmptyString(popupMsg.senderName)}"/>
    
  • core-war/src/main/webapp/SILVERMAIL/jsp/main.jsp+1 1 modified
    @@ -187,7 +187,7 @@
                   </c:if>
                 </view:arrayCellText>
                 <view:arrayCellText>
    -              <a href="${viewUrl}">${silfn:escapeHtml(userNotification.data.subject)}</a>
    +              <a href="${viewUrl}">${silfn:sanitizeHtml(userNotification.data.subject)}</a>
                 </view:arrayCellText>
                 <view:arrayCellText>
                   <a href="${viewUrl}">${silfn:escapeHtml(userNotification.data.senderName)}</a>
    
  • core-war/src/main/webapp/SILVERMAIL/jsp/readMessage.jsp+1 1 modified
    @@ -97,7 +97,7 @@
           </div>
         </c:if>
         <div class="content-notification rich-content">
    -        ${msg.body}
    +        ${silfn:sanitizeHtml(msg.body)}
         </div>
     
         <view:buttonPane>
    
  • core-war/src/main/webapp/SILVERMAIL/jsp/readSentNotification.jsp+1 1 modified
    @@ -84,7 +84,7 @@
           </div>
         </c:if>
         <div class="content-notification rich-content">
    -        ${notif.body}
    +        ${silfn:sanitizeHtml(notif.body)}
         </div>
         <view:buttonPane>
           <fmt:message var="deleteLabel" key="delete"/>
    
  • core-war/src/main/webapp/SILVERMAIL/jsp/sentUserNotifications.jsp+1 1 modified
    @@ -134,7 +134,7 @@ response.setDateHeader ("Expires",-1);          //prevents caching at the proxy
                   <a href="${viewUrl}">${silfn:formatDate(sentUserNotification.data.notifDate, _userLanguage)}</a>
                 </view:arrayCellText>
                 <view:arrayCellText>
    -              <a href="${viewUrl}">${silfn:escapeHtml(sentUserNotification.data.title)}</a>
    +              <a href="${viewUrl}">${silfn:sanitizeHtml(sentUserNotification.data.title)}</a>
                 </view:arrayCellText>
                 <view:arrayCellText>
                   <a href="${viewUrl}">${silfn:escapeHtml(sentUserNotification.data.source)}</a>
    
  • core-war/src/main/webapp/util/javaScript/vuejs/components/notification/silverpeas-user-notification-templates.jsp+1 1 modified
    @@ -80,7 +80,7 @@
            v-bind:class="mainClasses"
            v-on:mouseover="toggleButtons(true)"
            v-on:mouseleave="toggleButtons(false)">
    -    <div class="user-notification-subject">{{notification.subject}}</div>
    +    <div class="user-notification-subject" v-html="notification.subject"></div>
         <div class="date-from">
           <span class="user-notification-date">{{notification.date | displayAsDate}}</span>
           <span class="user-notification-from">{{notification.senderName}}</span>
    
  • core-web/src/main/java/org/silverpeas/core/webapi/notification/user/InboxUserNotificationEntity.java+4 2 modified
    @@ -27,6 +27,7 @@
     import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
     import org.apache.commons.lang3.builder.ToStringBuilder;
     import org.silverpeas.core.notification.user.server.channel.silvermail.SILVERMAILMessage;
    +import org.silverpeas.core.security.html.HtmlSanitizer;
     import org.silverpeas.core.util.logging.SilverLogger;
     import org.silverpeas.core.web.rs.WebEntity;
     
    @@ -142,15 +143,16 @@ public boolean isRead() {
       protected InboxUserNotificationEntity decorate(final SILVERMAILMessage notification) {
         this.id = notification.getId();
         this.source = notification.getSource();
    -    this.subject = notification.getSubject();
    +    final HtmlSanitizer htmlSanitizer = HtmlSanitizer.get();
    +    this.subject = htmlSanitizer.sanitize(notification.getSubject());
         this.senderName = notification.getSenderName();
         this.date = toLocalDate(notification.getDate()).toString();
         try {
           this.resourceViewUrl = UriBuilder.fromUri(notification.getUrl()).build();
         } catch (Exception e) {
           SilverLogger.getLogger(this).warn(e);
         }
    -    this.content = notification.getBody();
    +    this.content = htmlSanitizer.sanitize(notification.getBody());
         this.read = notification.getReaden() > 0;
         return this;
       }
    
  • core-web/src/main/java/org/silverpeas/core/web/mvc/route/ComponentRequestRouter.java+11 0 modified
    @@ -32,6 +32,7 @@
     import org.silverpeas.core.security.session.SessionManagement;
     import org.silverpeas.core.security.session.SessionManagementProvider;
     import org.silverpeas.core.security.token.Token;
    +import org.silverpeas.core.security.token.exception.TokenValidationException;
     import org.silverpeas.core.silverstatistics.volume.service.SilverStatisticsManager;
     import org.silverpeas.core.util.JSONCodec;
     import org.silverpeas.core.util.MultiSilverpeasBundle;
    @@ -205,6 +206,8 @@ private String computeDestination(HttpServletRequest request) {
           return destination;
         }
     
    +    validateSecurityTokens(request);
    +
         T ctrl = this.getComponentSessionController(session, componentId);
         if (ctrl == null) {
           ctrl = setComponentSessionController(session, mainSessionCtrl, spaceId, componentId);
    @@ -319,6 +322,14 @@ public void updateSessionManagement(HttpSession session, String destination) {
         sessionManagement.validateSession(session.getId());
       }
     
    +  private void validateSecurityTokens(final HttpServletRequest request) {
    +    try {
    +      SynchronizerTokenService.getInstance().validate(request, true);
    +    } catch (TokenValidationException ex) {
    +      throwHttpForbiddenError();
    +    }
    +  }
    +
       // isUserStateValid if the user is allowed to access the required component
       private boolean isUserAllowed(MainSessionController controller, String componentId) {
         boolean[] userAllowed = {componentId == null ||
    
  • core-web/src/main/java/org/silverpeas/core/web/util/viewgenerator/html/browsebars/BrowseBarComplete.java+1 2 modified
    @@ -33,7 +33,6 @@
     import org.silverpeas.core.admin.space.SpaceInstLight;
     import org.silverpeas.core.util.StringUtil;
     import org.silverpeas.core.util.URLUtil;
    -import org.silverpeas.core.util.WebEncodeHelper;
     import org.silverpeas.core.util.html.HtmlCleaner;
     import org.silverpeas.core.util.logging.SilverLogger;
     
    @@ -241,7 +240,7 @@ private void appendElement(StringBuilder breadcrumb, BrowseBarElement element) {
           breadcrumb.append(" id=\"").append(element.getId()).append("\"");
         }
         breadcrumb.append(">");
    -    breadcrumb.append(WebEncodeHelper.javaStringToHtmlString(element.getLabel()));
    +    breadcrumb.append(element.getLabel());
         if (StringUtil.isDefined(element.getLink())) {
           breadcrumb.append("</a>");
         } else {
    
  • core-web/src/main/java/org/silverpeas/core/web/util/viewgenerator/html/browsebars/BrowseBarElement.java+3 1 modified
    @@ -23,6 +23,8 @@
      */
     package org.silverpeas.core.web.util.viewgenerator.html.browsebars;
     
    +import org.silverpeas.core.security.html.HtmlSanitizer;
    +
     public class BrowseBarElement {
     
       private String label;
    @@ -40,7 +42,7 @@ public BrowseBarElement(String label, String link, String id) {
       }
     
       public String getLabel() {
    -    return label;
    +    return HtmlSanitizer.get().sanitize(label);
       }
     
       public String getLink() {
    
  • core-web/src/main/resources/META-INF/silverFunctions.tld+6 0 modified
    @@ -221,6 +221,12 @@
         <function-class>org.silverpeas.core.util.WebEncodeHelper</function-class>
         <function-signature>java.lang.String javaStringToJsString( java.lang.String ) </function-signature>
       </function>
    +  <function>
    +    <description>Function to encode a java String into a HTML String.</description>
    +    <name>sanitizeHtml</name>
    +    <function-class>org.silverpeas.core.security.html.HtmlSanitizer</function-class>
    +    <function-signature>java.lang.String ofHtml(java.lang.String)</function-signature>
    +  </function>
       <function>
         <description>Function to encode a java String into a HTML String.</description>
         <name>escapeHtml</name>
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.