CVE-2018-25084 (Other, published 2023-04-10T18:15Z)
Description: value: A vulnerability, which was classified as problematic, has been found in Ping Identity Self-Service Account Manager 1.1.2. Affected by this issue is some unknown functionality of the file src/main/java/com/unboundid/webapp/ssam/SSAMController.java. The manipulation leads to cross site scripting. The attack may be launched remotely. Upgrading to version 1.1.3 is able to address this issue. The patch is identified as f64b10d63bb19ca2228b0c2d561a1a6e5a3bf251. It is recommended to upgrade the affected component. VDB-225362 is the identifier assigned to this vulnerability.
Severity: nan (CVSS v3 base score: 6.1)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Repository: https://github.com/pingidentity/ssam
Files changed:
src/main/java/com/unboundid/webapp/ssam/HTTPHeaderFilter.java
src/main/java/com/unboundid/webapp/ssam/HTTPRequestParameterFilter.java
src/main/java/com/unboundid/webapp/ssam/SSAMController.java
src/main/resources/static/css/ssam.css
src/main/resources/static/js/ssam-security-patch.js
src/main/resources/templates/deletion-success.vm
src/main/resources/templates/error.vm
src/main/resources/templates/login.vm
src/main/resources/templates/recover-password-success.vm
src/main/resources/templates/recover-password-verify.vm
src/main/resources/templates/recover-password.vm
src/main/resources/templates/register.vm
src/main/resources/templates/registration-success.vm
src/main/resources/templates/registration-verify.vm
src/main/resources/templates/user.vm
Commit message: Added html escaping to help with XSS. Added frame busting to help with XFS. Added a method override filter so that only GETs and POSTs are accepted. Disabled autocomplete for password fields. Added ability for customer to set their HPKP headers.


Vulnerable code:
      model.addAttribute(attribute.getName(), attribute.getValue());
          model.addAttribute(name, value);
    
        <input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" required>
    
    
    
                  <input id="currentPassword" type="password" class="form-control" placeholder="Enter Current Password">
                  <input id="password" type="password" class="form-control" placeholder="Enter New Password">
                  <input id="confirmPassword" type="password" class="form-control" placeholder="Re-Enter New Password">
          userForm.append('<input type="hidden" name="cn" value="' + cn + '">');
          userForm.append('<input type="hidden" name="postalAddress" value="' + address + '">');

Fixed code:
/*
 * Copyright 2014-2017 Ping Identity Corporation
 * All Rights Reserved.
 */

package com.unboundid.webapp.ssam;

import org.springframework.stereotype.Component;
import javax.servlet.FilterConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletResponse;

@Component
public class HTTPHeaderFilter implements javax.servlet.Filter {
    public FilterConfig filterConfig;

    public void doFilter(final ServletRequest request,
                         final ServletResponse response, FilterChain chain)
            throws java.io.IOException, javax.servlet.ServletException {

        HttpServletResponse res = (HttpServletResponse) response;

        // Set this variable to the sha256 pin of your public key
        // This value can be generated using the "openssl" command line tool
        // https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning
        String pinSha256 = "";

        if(pinSha256.length() > 0)
        {
            res.setHeader("Public-Key-Pins", "max-age=518400; " +
                    "pin-sha256=\"" + pinSha256 + "\"; " +
                    "includeSubDomains");
        }

        chain.doFilter(request, response);
    }

    public void init(final FilterConfig filterConfig) { this.filterConfig = filterConfig; }

    public void destroy() {}

}
/*
 * Copyright 2014-2017 Ping Identity Corporation
 * All Rights Reserved.
 */

package com.unboundid.webapp.ssam;

import org.springframework.stereotype.Component;
import javax.servlet.FilterConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;

@Component
public class HTTPRequestParameterFilter implements javax.servlet.Filter {
  public FilterConfig filterConfig;

  public void doFilter(final ServletRequest request,
    final ServletResponse response, FilterChain chain)
    throws java.io.IOException, javax.servlet.ServletException {

    String curMethod = ((HttpServletRequest) request).getMethod();
    //only allow for GET and POST requests.
    if (curMethod.equalsIgnoreCase("get") || curMethod.equalsIgnoreCase("post"))
    {
      chain.doFilter(request, response);
    }
  }

  public void init(final FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
    }
  public void destroy() {}
}
import org.springframework.web.util.HtmlUtils;
      model.addAttribute(attribute.getName(), HtmlUtils.htmlEscape(attribute.getValue()));
          model.addAttribute(name, HtmlUtils.htmlEscape(value));
/*
 * None style added to help with Frame Busting
 * intended for older browsers without 'X-Frame-Options' header support.
 * This method comes from an OWASP write up by Gustav Rydstedt.
 */
html {
  display: none;
}

// frame busting
function buster(document_in, top_in) {
 if (self === top_in) {
   document_in.documentElement.style.display = "block";
 } else {
   top_in.location = self.location;
 }
}

// html escaping for potentially unsafe jQuery methods such as ".append()"
var entityMap = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#x27;',
    '/': '&#x2F;',
    '`': '&#x60;',
    '=': '&#x3D;'
};

function escapeHtml (string) {
    return String(string).replace(/[&<>"'`=\/]/g, function (s) {
      return entityMap[s];
    });
}

    <script src="js/ssam-security-patch.js"></script>
    <script type="text/javascript">
      buster(document, top);
    </script>
    <script src="js/ssam-security-patch.js"></script>
    <script type="text/javascript">
      buster(document, top);
    </script>
        <input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" autocomplete="off" required>
    <script src="js/ssam-security-patch.js"></script>
    <script type="text/javascript">
      buster(document, top);
    </script>

    <script src="js/ssam-security-patch.js"></script>
    <script type="text/javascript">
      buster(document, top);
    </script>
    <script src="js/ssam-security-patch.js"></script>
    <script type="text/javascript">
      buster(document, top);
    </script>
    <script src="js/ssam-security-patch.js"></script>
    <script type="text/javascript">
      buster(document, top);
    </script>
    <script src="js/ssam-security-patch.js"></script>
    <script type="text/javascript">
      buster(document, top);
    </script>

    <script src="js/ssam-security-patch.js"></script>
    <script type="text/javascript">
      buster(document, top);
    </script>

    <script src="js/ssam-security-patch.js"></script>
    <script type="text/javascript">
      buster(document, top);
    </script>
                  <input id="currentPassword" type="password" class="form-control" placeholder="Enter Current Password" autocomplete="off">
                  <input id="password" type="password" class="form-control" placeholder="Enter New Password" autocomplete="off">
                  <input id="confirmPassword" type="password" class="form-control" placeholder="Re-Enter New Password" autocomplete="off">
    <script src="js/ssam-security-patch.js"></script>
   	<script type="text/javascript">
   	  buster(document, top);
   	</script>
          userForm.append('<input type="hidden" name="cn" value="' + escapeHtml(cn) + '">');
          userForm.append('<input type="hidden" name="postalAddress" value="' + escapeHtml(address) + '">');