diff --git includes/file.inc includes/file.inc
index 5eed882..4665d43 100644
--- includes/file.inc
+++ includes/file.inc
@@ -1098,6 +1098,9 @@ function file_space_used($uid = NULL, $status = FILE_STATUS_PERMANENT) {
  * @param $validators
  *   An optional, associative array of callback functions used to validate the
  *   file. See file_validate() for a full discussion of the array format.
+ *   Beware: if not provided, there is no validation, which means that any
+ *   file extension can be uploaded. This should only be allowed for trusted
+ *   users, if at all.
  * @param $destination
  *   A string containing the URI $source should be copied to.
  *   This must be a stream wrapper URI. If this value is omitted, Drupal's
@@ -1160,28 +1163,42 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
       return FALSE;
   }
 
-  // Build the list of non-munged extensions.
-  // @todo: this should not be here. we need to figure out the right place.
-  $extensions = '';
-  foreach ($user->roles as $rid => $name) {
-    $extensions .= ' ' . variable_get("upload_extensions_$rid",
-    variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp'));
-  }
-
   // Begin building file object.
   $file = new stdClass();
   $file->uid      = $user->uid;
   $file->status   = 0;
-  $file->filename = file_munge_filename(trim(basename($_FILES['files']['name'][$source]), '.'), $extensions);
+  $file->filename = trim(basename($_FILES['files']['name'][$source]), '.');
   $file->uri      = $_FILES['files']['tmp_name'][$source];
   $file->filemime = file_get_mimetype($file->filename);
   $file->filesize = $_FILES['files']['size'][$source];
 
-  // Rename potentially executable files, to help prevent exploits.
-  if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
+  if (isset($validators['file_validate_extensions'])) {
+    // Build the list of non-munged extensions if the caller provided them.
+    $extensions = $validators['file_validate_extensions'][0];
+  } else {
+    // Caller didn't provide any extensions, so provide a limited safe list for
+    // file_munge_filename(). Any extension not in this list will be munged.
+    $extensions = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp';  
+  }
+
+  // Munge the filename to protect against possible malicious extension hiding
+  // within an unknown file type (ie: filename.html.foo).
+  $file->filename = file_munge_filename($file->filename, $extensions);
+
+  // Rename potentially executable files, to help prevent exploits (i.e. will
+  // rename filename.php.foo and filename.php to filename.php.foo.txt and
+  // filename.php.txt, respectively). Don't rename if 'allow_insecure_uploads'
+  // evaluates to TRUE.
+  if (!variable_get('allow_insecure_uploads', 0) && preg_match('/\.(php|pl|py|cgi|asp|js)(\.|$)/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
     $file->filemime = 'text/plain';
     $file->uri .= '.txt';
     $file->filename .= '.txt';
+    // The .txt extension may not be in the allowed list of extensions. We have
+    // to add it here or else the file upload will fail.
+    if (!empty($extensions)) {
+      $validators['file_validate_extensions'][0] .= ' txt';
+      drupal_set_message(t('For security reasons, your upload has been renamed to %filename.', array('%filename' => $file->filename)));
+    }
   }
 
   // If the destination is not provided, use the temporary directory.
