diff -rpu simple_payments_orig/gateways/simple_payments_paypal/simple_payments_paypal.module simple_payments/gateways/simple_payments_paypal/simple_payments_paypal.module
--- simple_payments_orig/gateways/simple_payments_paypal/simple_payments_paypal.module	2010-08-08 18:39:12.000000000 -0300
+++ simple_payments/gateways/simple_payments_paypal/simple_payments_paypal.module	2010-08-27 12:01:06.000000000 -0300
@@ -18,7 +18,8 @@ define('SIMPLE_PAYMENTS_PAYPAL_IPN_PATH'
  *   and the following:
  *     'uid' - the uid of the user who is making this payment (defaults to the current user)
  *     'nid' - the nid of the node this payment relates to
- *     'module' - the module that should receive a callback when the payment is complete
+ *     'module' - the module that should receive a callback when the payment is complete, this
+ *                module may also implement the hook hook_simple_payments_paypal_verify_receiver_email
  *     'type' - any payment subclassification the module wishes to use
  *     'custom' - data specific to the module / type, e.g. cart_id
  *
@@ -77,9 +78,16 @@ function simple_payments_paypal_admin_fo
 		'#type' => 'textfield',
 		'#title' => t('Account'),
 		'#default_value' => variable_get('simple_payments_paypal_account', ''),
-		'#description' => '(email address)',
+		'#description' => 'Email address of receivers paypal account.',
 	);
 
+  $form['simple_payments_paypal_account_validate_receiver_email'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Validate account'),
+    '#description' => t('Validate the receiver’s email address is registered to the given paypal account above when receiving paypals payment confirmation. This is recommended to prevent spoofig.'),
+    '#default_value' => variable_get('simple_payments_paypal_account_validate_receiver_email', TRUE),
+  );
+
   $form['simple_payments_paypal_sandbox'] = array(
     '#type' => 'radios',
     '#title' => t('Sandbox/development mode'),
@@ -141,25 +149,62 @@ function _simple_payments_paypal_ipn_ver
 
 /**
  * Handles an incoming PayPal IPN.
+ * 
+ * 
+ * If the implementation of hook_payment_paypal_form provides the paypal account
+ * (set by $vars['business']), it's recommended to implement 
+ * hook_simple_payments_paypal_verify_receiver_email to provide a
+ * custom validation of receivers email (paypal account) - this function 
+ * should return true if receivers email  matches the one corresponding to the
+ * transaction (before set in $vars['business']), otherwise return false.
+ * 
+ * @see: https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNIntro
  */
 function simple_payments_paypal_ipn() {
-	$ipn = $_POST;
-
-	if(!_simple_payments_paypal_ipn_verify($ipn))
-		return;
-	
-	if($ipn['payment_status'] != 'Completed')
-	  return;
-	
-	
+  $ipn = $_POST;
+  
+  if(!_simple_payments_paypal_ipn_verify($ipn)) {
+    return;
+  }
+  
+  if($ipn['payment_status'] != 'Completed' || empty($ipn['txn_id']) || empty($ipn['receiver_email'])) {
+    return;
+  }
+  
+  // Extracts payment variables that were encoded in the 'custom' field.
   $payment = simple_payments_explode_custom($ipn['custom']);
-
+  
   $payment['gateway'] = 'paypal';
-	$payment['currency'] = $ipn['mc_currency'];
-	$payment['amount'] = bcmul($ipn['mc_gross'], 100);
+  $payment['currency'] = $ipn['mc_currency'];
+  $payment['amount'] = bcmul($ipn['mc_gross'], 100);
   $payment['timestamp'] = strtotime($ipn['payment_date']);
-	$payment['details'] = $ipn;
-	
-	simple_payments_payment_received($payment);
+  // Keep this ID to avoid processing the transaction twice
+  $payment['transaction_id'] = $ipn['txn_id'];
+  $payment['details'] = $ipn;
+  
+  // Validate that the receiver’s email address is registered to given paypal account
+  // to make sure that this is not a spoof
+  $valid_receiver_email = TRUE;
+  if (function_exists($payment['module'] .'_'. 'simple_payments_paypal_verify_receiver_email')) {
+    // call hook_simple_payments_paypal_verify_receiver_email to allow the implementing module
+    // to validate the receiver’s email address
+    $valid_receiver_email = module_invoke($payment['module'], 'simple_payments_paypal_verify_receiver_email', $payment);
+  }
+  else if(variable_get('simple_payments_paypal_account_validate_receiver_email', TRUE) && variable_get('simple_payments_paypal_account', '')) {
+    // validate against simple_payments_paypal_account (set by settings form)
+    if (variable_get('simple_payments_paypal_account', '') != $ipn['receiver_email']) {
+      $valid_receiver_email = FALSE;
+    }
+  }
+  
+  if (!$valid_receiver_email) {
+    watchdog('simple_payments_paypal', 'receiver_email send by PayPal IPN (@receiver_email) does 
+      not match the known one - possibly someone tried to spoof paypals payment confirmation.',
+      array('@receiver_email' => $ipn['receiver_email']), WATCHDOG_ERROR
+    );
+    return;
+  }
+  
+  simple_payments_payment_received($payment);
 }
 
diff -rpu simple_payments_orig/simple_payments.install simple_payments/simple_payments.install
--- simple_payments_orig/simple_payments.install	2010-08-08 17:43:26.000000000 -0300
+++ simple_payments/simple_payments.install	2010-08-27 11:56:55.000000000 -0300
@@ -21,11 +21,13 @@ function simple_payments_schema() {
       'timestamp' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE),
       'details' => array('type' => 'text', 'not null' => TRUE, 'serialize' => TRUE),
       'processed' => array('type' => 'int', 'unsigned' => TRUE),
+      'transaction_id' => array('type' => 'varchar', 'length' => 255),
     ),
     'primary key' => array('payment_id'),
     'indexes' => array(
       'nid' => array('nid'),
-      'uid' => array('uid')
+      'uid' => array('uid'),
+      'transaction_id' => array('transaction_id'),
     ),
   );
   
