diff --git a/core/modules/path/path.module b/core/modules/path/path.module
index 67fc536..5ee92e1 100644
--- a/core/modules/path/path.module
+++ b/core/modules/path/path.module
@@ -178,11 +178,58 @@ function path_form_element_validate($element, &$form_state, $complete_form) {
     $query->range(0, 1);
     if ($query->execute()->fetchField()) {
       form_error($element, t('The alias is already in use.'));
+    } else {
+      // If it isn't a duplicate, it still might be invalid.
+      $valid = path_alias_is_valid($path['alias']);
+      if ($valid !== TRUE) {
+        form_error($element, $valid);
+      }
     }
   }
 }
 
 /**
+ * Validates that a path alias is valid.
+ *
+ * @param $alias
+ *   A string containing the alias in question.
+ *
+ * @return
+ *   TRUE if the alias is valid, otherwise the error message.
+ */
+function path_alias_is_valid($alias) {
+  $alias = strtolower(trim($alias, '/ '));
+
+  // We could create an alias that would conflict with another node/user/taxonomy
+  // later on, so we need to take account of that. (e.g. Create node 7
+  // with the alias 'node/9/delete'. It will make it impossible to delete
+  // node 9 later on without modifying node 7 first.)
+  $parts = explode('/', $alias, 2);
+  $restricted_paths = array('node', 'taxonomy', 'user');
+  if (in_array($parts[0], $restricted_paths)) {
+    return t('The alias cannot start with "@part"', array('@part' => $parts[0]));
+  }
+
+  // Verify that no other module has reserved this address
+  $router_item = menu_get_item($alias);
+  if (!empty($router_item)) {
+    return t('The alias is reserved by the system');
+  }
+  
+  // Before invoking Drupal, the webserver will first check the local
+  // filesystem for files/folders that match the path, so Drupal cannot
+  // match any path that would match an item on the filesystem.
+  // Additionally, .htaccess redirects some D7 paths to their D8 counterparts
+  // (e.g. cron.php). Those have to be enumerated and checked seperately.
+  $restricted_files = array('install.php', 'cron.php', 'update.php');
+  if (file_exists($alias) || in_array($alias, $restricted_files)) {
+    return t('The alias conflicts with an item on the filesystem');
+  }
+
+  return TRUE;
+}
+
+/**
  * Implements hook_node_insert().
  */
 function path_node_insert($node) {
diff --git a/core/modules/path/path.test b/core/modules/path/path.test
index d652654..7b37554 100644
--- a/core/modules/path/path.test
+++ b/core/modules/path/path.test
@@ -212,6 +212,27 @@ class PathAliasTestCase extends PathTestCase {
     $this->assertText(t('The alias is already in use.'));
     $this->assertFieldByXPath("//input[@name='path[alias]' and contains(@class, 'error')]", $edit['path[alias]'], 'Textfield exists and has the error class.');
   }
+
+  /**
+   * Tests that only valid aliases pass path_alias_is_valid().
+   */
+  function testPathAliasIsValid() {
+    $tests = array(
+      'admin' => 'The alias is reserved by the system',
+      '/Admin/content/' => 'The alias is reserved by the system',
+      'Update.php' => 'The alias conflicts with an item on the filesystem',
+      'core/modules' => 'The alias conflicts with an item on the filesystem',
+      'node/10000/edit' => 'The alias cannot start with "node"',
+      'User' => 'The alias cannot start with "user"',
+      'user/login' => 'The alias cannot start with "user"',
+      'users_are_people_too' => TRUE,
+      'dries-sings-the-drupal-song' => TRUE,
+    );
+    foreach ($tests AS $alias => $expected) {
+      $result = path_alias_is_valid($alias);
+      $this->assertIdentical($expected, $result);
+    }
+  }
 }
 
 /**
