diff --git includes/ajax.inc includes/ajax.inc
index 910bfe4..aea7449 100644
--- includes/ajax.inc
+++ includes/ajax.inc
@@ -322,7 +322,7 @@ function ajax_form_callback() {
 
   // This call recreates the form relying solely on the $form_state that
   // drupal_process_form() set up.
-  $form = drupal_rebuild_form($form_id, $form_state, $form_build_id);
+  $form = ajax_rebuild_form($form_id, $form_state, $form['#action'], $form_build_id);
 
   // $triggering_element_path in a simple form might just be 'myselect', which
   // would mean we should use the element $form['myselect']. For nested form
@@ -517,6 +517,65 @@ function ajax_process_form($element, &$form_state) {
 }
 
 /**
+ * Retrieves a form, caches it and processes it again setting the action of the
+ * old form.
+ *
+ * If your AHAH callback simulates the pressing of a button, then your AHAH
+ * callback will need to do the same as what drupal_get_form would do when the
+ * button is pressed: get the form from the cache, run drupal_process_form over
+ * it and then if it needs rebuild, run ajax_rebuild_form over it. Then send
+ * back a part of the returned form.
+ * $form_state['clicked_button']['#array_parents'] will help you to find which
+ * part.
+ *
+ * @param $form_id
+ *   The unique string identifying the desired form. If a function
+ *   with that name exists, it is called to build the form array.
+ *   Modules that need to generate the same form (or very similar forms)
+ *   using different $form_ids can implement hook_forms(), which maps
+ *   different $form_id values to the proper form constructor function. Examples
+ *   may be found in node_forms(), search_forms(), and user_forms().
+ * @param $form_state
+ *   A keyed array containing the current state of the form.
+ * @param $form_action
+ *   The action property of the form.
+ * @param $form_build_id
+ *   Form cache id used to re-cache the form with the same csid.
+ * @return
+ *   The newly built form.
+ */
+ function ajax_rebuild_form($form_id, &$form_state, $form_action, $form_build_id) {
+  // AJAX forms call ajax_rebuild_form() even when $form_state['rebuild']
+  // isn't set, but _form_builder_handle_input_element() needs to distinguish a
+  // rebuild from an initial build in order to process user input correctly.
+  // Form constructors and form processing functions may also need to handle a
+  // rebuild differently than an initial build.
+  $form_state['rebuild'] = TRUE;
+
+  $form = drupal_retrieve_form($form_id, $form_state);
+
+  $form['#build_id'] = $form_build_id;
+  drupal_prepare_form($form_id, $form, $form_state);
+
+  $form['#action'] = $form_action;
+
+  if (empty($form_state['no_cache'])) {
+    // We cache the form structure and the form state so it can be retrieved
+    // later for validation.
+    form_set_cache($form_build_id, $form, $form_state);
+  }
+
+  // Clear out all group associations as these might be different when
+  // re-rendering the form.
+  $form_state['groups'] = array();
+
+  // Do not call drupal_process_form(), since it would prevent the rebuilt form
+  // to submit.
+  $form = form_builder($form_id, $form, $form_state);
+  return $form;
+}
+
+/**
  * @} End of "defgroup ajax".
  */
 
diff --git includes/form.inc includes/form.inc
index d4386f4..a293c4a 100644
--- includes/form.inc
+++ includes/form.inc
@@ -286,14 +286,6 @@ function form_state_defaults() {
 /**
  * Retrieves a form, caches it and processes it again.
  *
- * If your AHAH callback simulates the pressing of a button, then your AHAH
- * callback will need to do the same as what drupal_get_form would do when the
- * button is pressed: get the form from the cache, run drupal_process_form over
- * it and then if it needs rebuild, run drupal_rebuild_form over it. Then send
- * back a part of the returned form.
- * $form_state['clicked_button']['#array_parents'] will help you to find which
- * part.
- *
  * @param $form_id
  *   The unique string identifying the desired form. If a function
  *   with that name exists, it is called to build the form array.
@@ -303,34 +295,26 @@ function form_state_defaults() {
  *   may be found in node_forms(), search_forms(), and user_forms().
  * @param $form_state
  *   A keyed array containing the current state of the form.
- * @param $form_build_id
- *   If the AHAH callback calling this function only alters part of the form,
- *   then pass in the existing form_build_id so we can re-cache with the same
- *   csid.
  * @return
  *   The newly built form.
  */
-function drupal_rebuild_form($form_id, &$form_state, $form_build_id = NULL) {
-  // AJAX and other contexts may call drupal_rebuild_form() even when
-  // $form_state['rebuild'] isn't set, but _form_builder_handle_input_element()
-  // needs to distinguish a rebuild from an initial build in order to process
-  // user input correctly. Form constructors and form processing functions may
-  // also need to handle a rebuild differently than an initial build.
+function drupal_rebuild_form($form_id, &$form_state) {
+  // Contexts may call drupal_rebuild_form() even when $form_state['rebuild']
+  // isn't set, but _form_builder_handle_input_element() needs to distinguish a 
+  // rebuild from an initial build in order to process user input correctly.
+  // Form constructors and form processing functions may also need to handle a
+  // rebuild differently than an initial build.
   $form_state['rebuild'] = TRUE;
 
   $form = drupal_retrieve_form($form_id, $form_state);
 
-  if (!isset($form_build_id)) {
-    // We need a new build_id for the new version of the form.
-    $form_build_id = 'form-' . md5(mt_rand());
-  }
-  $form['#build_id'] = $form_build_id;
+  $form['#build_id'] = 'form-' . md5(mt_rand());
   drupal_prepare_form($form_id, $form, $form_state);
 
   if (empty($form_state['no_cache'])) {
     // We cache the form structure and the form state so it can be retrieved
     // later for validation.
-    form_set_cache($form_build_id, $form, $form_state);
+    form_set_cache($form['#build_id'], $form, $form_state);
   }
 
   // Clear out all group associations as these might be different when
diff --git modules/file/file.module modules/file/file.module
index 03e3812..c1ae7df 100644
--- modules/file/file.module
+++ modules/file/file.module
@@ -239,7 +239,7 @@ function file_ajax_upload() {
 
   // This call recreates the form relying solely on the form_state that the
   // drupal_process_form() set up.
-  $form = drupal_rebuild_form($form_id, $form_state, $form_build_id);
+  $form = ajax_rebuild_form($form_id, $form_state, $form['#action'], $form_build_id);
 
   // Retrieve the element to be rendered.
   foreach ($form_parents as $parent) {
diff --git modules/simpletest/tests/ajax.test modules/simpletest/tests/ajax.test
index 7417e4f..28e7d0d 100644
--- modules/simpletest/tests/ajax.test
+++ modules/simpletest/tests/ajax.test
@@ -189,3 +189,48 @@ class AJAXFormValuesTestCase extends AJAXTestCase {
     }
   }
 }
+
+/**
+ * Tests to ensure the original form action is preserved via ajax_rebuild_form.
+ */
+class AJAXFormActionTestCase extends AJAXTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'AJAX form action',
+      'description' => 'Tests to ensure the original form action is preserved across AJAX requests.',
+      'group' => 'AJAX',
+    );
+  }
+
+  /**
+   * Test to make sure the form action is preserved for
+   * ajax_forms_test_get_form.
+   */
+  function testAJAXAction() {
+    $form_action = 'ajax_forms_test_get_form';
+    $this->drupalGet($form_action);
+
+    // Parse the form for the form build id.
+    $build_id_element = $this->xpath('//form[@id="ajax-forms-test-simple-form"]/div/input[@name="form_build_id"]');
+    $build_id = FALSE;
+    foreach ($build_id_element[0]->attributes() as $key => $value) {
+      if ($key == 'value') {
+        $build_id = $value;
+      }
+    }
+
+    $this->assertTrue($build_id, t('Found form build id @id', array('@id' => $build_id)));
+
+    $form_state = array(
+      'build_info' => array(
+        'args' => array(
+          array(),
+          array(),
+        ),
+      ),
+    );
+    $rebuilt_form = ajax_rebuild_form('ajax_forms_test_simple_form', $form_state, $form_action, $build_id);
+
+    $this->assertEqual($rebuilt_form['#action'], $form_action, 'Form action was preserved across AJAX request');
+  }
+}
