diff --git a/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php b/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php
index 4f2e23b980b944e23dd2c4bea376c716dee8229a..eed8739ddc891026b3a5df2c380347f33a0ecae6 100644
--- a/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php
+++ b/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php
@@ -7,10 +7,12 @@
 
 namespace Drupal\Core\Entity\Element;
 
+use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\Tags;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element\Textfield;
+use Drupal\Core\Site\Settings;
 use Drupal\user\EntityOwnerInterface;
 
 /**
@@ -112,11 +114,22 @@ public static function processEntityAutocomplete(array &$element, FormStateInter
       $element['#autocreate']['uid'] = isset($element['#autocreate']['uid']) ? $element['#autocreate']['uid'] : \Drupal::currentUser()->id();
     }
 
+    // Store the selection settings in the key/value store and pass a hashed key
+    // in the route parameters.
+    $selection_settings = isset($element['#selection_settings']) ? $element['#selection_settings'] : [];
+    $data = serialize($selection_settings) . $element['#target_type'] . $element['#selection_handler'];
+    $selection_settings_key = Crypt::hmacBase64($data, Settings::getHashSalt());
+
+    $key_value_storage = \Drupal::keyValue('entity_autocomplete');
+    if (!$key_value_storage->has($selection_settings_key)) {
+      $key_value_storage->set($selection_settings_key, $selection_settings);
+    }
+
     $element['#autocomplete_route_name'] = 'system.entity_autocomplete';
     $element['#autocomplete_route_parameters'] = array(
       'target_type' => $element['#target_type'],
       'selection_handler' => $element['#selection_handler'],
-      'selection_settings' => $element['#selection_settings'] ? base64_encode(serialize($element['#selection_settings'])) : '',
+      'selection_settings_key' => $selection_settings_key,
     );
 
     return $element;
diff --git a/core/modules/field/src/Tests/FieldUnitTestBase.php b/core/modules/field/src/Tests/FieldUnitTestBase.php
index 3c2b53546207999b8d72caaed3fec1279dc332d5..9587a4a792d05df015483307b02325a605a6a819 100644
--- a/core/modules/field/src/Tests/FieldUnitTestBase.php
+++ b/core/modules/field/src/Tests/FieldUnitTestBase.php
@@ -50,8 +50,7 @@ protected function setUp() {
 
     $this->installEntitySchema('entity_test');
     $this->installEntitySchema('user');
-    $this->installSchema('system', array('sequences'));
-    $this->installSchema('system', array('router'));
+    $this->installSchema('system', ['router', 'sequences', 'key_value']);
 
     // Set default storage backend and configure the theme system.
     $this->installConfig(array('field', 'system'));
diff --git a/core/modules/system/src/Controller/EntityAutocompleteController.php b/core/modules/system/src/Controller/EntityAutocompleteController.php
index 3da9b853bf9d443f37e439bfe09a86c1968a2e04..44b6596ffd520566a1cf5b0c80c572fefda63118 100644
--- a/core/modules/system/src/Controller/EntityAutocompleteController.php
+++ b/core/modules/system/src/Controller/EntityAutocompleteController.php
@@ -7,13 +7,17 @@
 
 namespace Drupal\system\Controller;
 
+use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\Tags;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Entity\EntityAutocompleteMatcher;
+use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
+use Drupal\Core\Site\Settings;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
 /**
  * Defines a route controller for entity autocomplete form elements.
@@ -27,14 +31,24 @@ class EntityAutocompleteController extends ControllerBase {
    */
   protected $matcher;
 
+  /**
+   * The key value store.
+   *
+   * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
+   */
+  protected $keyValue;
+
   /**
    * Constructs a EntityAutocompleteController object.
    *
    * @param \Drupal\Core\Entity\EntityAutocompleteMatcher $matcher
    *   The autocomplete matcher for entity references.
+   * @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $key_value
+   *   The key value factory.
    */
