diff --git a/config-templates/config.php b/config-templates/config.php
index 66d1cf49e520959a3c9b754d1a18eb90b2fdb23a..989273329f8e6f801532b9073d4a3875ceb1a32b 100644
--- a/config-templates/config.php
+++ b/config-templates/config.php
@@ -701,13 +701,26 @@ $config = array (
 	'proxy' => NULL,
 
 	/*
-	 * Array of URL's to allow a trusted redirect to.
+	 * Array of domains that are allowed when generating links or redirections
+	 * to URLs. simpleSAMLphp will use this option to determine whether to
+	 * to consider a given URL valid or not, but you should always validate
+	 * URLs obtained from the input on your own (i.e. ReturnTo or RelayState
+	 * parameters obtained from the $_REQUEST array).
 	 *
-	 * Set to NULL to disable.
+	 * Set to NULL to disable checking of URLs.
+	 *
+	 * simpleSAMLphp will automatically add your own domain (either by checking
+	 * it dinamically, or by using the domain defined in the 'baseurlpath'
+	 * directive, the latter having precedence) to the list of trusted domains,
+	 * in case this option is NOT set to NULL. In that case, you are explicitly
+	 * telling simpleSAMLphp to verify URLs.
+	 *
+	 * Set to an empty array to disallow ALL redirections or links pointing to
+	 * an external URL other than your own domain.
 	 *
 	 * Example:
-	 *   'redirect.trustedsites' => array('sp.example.com', 'othersite.org'),
+	 *   'trusted.url.domains' => array('sp.example.com', 'app.example.com'),
 	 */
-	'redirect.trustedsites' => NULL,
+	'trusted.url.domains' => NULL,
 
 );
diff --git a/docs/simplesamlphp-sp-migration.txt b/docs/simplesamlphp-sp-migration.txt
index 72a165e71a07ffd4cff1ed7a7f7566ffa60da17b..7b425e0e0dd48da8c041d8351a7947ad1aaa6734 100644
--- a/docs/simplesamlphp-sp-migration.txt
+++ b/docs/simplesamlphp-sp-migration.txt
@@ -209,6 +209,9 @@ If you want to return to a specific URL after logging out, you should include th
 
     $as->logout('https://example.org/');
 
+Please make sure the URL is trusted. If you obtain the URL from the user input, make sure it is trusted before
+calling $as->logout(), by using the SimpleSAML_Utilities::checkURLAllowed() method.
+
 
 #### Login link
 
diff --git a/lib/SimpleSAML/Auth/BWC.php b/lib/SimpleSAML/Auth/BWC.php
index 290c514b506e31d30f4af255e2a017188dbff135..923e9789a90d38f2b6c543e1289aa9da45c27411 100644
--- a/lib/SimpleSAML/Auth/BWC.php
+++ b/lib/SimpleSAML/Auth/BWC.php
@@ -143,19 +143,19 @@ class SimpleSAML_Auth_BWC extends SimpleSAML_Auth_Simple {
 		$session = SimpleSAML_Session::getInstance();
 		if (!$session->isValid($this->authority)) {
 			/* Not authenticated to this authentication source. */
-			SimpleSAML_Utilities::redirectUntrustedURL($url);
+			SimpleSAML_Utilities::redirectTrustedURL($url);
 			assert('FALSE');
 		}
 
 		if ($this->authority === 'saml2') {
 			$config = SimpleSAML_Configuration::getInstance();
-			SimpleSAML_Utilities::redirectUntrustedURL('/' . $config->getBaseURL() . 'saml2/sp/initSLO.php',
+			SimpleSAML_Utilities::redirectTrustedURL('/' . $config->getBaseURL() . 'saml2/sp/initSLO.php',
 				array('RelayState' => $url)
 			);
 		}
 
 		$session->doLogout($this->authority);
-		SimpleSAML_Utilities::redirectUntrustedURL($url);
+		SimpleSAML_Utilities::redirectTrustedURL($url);
 	}
 
 }
