diff --git a/mollom.module b/mollom.module
index 0113c5f..59b0637 100644
--- a/mollom.module
+++ b/mollom.module
@@ -726,9 +726,6 @@ function mollom_form_alter(&$form, &$form_state, $form_id) {
         '#weight' => (isset($form['actions']['#weight']) ? $form['actions']['#weight'] - 1 : 99),
         '#tree' => TRUE,
       );
-      // Enable caching of this form; required for our form validation and
-      // submit handlers.
-      $form_state['cache'] = TRUE;
 
       // Add Mollom form validation handlers.
       // Form-level validation handlers are required, since we need access to
@@ -1562,6 +1559,15 @@ function mollom_process_mollom($element, &$form_state, $complete_form) {
     'response' => array(
     ),
   );
+  // @todo Insecure, as malicious bots may simply omit the POST data. We need a
+  //   way to uniquely identify whether the CAPTCHA element was shown in the
+  //   last form build that was presented to the user, without relying on form
+  //   cache. And also the reverse: If the CAPTCHA was solved correctly,
+  //   subsequent builds need to retain that state.
+  if (isset($form_state['input']['mollom']['captcha'])) {
+    $form_state['mollom']['require_captcha'] = TRUE;
+  }
+
   // Instantiate a new Mollom class, unless there is not a cached one.
   if (!isset($form_state['mollom']['class'])) {
     $form_state['mollom']['class'] = mollom();
@@ -1737,8 +1743,8 @@ function mollom_validate_analysis(&$form, &$form_state) {
   if (isset($data['postId'])) {
     unset($data['postId']);
   }
-  if (isset($form_state['mollom']['response']['content']['id'])) {
-    $data['id'] = $form_state['mollom']['response']['content']['id'];
+  if (isset($form_state['input']['mollom']['contentId'])) {
+    $data['id'] = $form_state['input']['mollom']['contentId'];
   }
   $data['checks'] = $form_state['mollom']['checks'];
   $data['strictness'] = $form_state['mollom']['strictness'];
@@ -1769,6 +1775,12 @@ function mollom_validate_analysis(&$form, &$form_state) {
   // since this is not a element-level but a form-level validation handler.
   $form['mollom']['contentId']['#value'] = $result['contentId'];
 
+  // #type 'input' accepts #input, but actual user input is ignored. In case of
+  // a form validation error, the form is potentially built and processed again
+  // in order to be re-rendered. In that case, we want the user-exposed hidden
+  // input fields to contain the IDs returned by Mollom.
+  $form_state['input']['mollom']['contentId'] = $form_state['values']['mollom']['contentId'];
+
   // Prepare watchdog message teaser text.
   $teaser = '--';
   if (isset($data['postTitle'])) {
@@ -1904,8 +1916,8 @@ function mollom_validate_captcha(&$form, &$form_state) {
     return;
   }
   $data = array(
-    'id' => $form_state['mollom']['response']['captcha']['id'],
-    'solution' => $form_state['values']['mollom']['captcha'],
+    'id' => $form_state['input']['mollom']['captchaId'],
+    'solution' => $form_state['input']['mollom']['captcha'],
     'authorIp' => $all_data['authorIp'],
   );
   if (isset($all_data['authorId'])) {
@@ -1934,6 +1946,12 @@ function mollom_validate_captcha(&$form, &$form_state) {
   // since this is not a element-level but a form-level validation handler.
   $form['mollom']['captchaId']['#value'] = $result['captchaId'];
 
+  // #type 'input' accepts #input, but actual user input is ignored. In case of
+  // a form validation error, the form is potentially built and processed again
+  // in order to be re-rendered. In that case, we want the user-exposed hidden
+  // input fields to contain the IDs returned by Mollom.
+  $form_state['input']['mollom']['captchaId'] = $form_state['values']['mollom']['captchaId'];
+
   if (!empty($result['solved'])) {
     $form_state['mollom']['passed_captcha'] = TRUE;
     $form['mollom']['captcha']['#access'] = FALSE;
diff --git a/tests/mollom.test b/tests/mollom.test
index b3cf50c..da6cc12 100644
--- a/tests/mollom.test
+++ b/tests/mollom.test
@@ -130,6 +130,11 @@ class MollomWebTestCase extends DrupalWebTestCase {
     // @todo Remove this override.
     variable_set('theme_default', 'garland');
 
+    // Force-enable (aggressive) page caching to resemble reverse-proxies.
+    variable_set('cache', 1);
+    variable_set('cache_lifetime', 60);
+    variable_set('page_cache_maximum_age', 180);
+
     // If not explicitly disabled by a test, setup and validate testing keys,
     // and create a default admin user.
     if (empty($this->disableDefaultSetup)) {
