diff --git a/CHANGELOG.md b/CHANGELOG.md
index 389ec917bb2460c29e0b4fb7e54eac4d8aac63fd..824c9fcc4bd80477389ab28811c1405f06e663cc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,29 @@
 # Changelog
 
+## 2.2.2
+This release fixes a security vulnerability caused by the CORS implementation.
+Origins allowed for CORS can now be set in the configuration via
+`security.cors.origins`. (Reported by Rainer Rillke at Wikimedia)
+
+Additional changes:
+* Libraries have been upgraded to fix potential bugs
+
+## 2.1.2
+This release fixes a security vulnerability caused by the CORS implementation.
+Support for cross-origin requests has been removed. Use ARSnova version 2.2 or
+newer for proper CORS. (Reported by Rainer Rillke at Wikimedia)
+
+Additional changes:
+* Libraries have been upgraded to fix potential bugs
+
+## 2.0.4
+This release fixes a security vulnerability caused by the CORS implementation.
+Support for cross-origin requests has been removed. Use ARSnova version 2.2 or
+newer for proper CORS. (Reported by Rainer Rillke at Wikimedia)
+
+Additional changes:
+* Libraries have been upgraded to fix potential bugs
+
 ## 2.3.2
 This release fixes a security vulnerability in the account management API. It is
 highly recommended to upgrade if you are using database authentication.
diff --git a/pom.xml b/pom.xml
index 84579700e6317a3ccd1e39dac9ce383f3c511701..32a53802d2b0660dfb2aae5f3b39d6e5bcb60deb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -325,7 +325,7 @@
 			<plugin>
 				<groupId>org.eclipse.jetty</groupId>
 				<artifactId>jetty-maven-plugin</artifactId>
-				<version>9.2.16.v20160414</version>
+				<version>9.2.17.v20160517</version>
 				<configuration>
 					<scanIntervalSeconds>1</scanIntervalSeconds>
 					<webApp>
diff --git a/src/main/java/de/thm/arsnova/config/ExtraConfig.java b/src/main/java/de/thm/arsnova/config/ExtraConfig.java
index 36b3e2a0fc192610f91d4034c96ea447c6f5307b..e7f71f36818076b1139db5f00c382e964e956366 100644
--- a/src/main/java/de/thm/arsnova/config/ExtraConfig.java
+++ b/src/main/java/de/thm/arsnova/config/ExtraConfig.java
@@ -18,6 +18,7 @@
 package de.thm.arsnova.config;
 
 import de.thm.arsnova.ImageUtils;
+import de.thm.arsnova.web.CorsFilter;
 import de.thm.arsnova.connector.client.ConnectorClient;
 import de.thm.arsnova.connector.client.ConnectorClientImpl;
 import de.thm.arsnova.socket.ARSnovaSocket;
@@ -40,6 +41,9 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 
 
+import java.util.Arrays;
+import java.util.Collections;
+
 /**
  * Loads property file and configures non-security related beans and components.
  */
