VYPR
Low severityNVD Advisory· Published Apr 5, 2010· Updated Apr 29, 2026

CVE-2010-0684

CVE-2010-0684

Description

Cross-site scripting (XSS) vulnerability in createDestination.action in Apache ActiveMQ before 5.3.1 allows remote authenticated users to inject arbitrary web script or HTML via the JMSDestination parameter in a queue action.

AI Insight

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

Apache ActiveMQ before 5.3.1 is vulnerable to stored XSS via the JMSDestination parameter in createDestination.action, allowing authenticated users to inject arbitrary scripts.

Vulnerability

A cross-site scripting (XSS) vulnerability exists in createDestination.action in Apache ActiveMQ before version 5.3.1 [4]. The flaw allows remote authenticated users to inject arbitrary web script or HTML through the JMSDestination parameter in a queue action [1][4]. The issue was fixed by escaping the output of various JMS fields across multiple files, including header.jsp and message.jsp, to prevent script injection [1][3].

Exploitation

An authenticated attacker can send a crafted request to createDestination.action with a malicious payload in the JMSDestination parameter [1][4]. The injected script is then rendered in the web console without proper sanitization, enabling execution in the browser context of other users who view the affected pages [1][3]. The attack requires network access to the web console and a valid authenticated session.

Impact

Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of the victim's session within the ActiveMQ web console [1][4]. This can lead to theft of credentials, session hijacking, unauthorized actions on the broker, or defacement of the console interface [4].

Mitigation

Apache ActiveMQ 5.3.1, released on 2010-04-05, fixes this vulnerability by properly escaping user-supplied input in the web console [1][2][4]. Users should upgrade to version 5.3.1 or later. No workaround is available for older versions. The fix also included CSRF protections and additional output escaping for related JMS fields [2][3].

AI Insight generated on May 23, 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.apache.activemq:activemq-parentMaven
< 5.3.15.3.1

Affected products

25
  • Apache/Activemq24 versions
    cpe:2.3:a:apache:activemq:*:*:*:*:*:*:*:*+ 23 more
    • cpe:2.3:a:apache:activemq:*:*:*:*:*:*:*:*range: <=5.3.0
    • cpe:2.3:a:apache:activemq:1.1:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:1.2:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:1.3:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:1.4:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:1.5:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:2.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:2.1:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:3.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:3.1:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:3.2:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:3.2.1:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:3.2.2:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:4.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:4.0.1:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:4.0.2:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:4.0:m4:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:4.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:4.1.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:4.1.1:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:5.0.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:5.1.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:activemq:5.2.0:*:*:*:*:*:*:*
    • (no CPE)range: <5.3.1

Patches

3
2895197d0dad

https://issues.apache.org/activemq/browse/AMQ-2613 - more web console sanitation