-  public function __construct(EntityAutocompleteMatcher $matcher) {
+  public function __construct(EntityAutocompleteMatcher $matcher, KeyValueStoreInterface $key_value) {
     $this->matcher = $matcher;
+    $this->keyValue = $key_value;
   }
 
   /**
@@ -42,7 +56,8 @@ public function __construct(EntityAutocompleteMatcher $matcher) {
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('entity.autocomplete_matcher')
+      $container->get('entity.autocomplete_matcher'),
+      $container->get('keyvalue')->get('entity_autocomplete')
     );
   }
 
@@ -55,21 +70,40 @@ public static function create(ContainerInterface $container) {
    *   The ID of the target entity type.
    * @param string $selection_handler
    *   The plugin ID of the entity reference selection handler.
-   * @param string $selection_settings
-   *   The settings that will be passed to the selection handler.
+   * @param string $selection_settings_key
+   *   The hashed key of the key/value entry that holds the selection handler
+   *   settings.
    *
    * @return \Symfony\Component\HttpFoundation\JsonResponse
    *   The matched entity labels as a JSON response.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+   *   Thrown if the selection settings key is not found in the key/value store
+   *   or if it does not match the stored data.
    */
-  public function handleAutocomplete(Request $request, $target_type, $selection_handler, $selection_settings = '') {
+  public function handleAutocomplete(Request $request, $target_type, $selection_handler, $selection_settings_key) {
     $matches = array();
     // Get the typed string from the URL, if it exists.
     if ($input = $request->query->get('q')) {
       $typed_string = Tags::explode($input);
       $typed_string = Unicode::strtolower(array_pop($typed_string));
 
-      // Selection settings are passed in as an encoded serialized array.
-      $selection_settings = $selection_settings ? unserialize(base64_decode($selection_settings)) : array();
+      // Selection settings are passed in as a hashed key of a serialized array
+      // stored in the key/value store.
+      $selection_settings = $this->keyValue->get($selection_settings_key, FALSE);
+      if ($selection_settings !== FALSE) {
+        $selection_settings_hash = Crypt::hmacBase64(serialize($selection_settings) . $target_type . $selection_handler, Settings::getHashSalt());
+        if ($selection_settings_hash !== $selection_settings_key) {
+          // Disallow access when the selection settings hash does not match the
+          // passed-in key.
+          throw new AccessDeniedHttpException('Invalid selection settings key.');
+        }
+      }
+      else {
+        // Disallow access when the selection settings key is not found in the
+        // key/value store.
+        throw new AccessDeniedHttpException();
+      }
 
       $matches = $this->matcher->getMatches($target_type, $selection_handler, $selection_settings, $typed_string);
     }
diff --git a/core/modules/system/src/Tests/Entity/EntityAutocompleteTest.php b/core/modules/system/src/Tests/Entity/EntityAutocompleteTest.php
index 949b7ccf37d4013aa45d7b4fa3bc8587492ef953..d1425c304d3f038fe1cd8ba9122fd01895513403 100644
--- a/core/modules/system/src/Tests/Entity/EntityAutocompleteTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityAutocompleteTest.php
@@ -8,10 +8,13 @@
 namespace Drupal\system\Tests\Entity;
 
 use Drupal\Component\Serialization\Json;
+use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Component\Utility\Tags;
+use Drupal\Core\Site\Settings;
 use Drupal\system\Controller\EntityAutocompleteController;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
 /**
  * Tests the autocomplete functionality.
@@ -34,6 +37,14 @@ class EntityAutocompleteTest extends EntityUnitTestBase {
    */
   protected $bundle = 'entity_test';
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('system', ['key_value']);
+  }
+
   /**
    * Tests autocompletion edge cases with slashes in the names.
    */
@@ -86,6 +97,47 @@ function testEntityReferenceAutocompletion() {
     $this->assertIdentical(reset($data), $target, 'Autocomplete returns an entity label containing a comma and a slash.');
   }
 
+  /**
+   * Tests that missing or invalid selection setting key are handled correctly.
+   */
+  public function testSelectionSettingsHandling() {
+    $entity_reference_controller = EntityAutocompleteController::create($this->container);
+    $request = Request::create('entity_reference_autocomplete/' . $this->entityType . '/default');
+    $request->query->set('q', $this->randomString());
+
+    try {
+      // Pass an invalid selection settings key (i.e. one that does not exist
+      // in the key/value store).
+      $selection_settings_key = $this->randomString();
+      $entity_reference_controller->handleAutocomplete($request, $this->entityType, 'default', $selection_settings_key);
+
+      $this->fail('Non-existent selection settings key throws an exception.');
+    }
+    catch (AccessDeniedHttpException $e) {
+      $this->pass('Non-existent selection settings key throws an exception.');
+    }
+
+    try {
+      // Generate a valid hash key but store a modified settings array.
+      $selection_settings = [];
+      $selection_settings_key = Crypt::hmacBase64(serialize($selection_settings) . $this->entityType . 'default', Settings::getHashSalt());
+
+      $selection_settings[$this->randomMachineName()] = $this->randomString();
+      \Drupal::keyValue('entity_autocomplete')->set($selection_settings_key, $selection_settings);
+
+      $entity_reference_controller->handleAutocomplete($request, $this->entityType, 'default', $selection_settings_key);
+    }
+    catch (AccessDeniedHttpException $e) {
+      if ($e->getMessage() == 'Invalid selection settings key.') {
+        $this->pass('Invalid selection settings key throws an exception.');
+      }
+      else {
+        $this->fail('Invalid selection settings key throws an exception.');
+      }
+    }
+
+  }
+
   /**
    * Returns the result of an Entity reference autocomplete request.
    *
@@ -99,8 +151,12 @@ protected function getAutocompleteResult($input) {
     $request = Request::create('entity_reference_autocomplete/' . $this->entityType . '/default');
     $request->query->set('q', $input);
 
+    $selection_settings = [];
+    $selection_settings_key = Crypt::hmacBase64(serialize($selection_settings) . $this->entityType . 'default', Settings::getHashSalt());
+    \Drupal::keyValue('entity_autocomplete')->set($selection_settings_key, $selection_settings);
+
     $entity_reference_controller = EntityAutocompleteController::create($this->container);
-    $result = $entity_reference_controller->handleAutocomplete($request, $this->entityType, 'default')->getContent();
+    $result = $entity_reference_controller->handleAutocomplete($request, $this->entityType, 'default', $selection_settings_key)->getContent();
 
     return Json::decode($result);
   }
diff --git a/core/modules/system/src/Tests/Entity/FieldWidgetConstraintValidatorTest.php b/core/modules/system/src/Tests/Entity/FieldWidgetConstraintValidatorTest.php
index 4a561987525697c930ef129c2159e314ceebeeef..0ed3ec7086f5e629a0aded375c60751486e3f86a 100644
--- a/core/modules/system/src/Tests/Entity/FieldWidgetConstraintValidatorTest.php
+++ b/core/modules/system/src/Tests/Entity/FieldWidgetConstraintValidatorTest.php
@@ -26,7 +26,7 @@ class FieldWidgetConstraintValidatorTest extends KernelTestBase {
   protected function setUp() {
     parent::setUp();
 
-    $this->installSchema('system', 'router');
+    $this->installSchema('system', ['router', 'key_value']);
     $this->container->get('router.builder')->rebuild();
 
     $this->installEntitySchema('user');
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index 661f4e00300f0cfee5367ddf3fa7459b4a8b178b..12e7d9accdc44b3a7d611a77089d38aeba54282d 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -476,9 +476,8 @@ system.admin_content:
     _permission: 'access administration pages'
 
 system.entity_autocomplete:
-  path: '/entity_reference_autocomplete/{target_type}/{selection_handler}/{selection_settings}'
+  path: '/entity_reference_autocomplete/{target_type}/{selection_handler}/{selection_settings_key}'
   defaults:
     _controller: '\Drupal\system\Controller\EntityAutocompleteController::handleAutocomplete'
-    selection_settings: ''
   requirements:
     _access: 'TRUE'