diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php
index fe6d104..350286f 100644
--- a/core/lib/Drupal/Core/Form/FormBuilder.php
+++ b/core/lib/Drupal/Core/Form/FormBuilder.php
@@ -19,6 +19,7 @@
 use Drupal\Core\Form\Exception\BrokenPostRequestException;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Render\ElementInfoManagerInterface;
+use Drupal\Core\Site\Settings;
 use Drupal\Core\Theme\ThemeManagerInterface;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
@@ -603,6 +604,20 @@ public function processForm($form_id, &$form, FormStateInterface &$form_state) {
   }
 
   /**
+   * #lazy_builder callback; renders a form action URL.
+   *
+   * @return array
+   *   A renderable array representing the form action.
+   */
+  public function renderPlaceholderFormAction() {
+    return [
+      '#type' => 'markup',
+      '#markup' => $this->buildFormAction(),
+      '#cache' => ['contexts' => ['url']],
+    ];
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function prepareForm($form_id, &$form, FormStateInterface &$form_state) {
@@ -612,7 +627,17 @@ public function prepareForm($form_id, &$form, FormStateInterface &$form_state) {
 
     // Only update the action if it is not already set.
     if (!isset($form['#action'])) {
-      $form['#action'] = $this->buildFormAction();
+      // Generate a placeholder and a render array to replace it.
+      $placeholder = hash('sha1', 'form_action');
+      $placeholder_render_array = [
+        '#lazy_builder' => ['form_builder:renderPlaceholderFormAction', []],
+      ];
+
+      // Instead of setting an actual action URL, we set the placeholder, which
+      // will be replaced at the very last moment. This ensures forms with
+      // dynamically generated action URLs don't break cacheability.
+      $form['#attached']['placeholders'][$placeholder] = $placeholder_render_array;
+      $form['#action'] = $placeholder;
     }
 
     // Fix the form method, if it is 'get' in $form_state, but not in $form.
diff --git a/core/modules/block/src/Tests/BlockFormInBlockTest.php b/core/modules/block/src/Tests/BlockFormInBlockTest.php
new file mode 100644
index 0000000..ea2fbdd
--- /dev/null
+++ b/core/modules/block/src/Tests/BlockFormInBlockTest.php
@@ -0,0 +1,127 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\Tests\BlockFormInBlockTest.
+ */
+
+namespace Drupal\block\Tests;
+
+use Drupal\Core\Cache\Cache;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests form in block caching.
+ *
+ * @group block
+ */
+class BlockFormInBlockTest extends WebTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = ['block', 'block_test', 'test_page_test'];
+
+  /**
+   * A user with permission to create and edit books and to administer blocks.
+   *
+   * @var object
+   */
+  protected $adminUser;
+
+  /**
+   * An authenticated user to test block caching.
+   *
+   * @var object
+   */
+  protected $normalUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Create an admin user, log in and enable test blocks.
+    $this->adminUser = $this->drupalCreateUser(['administer blocks', 'access administration pages']);
+    $this->drupalLogin($this->adminUser);
+
+    // Create additional users to test caching modes.
+    $this->normalUser = $this->drupalCreateUser();
+    $this->drupalLogin($this->normalUser);
+
+    // Enable our test block.
+   $this->drupalPlaceBlock('test_form_in_block');
+  }
+
+  /**
+   * Test to see if form in block's redirect isn't cached.
+   */
+  function testCachePerPage() {
+    $form_values = ['email' => 'test@example.com'];
+
+    // Go to "test-page" and test if the block is enabled.
+    $this->drupalGet('test-page');
+    $this->assertResponse(200);
+    $this->assertText('Your .com email address.', 'form found');
+
+    // Make sure that we're currently still on /test-page after submitting the
+    // form.
+    $this->drupalPostForm(NULL, $form_values, t('Submit'));
+    $this->assertUrl('test-page');
+    $this->assertText(t('Your email address is @email', ['@email' => 'test@example.com']));
+
+    // Go to a different page and see if the block is enabled there as well.
+    $this->drupalGet('test-render-title');
+    $this->assertResponse(200);
+    $this->assertText('Your .com email address.', 'form found');
+
+    // Make sure that submitting the form didn't redirect us to the first page
+    // we submitted the form from after submitting the form from
+    // /test-render-title.
+    $this->drupalPostForm(NULL, $form_values, t('Submit'));
+    $this->assertUrl('test-render-title');
+    $this->assertText(t('Your email address is @email', ['@email' => 'test@example.com']));
+  }
+
+  /**
+   * When there are two forms on the same page, that
+   */
+  public function testMultipleFormsPerPage() {
+    $this->drupalPlaceBlock('test_favorite_animal_in_block');
+
+    // Go to "test-page" and test if the block are enabled.
+    $this->drupalGet('test-page');
+    $this->assertResponse(200);
+    $this->assertText('Your .com email address.', 'form found');
+    $this->assertText('Your favorite animal.', 'Favorite Animal form found');
+
+    // Make sure that we're currently still on /test-page after submitting the
+    // form.
+    $this->drupalPostForm(NULL, ['email' => 'test@example.com'], t('Submit'));
+    $this->assertUrl('test-page');
+    $this->assertText(t('Your email address is @email', ['@email' => 'test@example.com']));
+
+    // Make sure that we're currently still on /test-page after submitting the
+    // second form.
+    $this->drupalPostForm(NULL, ['favorite_animal' => 'Llama'], t('Submit your chosen animal'));
+    $this->assertUrl('test-page');
+    $this->assertText(t('Your favorite animal is: @favorite_animal', ['@favorite_animal' => 'Llama']));
+
+    // Go to a different page and see if the blocks are enabled there as well.
+    $this->drupalGet('test-render-title');
+    $this->assertResponse(200);
+    $this->assertText('Your .com email address.', 'form found');
+    $this->assertText('Your favorite animal.', 'Favorite Animal form found');
+
+    // Make sure that submitting the form didn't redirect us to the first page
+    // we submitted the form from after submitting the form from
+    // /test-render-title.
+    $this->drupalPostForm(NULL, ['favorite_animal' => 'kitten'], t('Submit your chosen animal'));
+    $this->assertUrl('test-render-title');
+    $this->assertText(t('Your favorite animal is: @favorite_animal', ['@favorite_animal' => 'kitten']));
+  }
+
+}
diff --git a/core/modules/block/tests/modules/block_test/src/Form/FavoriteAnimalTestForm.php b/core/modules/block/tests/modules/block_test/src/Form/FavoriteAnimalTestForm.php
new file mode 100644
index 0000000..2e40675
--- /dev/null
+++ b/core/modules/block/tests/modules/block_test/src/Form/FavoriteAnimalTestForm.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_test\Form\FavoriteAnimalTestForm.
+ */
+
+namespace Drupal\block_test\Form;
+
+use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
+
+class FavoriteAnimalTestForm extends FormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'block_test_form_favorite_animal_test';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $form['favorite_animal'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Your favorite animal.')
+    ];
+
+    $form['submit_animal'] = [
+      '#type' => 'submit',
+      '#value' => $this->t('Submit your chosen animal'),
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    drupal_set_message($this->t('Your favorite animal is: @favorite_animal', ['@favorite_animal' => $form['favorite_animal']['#value']]));
+  }
+
+}
diff --git a/core/modules/block/tests/modules/block_test/src/Form/TestForm.php b/core/modules/block/tests/modules/block_test/src/Form/TestForm.php
new file mode 100644
index 0000000..c0a0694
--- /dev/null
+++ b/core/modules/block/tests/modules/block_test/src/Form/TestForm.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_test\Form\TestForm.
+ */
+
+namespace Drupal\block_test\Form;
+
+use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
+
+class TestForm extends FormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'block_test_form_test';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $form['email'] = [
+      '#type' => 'email',
+      '#title' => $this->t('Your .com email address.')
+    ];
+
+    $form['show'] = [
+      '#type' => 'submit',
+      '#value' => $this->t('Submit'),
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    if (strpos($form_state->getValue('email'), '.com') === FALSE) {
+      $form_state->setErrorByName('email', $this->t('This is not a .com email address.'));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    drupal_set_message($this->t('Your email address is @email', ['@email' => $form['email']['#value']]));
+  }
+
+}
diff --git a/core/modules/block/tests/modules/block_test/src/Plugin/Block/FavoriteAnimalFormBlock.php b/core/modules/block/tests/modules/block_test/src/Plugin/Block/FavoriteAnimalFormBlock.php
new file mode 100644
index 0000000..9129686
--- /dev/null
+++ b/core/modules/block/tests/modules/block_test/src/Plugin/Block/FavoriteAnimalFormBlock.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_test\Plugin\Block\FavoriteAnimalFormBlock.
+ */
+
+namespace Drupal\block_test\Plugin\Block;
+
+use Drupal\Core\Block\BlockBase;
+
+/**
+ * Provides a block to test caching.
+ *
+ * @Block(
+ *   id = "test_favorite_animal_in_block",
+ *   admin_label = @Translation("Test form block caching, favorite animal")
+ * )
+ */
+class FavoriteAnimalFormBlock extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    return \Drupal::formBuilder()->getForm('Drupal\block_test\Form\FavoriteAnimalTestForm');
+  }
+
+}
diff --git a/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestFormBlock.php b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestFormBlock.php
new file mode 100644
index 0000000..feeb9df
--- /dev/null
+++ b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestFormBlock.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_test\Plugin\Block\TestFormBlock.
+ */
+
+namespace Drupal\block_test\Plugin\Block;
+
+use Drupal\Core\Block\BlockBase;
+
+/**
+ * Provides a block to test caching.
+ *
+ * @Block(
+ *   id = "test_form_in_block",
+ *   admin_label = @Translation("Test form block caching")
+ * )
+ */
+class TestFormBlock extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    return \Drupal::formBuilder()->getForm('Drupal\block_test\Form\TestForm');
+  }
+
+}
