diff --git a/core/core.services.yml b/core/core.services.yml
index 5cd3422..9ab7bae 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -1010,6 +1010,10 @@ services:
     arguments: ['@url_generator', '@router.request_context']
     tags:
       - { name: event_subscriber }
+  redirect_leading_slashes:
+    class: Drupal\Core\EventSubscriber\RedirectLeadingSlashes
+    tags:
+      - { name: event_subscriber }
   request_close_subscriber:
     class: Drupal\Core\EventSubscriber\RequestCloseSubscriber
     tags:
diff --git a/core/lib/Drupal/Core/EventSubscriber/RedirectLeadingSlashes.php b/core/lib/Drupal/Core/EventSubscriber/RedirectLeadingSlashes.php
new file mode 100644
index 0000000..5ed1413
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/RedirectLeadingSlashes.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\EventSubscriber\RedirectLeadingSlashes.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Redirects paths starting with multiple slashes to a single slash.
+ */
+class RedirectLeadingSlashes implements EventSubscriberInterface {
+
+  /**
+   * Redirects paths starting with multiple slashes to a single slash.
+   *
+   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+   *   The Event to process.
+   */
+  public function redirect(GetResponseEvent $event) {
+    $request = $event->getRequest();
+    $request_uri = $request->getRequestUri();
+    // It is impossible to create a link or a route to a path starting with
+    // leading slashes. However if a form is added to the 404 page that submits
+    // back to the same URI this presents an open redirect vulnerability.
+    if (strpos($request_uri, '//') === 0) {
+      $request_uri = '/' . ltrim($request_uri, '/');
+      $event->setResponse(new RedirectResponse($request->getUriForPath($request_uri)));
+    }
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('redirect', 1000);
+    return $events;
+  }
+
+}
diff --git a/core/modules/system/src/Tests/Routing/RouterTest.php b/core/modules/system/src/Tests/Routing/RouterTest.php
index 8fbc3f0..161be4b 100644
--- a/core/modules/system/src/Tests/Routing/RouterTest.php
+++ b/core/modules/system/src/Tests/Routing/RouterTest.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\simpletest\WebTestBase;
+use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Exception\RouteNotFoundException;
 
 /**
@@ -248,4 +249,22 @@ public function testRouterUninstallInstall() {
     $route = \Drupal::service('router.route_provider')->getRouteByName('router_test.1');
     $this->assertNotNull($route, 'Route exists after module installation');
   }
+
+  /**
+   * Ensure that multiple leading slashes are redirected.
+   */
+  public function testLeadingSlashes() {
+    // Confirm that the router can get to a controller.
+    $request = $this->container->get('request_stack')->getCurrentRequest();
+    $url = $request->getUriForPath('//router_test/test1');
+    $this->drupalGet($url);
+    $this->assertEqual(1, $this->redirectCount, $url . " redirected to " . $this->url);
+    $this->assertUrl($this->container->get('url_generator')->generateFromPath('router_test/test1'));
+
+    $url = $request->getUriForPath('/////////////////////////////////////////////////router_test/test1');
+    $this->drupalGet($url);
+    $this->assertEqual(1, $this->redirectCount, $url . " redirected to " . $this->url);
+    $this->assertUrl($this->container->get('url_generator')->generateFromPath('router_test/test1'));
+  }
+
 }
