diff --git a/includes/common.inc b/includes/common.inc
index 0906f8714b0f548c61d64822a07f5d9742e60592..2de18d1fe3560c6ddfe802eb7fd79fa7df7d8a29 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -362,6 +362,11 @@ function drupal_not_found() {
 
   watchdog('page not found', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);
 
+  // Keep old path for reference, and to allow forms to redirect to it.
+  if (!isset($_REQUEST['destination'])) {
+    $_REQUEST['destination'] = $_GET['q'];
+  }
+
   $path = drupal_get_normal_path(variable_get('site_404', ''));
   if ($path && $path != $_GET['q']) {
     // Custom 404 handler. Set the active item in case there are tabs to
@@ -389,9 +394,13 @@ function drupal_not_found() {
  */
 function drupal_access_denied() {
   drupal_set_header('403 Forbidden');
-
   watchdog('access denied', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);
 
+  // Keep old path for reference, and to allow forms to redirect to it.
+  if (!isset($_REQUEST['destination'])) {
+    $_REQUEST['destination'] = $_GET['q'];
+  }
+
   $path = drupal_get_normal_path(variable_get('site_403', ''));
   if ($path && $path != $_GET['q']) {
     // Custom 403 handler. Set the active item in case there are tabs to
diff --git a/modules/search/search.module b/modules/search/search.module
index 1fd065536e09cdd89a80ecbffc8220f4e3fd204a..479010d972c197e270a099a47a584b95a590a35f 100644
--- a/modules/search/search.module
+++ b/modules/search/search.module
@@ -1116,6 +1116,14 @@ function search_box(&$form_state, $form_id) {
  * Process a block search form submission.
  */
 function search_box_form_submit($form, &$form_state) {
+  // The search form relies on control of the redirect destination for its
+  // functionality, so we override any static destination set in the request,
+  // for example by drupal_access_denied() or drupal_not_found()
+  // (see http://drupal.org/node/292565).
+  if (isset($_REQUEST['destination'])) {
+    unset($_REQUEST['destination']);
+  }
+
   $form_id = $form['form_id']['#value'];
   $form_state['redirect'] = 'search/node/' . trim($form_state['values'][$form_id]);
 }
diff --git a/modules/system/system.test b/modules/system/system.test
index ad262e03f88a438ca64e05f3ee2ec32cfded6920..a48cbd95a719193aa6ab207d3fde12c407bd571b 100644
--- a/modules/system/system.test
+++ b/modules/system/system.test
@@ -510,7 +510,7 @@ class AccessDeniedTestCase extends DrupalWebTestCase {
     parent::setUp();
 
     // Create an administrative user.
-    $this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
+    $this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer blocks'));
     $this->drupalLogin($this->admin_user);
   }
 
@@ -547,6 +547,22 @@ class AccessDeniedTestCase extends DrupalWebTestCase {
     $this->drupalGet('admin');
     $this->assertText(t('Access denied'), t('Found the default 403 page'));
     $this->assertText(t('User login'), t('Blocks are shown on the default 403 page'));
+
+    // Log back in, set the custom 403 page to /user and remove the block
+    $this->drupalLogin($this->admin_user);
+    variable_set('site_403', 'user');
+    $this->drupalPost('admin/structure/block', array('user_login[region]' => '-1'), t('Save blocks'));
+
+    // Check that we can log in from the 403 page.
+    $this->drupalLogout();
+    $edit = array(
+      'name' => $this->admin_user->name,
+      'pass' => $this->admin_user->pass_raw,
+    );
+    $this->drupalPost('admin/settings/site-information', $edit, t('Log in'));
+
+    // Check that we're still on the same page.
+    $this->assertText(t('Site information'));
   }
 }