diff --git a/lib/SimpleSAML/Auth/Default.php b/lib/SimpleSAML/Auth/Default.php
index 34686aa2d0926feb1a3bfc2715467113fa36bfc1..ca02e748eca51984f49c8bb39766dca55f415a89 100644
--- a/lib/SimpleSAML/Auth/Default.php
+++ b/lib/SimpleSAML/Auth/Default.php
@@ -19,13 +19,21 @@ class SimpleSAML_Auth_Default {
 	 * This function never returns.
 	 *
 	 * @param string $authId  The identifier of the authentication source.
-	 * @param string|array $return  The URL or function we should direct the user to after authentication.
-	 * @param string|NULL $errorURL  The URL we should direct the user to after failed authentication.
-	 *                               Can be NULL, in which case a standard error page will be shown.
-	 * @param array $params  Extra information about the login. Different authentication requestors may
-	 *                       provide different information. Optional, will default to an empty array.
+	 * @param string|array $return The URL or function we should direct the
+	 * user to after authentication. If using a URL obtained from user input,
+	 * please make sure to check it by calling
+	 * SimpleSAML_Utilities::checkURLAllowed().
+	 * @param string|NULL $errorURL The URL we should direct the user to after
+	 * failed authentication. Can be NULL, in which case a standard error page
+	 * will be shown. If using a URL obtained from user input, please make sure
+	 * to check it by calling SimpleSAML_Utilities::checkURLAllowed().
+	 * @param array $params Extra information about the login. Different
+	 * authentication requestors may provide different information. Optional,
+	 * will default to an empty array.
 	 */
-	public static function initLogin($authId, $return, $errorURL = NULL, array $params = array()) {
+	public static function initLogin($authId, $return, $errorURL = NULL,
+		array $params = array()) {
+
 		assert('is_string($authId)');
 		assert('is_string($return) || is_array($return)');
 		assert('is_string($errorURL) || is_null($errorURL)');
@@ -121,7 +129,7 @@ class SimpleSAML_Auth_Default {
 
 		if (is_string($return)) {
 			/* Redirect... */
-			SimpleSAML_Utilities::redirectUntrustedURL($return);
+			SimpleSAML_Utilities::redirectTrustedURL($return);
 		} else {
 			call_user_func($return, $state);
 			assert('FALSE');
@@ -132,11 +140,16 @@ class SimpleSAML_Auth_Default {
 	/**
 	 * Start logout.
 	 *
-	 * This function starts a logout operation from the current authentication source. This function
-	 * will return if the logout operation does not require a redirect.
+	 * This function starts a logout operation from the current authentication
+	 * source. This function will return if the logout operation does not
+	 * require a redirect.
 	 *
-	 * @param string $returnURL  The URL we should redirect the user to after logging out.
-	 * @param string|NULL $authority  The authentication source we are logging out from, or NULL to log out of the most recent.
+	 * @param string $returnURL The URL we should redirect the user to after
+	 * logging out. No checking is performed on the URL, so make sure to verify
+	 * it on beforehand if the URL is obtained from user input. Refer to
+	 * SimpleSAML_Utilities::checkURLAllowed() for more information.
+	 * @param string|NULL $authority The authentication source we are logging
+	 * out from, or NULL to log out from the most recent.
 	 */
 	public static function initLogoutReturn($returnURL, $authority = NULL) {
 		assert('is_string($returnURL)');
@@ -171,11 +184,16 @@ class SimpleSAML_Auth_Default {
 	/**
 	 * Start logout.
 	 *
-	 * This function starts a logout operation from the current authentication source. This function
-	 * never returns.
+	 * This function starts a logout operation from the current authentication
+	 * source. This function never returns.
 	 *
-	 * @param string $returnURL  The URL we should redirect the user to after logging out.
-	 * @param string|NULL $authority  The authentication source we are logging out from, or NULL to log out of the most recent.
+	 * @param string $returnURL The URL we should redirect the user to after
+	 * logging out. No checking is performed on the URL, so make sure to verify
+	 * it on beforehand if the URL is obtained from user input. Refer to
+	 * SimpleSAML_Utilities::checkURLAllowed() for more information.
+	 * @param string|NULL $authority The authentication source we are logging
+	 * out from, or NULL to log out from the most recent.
+	 * @return void This function never returns.
 	 */
 	public static function initLogout($returnURL, $authority = NULL) {
 		assert('is_string($returnURL)');
@@ -184,7 +202,7 @@ class SimpleSAML_Auth_Default {
 		self::initLogoutReturn($returnURL, $authority);
 
 		/* Redirect... */
-		SimpleSAML_Utilities::redirectUntrustedURL($returnURL);
+		SimpleSAML_Utilities::redirectTrustedURL($returnURL);
 	}
 
 
@@ -202,7 +220,7 @@ class SimpleSAML_Auth_Default {
 		$returnURL = $state['SimpleSAML_Auth_Default.ReturnURL'];
 
 		/* Redirect... */
-		SimpleSAML_Utilities::redirectUntrustedURL($returnURL);
+		SimpleSAML_Utilities::redirectTrustedURL($returnURL);
 	}
 
 
@@ -239,10 +257,14 @@ class SimpleSAML_Auth_Default {
 	 *
 	 * This is used to handle IdP initiated SSO.
 	 *
-	 * @param string $authId  The id of the authentication source that received the request.
-	 * @param array $state  A state array.
-	 * @param string $redirectTo  The URL we should redirect the user to after
-	 *                            updating the session.
+	 * @param string $authId The id of the authentication source that received
+	 * the request.
+	 * @param array $state A state array.
+	 * @param string $redirectTo The URL we should redirect the user to after
+	 * updating the session. The function will check if the URL is allowed, so
+	 * there is no need to manually check the URL on beforehand. Please refer
+	 * to the 'trusted.url.domains' configuration directive for more
+	 * information about allowing (or disallowing) URLs.
 	 */
 	public static function handleUnsolicitedAuth($authId, array $state, $redirectTo) {
 		assert('is_string($authId)');
diff --git a/lib/SimpleSAML/Auth/ProcessingChain.php b/lib/SimpleSAML/Auth/ProcessingChain.php
index da04532642d0cff4679236166f29aca9e6c7fb6b..1b60e3326a82d25dae1125d4bf0a763e24d14e65 100644
--- a/lib/SimpleSAML/Auth/ProcessingChain.php
+++ b/lib/SimpleSAML/Auth/ProcessingChain.php
@@ -248,7 +248,7 @@ class SimpleSAML_Auth_ProcessingChain {
 			 * in $state['ReturnURL'].
 			 */
 			$id = SimpleSAML_Auth_State::saveState($state, self::COMPLETED_STAGE);
-			SimpleSAML_Utilities::redirectUntrustedURL($state['ReturnURL'], array(self::AUTHPARAM => $id));
+			SimpleSAML_Utilities::redirectTrustedURL($state['ReturnURL'], array(self::AUTHPARAM => $id));
 		} else {
 			/* Pass the state to the function defined in $state['ReturnCall']. */
 
@@ -302,8 +302,11 @@ class SimpleSAML_Auth_ProcessingChain {
 	/**
 	 * Retrieve a state which has finished processing.
 	 *
-	 * @param string $id  The identifier of the state. This can be found in the request parameter
-	 *                    with index from SimpleSAML_Auth_ProcessingChain::AUTHPARAM.
+	 * @param string $id The state identifier. This can be found in the
+	 * SimpleSAML_Auth_ProcessingChain::AUTHPARAM request parameter. Please
+	 * make sure to sanitize it properly by calling the
+	 * SimpleSAML_Utilities::checkURLAllowed() function with the embedded
+	 * restart URL, if any. See also SimpleSAML_Utilities::getURLFromStateID().
 	 */
 	public static function fetchProcessedState($id) {
 		assert('is_string($id)');
@@ -351,5 +354,3 @@ class SimpleSAML_Auth_ProcessingChain {
 	}
 
 }
-
-?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/Auth/Simple.php b/lib/SimpleSAML/Auth/Simple.php
index 8577379e88e7d24a9f9c06314edc79081361f395..4f7d8fb057ef0b0aa53294693f53c8dd3eb83d93 100644
--- a/lib/SimpleSAML/Auth/Simple.php
+++ b/lib/SimpleSAML/Auth/Simple.php
@@ -219,7 +219,7 @@ class SimpleSAML_Auth_Simple {
 				$params[$state['ReturnStateParam']] = $stateID;
 			}
 
-			SimpleSAML_Utilities::redirectUntrustedURL($state['ReturnTo'], $params);
+			SimpleSAML_Utilities::redirectTrustedURL($state['ReturnTo'], $params);
 		}
 	}
 
diff --git a/lib/SimpleSAML/Auth/State.php b/lib/SimpleSAML/Auth/State.php
index 57387665d8045fe115ee2e8bd21d8983dd4063b7..0b74da24c533a9ec61259bd20b6c81f74d0f4486 100644
--- a/lib/SimpleSAML/Auth/State.php
+++ b/lib/SimpleSAML/Auth/State.php
@@ -211,13 +211,7 @@ class SimpleSAML_Auth_State {
 		assert('is_bool($allowMissing)');
 		SimpleSAML_Logger::debug('Loading state: ' . var_export($id, TRUE));
 
-		$tmp = explode(':', $id, 2);
-		$id = $tmp[0];
-		if (count($tmp) === 2) {
-			$restartURL = $tmp[1];
-		} else {
-			$restartURL = NULL;
-		}
+		$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
 
 		$session = SimpleSAML_Session::getInstance();
 		$state = $session->getData('SimpleSAML_Auth_State', $id);
diff --git a/lib/SimpleSAML/IdP.php b/lib/SimpleSAML/IdP.php
index 630662dd752895131050ef9f3898cec75f2c7d7d..d94c4274acfd1e602d776fac35bd0d343310fb72 100644
--- a/lib/SimpleSAML/IdP.php
+++ b/lib/SimpleSAML/IdP.php
@@ -529,7 +529,7 @@ class SimpleSAML_IdP {
 	public static function finishLogoutRedirect(SimpleSAML_IdP $idp, array $state) {
 		assert('isset($state["core:Logout:URL"])');
 
-		SimpleSAML_Utilities::redirectUntrustedURL($state['core:Logout:URL']);
+		SimpleSAML_Utilities::redirectTrustedURL($state['core:Logout:URL']);
 		assert('FALSE');
 	}
 
diff --git a/lib/SimpleSAML/IdP/LogoutTraditional.php b/lib/SimpleSAML/IdP/LogoutTraditional.php
index 86ce301e9a717169bd52cfb41a029c4c2c6e4531..f9fa132f7ae9440421863a982a4e870f3e258f19 100644
--- a/lib/SimpleSAML/IdP/LogoutTraditional.php
+++ b/lib/SimpleSAML/IdP/LogoutTraditional.php
@@ -76,6 +76,12 @@ class SimpleSAML_IdP_LogoutTraditional extends SimpleSAML_IdP_LogoutHandler {
 			throw new SimpleSAML_Error_Exception('RelayState lost during logout.');
 		}
 
+		// sanitize the input
+		$restartURL = SimpleSAML_Utilities::getURLFromStateID($relayState);
+		if (!is_null($restartURL)) {
+			SimpleSAML_Utilities::checkURLAllowed($restartURL);
+		}
+
 		$state = SimpleSAML_Auth_State::loadState($relayState, 'core:LogoutTraditional');
 
 		if ($error === NULL) {
diff --git a/lib/SimpleSAML/Utilities.php b/lib/SimpleSAML/Utilities.php
index 0b37bf839d4bcde52a9266109c0ea8ab0b5842e3..cd7ef1f2877421f25b863d0605bab23c8e54496f 100644
--- a/lib/SimpleSAML/Utilities.php
+++ b/lib/SimpleSAML/Utilities.php
@@ -298,17 +298,80 @@ class SimpleSAML_Utilities {
 	}
 
 
+	/**
+	 * Check if a URL is valid and is in our list of allowed URLs.
+	 *
+	 * @param string $url The URL to check.
+	 * @param array $trustedSites An optional white list of domains. If none
+	 * specified, the 'trusted.url.domains' configuration directive will be
+	 * used.
+	 * @return string The normalized URL itself if it is allowed.
+	 * @throws SimpleSAML_Error_Exception if the URL is malformed or is not
+	 * allowed by configuration.
+	 */
+	public static function checkURLAllowed($url, array $trustedSites = NULL) {
+		$url = self::normalizeURL($url);
+
+		// verify that the URL points to an http or https site
+		if (!preg_match('@^https?://@i', $url)) {
+			throw new SimpleSAML_Error_Exception('Invalid URL: '.$url);
+		}
+
+		// get the white list of domains
+		if ($trustedSites === NULL) {
+			$trustedSites = SimpleSAML_Configuration::getInstance()->getArray('trusted.url.domains', NULL);
+			if ($trustedSites === NULL) {
+				$trustedSites = SimpleSAML_Configuration::getInstance()->getArray('redirect.trustedsites', NULL);
+			}
+		}
+
+		// validates the URL's host is among those allowed
+		if ($trustedSites !== NULL) {
+			assert(is_array($trustedSites));
+			preg_match('@^https?://([^/]+)@i', $url, $matches);
+			$hostname = $matches[1];
+
+			// add self host to the white list
+			$self_host = self::getSelfHost();
+			$trustedSites[] = $self_host;
+
+			/* Throw exception due to redirection to untrusted site */
+			if (!in_array($hostname, $trustedSites)) {
+				throw new SimpleSAML_Error_Exception('URL not allowed: '.$url);
+			}
+		}
+		return $url;
+	}
+
+
+	/**
+	 * Get a URL embedded in a StateID, in the form 'id:url'.
+	 *
+	 * @param string $stateId The state ID to use.
+	 * @return string The embedded URL if found, NULL otherwise.
+	 */
+	public static function getURLFromStateID($stateId) {
+		$tmp = explode(':', $stateId, 2);
+		$id = $tmp[0];
+		$url = NULL;
+		if (count($tmp) === 2) {
+			$url = $tmp[1];
+		}
+		return $url;
+	}
+
+
 	public static function checkDateConditions($start=NULL, $end=NULL) {
 		$currentTime = time();
 	
-		if (! empty($start)) {
+		if (!empty($start)) {
 			$startTime = SAML2_Utils::parseSAML2Time($start);
 			/* Allow for a 10 minute difference in Time */
 			if (($startTime < 0) || (($startTime - 600) > $currentTime)) {
 				return FALSE;
 			}
 		}
-		if (! empty($end)) {
+		if (!empty($end)) {
 			$endTime = SAML2_Utils::parseSAML2Time($end);
 			if (($endTime < 0) || ($endTime <= $currentTime)) {
 				return FALSE;
@@ -493,113 +556,20 @@ class SimpleSAML_Utilities {
 		return true;
 	}
 
-
-	/**
-	 * This function redirects the user to the specified address.
-	 *
-	 * This function will use the "HTTP 303 See Other" redirection if the
-	 * current request used the POST method and the HTTP version is 1.1.
-	 * Otherwise, a "HTTP 302 Found" redirection will be used.
-	 *
-	 * The fuction will also generate a simple web page with a clickable
-	 * link to the target page.
-	 *
-	 * @param string $url The URL we should redirect to. This URL may include
-	 * query parameters. If this URL is a relative URL (starting with '/'),
-	 * then it will be turned into an absolute URL by prefixing it with the
-	 * absolute URL to the root of the website.
-	 * @param string[] $parameters An array with extra query string parameters
-	 * which should be appended to the URL. The name of the parameter is the
-	 * array index. The value of the parameter is the value stored in the index.
-	 * Both the name and the value will be urlencoded. If the value is NULL,
-	 * then the parameter will be encoded as just the name, without a value.
-	 * @param string[] $allowed_redirect_hosts An array with a whitelist of
-	 * hosts for which redirects are allowed. If NULL, redirections will be
-	 * allowed to any host. Otherwise, the host of the $url provided must be
-	 * present in this parameter. If the host is not whitelisted, an exception
-	 * will be thrown.
-	 *
-	 * @return void This function never returns.
-	 * @deprecated 1.12.0 This function will be removed from the API. Use
-	 * accordingly the redirectTrustedURL or redirectUntrustedURL functions
-	 * instead.
+	/*
+	 * This is a temporary function, holding the redirect() functionality,
+	 * meanwhile we are deprecating the it.
 	 */
-	public static function redirect($url, $parameters = array(), $allowed_redirect_hosts = NULL) {
-		assert(is_string($url));
-		assert(strlen($url) > 0);
-		assert(is_array($parameters));
-		if($allowed_redirect_hosts != NULL) assert(is_array($allowed_redirect_hosts));
-
-		/* Check for relative URL. */
-		if(substr($url, 0, 1) === '/') {
-			/* Prefix the URL with the url to the root of the
-			 * website.
-			 */
-			$url = self::selfURLhost() . $url;
+	private static function _doRedirect($url, $parameters = array()) {
+		if (!empty($parameters)) {
+			$url = self::addURLparameter($url, $parameters);
 		}
 
-		/* Verify that the URL points to an http or https site. */
-		if (!preg_match('@^https?://@i', $url)) {
-			throw new SimpleSAML_Error_Exception('Redirect to invalid URL: ' . $url);
-		}
-
-		/* Validates the URL's host is among those allowed. */
-		if ($allowed_redirect_hosts !== NULL) {
-			preg_match('@^https?://([^/]+)@i', $url, $matches);
-			$hostname = $matches[1];
-
-			// add self host to the white list
-			$self_host = self::getSelfHost();
-			$allowed_redirect_hosts[] = $self_host;
-
-			/* Throw exception due to redirection to untrusted site */
-			if(!in_array($hostname, $allowed_redirect_hosts)) {
-				throw new SimpleSAML_Error_Exception('Redirection not to allowed to URL: ' . $url);
-			}
-		}
-
-		/* Determine which prefix we should put before the first
-		 * parameter.
-		 */
-		if(strpos($url, '?') === FALSE) {
-			$paramPrefix = '?';
-		} else {
-			$paramPrefix = '&';
-		}
-
-		/* Iterate over the parameters and append them to the query
-		 * string.
-		 */
-		foreach($parameters as $name => $value) {
-
-			/* Encode the parameter. */
-			if($value === NULL) {
-				$param = urlencode($name);
-			} elseif (is_array($value)) {
-				$param = "";
-				foreach ($value as $val) {
-					$param .= urlencode($name) . "[]=" . urlencode($val) . '&';				
-				}
-			} else {
-				$param = urlencode($name) . '=' .
-					urlencode($value);
-			}
-
-			/* Append the parameter to the query string. */
-			$url .= $paramPrefix . $param;
-
-			/* Every following parameter is guaranteed to follow
-			 * another parameter. Therefore we use the '&' prefix.
-			 */
-			$paramPrefix = '&';
-		}
-
-
 		/* Set the HTTP result code. This is either 303 See Other or
 		 * 302 Found. HTTP 303 See Other is sent if the HTTP version
 		 * is HTTP/1.1 and the request type was a POST request.
 		 */
-		if($_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1' &&
+		if ($_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1' &&
 			$_SERVER['REQUEST_METHOD'] === 'POST') {
 			$code = 303;
 		} else {
@@ -630,7 +600,8 @@ class SimpleSAML_Utilities {
 		echo '<h1>Redirect</h1>';
 		echo '<p>';
 		echo 'You were redirected to: ';
-		echo '<a id="redirlink" href="' . htmlspecialchars($url) . '">' . htmlspecialchars($url) . '</a>';
+		echo '<a id="redirlink" href="' .
+			htmlspecialchars($url) . '">' . htmlspecialchars($url) . '</a>';
 		echo '<script type="text/javascript">document.getElementById("redirlink").focus();</script>';
 		echo '</p>';
 		echo '</body>';
@@ -638,6 +609,51 @@ class SimpleSAML_Utilities {
 
 		/* End script execution. */
 		exit;
+	} 
+
+
+	/**
+	 * This function redirects the user to the specified address.
+	 *
+	 * This function will use the "HTTP 303 See Other" redirection if the
+	 * current request used the POST method and the HTTP version is 1.1.
+	 * Otherwise, a "HTTP 302 Found" redirection will be used.
+	 *
+	 * The fuction will also generate a simple web page with a clickable
+	 * link to the target page.
+	 *
+	 * @param string $url The URL we should redirect to. This URL may include
+	 * query parameters. If this URL is a relative URL (starting with '/'),
+	 * then it will be turned into an absolute URL by prefixing it with the
+	 * absolute URL to the root of the website.
+	 * @param string[] $parameters An array with extra query string parameters
+	 * which should be appended to the URL. The name of the parameter is the
+	 * array index. The value of the parameter is the value stored in the index.
+	 * Both the name and the value will be urlencoded. If the value is NULL,
+	 * then the parameter will be encoded as just the name, without a value.
+ 	 * @param string[] $allowed_redirect_hosts An array with a whitelist of
+	 * hosts for which redirects are allowed. If NULL, redirections will be
+	 * allowed to any host. Otherwise, the host of the $url provided must be
+	 * present in this parameter. If the host is not whitelisted, an exception
+	 * will be thrown.
+	 *
+	 * @return void This function never returns.
+	 * @deprecated 1.12.0 This function will be removed from the API. Instead,
+	 * use the redirectTrustedURL or redirectUntrustedURL functions
+	 * accordingly.
+	 */
+	public static function redirect($url, $parameters = array(),
+		$allowed_redirect_hosts = NULL) {
+		
+		assert(is_string($url));
+		assert(strlen($url) > 0);
+		assert(is_array($parameters));
+
+		$url = self::normalizeURL($url);
+		if ($allowed_redirect_hosts !== NULL) {
+			$url = self::checkURLAllowed($url, $allowed_redirect_hosts);	
+		}
+		self::_doRedirect($url, $parameters);
 	}
 
 	/**
@@ -665,26 +681,27 @@ class SimpleSAML_Utilities {
 	 * @return void This function never returns.
 	 */
 	public static function redirectTrustedURL($url, $parameters = array()) {
-		self::redirect($url, $parameters);
+		$url = self::normalizeURL($url);
+		self::_doRedirect($url, $parameters);
 	}
 
 	/**
 	 * This function redirects to the specified URL after performing the
-	 * appropriate security checks on it. Particularly, it will make sure
-	 * that the provided URL is allowed by the 'redirect.trustedsites'
-	 * directive in the configuration.
+	 * appropriate security checks on it. Particularly, it will make sure that
+	 * the provided URL is allowed by the 'redirect.trustedsites' directive
+	 * in the configuration.
 	 *
-	 * If the aforementioned option is not set or the URL does corresponds
-	 * to a trusted site, it performs a redirection to it. If the site is
-	 * not trusted, an exception will be thrown.
+	 * If the aforementioned option is not set or the URL does correspond to a
+	 * trusted site, it performs a redirection to it. If the site is not
+	 * trusted, an exception will be thrown.
 	 *
 	 * See the redirectTrustedURL function for more details.
 	 * 
 	 * @return void This function never returns.
 	 */
 	public static function redirectUntrustedURL($url, $parameters = array()) {
-		$trustedSites = SimpleSAML_Configuration::getInstance()->getArray('redirect.trustedsites', NULL);
-		self::redirect($url, $parameters, $trustedSites);
+		$url = self::checkURLAllowed($url);
+		self::_doRedirect($url, $parameters);
 	}
 
 	/**
@@ -1150,8 +1167,7 @@ class SimpleSAML_Utilities {
 			$base = self::getBaseURL();
 		}
 
-
-		if(!preg_match('$^((((\w+:)//[^/]+)(/[^?#]*))(?:\?[^#]*)?)(?:#.*)?$', $base, $baseParsed)) {
+		if(!preg_match('/^((((\w+:)\/\/[^\/]+)(\/[^?#]*))(?:\?[^#]*)?)(?:#.*)?/', $base, $baseParsed)) {
 			throw new Exception('Unable to parse base url: ' . $base);
 		}
 
diff --git a/lib/SimpleSAML/XHTML/IdPDisco.php b/lib/SimpleSAML/XHTML/IdPDisco.php
index c1c5be0c46c5769f026f2081bf6a6645c74da342..7e7eeb93859b95e88925ddbf7cf795edf11359c9 100644
--- a/lib/SimpleSAML/XHTML/IdPDisco.php
+++ b/lib/SimpleSAML/XHTML/IdPDisco.php
@@ -124,7 +124,7 @@ class SimpleSAML_XHTML_IdPDisco {
 		if(!array_key_exists('return', $_GET)) {
 			throw new Exception('Missing parameter: return');
 		} else {
-			$this->returnURL = $_GET['return'];
+			$this->returnURL = SimpleSAML_Utilities::checkURLAllowed($_GET['return']);
 		}
 		
 		$this->isPassive = FALSE;
@@ -474,7 +474,7 @@ class SimpleSAML_XHTML_IdPDisco {
 				
 			} else {
 				$this->log('Choice made [' . $idp . '] (Redirecting the user back. returnIDParam=' . $this->returnIdParam . ')');
-				SimpleSAML_Utilities::redirectUntrustedURL($this->returnURL, array($this->returnIdParam => $idp));
+				SimpleSAML_Utilities::redirectTrustedURL($this->returnURL, array($this->returnIdParam => $idp));
 			}
 			
 			return;
@@ -482,7 +482,7 @@ class SimpleSAML_XHTML_IdPDisco {
 		
 		if ($this->isPassive) {
 			$this->log('Choice not made. (Redirecting the user back without answer)');
-			SimpleSAML_Utilities::redirectUntrustedURL($this->returnURL);
+			SimpleSAML_Utilities::redirectTrustedURL($this->returnURL);
 			return;
 		}
 
@@ -500,7 +500,7 @@ class SimpleSAML_XHTML_IdPDisco {
         
         if(sizeof($idpintersection)  == 1) {
             $this->log('Choice made [' . $idpintersection[0] . '] (Redirecting the user back. returnIDParam=' . $this->returnIdParam . ')');
-            SimpleSAML_Utilities::redirectUntrustedURL($this->returnURL, array($this->returnIdParam => $idpintersection[0]));
+            SimpleSAML_Utilities::redirectTrustedURL($this->returnURL, array($this->returnIdParam => $idpintersection[0]));
         }
 
 		/*
diff --git a/modules/InfoCard/lib/Auth/Source/ICAuth.php b/modules/InfoCard/lib/Auth/Source/ICAuth.php
index 39e746c56b6b409f0866ead18fa502eaab1daca8..0b76ed1c08b03ebf4500741de0dd58440e68ba7e 100644
--- a/modules/InfoCard/lib/Auth/Source/ICAuth.php
+++ b/modules/InfoCard/lib/Auth/Source/ICAuth.php
@@ -42,7 +42,6 @@ class sspmod_InfoCard_Auth_Source_ICAuth extends SimpleSAML_Auth_Source {
 	
 
 	public static function handleLogin($authStateId, $xmlToken) {
-SimpleSAML_Logger::debug('ENTRA en icauth');
 		assert('is_string($authStateId)');		
 
 		$config = SimpleSAML_Configuration::getInstance();
@@ -61,14 +60,20 @@ SimpleSAML_Logger::debug('ENTRA en icauth');
     	SimpleSAML_Logger::debug("NOXMLtoken: ".$xmlToken);
 		$claims = $infocard->process($xmlToken);
  		if($claims->isValid()) {
-//		if(false) {
 			$attributes = array();
 			foreach ($Infocard['requiredClaims'] as $claim => $data){
 				$attributes[$claim] = array($claims->$claim);
 			}
 			foreach ($Infocard['optionalClaims'] as $claim => $data){
 				$attributes[$claim] = array($claims->$claim);
-			}	
+			}
+
+			// sanitize the input
+			$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId);
+			if (!is_null($restartURL)) {
+				SimpleSAML_Utilities::checkURLAllowed($restartURL);
+			}
+
 			/* Retrieve the authentication state. */
 			$state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
 			/* Find authentication source. */
@@ -78,12 +83,10 @@ SimpleSAML_Logger::debug('ENTRA en icauth');
 				throw new Exception('Could not find authentication source with id ' . $state[self::AUTHID]);
 			}			
 			$state['Attributes'] = $attributes;	
-SimpleSAML_Logger::debug('VALIDA');
 			unset($infocard);
 			unset($claims);
 			SimpleSAML_Auth_Source::completeAuth($state);
 		} else {
-SimpleSAML_Logger::debug('NO VALIDA ERROR:'.$claims->getErrorMsg());
 			unset($infocard);
 			unset($claims);
 			return 'wrong_IC';
diff --git a/modules/aselect/www/credentials.php b/modules/aselect/www/credentials.php
index 3d3b8cba1204a903c768285f831c544bc253a113..dc0afe7e4bde51319df8d0de887d9fc6c9d93bd5 100644
--- a/modules/aselect/www/credentials.php
+++ b/modules/aselect/www/credentials.php
@@ -7,7 +7,18 @@
  * @author Wessel Dankers, Tilburg University
  */
 function check_credentials() {
-	$state = SimpleSAML_Auth_State::loadState($_REQUEST['ssp_state'], 'aselect:login');
+	
+	if (!array_key_exists('ssp_state', $_REQUEST))
+		SimpleSAML_Auth_State::throwException($state, new SimpleSAML_Error_Exception("Missing ssp_state parameter"));	
+	$id = $_REQUEST['ssp_state'];
+
+	// sanitize the input
+	$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+	if (!is_null($restartURL)) {
+		SimpleSAML_Utilities::checkURLAllowed($restartURL);
+	}
+
+	$state = SimpleSAML_Auth_State::loadState($id, 'aselect:login');
 
 	if(!array_key_exists('a-select-server', $_REQUEST))
 		SimpleSAML_Auth_State::throwException($state, new SimpleSAML_Error_Exception("Missing a-select-server parameter"));
diff --git a/modules/authYubiKey/lib/Auth/Source/YubiKey.php b/modules/authYubiKey/lib/Auth/Source/YubiKey.php
index ae98920d61113455fb6bea97f886567456e8ba81..6b14128974a15b0ee6fe092ae48443c8164fb998 100644
--- a/modules/authYubiKey/lib/Auth/Source/YubiKey.php
+++ b/modules/authYubiKey/lib/Auth/Source/YubiKey.php
@@ -124,6 +124,12 @@ class sspmod_authYubiKey_Auth_Source_YubiKey extends SimpleSAML_Auth_Source {
 		assert('is_string($authStateId)');
 		assert('is_string($otp)');
 
+		// sanitize the input
+		$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId);
+		if (!is_null($restartURL)) {
+			SimpleSAML_Utilities::checkURLAllowed($restartURL);
+		}
+
 		/* Retrieve the authentication state. */
 		$state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
 
diff --git a/modules/authfacebook/www/linkback.php b/modules/authfacebook/www/linkback.php
index 3a27fe5ea90b031ecece39df264d2da6f9c5cd85..2305f773dbe96eb5aad664437b729534d55e74c2 100644
--- a/modules/authfacebook/www/linkback.php
+++ b/modules/authfacebook/www/linkback.php
@@ -9,6 +9,13 @@ if (!array_key_exists('AuthState', $_REQUEST) || empty($_REQUEST['AuthState']))
 }
 
 $stateID = $_REQUEST['AuthState'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateID);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($stateID, sspmod_authfacebook_Auth_Source_Facebook::STAGE_INIT);
 
 /* Find authentication source. */
diff --git a/modules/authlinkedin/www/linkback.php b/modules/authlinkedin/www/linkback.php
index 961eaa6bf423e56b8719f152c4976be1b95a7ac2..a169f04ee17532fd329e3e72b9c3deb3e3390f3a 100644
--- a/modules/authlinkedin/www/linkback.php
+++ b/modules/authlinkedin/www/linkback.php
@@ -10,6 +10,12 @@ if (array_key_exists('stateid', $_REQUEST)) {
         throw new Exception('Lost OAuth Client State');
 }
 
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($stateId, sspmod_authlinkedin_Auth_Source_LinkedIn::STAGE_INIT);
 
 // http://developer.linkedin.com/docs/DOC-1008#2_Redirect_the_User_to_our_Authorization_Server
diff --git a/modules/authmyspace/www/linkback.php b/modules/authmyspace/www/linkback.php
index 93c45153c5f76d96dd5fa76e47ccf25acd6f4ded..81683c8373f45b93fcc2b44d4639405881ff1dfe 100644
--- a/modules/authmyspace/www/linkback.php
+++ b/modules/authmyspace/www/linkback.php
@@ -10,6 +10,12 @@ if (array_key_exists('stateid', $_REQUEST)) {
 	throw new Exception('State Lost - not returned by MySpace Auth');
 }
 
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($stateId, sspmod_authmyspace_Auth_Source_MySpace::STAGE_INIT);
 
 if (array_key_exists('oauth_problem', $_REQUEST)) {
diff --git a/modules/authorize/www/authorize_403.php b/modules/authorize/www/authorize_403.php
index 54d702fb0c21d88bd4f9aae8ef9c8567e1054261..613fa1034aa5026e79d28b961b0bc58a10f5acf7 100644
--- a/modules/authorize/www/authorize_403.php
+++ b/modules/authorize/www/authorize_403.php
@@ -11,6 +11,13 @@ if (!array_key_exists('StateId', $_REQUEST)) {
 }
 
 $id = $_REQUEST['StateId'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'authorize:Authorize');
 
 $globalConfig = SimpleSAML_Configuration::getInstance();
diff --git a/modules/authtwitter/www/linkback.php b/modules/authtwitter/www/linkback.php
index de6ec85ce392d5059567924129f06439f89fd99f..0ebea758af5b6061e57fd95cd2be340eef5ce9a5 100644
--- a/modules/authtwitter/www/linkback.php
+++ b/modules/authtwitter/www/linkback.php
@@ -9,6 +9,12 @@ if (!array_key_exists('AuthState', $_REQUEST) || empty($_REQUEST['AuthState']))
 }
 $stateID = $_REQUEST['AuthState'];
 
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateID);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($stateID, sspmod_authtwitter_Auth_Source_Twitter::STAGE_INIT);
 
 /* Find authentication source. */
diff --git a/modules/authwindowslive/www/linkback.php b/modules/authwindowslive/www/linkback.php
index 7ae42661fbefa80587413ecac23b76fffac95807..ee8452de461c5b11ab54beb1d561ed6e2a59c0ea 100644
--- a/modules/authwindowslive/www/linkback.php
+++ b/modules/authwindowslive/www/linkback.php
@@ -6,6 +6,13 @@
 
 if (array_key_exists('wrap_client_state', $_REQUEST)) {
 	$stateId = $_REQUEST['wrap_client_state'];
+	
+	// sanitize the input
+	$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId);
+	if (!is_null($restartURL)) {
+		SimpleSAML_Utilities::checkURLAllowed($restartURL);
+	}
+
 	$state = SimpleSAML_Auth_State::loadState($stateId, sspmod_authwindowslive_Auth_Source_LiveID::STAGE_INIT);
 } else {
 	throw new Exception('Lost OAuth-WRAP Client State');
diff --git a/modules/cas/www/linkback.php b/modules/cas/www/linkback.php
index 1e6740c0bdcc6ba9d2190c1656a0642aa821ce85..8fe43e2f50bac1452d63f2280f8545b392a7621b 100644
--- a/modules/cas/www/linkback.php
+++ b/modules/cas/www/linkback.php
@@ -13,6 +13,12 @@ if (!isset($_GET['ticket'])) {
 	throw new SimpleSAML_Error_BadRequest('Missing ticket parameter.');
 }
 
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($stateId, sspmod_cas_Auth_Source_CAS::STAGE_INIT);
 $state['cas:ticket'] = (string)$_GET['ticket'];
 
diff --git a/modules/casserver/www/login.php b/modules/casserver/www/login.php
index e59c3324877acf4dd71320c2f5016cc897b9f781..0410acdc3229a65f821550ac441e2c89e38249dc 100644
--- a/modules/casserver/www/login.php
+++ b/modules/casserver/www/login.php
@@ -48,10 +48,8 @@ storeTicket($ticket, $path, array('service' => $service,
 	'proxies' => array(),
 	'validbefore' => time() + 5));
 
-SimpleSAML_Utilities::redirectUntrustedURL(
+SimpleSAML_Utilities::redirectTrustedURL(
 	SimpleSAML_Utilities::addURLparameter($service,
 		array('ticket' => $ticket)
 	)
 );
-
-?>
diff --git a/modules/cdc/lib/Server.php b/modules/cdc/lib/Server.php
index 8c962eb19fd2c02acf260c1e8841e4c3cf1fe27e..d4dacf736711f73ebb82540f009fc37b2d6061b0 100644
--- a/modules/cdc/lib/Server.php
+++ b/modules/cdc/lib/Server.php
@@ -327,7 +327,7 @@ class sspmod_cdc_Server {
 
 		$url = SimpleSAML_Utilities::addURLparameter($to, $params);
 		if (strlen($url) < 2048) {
-			SimpleSAML_Utilities::redirectUntrustedURL($url);
+			SimpleSAML_Utilities::redirectTrustedURL($url);
 		} else {
 			SimpleSAML_Utilities::postRedirect($to, $params);
 		}
diff --git a/modules/cdc/www/resume.php b/modules/cdc/www/resume.php
index 6e4fcf381caa8613dbda4f593bf06c29481ea039..549be22885b8999aa4fe65b270898f01a4a07fbe 100644
--- a/modules/cdc/www/resume.php
+++ b/modules/cdc/www/resume.php
@@ -17,6 +17,12 @@ if (!isset($response['id'])) {
 	throw new SimpleSAML_Error_BadRequest('CDCResponse without id.');
 }
 
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($response['id']);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($response['id'], 'cdc:resume');
 
 SimpleSAML_Auth_ProcessingChain::resumeProcessing($state);
diff --git a/modules/consent/www/getconsent.php b/modules/consent/www/getconsent.php
index 3628bd1abb95704f075d0b2ada61ba301b3846f6..3e30817022f73720206f32b872fa58ae1a49c2d1 100644
--- a/modules/consent/www/getconsent.php
+++ b/modules/consent/www/getconsent.php
@@ -31,6 +31,13 @@ if (!array_key_exists('StateId', $_REQUEST)) {
 }
 
 $id = $_REQUEST['StateId'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'consent:request');
 
 if (array_key_exists('core:SP', $state)) {
diff --git a/modules/consent/www/logout.php b/modules/consent/www/logout.php
index 55903707b5ad4c6cd8f7bf0cca4197cbdbb8f6e4..1e464294a1cc4089903d5e598a3e45c187a68c95 100644
--- a/modules/consent/www/logout.php
+++ b/modules/consent/www/logout.php
@@ -10,6 +10,13 @@ if (!array_key_exists('StateId', $_GET)) {
     throw new SimpleSAML_Error_BadRequest('Missing required StateId query parameter.');
 }
 $id = (string)$_GET['StateId'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'consent:request');
 
 $state['Responder'] = array('sspmod_consent_Logout', 'postLogout');
diff --git a/modules/consent/www/noconsent.php b/modules/consent/www/noconsent.php
index 06e5554c0ea7868e802c0622705ecacfd0346ae7..37b5920117a250715eaf794232ef29522561d12d 100644
--- a/modules/consent/www/noconsent.php
+++ b/modules/consent/www/noconsent.php
@@ -12,6 +12,13 @@ if (!array_key_exists('StateId', $_REQUEST)) {
 }
 
 $id = $_REQUEST['StateId'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'consent:request');
 
 $resumeFrom = SimpleSAML_Module::getModuleURL(
diff --git a/modules/core/lib/Auth/UserPassBase.php b/modules/core/lib/Auth/UserPassBase.php
index 633a7484afce369e9d2df6416edfeb910ca3d183..c7ff0bebebaf068296a33793c4d2aa1ee038d878 100644
--- a/modules/core/lib/Auth/UserPassBase.php
+++ b/modules/core/lib/Auth/UserPassBase.php
@@ -197,6 +197,12 @@ abstract class sspmod_core_Auth_UserPassBase extends SimpleSAML_Auth_Source {
 		assert('is_string($username)');
 		assert('is_string($password)');
 
+		// sanitize the input
+		$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId);
+		if (!is_null($restartURL)) {
+			SimpleSAML_Utilities::checkURLAllowed($restartURL);
+		}
+
 		/* Here we retrieve the state array we saved in the authenticate-function. */
 		$state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
 
diff --git a/modules/core/lib/Auth/UserPassOrgBase.php b/modules/core/lib/Auth/UserPassOrgBase.php
index f79c3aefa265b47339434a03d5528d349426e4c5..9c7af9731f17ea33bbf7f28864e6db8612e606ff 100644
--- a/modules/core/lib/Auth/UserPassOrgBase.php
+++ b/modules/core/lib/Auth/UserPassOrgBase.php
@@ -209,6 +209,12 @@ abstract class sspmod_core_Auth_UserPassOrgBase extends SimpleSAML_Auth_Source {
 		assert('is_string($password)');
 		assert('is_string($organization)');
 
+		// sanitize the input
+		$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId);
+		if (!is_null($restartURL)) {
+			SimpleSAML_Utilities::checkURLAllowed($restartURL);
+		}
+
 		/* Retrieve the authentication state. */
 		$state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
 
@@ -257,6 +263,12 @@ abstract class sspmod_core_Auth_UserPassOrgBase extends SimpleSAML_Auth_Source {
 	public static function listOrganizations($authStateId) {
 		assert('is_string($authStateId)');
 
+		// sanitize the input
+		$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId);
+		if (!is_null($restartURL)) {
+			SimpleSAML_Utilities::checkURLAllowed($restartURL);
+		}
+
 		/* Retrieve the authentication state. */
 		$state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
 
diff --git a/modules/core/www/as_login.php b/modules/core/www/as_login.php
index a30bd1f77f3c08c2d1f6695d2df52ac863fabf04..09c07209cf4c108f85d51317a862b33ba9dc7770 100644
--- a/modules/core/www/as_login.php
+++ b/modules/core/www/as_login.php
@@ -19,7 +19,7 @@ if (!is_string($_REQUEST['AuthId'])) {
  * Setting up the options for the requireAuth() call later..
  */
 $options = array(
-	'ReturnTo' => $_REQUEST['ReturnTo'],
+	'ReturnTo' => SimpleSAML_Utilities::checkURLAllowed($_REQUEST['ReturnTo']),
 );
 
 /*
@@ -30,9 +30,7 @@ if (!empty($_REQUEST['saml:idp'])) {
 	$options['saml:idp'] = $_REQUEST['saml:idp'];
 }
 
-
-
 $as = new SimpleSAML_Auth_Simple($_REQUEST['AuthId']);
 $as->requireAuth($options);
 
-SimpleSAML_Utilities::redirectUntrustedURL($_REQUEST['ReturnTo']);
+SimpleSAML_Utilities::redirectTrustedURL($options['ReturnTo']);
diff --git a/modules/core/www/as_logout.php b/modules/core/www/as_logout.php
index 5ae8a39c3d59eda109097e1ef77644967b6b971c..dad67d213ff2234adb08232de77353baae8ddb18 100644
--- a/modules/core/www/as_logout.php
+++ b/modules/core/www/as_logout.php
@@ -16,4 +16,4 @@ if (!isset($_REQUEST['AuthId']) || !is_string($_REQUEST['AuthId'])) {
 }
 
 $as = new SimpleSAML_Auth_Simple($_REQUEST['AuthId']);
-$as->logout($_REQUEST['ReturnTo']);
+$as->logout(SimpleSAML_Utilities::checkURLAllowed($_REQUEST['ReturnTo']));
diff --git a/modules/core/www/bwc_resumeauth.php b/modules/core/www/bwc_resumeauth.php
index 68b2055049e7659819f1f320e297068f9362dcd5..df937077d15ff6dd58e05c0a82893465a2e9e07f 100644
--- a/modules/core/www/bwc_resumeauth.php
+++ b/modules/core/www/bwc_resumeauth.php
@@ -20,7 +20,7 @@ if ($requestcache['ForceAuthn'] && $requestcache['core:prevSession'] === $sessio
 }
 
 if (isset($state['ReturnTo'])) {
-	SimpleSAML_Utilities::redirectUntrustedURL($state['ReturnTo']);
+	SimpleSAML_Utilities::redirectTrustedURL($state['ReturnTo']);
 }
 
 foreach ($session->getAuthState($authority) as $k => $v) {
diff --git a/modules/core/www/cleardiscochoices.php b/modules/core/www/cleardiscochoices.php
index c94e411e211b4bef7f01f54becd4d04957862c45..afd72997fea12bd52d4ea6987401adf59cc6694d 100644
--- a/modules/core/www/cleardiscochoices.php
+++ b/modules/core/www/cleardiscochoices.php
@@ -26,12 +26,12 @@ foreach($_COOKIE as $cookieName => $value) {
 
 /* Find where we should go now. */
 if(array_key_exists('ReturnTo', $_REQUEST)) {
-	$returnTo = $_REQUEST['ReturnTo'];
+	$returnTo = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['ReturnTo']);
 } else {
 	/* Return to the front page if no other destination is given. This is the same as the base cookie path. */
 	$returnTo = $cookiePath;
 }
 
 /* Redirect to destination. */
-SimpleSAML_Utilities::redirectUntrustedURL($returnTo);
+SimpleSAML_Utilities::redirectTrustedURL($returnTo);
 
diff --git a/modules/core/www/idp/logout-iframe-done.php b/modules/core/www/idp/logout-iframe-done.php
index 72a1e26f78085e5b6ba7574b92188c91e470c36a..62539988b6f5d08a8d01f40e4077e13aa7f69799 100644
--- a/modules/core/www/idp/logout-iframe-done.php
+++ b/modules/core/www/idp/logout-iframe-done.php
@@ -5,6 +5,12 @@ if (!isset($_REQUEST['id'])) {
 }
 $id = (string)$_REQUEST['id'];
 
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'core:Logout-IFrame');
 $idp = SimpleSAML_IdP::getByState($state);
 
diff --git a/modules/core/www/idp/logout-iframe.php b/modules/core/www/idp/logout-iframe.php
index 1b751e931b2ba112e6ae6dacad25c6297b5c3f5a..53cdcfc94f564062204dde3bab462c4cf6721f6f 100644
--- a/modules/core/www/idp/logout-iframe.php
+++ b/modules/core/www/idp/logout-iframe.php
@@ -19,6 +19,12 @@ if ($type !== 'embed' && $type !== 'async') {
 	SimpleSAML_Stats::log('core:idp:logout-iframe:page', array('type' => $type));
 }
 
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'core:Logout-IFrame');
 $idp = SimpleSAML_IdP::getByState($state);
 
diff --git a/modules/core/www/idp/resumelogout.php b/modules/core/www/idp/resumelogout.php
index 37c3e60f5eaf936ae93ab479947b70cf13501206..f93c8e968365e40dac78e8650c19cab765e67f1e 100644
--- a/modules/core/www/idp/resumelogout.php
+++ b/modules/core/www/idp/resumelogout.php
@@ -5,6 +5,12 @@ if (!isset($_REQUEST['id'])) {
 }
 $id = (string)$_REQUEST['id'];
 
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'core:Logout:afterbridge');
 $idp = SimpleSAML_IdP::getByState($state);
 
diff --git a/modules/core/www/login-admin.php b/modules/core/www/login-admin.php
index 83886a181a27edac1954710c04bdfe3b2ab5e5fd..3e6438f3ea10e3b2dea80fb3da1ea30d3c6a48c9 100644
--- a/modules/core/www/login-admin.php
+++ b/modules/core/www/login-admin.php
@@ -6,9 +6,8 @@
 if (!array_key_exists('ReturnTo', $_REQUEST)) {
 	throw new SimpleSAML_Error_BadRequest('Missing ReturnTo parameter.');
 }
-$returnTo = $_REQUEST['ReturnTo'];
 
 SimpleSAML_Utilities::requireAdmin();
 
-SimpleSAML_Utilities::redirectUntrustedURL($returnTo);
+SimpleSAML_Utilities::redirectUntrustedURL($_REQUEST['ReturnTo']);
 
diff --git a/modules/core/www/loginuserpass.php b/modules/core/www/loginuserpass.php
index 71da3aeaee7481e25c881e23a4c4bbaf737f0d98..cda363b4015e35804d89cc55546b5c0d98919b41 100644
--- a/modules/core/www/loginuserpass.php
+++ b/modules/core/www/loginuserpass.php
@@ -15,6 +15,12 @@ if (!array_key_exists('AuthState', $_REQUEST)) {
 }
 $authStateId = $_REQUEST['AuthState'];
 
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 /* Retrieve the authentication state. */
 $state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_core_Auth_UserPassBase::STAGEID);
 
diff --git a/modules/core/www/loginuserpassorg.php b/modules/core/www/loginuserpassorg.php
index cda773bfc47fffca8aa66c1070dfbb1145baa61b..abd9a532e563c6bf30d2117ccb4682bf22a2ff77 100644
--- a/modules/core/www/loginuserpassorg.php
+++ b/modules/core/www/loginuserpassorg.php
@@ -15,6 +15,12 @@ if (!array_key_exists('AuthState', $_REQUEST)) {
 }
 $authStateId = $_REQUEST['AuthState'];
 
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 /* Retrieve the authentication state. */
 $state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_core_Auth_UserPassOrgBase::STAGEID);
 
diff --git a/modules/core/www/short_sso_interval.php b/modules/core/www/short_sso_interval.php
index 5a51470a338ed201d09cadf748498443bacd56e6..e9e5b159dd65fff01b4eabf2b86b4c8b3e9495a4 100644
--- a/modules/core/www/short_sso_interval.php
+++ b/modules/core/www/short_sso_interval.php
@@ -12,6 +12,13 @@ if (!array_key_exists('StateId', $_REQUEST)) {
 }
 
 $id = $_REQUEST['StateId'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'core:short_sso_interval');
 
 if (array_key_exists('continue', $_REQUEST)) {
diff --git a/modules/discopower/lib/PowerIdPDisco.php b/modules/discopower/lib/PowerIdPDisco.php
index 22459312b45df8850a1c794a770786a49be37c83..10aad002f4e8dc62106da0ba069cc58a4bc2d87e 100644
--- a/modules/discopower/lib/PowerIdPDisco.php
+++ b/modules/discopower/lib/PowerIdPDisco.php
@@ -203,7 +203,7 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco {
 				
 			} else {
 				$this->log('Choice made [' . $idp . '] (Redirecting the user back. returnIDParam=' . $this->returnIdParam . ')');
-				SimpleSAML_Utilities::redirectUntrustedURL($this->returnURL, array($this->returnIdParam => $idp));
+				SimpleSAML_Utilities::redirectTrustedURL($this->returnURL, array($this->returnIdParam => $idp));
 			}
 			
 			return;
@@ -211,7 +211,7 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco {
 		
 		if ($this->isPassive) {
 			$this->log('Choice not made. (Redirecting the user back without answer)');
-			SimpleSAML_Utilities::redirectUntrustedURL($this->returnURL);
+			SimpleSAML_Utilities::redirectTrustedURL($this->returnURL);
 			return;
 		}
 
diff --git a/modules/exampleauth/lib/Auth/Source/External.php b/modules/exampleauth/lib/Auth/Source/External.php
index d3b16f020c19ca4d64edac6971d2fcaaf169456d..282c6a46da301c5e61f54093b5bb7e6ff16e2491 100644
--- a/modules/exampleauth/lib/Auth/Source/External.php
+++ b/modules/exampleauth/lib/Auth/Source/External.php
@@ -186,6 +186,12 @@ class sspmod_exampleauth_Auth_Source_External extends SimpleSAML_Auth_Source {
 		}
 		$stateId = (string)$_REQUEST['State'];
 
+		// sanitize the input
+		$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId);
+		if (!is_null($restartURL)) {
+			SimpleSAML_Utilities::checkURLAllowed($restartURL);
+		}
+
 		/*
 		 * Once again, note the second parameter to the loadState function. This must
 		 * match the string we used in the saveState-call above.
diff --git a/modules/exampleauth/www/authpage.php b/modules/exampleauth/www/authpage.php
index 21a284b22f29c1e5c6aa19a60d846f11a0f603a5..bcd01b8d4126fa51b821a37ee7b4418469500cab 100644
--- a/modules/exampleauth/www/authpage.php
+++ b/modules/exampleauth/www/authpage.php
@@ -14,7 +14,7 @@ if (!isset($_REQUEST['ReturnTo'])) {
 	die('Missing ReturnTo parameter.');
 }
 
-$returnTo = $_REQUEST['ReturnTo'];
+$returnTo = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['ReturnTo']);
 
 
 /*
@@ -31,6 +31,13 @@ if (!preg_match('@State=(.*)@', $returnTo, $matches)) {
 	die('Invalid ReturnTo URL for this example.');
 }
 $stateId = urldecode($matches[1]);
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 SimpleSAML_Auth_State::loadState($stateId, 'exampleauth:External');
 
 /*
@@ -87,8 +94,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
 		$_SESSION['mail'] = $user['mail'];
 		$_SESSION['type'] = $user['type'];
 
-		header('Location: ' . $returnTo);
-		exit();
+		SimpleSAML_Utilities::redirectTrustedURL($returnTo);
 	}
 }
 
diff --git a/modules/exampleauth/www/redirecttest.php b/modules/exampleauth/www/redirecttest.php
index 39a1b5450b381dbc7c5976c3be4e18f27894e342..c6d4fb86e1aa94d0179f429607e39d9adb06d34b 100644
--- a/modules/exampleauth/www/redirecttest.php
+++ b/modules/exampleauth/www/redirecttest.php
@@ -13,6 +13,13 @@ if (!array_key_exists('StateId', $_REQUEST)) {
 }
 
 $id = $_REQUEST['StateId'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'exampleauth:redirectfilter-test');
 
 $state['Attributes']['RedirectTest2'] = array('OK');
diff --git a/modules/expirycheck/www/about2expire.php b/modules/expirycheck/www/about2expire.php
index c69624723ac223fa571725031458ce2581eb1ba2..487b3f8dffc8679e396c7e2ad3d9a30f86f4a548 100644
--- a/modules/expirycheck/www/about2expire.php
+++ b/modules/expirycheck/www/about2expire.php
@@ -14,6 +14,13 @@ if (!array_key_exists('StateId', $_REQUEST)) {
 }
 
 $id = $_REQUEST['StateId'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'expirywarning:about2expire');
 
 
diff --git a/modules/expirycheck/www/expired.php b/modules/expirycheck/www/expired.php
index 9b94cadbcec3a7df15f5e88aed680b7539571e69..5ec7b93a10505faa1d8299ae99f0734ccb742f45 100644
--- a/modules/expirycheck/www/expired.php
+++ b/modules/expirycheck/www/expired.php
@@ -14,6 +14,13 @@ if (!array_key_exists('StateId', $_REQUEST)) {
 }
 
 $id = $_REQUEST['StateId'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'expirywarning:expired');
 
 $globalConfig = SimpleSAML_Configuration::getInstance();
diff --git a/modules/multiauth/www/selectsource.php b/modules/multiauth/www/selectsource.php
index 329a1bf4909c26e82fedd3ee899da06d18ab12dd..afa28ed50d7a39acc49fa0f1288bfcf3328c75f3 100644
--- a/modules/multiauth/www/selectsource.php
+++ b/modules/multiauth/www/selectsource.php
@@ -16,6 +16,12 @@ if (!array_key_exists('AuthState', $_REQUEST)) {
 }
 $authStateId = $_REQUEST['AuthState'];
 
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 /* Retrieve the authentication state. */
 $state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_multiauth_Auth_Source_MultiAuth::STAGEID);
 
diff --git a/modules/negotiate/www/backend.php b/modules/negotiate/www/backend.php
index f9d3622296bcf95b3ac7fcd170ddc782a8c9e1b3..347ce8dc9689584df7c9b9c50778c4c0275c6315 100644
--- a/modules/negotiate/www/backend.php
+++ b/modules/negotiate/www/backend.php
@@ -10,6 +10,13 @@
  */
 
 $authStateId = $_REQUEST['AuthState'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_negotiate_Auth_Source_Negotiate::STAGEID);
 SimpleSAML_Logger::debug('backend - fallback: '.$state['LogoutState']['negotiate:backend']);
 
diff --git a/modules/negotiate/www/retry.php b/modules/negotiate/www/retry.php
index 2d12eab97ebe92777c8108b067a8aed5e1472a4b..858b8367875a3d4e8d317d3dc2128de69c520546 100644
--- a/modules/negotiate/www/retry.php
+++ b/modules/negotiate/www/retry.php
@@ -10,6 +10,13 @@
  */
 
 $authStateId = $_REQUEST['AuthState'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($authStateId);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_negotiate_Auth_Source_Negotiate::STAGEID);
 
 $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
diff --git a/modules/oauth/www/authorize.php b/modules/oauth/www/authorize.php
index 9b3e032e12bb4fe24347835b5fa8aa69f3b4d40c..583c86efc924ca084c73ff3e8021ca8fbe50b634 100644
--- a/modules/oauth/www/authorize.php
+++ b/modules/oauth/www/authorize.php
@@ -56,7 +56,7 @@ try {
 
 	if ($url) {
 		// If authorize() returns a URL, take user there (oauth1.0a)
-		SimpleSAML_Utilities::redirectUntrustedURL($url);
+		SimpleSAML_Utilities::redirectTrustedURL($url);
 	} 
 	else if (isset($_REQUEST['oauth_callback'])) {
 		// If callback was provided in the request (oauth1.0)
diff --git a/modules/openid/www/consumer.php b/modules/openid/www/consumer.php
index 889fbf59c158f56801437d8eb92d0500ad7a00f1..0f8067c0e95276c4353883f2cfa72ed1d009fb4b 100644
--- a/modules/openid/www/consumer.php
+++ b/modules/openid/www/consumer.php
@@ -6,6 +6,13 @@ if (!array_key_exists('AuthState', $_REQUEST) || empty($_REQUEST['AuthState']))
 }
 
 $authState = $_REQUEST['AuthState'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($authState);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($authState, 'openid:init');
 $sourceId = $state['openid:AuthId'];
 $authSource = SimpleSAML_Auth_Source::getById($sourceId);
diff --git a/modules/openid/www/linkback.php b/modules/openid/www/linkback.php
index 180f9e18e3e081b1d5e9a52f2ac1a0ba8440a7c5..6108ca73e3ff53268acad343eb2272de1738e0df 100644
--- a/modules/openid/www/linkback.php
+++ b/modules/openid/www/linkback.php
@@ -6,6 +6,13 @@ if (!array_key_exists('AuthState', $_REQUEST) || empty($_REQUEST['AuthState']))
 }
 
 $authState = $_REQUEST['AuthState'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($authState);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($authState, 'openid:auth');
 $sourceId = $state['openid:AuthId'];
 $authSource = SimpleSAML_Auth_Source::getById($sourceId);
diff --git a/modules/openidProvider/lib/Server.php b/modules/openidProvider/lib/Server.php
index f0596d18fa1e5a0fd68add0ee9494ab1929d55aa..1382cd84dd72dd4c8b3135dbb70ba0b7d65fff48 100644
--- a/modules/openidProvider/lib/Server.php
+++ b/modules/openidProvider/lib/Server.php
@@ -329,6 +329,12 @@ class sspmod_openidProvider_Server {
 	public function loadState($stateId) {
 		assert('is_string($stateId)');
 
+		// sanitize the input
+		$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId);
+		if (!is_null($restartURL)) {
+			SimpleSAML_Utilities::checkURLAllowed($restartURL);
+		}
+
 		return SimpleSAML_Auth_State::loadState($stateId, 'openidProvider:resumeState');
 	}
 
diff --git a/modules/papi/lib/Auth/Source/PAPI.php b/modules/papi/lib/Auth/Source/PAPI.php
index ead66c8832a1b69ec5e6adaa9864bf965d2d0437..c074093460763cee6db69cb07fdd343185f9b941 100644
--- a/modules/papi/lib/Auth/Source/PAPI.php
+++ b/modules/papi/lib/Auth/Source/PAPI.php
@@ -115,6 +115,13 @@ class sspmod_papi_Auth_Source_PAPI extends SimpleSAML_Auth_Source {
         if (isset($_REQUEST['SSPStateID'])) {
 			// yes! restore original request
            	$this->_stateId = (string)$_REQUEST['SSPStateID'];
+           	
+			// sanitize the input
+			$restartURL = SimpleSAML_Utilities::getURLFromStateID($this->_stateId);
+			if (!is_null($restartURL)) {
+				SimpleSAML_Utilities::checkURLAllowed($restartURL);
+			}
+
            	$state = SimpleSAML_Auth_State::loadState($this->_stateId, self::STAGE_INIT);
 		} else if (!$this->_poa->isAuthenticated()) { 
 			// no! we have to save the request
@@ -161,6 +168,13 @@ class sspmod_papi_Auth_Source_PAPI extends SimpleSAML_Auth_Source {
     		$this->_poa->logout(true);
     	} else if (isset($_REQUEST['SSPStateID'])) {
     		$this->_stateId = (string)$_REQUEST['SSPStateID'];
+
+			// sanitize the input
+			$restartURL = SimpleSAML_Utilities::getURLFromStateID($this->_stateId);
+			if (!is_null($restartURL)) {
+				SimpleSAML_Utilities::checkURLAllowed($restartURL);
+			}
+
     		$state = SimpleSAML_Auth_State::loadState($this->_stateId, self::STAGE_INIT);
     	} else {
     		return;
diff --git a/modules/preprodwarning/www/showwarning.php b/modules/preprodwarning/www/showwarning.php
index d8db6456098bc8323af431fd49ab195f2c27292a..2c50860dd7a933d891115af6998751fe7c3f486d 100644
--- a/modules/preprodwarning/www/showwarning.php
+++ b/modules/preprodwarning/www/showwarning.php
@@ -15,6 +15,13 @@ if (!array_key_exists('StateId', $_REQUEST)) {
 }
 
 $id = $_REQUEST['StateId'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($id);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
 $state = SimpleSAML_Auth_State::loadState($id, 'warning:request');
 
 
diff --git a/modules/saml/www/sp/discoresp.php b/modules/saml/www/sp/discoresp.php
index 6d9af381ed1ac06bf985052aff6f67f527f57d2d..1479f8a42b8d7fb95e17c1255e6a7590e7f74401 100644
--- a/modules/saml/www/sp/discoresp.php
+++ b/modules/saml/www/sp/discoresp.php
@@ -12,7 +12,15 @@ if (!array_key_exists('idpentityid', $_REQUEST)) {
 	throw new SimpleSAML_Error_BadRequest('Missing idpentityid to discovery service response handler');
 }
 
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['AuthID'], 'saml:sp:sso');
+$stateID = $_REQUEST['AuthID'];
+
+// sanitize the input
+$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateID);
+if (!is_null($restartURL)) {
+	SimpleSAML_Utilities::checkURLAllowed($restartURL);
+}
+
+$state = SimpleSAML_Auth_State::loadState($stateID, 'saml:sp:sso');
 
 /* Find authentication source. */
 assert('array_key_exists("saml:sp:AuthId", $state)');
diff --git a/modules/saml/www/sp/saml1-acs.php b/modules/saml/www/sp/saml1-acs.php
index 28ba7114382ac2881dc0f766246b4bd5a97df7ba..d9a594c5ef90f8b2fec969074be8d90e41548183 100644
--- a/modules/saml/www/sp/saml1-acs.php
+++ b/modules/saml/www/sp/saml1-acs.php
@@ -19,17 +19,25 @@ $source = SimpleSAML_Auth_Source::getById($sourceId, 'sspmod_saml_Auth_Source_SP
 
 SimpleSAML_Logger::debug('Received SAML1 response');
 
-
 $target = (string)$_REQUEST['TARGET'];
+
 if (preg_match('@^https?://@i', $target)) {
 	/* Unsolicited response. */
 	$state = array(
 		'saml:sp:isUnsolicited' => TRUE,
 		'saml:sp:AuthId' => $sourceId,
-		'saml:sp:RelayState' => $target,
+		'saml:sp:RelayState' => SimpleSAML_Utilities::checkURLAllowed($target),
 	);
 } else {
-	$state = SimpleSAML_Auth_State::loadState($_REQUEST['TARGET'], 'saml:sp:sso');
+	$stateID = $_REQUEST['TARGET'];
+
+	// sanitize the input
+	$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateID);
+	if (!is_null($restartURL)) {
+		SimpleSAML_Utilities::checkURLAllowed($restartURL);
+	}
+
+	$state = SimpleSAML_Auth_State::loadState($stateID, 'saml:sp:sso');
 
 	/* Check that the authentication source is correct. */
 	assert('array_key_exists("saml:sp:AuthId", $state)');
@@ -80,4 +88,4 @@ $state['LogoutState'] = $logoutState;
 $source->handleResponse($state, $responseIssuer, $attributes);
 assert('FALSE');
 
-?>
\ No newline at end of file
+?>
diff --git a/modules/saml/www/sp/saml2-acs.php b/modules/saml/www/sp/saml2-acs.php
index a3c8200bcdc1033ed12537edaf282d7eacee527b..09723b64235cab45fbd49d67ea94b819de6d99f8 100644
--- a/modules/saml/www/sp/saml2-acs.php
+++ b/modules/saml/www/sp/saml2-acs.php
@@ -52,6 +52,13 @@ $idpMetadata = array();
 
 $stateId = $response->getInResponseTo();
 if (!empty($stateId)) {
+
+	// sanitize the input
+	$restartURL = SimpleSAML_Utilities::getURLFromStateID($stateId);
+	if (!is_null($restartURL)) {
+		SimpleSAML_Utilities::checkURLAllowed($restartURL);
+	}
+
 	/* This is a response to a request we sent earlier. */
 	$state = SimpleSAML_Auth_State::loadState($stateId, 'saml:sp:sso');
 
@@ -75,7 +82,7 @@ if (!empty($stateId)) {
 	$state = array(
 		'saml:sp:isUnsolicited' => TRUE,
 		'saml:sp:AuthId' => $sourceId,
-		'saml:sp:RelayState' => $response->getRelayState(),
+		'saml:sp:RelayState' => SimpleSAML_Utilities::checkURLAllowed($response->getRelayState()),
 	);
 }
 
diff --git a/modules/saml/www/sp/saml2-logout.php b/modules/saml/www/sp/saml2-logout.php
index d2b26b06e9113e4198503b2b14635c1ea68caa68..5d360243338c93e0a45a2653a87ebe51c894e6a3 100644
--- a/modules/saml/www/sp/saml2-logout.php
+++ b/modules/saml/www/sp/saml2-logout.php
@@ -54,6 +54,12 @@ if ($message instanceof SAML2_LogoutResponse) {
 		SimpleSAML_Logger::warning('Unsuccessful logout. Status was: ' . sspmod_saml_Message::getResponseError($message));
 	}
 
+	// sanitize the input
+	$restartURL = SimpleSAML_Utilities::getURLFromStateID($relayState);
+	if (!is_null($restartURL)) {
+		SimpleSAML_Utilities::checkURLAllowed($restartURL);
+	}
+
 	$state = SimpleSAML_Auth_State::loadState($relayState, 'saml:slosent');
 	$state['saml:sp:LogoutStatus'] = $message->getStatus();
 	SimpleSAML_Auth_Source::completeLogout($state);
diff --git a/www/auth/login-admin.php b/www/auth/login-admin.php
index 42ac0ecf0b66d816353d7ce86051ecfb2d9bfe04..597b353aa1a097708679447373a8a4f61dd5278b 100644
--- a/www/auth/login-admin.php
+++ b/www/auth/login-admin.php
@@ -20,7 +20,7 @@ if (!array_key_exists('RelayState', $_REQUEST)) {
 	throw new SimpleSAML_Error_Error('NORELAYSTATE');
 }
 
-$relaystate = $_REQUEST['RelayState'];
+$relaystate = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']);
 
 $correctpassword = $config->getString('auth.adminpassword', '123');
 
@@ -59,7 +59,7 @@ if (isset($_POST['password'])) {
 		else 
 			SimpleSAML_Logger::stats('AUTH-login-admin OK');
 		
-		SimpleSAML_Utilities::redirectUntrustedURL($relaystate);
+		SimpleSAML_Utilities::redirectTrustedURL($relaystate);
 		exit(0);
 	} else {
 		SimpleSAML_Logger::stats('AUTH-login-admin Failed');
@@ -82,6 +82,3 @@ if (isset($error)) {
 }
 
 $t->show();
-
-
-?>
diff --git a/www/auth/login-cas-ldap.php b/www/auth/login-cas-ldap.php
index 2ba907adee87641ea11519194a456fc3e4d737e7..281488d97c9e50d1119f484facd2b05db9f9fd90 100644
--- a/www/auth/login-cas-ldap.php
+++ b/www/auth/login-cas-ldap.php
@@ -30,8 +30,6 @@ try {
 
 	$casconfig = $casldapconfig[$idpentityid]['cas'];
 	$ldapconfig = $casldapconfig[$idpentityid]['ldap'];
-	
-	
 } catch (Exception $exception) {
 	throw new SimpleSAML_Error_Error('METADATA', $exception);
 }
@@ -44,8 +42,6 @@ if (!array_key_exists('RelayState', $_REQUEST)) {
 	throw new SimpleSAML_Error_Error('NORELAYSTATE');
 }
 
-
-
 function casValidate($cas) {
 
 	$service = SimpleSAML_Utilities::selfURL();
@@ -110,12 +106,7 @@ function casValidate($cas) {
 	}
 }
 
-
-
 try {
-	
-	$relaystate = $_REQUEST['RelayState'];
-
 	list($username, $casattributes) = casValidate($casconfig);
 	
 	SimpleSAML_Logger::info('AUTH - cas-ldap: '. $username . ' authenticated by ' . $casconfig['validate']);
@@ -132,11 +123,9 @@ try {
 	$session->setNameID(array(
 			'value' => SimpleSAML_Utilities::generateID(),
 			'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'));
-	SimpleSAML_Utilities::redirectUntrustedURL($relaystate);
+
+	SimpleSAML_Utilities::redirectUntrustedURL($_REQUEST['RelayState']);
 
 } catch(Exception $exception) {
 	throw new SimpleSAML_Error_Error('CASERROR', $exception);
 }
-
-
-?>
\ No newline at end of file
diff --git a/www/auth/login-ldapmulti.php b/www/auth/login-ldapmulti.php
index aab198afc883877f6eecf1b1e197ad1739a7246f..169800bc3387361467ad7236efe893fd8b8d7164 100644
--- a/www/auth/login-ldapmulti.php
+++ b/www/auth/login-ldapmulti.php
@@ -10,7 +10,6 @@ $session = SimpleSAML_Session::getInstance();
 $ldapconfigfile = $config->getBaseDir() . 'config/ldapmulti.php';
 require_once($ldapconfigfile);
 
-
 SimpleSAML_Logger::info('AUTH - ldap-multi: Accessing auth endpoint login-ldapmulti');
 
 $error = null;
@@ -23,6 +22,8 @@ if (!array_key_exists('RelayState', $_REQUEST)) {
 	throw new SimpleSAML_Error_Error('NORELAYSTATE');
 }
 
+$relaystate = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']);
+
 if (isset($_POST['username'])) {
 
 	try {
@@ -50,8 +51,7 @@ if (isset($_POST['username'])) {
 		$attributes = $ldap->getAttributes($dn, $ldapconfig['attributes']);
 						
 		SimpleSAML_Logger::info('AUTH - ldap-multi: '. $_POST['username'] . ' successfully authenticated');
-				
-				
+
 		$session->doLogin('login-ldapmulti');
 		$session->setAttributes($attributes);
 				
@@ -64,19 +64,16 @@ if (isset($_POST['username'])) {
 		 * Also log a specific attribute as set in the config: statistics.authlogattr
 		 */
 		$authlogattr = $config->getValue('statistics.authlogattr', null);
-		if ($authlogattr && array_key_exists($authlogattr, $attributes)) 
+		if ($authlogattr && array_key_exists($authlogattr, $attributes)) {
 			SimpleSAML_Logger::stats('AUTH-login-ldapmulti OK ' . $attributes[$authlogattr][0]);
-		else 
+		} else {
 			SimpleSAML_Logger::stats('AUTH-login-ldapmulti OK');
-				
-				
-		$returnto = $_REQUEST['RelayState'];
-		SimpleSAML_Utilities::redirectUntrustedURL($returnto);
+		}
+
+		SimpleSAML_Utilities::redirectTrustedURL($relaystate);
 
 	} catch (Exception $e) {
-		
 		$error = $e->getMessage();
-		
 	}	
 }
 
@@ -84,7 +81,7 @@ if (isset($_POST['username'])) {
 $t = new SimpleSAML_XHTML_Template($config, 'login-ldapmulti.php', 'login');
 
 $t->data['header'] = 'simpleSAMLphp: Enter username and password';	
-$t->data['relaystate'] = $_REQUEST['RelayState'];
+$t->data['relaystate'] = $relaystate;
 $t->data['ldapconfig'] = $ldapmulti;
 $t->data['org'] = $_REQUEST['org'];
 $t->data['error'] = $error;
diff --git a/www/auth/login-radius.php b/www/auth/login-radius.php
index b95c7ae92a304a4964937859c1db7344259566f8..5a80f49f0ebd1d32a1549ea3542d8629d41ec0ac 100644
--- a/www/auth/login-radius.php
+++ b/www/auth/login-radius.php
@@ -19,6 +19,8 @@ if (!array_key_exists('RelayState', $_REQUEST)) {
 	throw new SimpleSAML_Error_Error('NORELAYSTATE');
 }
 
+$relaystate = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']);
+
 if (isset($_POST['username'])) {
 
 
@@ -97,21 +99,18 @@ if (isset($_POST['username'])) {
 					'value' => SimpleSAML_Utilities::generateID(),
 					'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'));
 
-				
 				/**
 				 * Create a statistics log entry for every successfull login attempt.
 				 * Also log a specific attribute as set in the config: statistics.authlogattr
 				 */
 				$authlogattr = $config->getValue('statistics.authlogattr', null);
-				if ($authlogattr && array_key_exists($authlogattr, $attributes)) 
+				if ($authlogattr && array_key_exists($authlogattr, $attributes)) {
 					SimpleSAML_Logger::stats('AUTH-login-radius OK ' . $attributes[$authlogattr][0]);
-				else 
+				} else {
 					SimpleSAML_Logger::stats('AUTH-login-radius OK');
+				}
 
-	
-				$returnto = $_REQUEST['RelayState'];
-				SimpleSAML_Utilities::redirectUntrustedURL($returnto);
-				
+				SimpleSAML_Utilities::redirectTrustedURL($relaystate);
 	
 			case RADIUS_ACCESS_REJECT:
 			
@@ -125,13 +124,10 @@ if (isset($_POST['username'])) {
 			default:
 				SimpleSAML_Logger::critical('AUTH  -radius: General radius error: ' . radius_strerror($radius));
 				throw new Exception('Error during radius authentication: ' . radius_strerror($radius));
-				
 		}
 
 	} catch (Exception $e) {
-		
 		$error = $e->getMessage();
-		
 	}
 }
 
@@ -139,13 +135,10 @@ if (isset($_POST['username'])) {
 $t = new SimpleSAML_XHTML_Template($config, 'login.php', 'login');
 
 $t->data['header'] = 'simpleSAMLphp: Enter username and password';	
-$t->data['relaystate'] = $_REQUEST['RelayState'];
+$t->data['relaystate'] = $relaystate;
 $t->data['error'] = $error;
 if (isset($error)) {
 	$t->data['username'] = $_POST['username'];
 }
 
 $t->show();
-
-
-?>
diff --git a/www/auth/login-tlsclient.php b/www/auth/login-tlsclient.php
index 42e2678ae679d6ab94f870cd9f405ee1601a9602..0fb6e93925ca83a4f067816b866da2d23eba3d6f 100644
--- a/www/auth/login-tlsclient.php
+++ b/www/auth/login-tlsclient.php
@@ -23,9 +23,6 @@ if (!array_key_exists('RelayState', $_REQUEST)) {
 	throw new SimpleSAML_Error_Error('NORELAYSTATE');
 }
 
-$relaystate = $_REQUEST['RelayState'];
-
-
 try {
 
 	$attributes = array();
@@ -55,21 +52,21 @@ try {
 	
 	$session->setNameID(array(
 		'value' => SimpleSAML_Utilities::generateID(),
-		'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'));
+		'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient')
+	);
 		
 	/**
 	 * Create a statistics log entry for every successfull login attempt.
 	 * Also log a specific attribute as set in the config: statistics.authlogattr
 	 */
 	$authlogattr = $config->getValue('statistics.authlogattr', null);
-	if ($authlogattr && array_key_exists($authlogattr, $attributes)) 
+	if ($authlogattr && array_key_exists($authlogattr, $attributes)) {
 		SimpleSAML_Logger::stats('AUTH-tlsclient OK ' . $attributes[$authlogattr][0]);
-	else 
+	} else {
 		SimpleSAML_Logger::stats('AUTH-tlsclient OK');
-		
+	}
 
-	$returnto = $_REQUEST['RelayState'];
-	SimpleSAML_Utilities::redirectUntrustedURL($returnto);
+	SimpleSAML_Utilities::redirectUntrustedURL($_REQUEST['RelayState']);
 	
 	
 } catch (Exception $e) {
diff --git a/www/auth/login-wayf-ldap.php b/www/auth/login-wayf-ldap.php
index 73d5f57a4cf3b6dfc676922e82ecd732b7f44d69..9c8c25e52ea91cb9af03815fe36a83ad775665b6 100644
--- a/www/auth/login-wayf-ldap.php
+++ b/www/auth/login-wayf-ldap.php
@@ -42,7 +42,7 @@ if (!array_key_exists('RelayState', $_REQUEST)) {
 	throw new SimpleSAML_Error_Error('NORELAYSTATE');
 }
 
-$relaystate = $_REQUEST['RelayState'];
+$relaystate = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']);
 
 if ($username = $_POST['username']) {
 	try {
@@ -59,7 +59,7 @@ if ($username = $_POST['username']) {
 			$session->setNameID(array(
 					'value' => SimpleSAML_Utilities::generateID(),
 					'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'));
-			SimpleSAML_Utilities::redirectUntrustedURL($relaystate);
+			SimpleSAML_Utilities::redirectTrustedURL($relaystate);
 		}
 	} catch(Exception $e) {
 			throw new SimpleSAML_Error_Error('LDAPERROR', $e);
diff --git a/www/saml2/idp/SingleLogoutService.php b/www/saml2/idp/SingleLogoutService.php
index 618068cd88d3d413ba16cfc9494390598a5f6a36..45a1012a416e56665b2a6deedd11ad062f8905db 100644
--- a/www/saml2/idp/SingleLogoutService.php
+++ b/www/saml2/idp/SingleLogoutService.php
@@ -18,7 +18,7 @@ $idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
 $idp = SimpleSAML_IdP::getById('saml2:' . $idpEntityId);
 
 if (isset($_REQUEST['ReturnTo'])) {
-	$idp->doLogoutRedirect((string)$_REQUEST['ReturnTo']);
+	$idp->doLogoutRedirect(SimpleSAML_Utilities::checkURLAllowed((string)$_REQUEST['ReturnTo']));
 } else {
 	sspmod_saml_IdP_SAML2::receiveLogoutMessage($idp);
 }
diff --git a/www/saml2/idp/idpInitSingleLogoutServiceiFrame.php b/www/saml2/idp/idpInitSingleLogoutServiceiFrame.php
index 24f89b013842c4198538f47b9b45ab85851a7972..977265932c688928987d2c654cf5a4608725bce0 100644
--- a/www/saml2/idp/idpInitSingleLogoutServiceiFrame.php
+++ b/www/saml2/idp/idpInitSingleLogoutServiceiFrame.php
@@ -16,5 +16,5 @@ if (!isset($_REQUEST['RelayState'])) {
 	throw new SimpleSAML_Error_BadRequest('Missing required RelayState parameter.');
 }
 
-$idp->doLogoutRedirect((string)$_REQUEST['RelayState']);
+$idp->doLogoutRedirect(SimpleSAML_Utilities::checkURLAllowed((string)$_REQUEST['RelayState']));
 assert('FALSE');
diff --git a/www/saml2/idp/initSLO.php b/www/saml2/idp/initSLO.php
index d6b23adc351ac62e75e4c311dcc770f7d86fdb92..87191b7772776197e317132bc239fb526da994f4 100644
--- a/www/saml2/idp/initSLO.php
+++ b/www/saml2/idp/initSLO.php
@@ -11,6 +11,5 @@ if (!isset($_GET['RelayState'])) {
 	throw new SimpleSAML_Error_Error('NORELAYSTATE');
 }
 
-$returnTo = (string)$_GET['RelayState'];
-$idp->doLogoutRedirect($returnTo);
+$idp->doLogoutRedirect(SimpleSAML_Utilities::checkURLAllowed((string)$_GET['RelayState']));
 assert('FALSE');
\ No newline at end of file
diff --git a/www/saml2/sp/AssertionConsumerService.php b/www/saml2/sp/AssertionConsumerService.php
index e024489bacacfeb7f4bf46d9336928789de8deee..c7dc96f29034204b7502c5e8b0558355d3806bcd 100644
--- a/www/saml2/sp/AssertionConsumerService.php
+++ b/www/saml2/sp/AssertionConsumerService.php
@@ -47,7 +47,7 @@ function finishLogin($authProcState) {
 	global $session;
 	$session->doLogin('saml2', $authData);
 
-	SimpleSAML_Utilities::redirectUntrustedURL($authProcState['core:saml20-sp:TargetURL']);
+	SimpleSAML_Utilities::redirectTrustedURL($authProcState['core:saml20-sp:TargetURL']);
 }
 
 SimpleSAML_Logger::info('SAML2.0 - SP.AssertionConsumerService: Accessing SAML 2.0 SP endpoint AssertionConsumerService');
@@ -59,6 +59,13 @@ if (array_key_exists(SimpleSAML_Auth_ProcessingChain::AUTHPARAM, $_REQUEST)) {
 	/* We have returned from the authentication processing filters. */
 
 	$authProcId = $_REQUEST[SimpleSAML_Auth_ProcessingChain::AUTHPARAM];
+
+	// sanitize the input
+	$restartURL = SimpleSAML_Utilities::getURLFromStateID($authProcId);
+	if (!is_null($restartURL)) {
+		SimpleSAML_Utilities::checkURLAllowed($restartURL);
+	}
+
 	$authProcState = SimpleSAML_Auth_ProcessingChain::fetchProcessedState($authProcId);
 	finishLogin($authProcState);
 }
@@ -93,7 +100,7 @@ try {
 	if($info === NULL) {
 		/* Fall back to RelayState. */
 		$info = array();
-		$info['RelayState'] = $response->getRelayState();
+		$info['RelayState'] = SimpleSAML_Utilities::checkURLAllowed($response->getRelayState());
 		if(empty($info['RelayState'])) {
 			$info['RelayState'] = $spMetadata->getString('RelayState', NULL);
 		}
diff --git a/www/saml2/sp/SingleLogoutService.php b/www/saml2/sp/SingleLogoutService.php
index 0bd8c731e412223cde8ff8aa11c8f76bd33c3ea2..cf9f94cd06e761b6486da833236206cc2a6aa581 100644
--- a/www/saml2/sp/SingleLogoutService.php
+++ b/www/saml2/sp/SingleLogoutService.php
@@ -83,12 +83,14 @@ if ($message instanceof SAML2_LogoutRequest) {
 		$id = $message->getInResponseTo();
 	}
 
+	// 'spLogoutReturnTo' is checked before storing it in the
+	// session, so we trust it here.
 	$returnTo = $session->getData('spLogoutReturnTo', $id);
 	if (empty($returnTo)) {
 		throw new SimpleSAML_Error_Error('LOGOUTINFOLOST');
 	}
 
-	SimpleSAML_Utilities::redirectUntrustedURL($returnTo);
+	SimpleSAML_Utilities::redirectTrustedURL($returnTo);
 
 } else {
 	throw new SimpleSAML_Error_Error('SLOSERVICEPARAMS');
diff --git a/www/saml2/sp/initSLO.php b/www/saml2/sp/initSLO.php
index 8402a36c0de27cc35fa4f3686f9d1f751bf32abc..85c13bbe0540698e5215e7f4ffbc39cc5aa9ea7c 100644
--- a/www/saml2/sp/initSLO.php
+++ b/www/saml2/sp/initSLO.php
@@ -13,7 +13,7 @@ if (!$config->getBoolean('enable.saml20-sp', TRUE))
 
 
 if (isset($_REQUEST['RelayState'])) {
-	$returnTo = $_REQUEST['RelayState'];
+	$returnTo = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']);
 } else {
 	throw new SimpleSAML_Error_Error('NORELAYSTATE');
 }
@@ -25,7 +25,7 @@ try {
 	$idpEntityId = $session->getAuthData('saml2', 'saml:sp:IdP');
 	if ($idpEntityId === NULL) {
 		SimpleSAML_Logger::info('SAML2.0 - SP.initSLO: User not authenticated with an IdP.');
-		SimpleSAML_Utilities::redirectUntrustedURL($returnTo);
+		SimpleSAML_Utilities::redirectTrustedURL($returnTo);
 	}
 	$idpMetadata = $metadata->getMetaDataConfig($idpEntityId, 'saml20-idp-remote');
 	$SLOendpoint = $idpMetadata->getEndpointPrioritizedByBinding('SingleLogoutService', array(
@@ -34,8 +34,8 @@ try {
 		NULL);
 	if ($SLOendpoint === NULL) {
 		$session->doLogout('saml2');
-		SimpleSAML_Logger::info('SAML2.0 - SP.initSLO: No supported SingleLogoutService endpoint in IdP.');
-		SimpleSAML_Utilities::redirectUntrustedURL($returnTo);
+		SimpleSAML_Logger::info('SAML2.0 - SP.initSLO: No SingleLogoutService endpoint supported in the IdP.');
+		SimpleSAML_Utilities::redirectTrustedURL($returnTo);
 	}
 
 	$spEntityId = isset($_GET['spentityid']) ? $_GET['spentityid'] : $metadata->getMetaDataCurrentEntityID();
diff --git a/www/saml2/sp/initSSO.php b/www/saml2/sp/initSSO.php
index a9ee60fbe114ca143c4a5e4b835e92bafcd3ff7d..c6d17803688c9318dd1b4f983199f880732a9543 100644
--- a/www/saml2/sp/initSSO.php
+++ b/www/saml2/sp/initSSO.php
@@ -23,6 +23,7 @@ if (!$config->getBoolean('enable.saml20-sp', TRUE))
 if (empty($_GET['RelayState'])) {
 	throw new SimpleSAML_Error_Error('NORELAYSTATE');
 }
+$returnTo = SimpleSAML_Utilities::checkURLAllowed($_GET['RelayState']);
 
 $reachableIDPs = array();
 
@@ -134,7 +135,7 @@ try {
 
 	$assertionConsumerServiceURL = $metadata->getGenerated('AssertionConsumerService', 'saml20-sp-hosted');
 	$ar->setAssertionConsumerServiceURL($assertionConsumerServiceURL);
-	$ar->setRelayState($_REQUEST['RelayState']);
+	$ar->setRelayState($returnTo);
 
 	if ($isPassive) {
 		$ar->setIsPassive(TRUE);
@@ -156,9 +157,9 @@ try {
 
 	/* Save request information. */
 	$info = array();
-	$info['RelayState'] = $_REQUEST['RelayState'];
+	$info['RelayState'] = $returnTo;
 	if(array_key_exists('OnError', $_REQUEST)) {
-		$info['OnError'] = $_REQUEST['OnError'];
+		$info['OnError'] = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['OnError']);
 	}
 	$session->setData('SAML2:SP:SSO:Info', $ar->getId(), $info);
 
diff --git a/www/shib13/sp/AssertionConsumerService.php b/www/shib13/sp/AssertionConsumerService.php
index f523c28a47f08e0a84f90365be34c615521b7c40..bc5a4368ca3683205dd675c4286f71cfb867af67 100644
--- a/www/shib13/sp/AssertionConsumerService.php
+++ b/www/shib13/sp/AssertionConsumerService.php
@@ -47,6 +47,13 @@ if (array_key_exists(SimpleSAML_Auth_ProcessingChain::AUTHPARAM, $_REQUEST)) {
 	/* We have returned from the authentication processing filters. */
 
 	$authProcId = $_REQUEST[SimpleSAML_Auth_ProcessingChain::AUTHPARAM];
+
+	// sanitize the input
+	$restartURL = SimpleSAML_Utilities::getURLFromStateID($authProcId);
+	if (!is_null($restartURL)) {
+		SimpleSAML_Utilities::checkURLAllowed($restartURL);
+	}
+
 	$authProcState = SimpleSAML_Auth_ProcessingChain::fetchProcessedState($authProcId);
 	finishLogin($authProcState);
 }
@@ -86,7 +93,7 @@ try {
 	$authProcState = array(
 		'core:shib13-sp:NameID' => $authnResponse->getNameID(),
 		'core:shib13-sp:SessionIndex' => $authnResponse->getSessionIndex(),
-		'core:shib13-sp:TargetURL' => $relayState,
+		'core:shib13-sp:TargetURL' => SimpleSAML_Utilities::checkURLAllowed($relayState),
 		'ReturnURL' => SimpleSAML_Utilities::selfURLNoQuery(),
 		'Attributes' => $authnResponse->getAttributes(),
 		'Destination' => $spmetadata,
diff --git a/www/shib13/sp/initSSO.php b/www/shib13/sp/initSSO.php
index d666b8b86901a11bb950a19d88f104c57d29de29..5d40daae2b1835216d1c5487ff68f60309783184 100644
--- a/www/shib13/sp/initSSO.php
+++ b/www/shib13/sp/initSSO.php
@@ -70,7 +70,7 @@ if (!isset($session) || !$session->isValid('shib13') ) {
 		$ar = new SimpleSAML_XML_Shib13_AuthnRequest();
 		$ar->setIssuer($spentityid);	
 		if(isset($_GET['RelayState'])) 
-			$ar->setRelayState($_GET['RelayState']);
+			$ar->setRelayState(SimpleSAML_Utilities::checkURLAllowed($_GET['RelayState']));
 
 		SimpleSAML_Logger::info('Shib1.3 - SP.initSSO: SP (' . $spentityid . ') is sending AuthNRequest to IdP (' . $idpentityid . ')');
 
diff --git a/www/wsfed/sp/initSLO.php b/www/wsfed/sp/initSLO.php
index f31ebaaca2480ba1ed8720171fd2016d031030d3..318bfa2feb8d9e5cb81f7472172da253e0fe8551 100644
--- a/www/wsfed/sp/initSLO.php
+++ b/www/wsfed/sp/initSLO.php
@@ -13,7 +13,7 @@ if (!$config->getBoolean('enable.wsfed-sp', false))
 
 
 if (isset($_REQUEST['RelayState'])) {
-	$returnTo = $_REQUEST['RelayState'];
+	$returnTo = SimpleSAML_Utilities::checkURLAllowed($_REQUEST['RelayState']);
 } else {
 	throw new SimpleSAML_Error_Error('NORELAYSTATE');
 }
@@ -53,7 +53,7 @@ if (isset($session) ) {
 } else {
 
 	SimpleSAML_Logger::info('WS-Fed - SP.initSLO: User is already logged out. Go back to relaystate');
-	SimpleSAML_Utilities::redirectUntrustedURL($returnTo);
+	SimpleSAML_Utilities::redirectTrustedURL($returnTo);
 	
 }
 
diff --git a/www/wsfed/sp/initSSO.php b/www/wsfed/sp/initSSO.php
index 0e0b8613fdb009514264ac60189aa44fd3b6a166..f3f1ec7d7d56420ae42930b9b74eff235f18ba3b 100644
--- a/www/wsfed/sp/initSSO.php
+++ b/www/wsfed/sp/initSSO.php
@@ -46,7 +46,7 @@ if ($idpentityid == null) {
 }
 
 try {
-	$relaystate = $_GET['RelayState'];
+	$relaystate = SimpleSAML_Utilities::checkURLAllowed($_GET['RelayState']);
 	
 	$idpmeta = $metadata->getMetaData($idpentityid, 'wsfed-idp-remote');
 	$spmeta = $metadata->getMetaData($spentityid, 'wsfed-sp-hosted');