https://github.com/apache/activemqBosanac DejanApr 7, 2010via ghsa
4 files changed · +43 40
  • activemq-web-console/src/main/java/org/apache/activemq/web/controller/SendMessage.java+3 0 modified
    @@ -178,6 +178,9 @@ protected void appendHeaders(Message message, HttpServletRequest request) throws
                 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
                     Map.Entry entry = (Map.Entry) iter.next();
                     String name = (String) entry.getKey();
    +                if (name.equals("secret")) {
    +                	continue;
    +                }
                     Object value = entry.getValue();
                     if (isValidPropertyName(name)) {
                         if (value instanceof String[]) {
    
  • activemq-web-console/src/main/webapp/browse.jsp+5 5 modified
    @@ -41,13 +41,13 @@
     <tr>
     <td><a href="message.jsp?id=${row.JMSMessageID}&JMSDestination=<c:out value="${requestContext.queueBrowser.JMSDestination}" />" 
         title="${row.properties}">${row.JMSMessageID}</a></td>
    -<td>${row.JMSCorrelationID}</td>
    +<td><c:out value="${row.JMSCorrelationID}"/></td>
     <td><jms:persistent message="${row}"/></td>
    -<td>${row.JMSPriority}</td>
    -<td>${row.JMSRedelivered}</td>
    -<td>${row.JMSReplyTo}</td>
    +<td><c:out value="${row.JMSPriority}"/></td>
    +<td><c:out value="${row.JMSRedelivered}"/></td>
    +<td><c:out value="${row.JMSReplyTo}"/></td>
     <td><jms:formatTimestamp timestamp="${row.JMSTimestamp}"/></td>
    -<td>${row.JMSType}</td>
    +<td><c:out value="${row.JMSType}"/></td>
     <td>
         <a href="deleteMessage.action?JMSDestination=<c:out value="${row.JMSDestination}"/>&messageId=${row.JMSMessageID}&secret=<c:out value='${sessionScope["secret"]}'/>">Delete</a>
     </td>
    
  • activemq-web-console/src/main/webapp/connection.jsp+22 22 modified
    @@ -17,7 +17,7 @@
     <html>
     <head>
     <c:set var="row" value="${requestContext.connectionQuery.connection}"/>
    -<title>Connection ${requestContext.connectionQuery.connectionID}</title>
    +<title>Connection <c:out value="${requestContext.connectionQuery.connectionID}" /></title>
     </head>
     <body>
     
    @@ -26,40 +26,40 @@
     <c:when test="${empty row}">
     
     <div>
    -No connection could be found for ID ${requestContext.connectionQuery.connectionID}
    +No connection could be found for ID <c:out value="${requestContext.connectionQuery.connectionID}" />
     </div>
     
     </c:when>
     
     <c:otherwise>
     
    -<h2>Connection ${requestContext.connectionQuery.connectionID}</h2>
    +<h2>Connection <c:out value="${requestContext.connectionQuery.connectionID}" /></h2>
     
     <table id="header" class="sortable autostripe">
     	<tbody>
     		<tr>
     			<td class="label" title="Unique ID for this connection">Connection ID</td>
    -			<td>${requestContext.connectionQuery.connectionID}</td>
    +			<td><c:out value="${requestContext.connectionQuery.connectionID}" /></td>
     		</tr>
     		<tr>
     			<td class="label" tite="Hostname and port of the connected party">Remote Address</td>
    -			<td>${row.remoteAddress}</td>
    +			<td><c:out value="${row.remoteAddress}" /></td>
     		</tr>
     		<tr>
     			<td class="label">Active</td>
    -			<td>${row.active}</td>
    +			<td><c:out value="${row.active}" /></td>
     		</tr>
     		<tr>
     			<td class="label">Connected</td>
    -			<td>${row.connected}</td>
    +			<td><c:out value="${row.connected}" /></td>
     		</tr>
     		<tr>
     			<td class="label">Blocked</td>
    -			<td>${row.blocked}</td>
    +			<td><c:out value="${row.blocked}" /></td>
     		</tr>
     		<tr>
     			<td class="label">Slow</td>
    -			<td>${row.slow}</td>
    +			<td><c:out value="${row.slow}" /></td>
     		</tr>
     	</tbody>
     </table>
    @@ -96,29 +96,29 @@ No connection could be found for ID ${requestContext.connectionQuery.connectionI
     	<td>
     		<c:choose>
     			<c:when test="${consumer.destinationQueue}">
    -				Queue <a href="browse.jsp?JMSDestination=${consumer.destinationName}">${consumer.destinationName}</a>
    +				Queue <a href="browse.jsp?JMSDestination=${consumer.destinationName}"><c:out value="${consumer.destinationName}" /></a>
     			</c:when>
     			<c:when test="${consumer.destinationTopic}">
    -				Topic <a href="send.jsp?JMSDestination=${consumer.destinationName}">${consumer.destinationName}</a>
    +				Topic <a href="send.jsp?JMSDestination=${consumer.destinationName}"><c:out value="${consumer.destinationName}" /></a>
     			</c:when>
     			<c:otherwise>
    -				${consumer.destinationName}
    +				<c:out value="${consumer.destinationName}" />
     			</c:otherwise>
     		</c:choose>
     	</td>
    -	<td>${consumer.sessionId}</td>
    -	<td>${consumer.selector}</td>
    -	<td>${consumer.enqueueCounter}</td>
    -	<td>${consumer.dequeueCounter}</td>
    -	<td>${consumer.dispachedCounter}</td>
    -	<td>${consumer.dispatchedQueueSize}</td>
    +	<td><c:out value="${consumer.sessionId}" /></td>
    +	<td><c:out value="${consumer.selector}" /></td>
    +	<td><c:out value="${consumer.enqueueCounter}" /></td>
    +	<td><c:out value="${consumer.dequeueCounter}" /></td>
    +	<td><c:out value="${consumer.dispachedCounter}" /></td>
    +	<td><c:out value="${consumer.dispatchedQueueSize}" /></td>
     	<td>
    -		${consumer.prefetchSize}<br/>
    -		${consumer.maximumPendingMessageLimit}
    +		<c:out value="${consumer.prefetchSize}" /><br/>
    +		<c:out value="${consumer.maximumPendingMessageLimit}" />
     	</td>
     	<td>
    -		${consumer.exclusive}<br/>
    -		${consumer.retroactive}
    +		<c:out value="${consumer.exclusive}" /><br/>
    +		<c:out value="${consumer.retroactive}" />
     	</td>
     </tr>
     </c:forEach>
    
  • activemq-web-console/src/main/webapp/message.jsp+13 13 modified
    @@ -17,7 +17,7 @@
     <html>
     <head>
     <c:set var="row" value="${requestContext.messageQuery.message}"/>
    -<title>Message ${requestContext.messageQuery.id}</title>
    +<title>Message <c:out value="${requestContext.messageQuery.id}"/></title>
     </head>
     <body>
     
    @@ -26,7 +26,7 @@
     <c:when test="${empty row}">
     
     <div>
    -No message could be found for ID ${requestContext.messageQuery.id}
    +No message could be found for ID <c:out value="${requestContext.messageQuery.id}"/>
     </div>
     
     </c:when>
    @@ -47,51 +47,51 @@ No message could be found for ID ${requestContext.messageQuery.id}
     				<tbody>
     					<tr>
     						<td class="label" title="Unique Message ID for this message">Message ID</td>
    -						<td>${row.JMSMessageID}</td>
    +						<td><c:out value="${row.JMSMessageID}"/></td>
     					</tr>
     					<tr>
     						<td class="label">Destination</td>
     						<td><form:tooltip text="${row.JMSDestination}" length="50"/></td>
     					</tr>
     					<tr>
     						<td class="label" title="The ID used to correlate messages together in a conversation">Correlation ID</td>
    -						<td>${row.JMSCorrelationID}</td>
    +						<td><c:out value="${row.JMSCorrelationID}"/></td>
     					</tr>
     					<tr>
     						<td class="label" title="Message Group Identifier">Group</td>
    -						<td>${row.groupID}</td>
    +						<td><c:out value="${row.groupID}"/></td>
     					</tr>
     					<tr>
     						<td class="label" title="Message Group Sequence Number">Sequence</td>
    -						<td>${row.groupSequence}</td>
    +						<td><c:out value="${row.groupSequence}"/></td>
     					</tr>
     					<tr>
     						<td class="label">Expiration</td>
    -						<td>${row.JMSExpiration}</td>
    +						<td><c:out value="${row.JMSExpiration}"/></td>
     					</tr>
     					<tr>
     						<td class="label">Persistence</td>
     						<td><jms:persistent message="${row}"/></td>
     					</tr>
     					<tr>
     						<td class="label">Priority</td>
    -						<td>${row.JMSPriority}</td>
    +						<td><c:out value="${row.JMSPriority}"/></td>
     					</tr>
     					<tr>
     						<td class="label">Redelivered</td>
    -					    <td>${row.JMSRedelivered}</td>
    +					    <td><c:out value="${row.JMSRedelivered}"/></td>
     					</tr>
     					<tr>
     						<td class="label">Reply To</td>
    -						<td>${row.JMSReplyTo}</td>
    +						<td><c:out value="${row.JMSReplyTo}"/></td>
     					</tr>
     					<tr>
     						<td class="label">Timestamp</td>
     						<td><jms:formatTimestamp timestamp="${row.JMSTimestamp}"/></td>
     					</tr>
     					<tr>
     						<td class="label">Type</td>
    -						<td>${row.JMSType}</td>
    +						<td><c:out value="${row.JMSType}"/></td>
     					</tr>
     				</tbody>
     			</table>
    @@ -109,8 +109,8 @@ No message could be found for ID ${requestContext.messageQuery.id}
     				<tbody>
                        <form:forEachMapEntry items="${requestContext.messageQuery.propertiesMap}" var="prop">
     						<tr>
    -							<td class="label">${prop.key}</td>
    -							<td>${prop.value}</td>
    +							<td class="label"><c:out value="${prop.key}"/></td>
    +							<td><c:out value="${prop.value}"/></td>
     						</tr>
     						<tr>
     					</form:forEachMapEntry>
    
1f464b9412e1

merging 915269,915384 - https://issues.apache.org/activemq/browse/AMQ-2613 - XSS and CSRF vunerabilities

https://github.com/apache/activemqBosanac DejanFeb 23, 2010via ghsa
18 files changed · +82 34
  • activemq-web-console/src/main/java/org/apache/activemq/web/controller/CreateDestination.java+6 0 modified
    @@ -39,4 +39,10 @@ public ModelAndView handleRequest(HttpServletRequest request, HttpServletRespons
             return redirectToBrowseView();
         }
     
    +	public String[] getSupportedHttpMethods() {
    +		return new String[]{"POST"};
    +	}
    +    
    +    
    +
     }
    
  • activemq-web-console/src/main/java/org/apache/activemq/web/controller/CreateSubscriber.java+4 0 modified
    @@ -50,5 +50,9 @@ public ModelAndView handleRequest(HttpServletRequest request, HttpServletRespons
             getBrokerAdmin().createDurableSubscriber(getClientId(), getSubscriberName(), getValidDestination(), selector);
             return new ModelAndView("redirect:subscribers.jsp");
         }
    +    
    +	public String[] getSupportedHttpMethods() {
    +		return new String[]{"POST"};
    +	}
     
     }
    
  • activemq-web-console/src/main/java/org/apache/activemq/web/controller/SendMessage.java+4 0 modified
    @@ -209,4 +209,8 @@ protected boolean isValidPropertyName(String name) {
             // allow JMSX extensions or non JMS properties
             return name.startsWith("JMSX") || !name.startsWith("JMS");
         }
    +    
    +	public String[] getSupportedHttpMethods() {
    +		return new String[]{"POST"};
    +	}
     }
    
  • activemq-web-console/src/main/java/org/apache/activemq/web/handler/BindingBeanNameUrlHandlerMapping.java+19 1 modified
    @@ -16,8 +16,12 @@
      */
     package org.apache.activemq.web.handler;
     
    +import java.util.Arrays;
    +import java.util.UUID;
    +
     import javax.servlet.http.HttpServletRequest;
     
    +import org.apache.activemq.web.DestinationFacade;
     import org.apache.commons.logging.Log;
     import org.apache.commons.logging.LogFactory;
     import org.springframework.web.bind.ServletRequestDataBinder;
    @@ -41,8 +45,21 @@ protected Object getHandlerInternal(HttpServletRequest request) throws Exception
                 HandlerExecutionChain handlerExecutionChain = (HandlerExecutionChain) object;
                 object = handlerExecutionChain.getHandler();
             }
    -
    +        
             if (object != null) {
    +        	// prevent CSRF attacks
    +        	if (object instanceof DestinationFacade) {
    +        		// check supported methods
    +        		if (!Arrays.asList(((DestinationFacade)object).getSupportedHttpMethods()).contains(request.getMethod())) {
    +        			throw new UnsupportedOperationException("Unsupported method " + request.getMethod() + " for path " + request.getRequestURI());
    +        		}
    +        		// check the 'secret'
    +        		if (!request.getSession().getAttribute("secret").equals(request.getParameter("secret"))) {
    +        			throw new UnsupportedOperationException("Possible CSRF attack");
    +        		}
    +        	}
    +        	
    +        	
                 ServletRequestDataBinder binder = new ServletRequestDataBinder(object, "request");
                 try {
                     binder.bind(request);
    @@ -56,6 +73,7 @@ protected Object getHandlerInternal(HttpServletRequest request) throws Exception
                     throw e;
                 }
             }
    +        
             return object;
         }
     }
    
  • activemq-web-console/src/main/webapp/browse.jsp+3 3 modified
    @@ -39,7 +39,7 @@
     <tbody>
     <jms:forEachMessage queueBrowser="${requestContext.queueBrowser.browser}" var="row">
     <tr>
    -<td><a href="message.jsp?id=${row.JMSMessageID}&JMSDestination=${requestContext.queueBrowser.JMSDestination}" 
    +<td><a href="message.jsp?id=${row.JMSMessageID}&JMSDestination=<c:out value="${requestContext.queueBrowser.JMSDestination}" />" 
         title="${row.properties}">${row.JMSMessageID}</a></td>
     <td>${row.JMSCorrelationID}</td>
     <td><jms:persistent message="${row}"/></td>
    @@ -49,15 +49,15 @@
     <td><jms:formatTimestamp timestamp="${row.JMSTimestamp}"/></td>
     <td>${row.JMSType}</td>
     <td>
    -    <a href="deleteMessage.action?JMSDestination=${row.JMSDestination}&messageId=${row.JMSMessageID}">Delete</a>
    +    <a href="deleteMessage.action?JMSDestination=<c:out value="${row.JMSDestination}"/>&messageId=${row.JMSMessageID}&secret=<c:out value='${sessionScope["secret"]}'/>">Delete</a>
     </td>
     </tr>
     </jms:forEachMessage>
     </tbody>
     </table>
     
     <div>
    -<a href="queueConsumers.jsp?JMSDestination=${requestContext.queueBrowser.JMSDestination}">View Consumers</a>
    +<a href="queueConsumers.jsp?JMSDestination=<c:out value="${requestContext.queueBrowser.JMSDestination}"/>">View Consumers</a>
     </div>
     </body>
     </html>
    
  • activemq-web-console/src/main/webapp/graph.jsp+1 1 modified
    @@ -51,7 +51,7 @@
     <td>${row.JMSTimestamp}</td>
     <td>${row.JMSType}</td>
     <td>
    -    <a href="deleteDestination.action?destination=${row.JMSMessageID}">Delete</a>
    +    <a href="deleteDestination.action?destination=${row.JMSMessageID}&secret=<c:out value='${sessionScope["secret"]}'/>">Delete</a>
     </td>
     </tr>
     </jms:forEachMessage>
    
  • activemq-web-console/src/main/webapp/message.jsp+4 4 modified
    @@ -130,24 +130,24 @@ No message could be found for ID ${requestContext.messageQuery.id}
                     </thead>
                     <tbody>
                         <tr>
    -                        <td colspan="2"><a href="deleteMessage.action?JMSDestination=${row.JMSDestination}&messageId=${row.JMSMessageID}">Delete</a></td>
    +                        <td colspan="2"><a href="deleteMessage.action?JMSDestination=<c:out value="${row.JMSDestination}" />&messageId=${row.JMSMessageID}&secret=<c:out value='${sessionScope["secret"]}'/>">Delete</a></td>
                         </tr>
                         <tr class="odd">
    -                    <td><a href="javascript:confirmAction('queue', 'copyMessage.action?destination=%target%&JMSDestination=${row.JMSDestination}&messageId=${row.JMSMessageID}&JMSDestinationType=queue')">Copy</a></td>
    +                    <td><a href="javascript:confirmAction('queue', 'copyMessage.action?destination=%target%&JMSDestination=<c:out value="${row.JMSDestination}" />&messageId=${row.JMSMessageID}&JMSDestinationType=queue&secret=<c:out value='${sessionScope["secret"]}'/>')">Copy</a></td>
                             <td rowspan="2">
                                 <select id="queue">
                                     <option value=""> -- Please select --</option>
                                     <c:forEach items="${requestContext.brokerQuery.queues}" var="queues">
                                         <c:if test="${queues.name != requestContext.messageQuery.JMSDestination}">
    -                                    <option value="${queues.name}"><form:short text="${queues.name}"/></option>
    +                                    <option value="<c:out value="${queues.name}" />"><form:short text="${queues.name}"/></option>
                                         </c:if>
                                     </c:forEach>
                                 </select>
                             </td>
                             
                         </tr>
                         <tr class="odd">
    -                        <td><a href="javascript:confirmAction('queue', 'moveMessage.action?destination=%target%&JMSDestination=${row.JMSDestination}&messageId=${row.JMSMessageID}&JMSDestinationType=queue')">Move</a></td>
    +                        <td><a href="javascript:confirmAction('queue', 'moveMessage.action?destination=%target%&JMSDestination=<c:out value="${row.JMSDestination}" />&messageId=${row.JMSMessageID}&JMSDestinationType=queue&secret=<c:out value='${sessionScope["secret"]}'/>')">Move</a></td>
                         </tr>
                     </tbody>
                 </table>
    
  • activemq-web-console/src/main/webapp/queueConsumers.jsp+2 2 modified
    @@ -16,11 +16,11 @@
     --%>
     <html>
     <head>
    -<title>Consumers for ${requestContext.queueConsumerQuery.JMSDestination}</title>
    +<title>Consumers for <c:out value="${requestContext.queueConsumerQuery.JMSDestination}" /></title>
     </head>
     <body>
     
    -<h2>Active Consumers for ${requestContext.queueConsumerQuery.JMSDestination}</h2>
    +<h2>Active Consumers for <c:out value="${requestContext.queueConsumerQuery.JMSDestination}" /></h2>
     
     <table id="messages" class="sortable autostripe">
     <thead>
    
  • activemq-web-console/src/main/webapp/queues.jsp+11 9 modified
    @@ -21,8 +21,9 @@
     <body>
     
     <div>
    -<form action="createDestination.action" method="get">
    +<form action="createDestination.action" method="post">
         <input type="hidden" name="JMSDestinationType" value="queue"/>
    +    <input type="hidden" name="secret" value="<c:out value='${sessionScope["secret"]}'/>"/>
     
         <label name="destination">Queue Name</label>
         <input type="text" name="JMSDestination" value=""/>
    @@ -48,22 +49,23 @@
     </thead>
     <tbody>
     <c:forEach items="${requestContext.brokerQuery.queues}" var="row">
    +
     <tr>
    -<td><a href="browse.jsp?JMSDestination=${row.name}"><form:tooltip text="${row.name}" length="50"/></a></td>
    +<td><a href="browse.jsp?JMSDestination=<c:out value="${row.name}" />"><form:tooltip text="${row.name}" length="50"/></a></td>
     <td>${row.queueSize}</td>
     <td>${row.consumerCount}</td>
     <td>${row.enqueueCount}</td>
     <td>${row.dequeueCount}</td>
     <td>
    -    <a href="browse.jsp?JMSDestination=${row.name}">Browse</a>
    -	<a href="queueConsumers.jsp?JMSDestination=${row.name}">Active Consumers</a><br/>
    -    <a href="queueBrowse/${row.name}?view=rss&feedType=atom_1.0" title="Atom 1.0"><img src="images/feed_atom.png"/></a>
    -    <a href="queueBrowse/${row.name}?view=rss&feedType=rss_2.0" title="RSS 2.0"><img src="images/feed_rss.png"/></a>
    +    <a href="browse.jsp?JMSDestination=<c:out value="${row.name}" />">Browse</a>
    +	<a href="queueConsumers.jsp?JMSDestination=<c:out value="${row.name}" />">Active Consumers</a><br/>
    +    <a href="queueBrowse/<c:out value="${row.name}" />?view=rss&feedType=atom_1.0" title="Atom 1.0"><img src="images/feed_atom.png"/></a>
    +    <a href="queueBrowse/<c:out value="${row.name}" />?view=rss&feedType=rss_2.0" title="RSS 2.0"><img src="images/feed_rss.png"/></a>
     </td>
     <td>
    -    <a href="send.jsp?JMSDestination=${row.name}&JMSDestinationType=queue">Send To</a>
    -    <a href="purgeDestination.action?JMSDestination=${row.name}&JMSDestinationType=queue">Purge</a>
    -    <a href="deleteDestination.action?JMSDestination=${row.name}&JMSDestinationType=queue">Delete</a>
    +    <a href="send.jsp?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=queue">Send To</a>
    +    <a href="purgeDestination.action?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=queue&secret=<c:out value='${sessionScope["secret"]}'/>">Purge</a>
    +    <a href="deleteDestination.action?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=queue&secret=<c:out value='${sessionScope["secret"]}'/>">Delete</a>
     </td>
     </tr>
     </c:forEach>
    
  • activemq-web-console/src/main/webapp/send.jsp+2 1 modified
    @@ -23,6 +23,7 @@
     <h2>Send a JMS Message</h2>
     
     <form action="sendMessage.action" method="post">
    +<input type="hidden" name="secret" value="<c:out value='${sessionScope["secret"]}'/>"/>
     
     <table id="headers" class="autostripe">
     <thead>
    @@ -37,7 +38,7 @@
     	    <label for="JMSDestination">Destination</label>
     	</td>
     	<td>
    -	    <form:text name="JMSDestination"/>
    +	    <form:text name="JMSDestination" defaultValue="foo.bar" />
     	</td>
     	<td class="label">
     	    <label for="queue">Queue or Topic</label>
    
  • activemq-web-console/src/main/webapp/subscribers.jsp+3 2 modified
    @@ -20,8 +20,9 @@
     </head>
     <body>
     
    -<form action="createSubscriber.action" method="get">
    +<form action="createSubscriber.action" method="post">
         <input type="hidden" name="JMSDestinationType" value="topic"/>
    +    <input type="hidden" name="secret" value="<c:out value='${sessionScope["secret"]}'/>"/>
     
     <table id="createSubscribers" class="sortable autostripe">
     <thead>
    @@ -102,7 +103,7 @@
     <td>${row.enqueueCounter}</td>
     <td>${row.dequeueCounter}</td>
     <td>
    -    <a href="deleteSubscriber.action?clientId=${row.clientId}&subscriberName=${row.subscriptionName}">Delete</a>
    +    <a href="deleteSubscriber.action?clientId=${row.clientId}&subscriberName=${row.subscriptionName}&secret=<c:out value='${sessionScope["secret"]}'/>">Delete</a>
     </td>
     </tr>
     </c:forEach>
    
  • activemq-web-console/src/main/webapp/topics.jsp+4 3 modified
    @@ -23,6 +23,7 @@
     <div>
     <form action="createDestination.action" method="get">
         <input type="hidden" name="JMSDestinationType" value="topic"/>
    +    <input type="hidden" name="secret" value="<c:out value='${sessionScope["secret"]}'/>"/>
     
         <label name="destination">Topic Name</label>
         <input type="text" name="JMSDestination" value=""/>
    @@ -46,13 +47,13 @@
     <tbody>
     <c:forEach items="${requestContext.brokerQuery.topics}" var="row">
     <tr>
    -<td><a href="send.jsp?JMSDestination=${row.name}&JMSDestinationType=topic"><form:tooltip text="${row.name}" length="50"/></a></td>
    +<td><a href="send.jsp?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=topic"><form:tooltip text="${row.name}" length="50"/></a></td>
     <td>${row.consumerCount}</td>
     <td>${row.enqueueCount}</td>
     <td>${row.dequeueCount}</td>
     <td>
    -    <a href="send.jsp?JMSDestination=${row.name}&JMSDestinationType=topic">Send To</a>
    -    <a href="deleteDestination.action?JMSDestination=${row.name}&JMSDestinationType=topic">Delete</a>
    +    <a href="send.jsp?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=topic">Send To</a>
    +    <a href="deleteDestination.action?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=topic&secret=<c:out value='${sessionScope["secret"]}'/>">Delete</a>
     </td>
     </tr>
     </c:forEach>
    
  • activemq-web-console/src/main/webapp/WEB-INF/tags/form/short.tag+2 0 modified
    @@ -17,6 +17,8 @@
     <%@ attribute name="text" type="java.lang.String" required="true"  %>
     <%@ attribute name="length" type="java.lang.Integer" required="false" %>
     <%
    + text = org.apache.commons.lang.StringEscapeUtils.escapeHtml(text);
    + text = org.apache.commons.lang.StringEscapeUtils.escapeJavaScript(text);
      if (length == null)
         length = 20;
      if (text.length() <= 20) {
    
  • activemq-web-console/src/main/webapp/WEB-INF/tags/form/text.tag+7 5 modified
    @@ -19,10 +19,12 @@
     <%
         String value = request.getParameter(name);
         if (value == null || value.trim().length() == 0) {
    -    		value = defaultValue;
    -		}
    -		if (value == null) {
    -			value = "";
    -		}
    +    	value = defaultValue;
    +	}
    +	if (value == null) {
    +		value = "";
    +	}
    +	value = org.apache.commons.lang.StringEscapeUtils.escapeHtml(value);
    +
     %>
     <input type="text" name="${name}" value="<%= value %>"/>
    
  • activemq-web-console/src/main/webapp/WEB-INF/web.xml+2 2 modified
    @@ -50,7 +50,7 @@
     
       <filter-mapping>
         <filter-name>spring</filter-name>
    -    <url-pattern>/*</url-pattern>
    +    <url-pattern>*.jsp</url-pattern>
       </filter-mapping>
     
       <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    @@ -101,7 +101,7 @@
     
       <filter-mapping>
         <filter-name>session</filter-name>
    -    <url-pattern>/*</url-pattern>
    +    <url-pattern>*.jsp</url-pattern>
       </filter-mapping>
       <filter-mapping>
         <filter-name>spring-rq</filter-name>
    
  • activemq-web/src/main/java/org/apache/activemq/web/BrokerFacadeSupport.java+1 0 modified
    @@ -172,6 +172,7 @@ public Collection<NetworkConnectorViewMBean> getNetworkConnectors() throws Excep
         @SuppressWarnings("unchecked")
         public Collection<SubscriptionViewMBean> getQueueConsumers(String queueName) throws Exception {
             String brokerName = getBrokerName();
    +        queueName = StringUtils.replace(queueName, "\"", "_");
             ObjectName query = new ObjectName("org.apache.activemq:BrokerName=" + brokerName
                     + ",Type=Subscription,destinationType=Queue,destinationName=" + queueName + ",*");
             Set<ObjectName> queryResult = getManagementContext().queryNames(query, null);
    
  • activemq-web/src/main/java/org/apache/activemq/web/DestinationFacade.java+4 0 modified
    @@ -128,4 +128,8 @@ protected ModelAndView redirectToBrowseView() {
         protected String getPhysicalDestinationName() {
             return createDestination().getPhysicalName();
         }
    +    
    +    public String[] getSupportedHttpMethods() {
    +    	return new String[]{"GET", "POST"};
    +    }
     }
    
  • activemq-web/src/main/java/org/apache/activemq/web/SessionFilter.java+3 1 modified
    @@ -18,6 +18,7 @@
     package org.apache.activemq.web;
     
     import java.io.IOException;
    +import java.util.UUID;
     
     import javax.servlet.Filter;
     import javax.servlet.FilterChain;
    @@ -39,7 +40,8 @@ public void init(FilterConfig filterConfig) throws ServletException {
         }
     
         public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    -        ((HttpServletRequest)request).getSession(true);
    +    	// set secret to prevent CSRF attacks
    +        ((HttpServletRequest)request).getSession(true).setAttribute("secret", UUID.randomUUID().toString());;
             chain.doFilter(request, response);
         }
     
    
fed39c361982

https://issues.apache.org/activemq/browse/AMQ-2613 - fix XSS security problem in web console

https://github.com/apache/activemqBosanac DejanFeb 23, 2010via ghsa
9 files changed · +32 26
  • activemq-web-console/src/main/webapp/browse.jsp+3 3 modified
    @@ -39,7 +39,7 @@
     <tbody>
     <jms:forEachMessage queueBrowser="${requestContext.queueBrowser.browser}" var="row">
     <tr>
    -<td><a href="message.jsp?id=${row.JMSMessageID}&JMSDestination=${requestContext.queueBrowser.JMSDestination}" 
    +<td><a href="message.jsp?id=${row.JMSMessageID}&JMSDestination=<c:out value="${requestContext.queueBrowser.JMSDestination}" />" 
         title="${row.properties}">${row.JMSMessageID}</a></td>
     <td>${row.JMSCorrelationID}</td>
     <td><jms:persistent message="${row}"/></td>
    @@ -49,15 +49,15 @@
     <td><jms:formatTimestamp timestamp="${row.JMSTimestamp}"/></td>
     <td>${row.JMSType}</td>
     <td>
    -    <a href="deleteMessage.action?JMSDestination=${row.JMSDestination}&messageId=${row.JMSMessageID}">Delete</a>
    +    <a href="deleteMessage.action?JMSDestination=<c:out value="${row.JMSDestination}"/>&messageId=${row.JMSMessageID}">Delete</a>
     </td>
     </tr>
     </jms:forEachMessage>
     </tbody>
     </table>
     
     <div>
    -<a href="queueConsumers.jsp?JMSDestination=${requestContext.queueBrowser.JMSDestination}">View Consumers</a>
    +<a href="queueConsumers.jsp?JMSDestination=<c:out value="${requestContext.queueBrowser.JMSDestination}"/>">View Consumers</a>
     </div>
     </body>
     </html>
    
  • activemq-web-console/src/main/webapp/message.jsp+4 4 modified
    @@ -130,24 +130,24 @@ No message could be found for ID ${requestContext.messageQuery.id}
                     </thead>
                     <tbody>
                         <tr>
    -                        <td colspan="2"><a href="deleteMessage.action?JMSDestination=${row.JMSDestination}&messageId=${row.JMSMessageID}">Delete</a></td>
    +                        <td colspan="2"><a href="deleteMessage.action?JMSDestination=<c:out value="${row.JMSDestination}" />&messageId=${row.JMSMessageID}">Delete</a></td>
                         </tr>
                         <tr class="odd">
    -                    <td><a href="javascript:confirmAction('queue', 'copyMessage.action?destination=%target%&JMSDestination=${row.JMSDestination}&messageId=${row.JMSMessageID}&JMSDestinationType=queue')">Copy</a></td>
    +                    <td><a href="javascript:confirmAction('queue', 'copyMessage.action?destination=%target%&JMSDestination=<c:out value="${row.JMSDestination}" />&messageId=${row.JMSMessageID}&JMSDestinationType=queue')">Copy</a></td>
                             <td rowspan="2">
                                 <select id="queue">
                                     <option value=""> -- Please select --</option>
                                     <c:forEach items="${requestContext.brokerQuery.queues}" var="queues">
                                         <c:if test="${queues.name != requestContext.messageQuery.JMSDestination}">
    -                                    <option value="${queues.name}"><form:short text="${queues.name}"/></option>
    +                                    <option value="<c:out value="${queues.name}" />"><form:short text="${queues.name}"/></option>
                                         </c:if>
                                     </c:forEach>
                                 </select>
                             </td>
                             
                         </tr>
                         <tr class="odd">
    -                        <td><a href="javascript:confirmAction('queue', 'moveMessage.action?destination=%target%&JMSDestination=${row.JMSDestination}&messageId=${row.JMSMessageID}&JMSDestinationType=queue')">Move</a></td>
    +                        <td><a href="javascript:confirmAction('queue', 'moveMessage.action?destination=%target%&JMSDestination=<c:out value="${row.JMSDestination}" />&messageId=${row.JMSMessageID}&JMSDestinationType=queue')">Move</a></td>
                         </tr>
                     </tbody>
                 </table>
    
  • activemq-web-console/src/main/webapp/queueConsumers.jsp+2 2 modified
    @@ -16,11 +16,11 @@
     --%>
     <html>
     <head>
    -<title>Consumers for ${requestContext.queueConsumerQuery.JMSDestination}</title>
    +<title>Consumers for <c:out value="${requestContext.queueConsumerQuery.JMSDestination}" /></title>
     </head>
     <body>
     
    -<h2>Active Consumers for ${requestContext.queueConsumerQuery.JMSDestination}</h2>
    +<h2>Active Consumers for <c:out value="${requestContext.queueConsumerQuery.JMSDestination}" /></h2>
     
     <table id="messages" class="sortable autostripe">
     <thead>
    
  • activemq-web-console/src/main/webapp/queues.jsp+9 8 modified
    @@ -48,22 +48,23 @@
     </thead>
     <tbody>
     <c:forEach items="${requestContext.brokerQuery.queues}" var="row">
    +
     <tr>
    -<td><a href="browse.jsp?JMSDestination=${row.name}"><form:tooltip text="${row.name}" length="50"/></a></td>
    +<td><a href="browse.jsp?JMSDestination=<c:out value="${row.name}" />"><form:tooltip text="${row.name}" length="50"/></a></td>
     <td>${row.queueSize}</td>
     <td>${row.consumerCount}</td>
     <td>${row.enqueueCount}</td>
     <td>${row.dequeueCount}</td>
     <td>
    -    <a href="browse.jsp?JMSDestination=${row.name}">Browse</a>
    -	<a href="queueConsumers.jsp?JMSDestination=${row.name}">Active Consumers</a><br/>
    -    <a href="queueBrowse/${row.name}?view=rss&feedType=atom_1.0" title="Atom 1.0"><img src="images/feed_atom.png"/></a>
    -    <a href="queueBrowse/${row.name}?view=rss&feedType=rss_2.0" title="RSS 2.0"><img src="images/feed_rss.png"/></a>
    +    <a href="browse.jsp?JMSDestination=<c:out value="${row.name}" />">Browse</a>
    +	<a href="queueConsumers.jsp?JMSDestination=<c:out value="${row.name}" />">Active Consumers</a><br/>
    +    <a href="queueBrowse/<c:out value="${row.name}" />?view=rss&feedType=atom_1.0" title="Atom 1.0"><img src="images/feed_atom.png"/></a>
    +    <a href="queueBrowse/<c:out value="${row.name}" />?view=rss&feedType=rss_2.0" title="RSS 2.0"><img src="images/feed_rss.png"/></a>
     </td>
     <td>
    -    <a href="send.jsp?JMSDestination=${row.name}&JMSDestinationType=queue">Send To</a>
    -    <a href="purgeDestination.action?JMSDestination=${row.name}&JMSDestinationType=queue">Purge</a>
    -    <a href="deleteDestination.action?JMSDestination=${row.name}&JMSDestinationType=queue">Delete</a>
    +    <a href="send.jsp?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=queue">Send To</a>
    +    <a href="purgeDestination.action?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=queue">Purge</a>
    +    <a href="deleteDestination.action?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=queue">Delete</a>
     </td>
     </tr>
     </c:forEach>
    
  • activemq-web-console/src/main/webapp/send.jsp+1 1 modified
    @@ -37,7 +37,7 @@
     	    <label for="JMSDestination">Destination</label>
     	</td>
     	<td>
    -	    <form:text name="JMSDestination" defaultValue="foo.bar"/>
    +	    <form:text name="JMSDestination" defaultValue="foo.bar" />
     	</td>
     	<td class="label">
     	    <label for="queue">Queue or Topic</label>
    
  • activemq-web-console/src/main/webapp/topics.jsp+3 3 modified
    @@ -46,13 +46,13 @@
     <tbody>
     <c:forEach items="${requestContext.brokerQuery.topics}" var="row">
     <tr>
    -<td><a href="send.jsp?JMSDestination=${row.name}&JMSDestinationType=topic"><form:tooltip text="${row.name}" length="50"/></a></td>
    +<td><a href="send.jsp?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=topic"><form:tooltip text="${row.name}" length="50"/></a></td>
     <td>${row.consumerCount}</td>
     <td>${row.enqueueCount}</td>
     <td>${row.dequeueCount}</td>
     <td>
    -    <a href="send.jsp?JMSDestination=${row.name}&JMSDestinationType=topic">Send To</a>
    -    <a href="deleteDestination.action?JMSDestination=${row.name}&JMSDestinationType=topic">Delete</a>
    +    <a href="send.jsp?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=topic">Send To</a>
    +    <a href="deleteDestination.action?JMSDestination=<c:out value="${row.name}" />&JMSDestinationType=topic">Delete</a>
     </td>
     </tr>
     </c:forEach>
    
  • activemq-web-console/src/main/webapp/WEB-INF/tags/form/short.tag+2 0 modified
    @@ -17,6 +17,8 @@
     <%@ attribute name="text" type="java.lang.String" required="true"  %>
     <%@ attribute name="length" type="java.lang.Integer" required="false" %>
     <%
    + text = org.apache.commons.lang.StringEscapeUtils.escapeHtml(text);
    + text = org.apache.commons.lang.StringEscapeUtils.escapeJavaScript(text);
      if (length == null)
         length = 20;
      if (text.length() <= 20) {
    
  • activemq-web-console/src/main/webapp/WEB-INF/tags/form/text.tag+7 5 modified
    @@ -19,10 +19,12 @@
     <%
         String value = request.getParameter(name);
         if (value == null || value.trim().length() == 0) {
    -    		value = defaultValue;
    -		}
    -		if (value == null) {
    -			value = "";
    -		}
    +    	value = defaultValue;
    +	}
    +	if (value == null) {
    +		value = "";
    +	}
    +	value = org.apache.commons.lang.StringEscapeUtils.escapeHtml(value);
    +
     %>
     <input type="text" name="${name}" value="<%= value %>"/>
    
  • activemq-web/src/main/java/org/apache/activemq/web/BrokerFacadeSupport.java+1 0 modified
    @@ -172,6 +172,7 @@ public Collection<NetworkConnectorViewMBean> getNetworkConnectors() throws Excep
         @SuppressWarnings("unchecked")
         public Collection<SubscriptionViewMBean> getQueueConsumers(String queueName) throws Exception {
             String brokerName = getBrokerName();
    +        queueName = StringUtils.replace(queueName, "\"", "_");
             ObjectName query = new ObjectName("org.apache.activemq:BrokerName=" + brokerName
                     + ",Type=Subscription,destinationType=Queue,destinationName=" + queueName + ",*");
             Set<ObjectName> queryResult = getManagementContext().queryNames(query, null);
    

Vulnerability mechanics

Root cause

"The web console does not sanitize user-controlled input (e.g., JMSDestination parameter) before rendering it in HTML output, enabling stored/reflected cross-site scripting."

Attack vector

An attacker who is an authenticated user of the ActiveMQ web console can inject arbitrary HTML or JavaScript via the JMSDestination parameter when creating or interacting with a queue or topic. The injected payload is echoed back without sanitization in multiple JSP pages such as browse.jsp, queues.jsp, and connection.jsp [CWE-79]. The attack is triggered when a victim (including other authenticated users) views the affected page. The advisory and patches confirm that the input is not neutralized before being placed in HTML output [patch_id=20912, patch_id=20913].

Affected code

Multiple JSP files in the activemq-web-console module are affected, including connection.jsp, message.jsp, browse.jsp, queues.jsp, topics.jsp, queueConsumers.jsp, and subscribers.jsp. The custom tag files WEB-INF/tags/form/text.tag and WEB-INF/tags/form/short.tag also lacked output escaping. The Java controller SendMessage.java and CreateDestination.java are modified to restrict HTTP methods and add CSRF protections, but the XSS root cause is the missing HTML escaping in the JSP views [patch_id=20912, patch_id=20913, patch_id=20911].

What the fix does

The patches apply HTML entity escaping using JSTL's &lt;c:out&gt; tags and Apache Commons Lang StringEscapeUtils.escapeHtml() on all user-controlled values rendered in JSP pages [patch_id=20912, patch_id=20913]. For example, in connection.jsp and message.jsp, raw EL expressions like ${row.remoteAddress} are wrapped with &lt;c:out value="..."/&gt; to neutralize any embedded script tags. Additionally, the custom form:text and form:short tag files now call escapeHtml() on the output value [patch_id=20911]. These changes ensure that any attacker-supplied input is treated as plain text rather than executable HTML or JavaScript.

Preconditions

  • authAttacker must be an authenticated user of the ActiveMQ web console.
  • networkAttacker must be able to send HTTP requests to the web console (typically on port 8161).
  • inputAttacker supplies a crafted JMSDestination parameter containing HTML/JavaScript payload.

Reproduction

The bundle includes public PoC references (e.g., http://www.rajatswarup.com/CVE-2010-0684.txt). To reproduce: log into the ActiveMQ web console (pre-5.3.1), navigate to the Queues page, and create a queue with a name containing a JavaScript payload such as `&lt;script&gt;alert(1)&lt;/script&gt;`. When the queues list is rendered, the payload executes in the browser of any user viewing the page.

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

References

18

News mentions

0

No linked articles in our index yet.