@@ -65,3 +67,17 @@ function simple_payments_update_6101() {
   
   return $ret;
 }
+
+/**
+ * Add transaction_id field to simple_payments table.
+ */
+function simple_payments_update_6102() {
+  $ret = array();
+
+  $spec = array('type' => 'varchar', 'length' => 255);
+  $new_keys = array('indexes' => array('transaction_id' => array('transaction_id')));
+
+  db_add_field($ret, 'simple_payment', 'transaction_id', $spec, $new_keys);
+  
+  return $ret;
+}
\ No newline at end of file
diff -rpu simple_payments_orig/simple_payments.module simple_payments/simple_payments.module
--- simple_payments_orig/simple_payments.module	2009-11-17 00:48:49.000000000 -0300
+++ simple_payments/simple_payments.module	2010-08-27 11:42:13.000000000 -0300
@@ -192,6 +192,21 @@ function simple_payments_payment_process
  */
 function simple_payments_payment_received($payment) {
 
+  // detection of duplicate transactions
+  // Use the transaction ID to verify that the transaction has not already been processed, 
+	// which prevents duplicate transactions from being processed.
+	$payment_id = db_result(db_query("SELECT payment_id FROM {simple_payment} 
+	  WHERE transaction_id = '%s' AND gateway = '%s'", $payment['transaction_id'], $payment['gateway']
+	));
+	
+	if ($payment_id) {
+	  watchdog('simple_payments', 'Payment has been already processed 
+	    (payment gateway: @gateway, payment_id: @payment_id, transaction_id: @transaction_id)',
+	    array('@gateway' => $payment['gateway'], '@payment_id' => $payment_id, '@transaction_id' => $payment['transaction_id'])
+	  );
+	  return;
+	}
+
   drupal_write_record('simple_payment', $payment);
 
   _simple_payments_payment_log($payment);