diff --git a/core/modules/system/src/Tests/System/UncaughtExceptionTest.php b/core/modules/system/src/Tests/System/UncaughtExceptionTest.php
index b5a3b3d..02f0a82 100644
--- a/core/modules/system/src/Tests/System/UncaughtExceptionTest.php
+++ b/core/modules/system/src/Tests/System/UncaughtExceptionTest.php
@@ -17,6 +17,13 @@
 class UncaughtExceptionTest extends WebTestBase {
 
   /**
+   * Exceptions thrown by site under test that contain this text are ignored.
+   *
+   * @var string
+   */
+  protected $expectedExceptionMessage;
+
+  /**
    * Modules to enable.
    *
    * @var array
@@ -48,6 +55,7 @@ protected function setUp() {
    * Tests uncaught exception handling when system is in a bad state.
    */
   public function testUncaughtException() {
+    $this->expectedExceptionMessage = 'Oh oh, bananas in the instruments.';
     \Drupal::state()->set('error_service_test.break_bare_html_renderer', TRUE);
 
     $this->config('system.logging')
@@ -63,7 +71,7 @@ public function testUncaughtException() {
     $this->drupalGet('');
     $this->assertResponse(500);
     $this->assertText('The website encountered an unexpected error. Please try again later.');
-    $this->assertNoText('Oh oh, bananas in the instruments');
+    $this->assertNoText($this->expectedExceptionMessage);
 
     $this->config('system.logging')
       ->set('error_level', ERROR_REPORTING_DISPLAY_ALL)
@@ -78,30 +86,20 @@ public function testUncaughtException() {
     $this->drupalGet('');
     $this->assertResponse(500);
     $this->assertText('The website encountered an unexpected error. Please try again later.');
-    $this->assertText('Oh oh, bananas in the instruments');
+    $this->assertText($this->expectedExceptionMessage);
+    $this->assertExceptionFailure($this->expectedExceptionMessage, 'Ensure that monekys are found in the control room.');
   }
 
   /**
    * Tests a missing dependency on a service.
    */
   public function testMissingDependency() {
+    $this->expectedExceptionMessage = 'Argument 1 passed to Drupal\error_service_test\LonelyMonkeyClass::__construct() must be an instance of Drupal\Core\Database\Connection, non';
     $this->drupalGet('broken-service-class');
 
-    $message = 'Argument 1 passed to Drupal\error_service_test\LonelyMonkeyClass::__construct() must be an instance of Drupal\Core\Database\Connection, non';
-
     $this->assertRaw('The website encountered an unexpected error.');
-    $this->assertRaw($message);
-
-    $found_exception = FALSE;
-    foreach ($this->assertions as &$assertion) {
-      if (strpos($assertion['message'], $message) !== FALSE) {
-        $found_exception = TRUE;
-        $this->deleteAssert($assertion['message_id']);
-        unset($assertion);
-      }
-    }
-
-    $this->assertTrue($found_exception, 'Ensure that the exception of a missing constructor argument was triggered.');
+    $this->assertRaw($this->expectedExceptionMessage);
+    $this->assertExceptionFailure($this->expectedExceptionMessage, 'Ensure that the exception of a missing constructor argument was triggered.');
   }
 
   /**
@@ -123,21 +121,11 @@ public function testErrorContainer() {
     // process.
     \Drupal::setContainer($this->container);
 
+    $this->expectedExceptionMessage = 'Argument 1 passed to Drupal\system\Tests\Bootstrap\ErrorContainer::Drupal\system\Tests\Bootstrap\{closur';
     $this->drupalGet('');
 
-    $message = 'Argument 1 passed to Drupal\system\Tests\Bootstrap\ErrorContainer::Drupal\system\Tests\Bootstrap\{closur';
-    $this->assertRaw($message);
-
-    $found_error = FALSE;
-    foreach ($this->assertions as &$assertion) {
-      if (strpos($assertion['message'], $message) !== FALSE) {
-        $found_error = TRUE;
-        $this->deleteAssert($assertion['message_id']);
-        unset($assertion);
-      }
-    }
-
-    $this->assertTrue($found_error, 'Ensure that the error of the container was triggered.');
+    $this->assertRaw($this->expectedExceptionMessage);
+    $this->assertExceptionFailure($this->expectedExceptionMessage, 'Ensure that the error of the container was triggered.');
   }
 
   /**
@@ -159,22 +147,13 @@ public function testExceptionContainer() {
     // process.
     \Drupal::setContainer($this->container);
 
+    $this->expectedExceptionMessage = 'Thrown exception during Container::get';
     $this->drupalGet('');
 
-    $message = 'Thrown exception during Container::get';
 
     $this->assertRaw('The website encountered an unexpected error');
-    $this->assertRaw($message);
-
-    $found_exception = FALSE;
-    foreach ($this->assertions as &$assertion) {
-      if (strpos($assertion['message'], $message) !== FALSE) {
-        $found_exception = TRUE;
-        $this->deleteAssert($assertion['message_id']);
-        unset($assertion);
-      }
-    }
-    $this->assertTrue($found_exception, 'Ensure that the exception of the container was triggered.');
+    $this->assertRaw($this->expectedExceptionMessage);
+    $this->assertExceptionFailure($this->expectedExceptionMessage, 'Ensure that the exception of the container was triggered.');
   }
 
   /**
@@ -189,30 +168,43 @@ public function testLostDatabaseConnection() {
     );
     $this->writeSettings($settings);
 
+    $this->expectedExceptionMessage = '[1045] Access denied for user';
     $this->drupalGet('');
 
-    $message = 'Access denied for user';
-    $this->assertRaw($message);
+    $this->assertRaw($this->expectedExceptionMessage);
+    $this->assertExceptionFailure($this->expectedExceptionMessage, 'Ensure that the access denied DB connection exception is thrown.');
+  }
 
+  /**
+   * Asserts that an exception is present in the assertions and removes it.
+   *
+   * This ensures that expected failures are passes rather than failures.
+   *
+   * @param string $exception_message
+   *   The exception message to search for.
+   *
+   * @return bool
+   *   TRUE if the exception message was found.
+   */
+  protected function assertExceptionFailure($exception_message, $message) {
     $found_exception = FALSE;
     foreach ($this->assertions as &$assertion) {
-      if (strpos($assertion['message'], $message) !== FALSE) {
+      if (strpos($assertion['message'], $exception_message) !== FALSE) {
         $found_exception = TRUE;
         $this->deleteAssert($assertion['message_id']);
         unset($assertion);
       }
     }
-    $this->assertTrue($found_exception, 'Ensure that the access denied DB connection exception is thrown.');
-
+    return $this->assertTrue($found_exception, $message);
   }
 
   /**
    * {@inheritdoc}
    */
   protected function error($message = '', $group = 'Other', array $caller = NULL) {
-    if ($message === 'Oh oh, bananas in the instruments.') {
+    if (!empty($this->expectedExceptionMessage) && strpos($message, $this->expectedExceptionMessage) !== FALSE) {
       // We're expecting this error.
-      return;
+      return FALSE;
     }
     return parent::error($message, $group, $caller);
   }
