CVE-2013-7250: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site scripting (XSS) vulnerability in the JsonBuilder implementation in ProjectForge before 5.3 allows remote authenticated users to inject arbitrary web script or HTML via an autocompletion string, related to web/core/JsonBuilder.java and web/wicket/autocompletion/PFAutoCompleteBehavior.java.
CWE description: 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.
Published: 2014-01-02T14:59Z
Repository: https://github.com/micromata/projectforge-webapp
Language: Java
Files changed: src/main/java/org/projectforge/web/core/JsonBuilder.java, src/main/java/org/projectforge/web/wicket/autocompletion/PFAutoCompleteBehavior.java
Commit date: 2013-12-06 00:39:09 +0100
Commit message: Escapes now HTML (JsonBuilder).

Diff: diff --git a/src/main/java/org/projectforge/web/core/JsonBuilder.java b/src/main/java/org/projectforge/web/core/JsonBuilder.java
index dc6e8c1f9..519fc4868 100644
--- a/src/main/java/org/projectforge/web/core/JsonBuilder.java
+++ b/src/main/java/org/projectforge/web/core/JsonBuilder.java
@@ -29,10 +29,12 @@ import org.apache.commons.lang.ObjectUtils;
 
 public class JsonBuilder
 {
   final private StringBuilder sb = new StringBuilder();
 
+  private boolean escapeHtml;
+
   /**
    * Creates Json result string from the given list.<br/>
    * [["Horst"], ["Klaus"], ...]] // For single property<br/>
    * [["Klein", "Horst"],["Schmidt", "Klaus"], ...] // For two Properties (e. g. name, first name) [["id:37", "Klein", "Horst"],["id:42",
    * "Schmidt", "Klaus"], ...] // For two Properties (e. g. name, first name) with id. <br/>
@@ -47,10 +49,20 @@ public class JsonBuilder
     }
     final JsonBuilder builder = new JsonBuilder();
     return builder.append(col).getAsString();
   }
 
+  /**
+   * @param escapeHtml the escapeHtml to set (default is false).
+   * @return this for chaining.
+   */
+  public JsonBuilder setEscapeHtml(final boolean escapeHtml)
+  {
+    this.escapeHtml = escapeHtml;
+    return this;
+  }
+
   public String getAsString()
   {
     return sb.toString();
   }
 
@@ -115,11 +127,36 @@ public class JsonBuilder
         default:
           if (c < ' ') {
             t = "000" + Integer.toHexString(c);
             sb.append("\\u" + t.substring(t.length() - 4));
           } else {
-            sb.append(c);
+            if (escapeHtml == true) {
+              switch (c) {
+                case '<':
+                  sb.append("&lt;");
+                  break;
+                case '>':
+                  sb.append("&gt;");
+                  break;
+                case '&':
+                  sb.append("&amp;");
+                  break;
+                case '"':
+                  sb.append("&quot;");
+                  break;
+                case '\'':
+                  sb.append("&#x27;");
+                  break;
+                case '/':
+                  sb.append("&#x2F;");
+                  break;
+                default:
+                  sb.append(c);
+              }
+            } else {
+              sb.append(c);
+            }
           }
       }
     }
     sb.append('"');
     return sb.toString();
diff --git a/src/main/java/org/projectforge/web/wicket/autocompletion/PFAutoCompleteBehavior.java b/src/main/java/org/projectforge/web/wicket/autocompletion/PFAutoCompleteBehavior.java
index 3ba0493b1..3cd3118b7 100644
--- a/src/main/java/org/projectforge/web/wicket/autocompletion/PFAutoCompleteBehavior.java
+++ b/src/main/java/org/projectforge/web/wicket/autocompletion/PFAutoCompleteBehavior.java
@@ -243,10 +243,15 @@ public abstract class PFAutoCompleteBehavior<T> extends AbstractDefaultAjaxBehav
     return null;
   }
 
   private class MyJsonBuilder extends JsonBuilder
   {
+    private MyJsonBuilder()
+    {
+      setEscapeHtml(true);
+    }
+
     @SuppressWarnings("unchecked")
     @Override
     protected String formatValue(final Object obj)
     {
       if (obj instanceof String) {

Vulnerable code:             sb.append(c);
Fixed code:   private boolean escapeHtml;

  /**
   * @param escapeHtml the escapeHtml to set (default is false).
   * @return this for chaining.
   */
  public JsonBuilder setEscapeHtml(final boolean escapeHtml)
  {
    this.escapeHtml = escapeHtml;
    return this;
  }

            if (escapeHtml == true) {
              switch (c) {
                case '<':
                  sb.append("&lt;");
                  break;
                case '>':
                  sb.append("&gt;");
                  break;
                case '&':
                  sb.append("&amp;");
                  break;
                case '"':
                  sb.append("&quot;");
                  break;
                case '\'':
                  sb.append("&#x27;");
                  break;
                case '/':
                  sb.append("&#x2F;");
                  break;
                default:
                  sb.append(c);
              }
            } else {
              sb.append(c);
            }
    private MyJsonBuilder()
    {
      setEscapeHtml(true);
    }