diff --git a/authcache.module b/authcache.module
index ab67275..486b205 100644
--- a/authcache.module
+++ b/authcache.module
@@ -251,9 +251,17 @@ function authcache_form_alter(&$form, &$form_state, $form_id) {
 function authcache_form_comment_form_alter(&$form, &$form_state) {
   global $user;
 
-  if ($user->uid && authcache_page_is_cacheable() && isset($form['author']['_author'])) {
-    $message = t('User name on comment form. Enable Authcache User module or implement custom code capable of retrieving the user name.');
-    authcache_element_suspect($form['author']['_author'], $message);
+  // Author name is tainted when displaying the comment form for new comments.
+  // This is not the case when comments are edited though.
+  if ($user->uid && authcache_page_is_cacheable() && !$form_state['comment']->cid) {
+    $message = t('User name on comment form. Enable Authcache Comment module or implement custom code capable of retrieving/removing the user name.');
+
+    if (isset($form['author']['name']['#type']) && $form['author']['name']['#type'] === 'value') {
+      authcache_element_suspect($form['author']['name'], $message);
+    }
+    if (isset($form['author']['_author'])) {
+      authcache_element_suspect($form['author']['_author'], $message);
+    }
   }
 }
 
diff --git a/modules/authcache_comment/authcache_comment.module b/modules/authcache_comment/authcache_comment.module
index 9a40e63..d5aa62a 100644
--- a/modules/authcache_comment/authcache_comment.module
+++ b/modules/authcache_comment/authcache_comment.module
@@ -116,3 +116,47 @@ function authcache_comment_preprocess_comment(&$variables) {
     }
   }
 }
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Replace the username in the comment-form with a placeholder.
+ */
+function authcache_comment_form_comment_form_alter(&$form, &$form_state) {
+  global $user;
+
+  // When displaying the comment form for new comments (not on edit) prepare the
+  // author field such that the user name does not leak into the form cache.
+  if ($user->uid && authcache_page_is_cacheable() && !$form_state['comment']->cid) {
+
+    // Retrieve the username from settings.
+    if (isset($form['author']['_author']) && !authcache_element_is_cacheable($form['author']['_author'])) {
+      $replacement = array(
+        '#theme' => 'html_tag',
+        '#tag' => 'span',
+      );
+      authcache_user_attach_property($replacement, 'name');
+      $form['author']['_author']['#markup'] = render($replacement);
+      authcache_element_set_cacheable($form['author']['_author']);
+    }
+
+    // Remove the author name #value in order to prevent it from entering the
+    // form cache. Instead add a validation callback which will restore the
+    // value from the $user global upon submission.
+    if (isset($form['author']['name']['#type']) && $form['author']['name']['#type'] === 'value' && !authcache_element_is_cacheable($form['author']['name'])) {
+      $form['author']['name']['#value'] = '';
+      $form['author']['name']['#element_validate'][] = 'authcache_comment_form_restore_author';
+      authcache_element_set_cacheable($form['author']['name']);
+    }
+  }
+}
+
+/**
+ * Restore the name of the logged in user in the form author field.
+ */
+function authcache_comment_form_restore_author($element, &$form_state) {
+  global $user;
+
+  $element['#value'] = $user->name;
+  form_set_value($element, $element['#value'], $form_state);
+}
diff --git a/modules/authcache_comment/authcache_comment.test b/modules/authcache_comment/authcache_comment.test
index aac7ffd..705e501 100644
--- a/modules/authcache_comment/authcache_comment.test
+++ b/modules/authcache_comment/authcache_comment.test
@@ -86,7 +86,7 @@ class AuthcacheCommentTest extends DrupalWebTestCase {
    *
    * @see CommentHelperCase::postComment()
    */
-  protected function postComment($node, $comment, $subject = '', $contact = NULL) {
+  protected function postComment($node, $comment, $subject = '', $contact = NULL, $extra_post = NULL) {
     $langcode = LANGUAGE_NONE;
     $edit = array();
     $edit['comment_body[' . $langcode . '][0][value]'] = $comment;
@@ -113,19 +113,19 @@ class AuthcacheCommentTest extends DrupalWebTestCase {
       case DRUPAL_REQUIRED:
         // Preview required so no save button should be found.
         $this->assertNoFieldByName('op', t('Save'), 'Save button not found.');
-        $this->drupalPost(NULL, $edit, t('Preview'));
+        $this->drupalPost(NULL, $edit, t('Preview'), array(), array(), NULL, $extra_post);
         // Don't break here so that we can test post-preview field presence and
         // function below.
       case DRUPAL_OPTIONAL:
         $this->assertFieldByName('op', t('Preview'), 'Preview button found.');
         $this->assertFieldByName('op', t('Save'), 'Save button found.');
-        $this->drupalPost(NULL, $edit, t('Save'));
+        $this->drupalPost(NULL, $edit, t('Save'), array(), array(), NULL, $extra_post);
         break;
 
       case DRUPAL_DISABLED:
         $this->assertNoFieldByName('op', t('Preview'), 'Preview button not found.');
         $this->assertFieldByName('op', t('Save'), 'Save button found.');
-        $this->drupalPost(NULL, $edit, t('Save'));
+        $this->drupalPost(NULL, $edit, t('Save'), array(), array(), NULL, $extra_post);
         break;
     }
     $match = array();
@@ -161,6 +161,30 @@ class AuthcacheCommentTest extends DrupalWebTestCase {
   }
 
   /**
+   * Ensure that user setting is embedded for authenticated users.
+   */
+  public function testUserSettingInCommentForm() {
+    $this->stubmod->hook('authcache_p13n_client', array(
+      'authcache_p13n_test' => array(
+        'title' => t('Test Client'),
+        'enabled' => TRUE,
+      ),
+    ));
+
+    $setting_markup = $this->randomName(8);
+    $setting_stub = HookStub::on('theme_authcache_p13n_setting__authcache_p13n_test', $setting_markup);
+
+    // Then ensure that the setting is added when the site wide contact form is
+    // accessed with authenticated user.
+    $this->drupalLogin($this->member1);
+    $this->drupalGet('comment/reply/' . $this->node->nid);
+    $this->assertNoText($this->member1->name, 'Should remove the users name from the comment form');
+
+    $this->assertText($setting_markup);
+    $this->assertStub($setting_stub, HookStub::once());
+  }
+
+  /**
    * Test that the number of new comments is replaced by a partial.
    *
    * Covers authcache_comment_node_view_alter()
@@ -461,4 +485,106 @@ class AuthcacheCommentTest extends DrupalWebTestCase {
     );
     $this->assertEqual($expect, $result, 'Should report one new comment for member one now');
   }
+
+  /**
+   * Test that comments get properly attributed when the form cache is in use.
+   *
+   * Bug: https://www.drupal.org/node/2307555
+   */
+  public function testCommentAttributionWithFormCache() {
+    $this->stubmod->hook('authcache_p13n_client', array(
+      'authcache_p13n_test' => array(
+        'title' => t('Test Client'),
+        'enabled' => TRUE,
+      ),
+    ));
+
+    // Setup file field and cache object API.
+    module_enable(array('file', 'authcache_form', 'cacheobject'));
+    variable_set('cache_class_cache_form', 'CacheObjectAPIWrapper');
+    variable_set('cacheobject_class_cache_form', 'DrupalDatabaseCache');
+    $this->resetAll();
+
+    // Add a file-field to the comment entity. This will trigger the form cache
+    // because the file field widget uses Ajax.
+    $field = array(
+      'field_name' => 'field_document',
+      'type'  => 'file',
+      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+    );
+    field_create_field($field);
+    $instance = array(
+      'field_name' => 'field_document',
+      'entity_type' => 'comment',
+      'label' => 'Document',
+      'bundle' => 'comment_node_article',
+      'settings' => array(
+        'file_directory' => 'field/document',
+        'file_extensions' => 'txt doc docx pdf ods odt xls xlsx',
+        'max_filesize' => '2MB',
+        'title_field' => '',
+      ),
+      'widget' => array(
+        'type' => 'file_generic',
+        'weight' => -4,
+      ),
+      'display' => array(
+        'default' => array(
+          'type' => 'file_default',
+          'weight' => 10,
+        ),
+        'teaser' => array(
+          'type' => 'file_default',
+          'weight' => 10,
+        ),
+      ),
+    );
+    field_create_instance($instance);
+
+    // Create a clone of member1 with the same set of roles.
+    $cloned_member1 = $this->drupalCreateUser();
+    $cloned_member1->roles = $this->member1->roles;
+    user_save($cloned_member1);
+
+    $this->drupalLogin($this->member1);
+
+    // M1: Visit the node in order to warm the form cache.
+    $excluded_stub = $this->stubmod->hook('authcache_excluded');
+    $canceled_stub = $this->stubmod->hook('authcache_canceled');
+    $this->drupalGet('node/' . $this->node->nid);
+    $this->assertStub($excluded_stub, HookStub::never());
+    $this->assertStub($canceled_stub, HookStub::never());
+
+    // Record the current page content and url.
+    $content = $this->drupalGetContent();
+    $url = $this->getUrl();
+
+    // M2: Post a comment.
+    $this->drupalLogin($cloned_member1);
+
+    // Simulate a cache-hit by restoring the content and url from member1.
+    $this->drupalSetContent($content, $url);
+
+    // Compute CSRF token and supply it via the extra_post parameter.
+    $token = $this->drupalGetToken('comment_node_article_form');
+    $extra_post = '&form_token=' . urlencode($token);
+
+    $this->postComment(NULL, $this->randomName(8), '', NULL, $extra_post);
+
+    // Ensure that we are not running into CSRF protection.
+    $this->assertNoText('The form has become outdated.');
+
+    // Ensure that the comment is attributed to the clone of member1.
+    $this->assertText($cloned_member1->name);
+    $this->assertNoText($this->member1->name);
+
+    $this->drupalLogout();
+  }
+
+  /**
+   * Overrides the defective method in the parent class.
+   */
+  protected function drupalGetToken($value = '') {
+    return drupal_hmac_base64($value, $this->session_id . drupal_get_private_key() . drupal_get_hash_salt());
+  }
 }
diff --git a/modules/authcache_user/authcache_user.module b/modules/authcache_user/authcache_user.module
index 62be6fc..fa3f267 100644
--- a/modules/authcache_user/authcache_user.module
+++ b/modules/authcache_user/authcache_user.module
@@ -52,25 +52,6 @@ function authcache_user_form_alter(&$form, &$form_state, $form_id) {
 }
 
 /**
- * Implements hook_form_FORM_ID_alter().
- *
- * Replace the username in the comment-form with a placeholder.
- */
-function authcache_user_form_comment_form_alter(&$form, &$form_state) {
-  global $user;
-
-  if ($user->uid && isset($form['author']['_author']) && !authcache_element_is_cacheable($form['author']['_author'])) {
-    $replacement = array(
-      '#theme' => 'html_tag',
-      '#tag' => 'span',
-    );
-    authcache_user_attach_property($replacement, 'name');
-    $form['author']['_author']['#markup'] = render($replacement);
-    authcache_element_set_cacheable($form['author']['_author']);
-  }
-}
-
-/**
  * Attach setting loader for currently logged in user to the given element.
  */
 function authcache_user_attach_property(&$element, $property_name) {
diff --git a/modules/authcache_user/authcache_user.test b/modules/authcache_user/authcache_user.test
index 21dbe57..4431316 100644
--- a/modules/authcache_user/authcache_user.test
+++ b/modules/authcache_user/authcache_user.test
@@ -30,19 +30,14 @@ class AuthcacheUserTest extends DrupalWebTestCase {
     parent::setUp(array(
       'authcache_p13n_test',
       'authcache_user',
-      'comment',
       'contact',
     ));
 
     $this->member1 = $this->drupalCreateUser(array(
-      'access comments',
-      'post comments',
       'access user contact forms',
       'access site-wide contact form',
     ));
     $this->member2 = $this->drupalCreateUser(array(
-      'access comments',
-      'post comments',
       'access user contact forms',
       'access site-wide contact form',
     ));
@@ -141,30 +136,6 @@ class AuthcacheUserTest extends DrupalWebTestCase {
   }
 
   /**
-   * Ensure that user setting is embedded for authenticated users.
-   */
-  public function testCommentForm() {
-    $this->stubmod->hook('authcache_p13n_client', array(
-      'authcache_p13n_test' => array(
-        'title' => t('Test Client'),
-        'enabled' => TRUE,
-      ),
-    ));
-
-    $setting_markup = $this->randomName(8);
-    $setting_stub = HookStub::on('theme_authcache_p13n_setting__authcache_p13n_test', $setting_markup);
-
-    // Then ensure that the setting is added when the site wide contact form is
-    // accessed with authenticated user.
-    $this->drupalLogin($this->member1);
-    $this->drupalGet('comment/reply/' . $this->node->nid);
-    $this->assertNoText($this->member1->name, 'Should remove the users name from the comment form');
-
-    $this->assertText($setting_markup);
-    $this->assertStub($setting_stub, HookStub::once());
-  }
-
-  /**
    * User settings callback should return uid, name and mail of logged-in user.
    */
   public function testUserSettingsCallback() {