@@ -61,6 +65,7 @@ public class ExtraConfig extends WebMvcConfigurerAdapter {
 	@Value(value = "${security.ssl}") private boolean socketUseSll;
 	@Value(value = "${security.keystore}") private String socketKeystore;
 	@Value(value = "${security.storepass}") private String socketStorepass;
+	@Value(value = "${security.cors.origins:}") private String[] corsOrigins;
 
 	@Bean
 	public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
@@ -82,6 +87,11 @@ public class ExtraConfig extends WebMvcConfigurerAdapter {
 		return propertiesFactoryBean;
 	}
 
+	@Bean
+	public CorsFilter corsFilter() {
+		return new CorsFilter(Arrays.asList(corsOrigins));
+	}
+
 	@Bean(name = "connectorClient")
 	public ConnectorClient connectorClient() {
 		if (!connectorEnable) {
diff --git a/src/main/java/de/thm/arsnova/web/CorsFilter.java b/src/main/java/de/thm/arsnova/web/CorsFilter.java
index f4c434e02cc65f0a89da48cdb9acda407780cdd1..acd2f7dc1541bbee46c504e0a90d2a5d9065e3de 100644
--- a/src/main/java/de/thm/arsnova/web/CorsFilter.java
+++ b/src/main/java/de/thm/arsnova/web/CorsFilter.java
@@ -17,36 +17,52 @@
  */
 package de.thm.arsnova.web;
 
-import org.springframework.stereotype.Component;
-import org.springframework.web.filter.OncePerRequestFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
 
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
+import java.util.List;
 
-/**
- * Sets response headers to allow CORS requests.
- */
-@Component
-public class CorsFilter extends OncePerRequestFilter {
+public class CorsFilter extends org.springframework.web.filter.CorsFilter {
+	protected final Logger logger = LoggerFactory.getLogger(CorsFilter.class);
+
+	public CorsFilter(List<String> origins) {
+		super(configurationSource(origins));
+		logger.info("CorsFilter initialized. Allowed origins: {}", origins);
+	}
 
-	@Override
-	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
-			throws ServletException, IOException {
-		response.addHeader("Access-Control-Allow-Credentials", "true");
-		response.addHeader("Access-Control-Allow-Methods", "GET");
-		response.addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
+	private static UrlBasedCorsConfigurationSource configurationSource(List<String> origins) {
+		CorsConfiguration config;
+		UrlBasedCorsConfigurationSource source;
 
-		if (request.getHeader("origin") != null) {
-			response.addHeader("Access-Control-Allow-Origin", sanitizeOriginUrl(request.getHeader("origin")));
-		}
+		/* Grant full access from specified origins */
+		config = new CorsConfiguration();
+		config.setAllowedOrigins(origins);
+		config.addAllowedHeader("Accept");
+		config.addAllowedHeader("Content-Type");
+		config.addAllowedHeader("X-Requested-With");
+		config.addAllowedMethod("GET");
+		config.addAllowedMethod("POST");
+		config.addAllowedMethod("PUT");
+		config.addAllowedMethod("DELETE");
+		config.setAllowCredentials(true);
+		source = new UrlBasedCorsConfigurationSource();
+		source.registerCorsConfiguration("/**", config);
 
-		filterChain.doFilter(request, response);
-	}
+		/* Grant limited access from all origins */
+		config = new CorsConfiguration();
+		config.addAllowedOrigin("*");
+		config.addAllowedHeader("Accept");
+		config.addAllowedHeader("X-Requested-With");
+		config.addAllowedMethod("GET");
+		config.setAllowCredentials(true);
+		source = new UrlBasedCorsConfigurationSource();
+		source.registerCorsConfiguration("/", config);
+		source.registerCorsConfiguration("/arsnova-config", config);
+		source.registerCorsConfiguration("/configuration/", config);
+		source.registerCorsConfiguration("/statistics", config);
 
-	private String sanitizeOriginUrl(String originUrl) {
-		return originUrl.replaceAll("[\n\r]+", " ");
+		return source;
 	}
 }
diff --git a/src/main/resources/arsnova.properties.example b/src/main/resources/arsnova.properties.example
index b81d3369d0c51d9160b23fffccba1e9b21882ee6..cd63c90818bd45d4af4510362910bb4b70e930da 100644
--- a/src/main/resources/arsnova.properties.example
+++ b/src/main/resources/arsnova.properties.example
@@ -160,6 +160,15 @@ security.google.key=
 security.google.secret=
 
 
+################################################################################
+# Cross-Origin Resource Sharing
+################################################################################
+# CORS grants full API access to client-side (browser) applications from other
+# domains. Multiple entries are separated by commas. Untrusted and vulnerable
+# applications running on these domains pose a security risk to ARSnova users.
+#security.cors.origins=https://
+
+
 ################################################################################
 # ARSnova Connector (for LMS)
 ################################################################################
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
index 7daa0e4c21695641e954b8e1b98c8239c3c9e33a..95f404bd0d1c9ec724d76b00eb5aba0bff6f4818 100644
--- a/src/main/webapp/WEB-INF/web.xml
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -63,7 +63,7 @@
 
 	<filter>
 		<filter-name>corsFilter</filter-name>
-		<filter-class>de.thm.arsnova.web.CorsFilter</filter-class>
+		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 		<async-supported>true</async-supported>
 	</filter>
 	<filter-mapping>
diff --git a/src/test/resources/arsnova.properties.example b/src/test/resources/arsnova.properties.example
index b81d3369d0c51d9160b23fffccba1e9b21882ee6..cd63c90818bd45d4af4510362910bb4b70e930da 100644
--- a/src/test/resources/arsnova.properties.example
+++ b/src/test/resources/arsnova.properties.example
@@ -160,6 +160,15 @@ security.google.key=
 security.google.secret=
 
 
+################################################################################
+# Cross-Origin Resource Sharing
+################################################################################
+# CORS grants full API access to client-side (browser) applications from other
+# domains. Multiple entries are separated by commas. Untrusted and vulnerable
+# applications running on these domains pose a security risk to ARSnova users.
+#security.cors.origins=https://
+
+
 ################################################################################
 # ARSnova Connector (for LMS)
 ################################################################################