diff --git a/core/includes/file.inc b/core/includes/file.inc
index 675a2d5..f4ce382 100644
--- a/core/includes/file.inc
+++ b/core/includes/file.inc
@@ -134,6 +134,16 @@ const FILE_EXISTS_ERROR = 2;
 const FILE_STATUS_PERMANENT = 1;
 
 /**
+ * Allow only the listed file extensions.
+ */
+const FILE_ALLOW_EXTENSIONS_LISTED = 0;
+
+/**
+ * Allow all extensions except those listed.
+ */
+const FILE_ALLOW_EXTENSIONS_NOTLISTED = 1;
+
+/**
  * Provides Drupal stream wrapper registry.
  *
  * A stream wrapper is an abstraction of a file system that allows Drupal to
@@ -1163,7 +1173,7 @@ function file_unmanaged_move($source, $destination = NULL, $replace = FILE_EXIST
  *
  * Specifically, this function adds an underscore to all extensions that are
  * between 2 and 5 characters in length, internal to the file name, and not
- * included in $extensions.
+ * allowed by $extensions.
  *
  * Function behavior is also controlled by the Drupal variable
  * 'allow_insecure_uploads'. If 'allow_insecure_uploads' evaluates to TRUE, no
@@ -1173,6 +1183,9 @@ function file_unmanaged_move($source, $destination = NULL, $replace = FILE_EXIST
  *   File name to modify.
  * @param $extensions
  *   A space-separated list of extensions that should not be altered.
+ * @param $inclusion
+ *   If FILE_ALLOW_EXTENSIONS_NOTLISTED, the list of extensions is considered
+ *   a blacklist. Otherwise, it is considered a whitelist.
  * @param $alerts
  *   If TRUE, drupal_set_message() will be called to display a message if the
  *   file name was changed.
@@ -1180,12 +1193,12 @@ function file_unmanaged_move($source, $destination = NULL, $replace = FILE_EXIST
  * @return
  *   The potentially modified $filename.
  */
-function file_munge_filename($filename, $extensions, $alerts = TRUE) {
+function file_munge_filename($filename, $extensions, $alerts = TRUE, $inclusion = FILE_ALLOW_EXTENSIONS_LISTED) {
   $original = $filename;
 
   // Allow potentially insecure uploads for very savvy users and admin
   if (!variable_get('allow_insecure_uploads', 0)) {
-    $whitelist = array_unique(explode(' ', trim($extensions)));
+    $extensions_arr = array_unique(explode(' ', trim($extensions)));
 
     // Split the filename up by periods. The first part becomes the basename
     // the last part the final extension.
@@ -1194,13 +1207,17 @@ function file_munge_filename($filename, $extensions, $alerts = TRUE) {
     $final_extension = array_pop($filename_parts); // Remove final extension.
 
     // Loop through the middle parts of the name and add an underscore to the
-    // end of each section that could be a file extension but isn't in the list
-    // of allowed extensions.
+    // end of each section that could be a file extension but is restricted by
+    // the given extension list
     foreach ($filename_parts as $filename_part) {
       $new_filename .= '.' . $filename_part;
-      if (!in_array($filename_part, $whitelist) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) {
+      if ($inclusion == FILE_ALLOW_EXTENSIONS_NOTLISTED && in_array($filename_part, $extensions_arr) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) {
         $new_filename .= '_';
       }
+      elseif (!in_array($filename_part, $extensions_arr) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) {
+        $new_filename .= '_';
+      }
+
     }
     $filename = $new_filename . '.' . $final_extension;
 
@@ -1533,6 +1550,7 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
     if (isset($validators['file_validate_extensions'][0])) {
       // Build the list of non-munged extensions if the caller provided them.
       $extensions = $validators['file_validate_extensions'][0];
+      $validators['file_validate_extensions'][1] = (isset($validators['file_validate_extensions'][1])) ? $validators['file_validate_extensions'][1] : FILE_ALLOW_EXTENSIONS_LISTED;
     }
     else {
       // If 'file_validate_extensions' is set and the list is empty then the
@@ -1547,12 +1565,13 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
     $extensions = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp';
     $validators['file_validate_extensions'] = array();
     $validators['file_validate_extensions'][0] = $extensions;
+    $validators['file_validate_extensions'][1] = FILE_ALLOW_EXTENSIONS_LISTED;
   }
 
   if (!empty($extensions)) {
     // 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);
+    $file->filename = file_munge_filename($file->filename, $validators['file_validate_extensions'][0], TRUE, $validators['file_validate_extensions'][1]);
   }
 
   // Rename potentially executable files, to help prevent exploits (i.e. will
@@ -1561,14 +1580,23 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
   // 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.
+    $file->uri .= '_.txt';
+    $file->filename .= '_.txt';
+    // The txt extension may be missing from our whitelist, or exist in the
+    // blacklist. We need to update the list or the 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 ($validators['file_validate_extensions'][1] == FILE_ALLOW_EXTENSIONS_NOTLISTED) {
+        $validators['file_validate_extensions'][0] = preg_replace('/(^txt\b\s?|\b\s?txt\b)/i', '', $validators['file_validate_extensions'][0]);
+        if (!strlen($validators['file_validate_extensions'][0])) {
+          // The only extension was removed, so remove the validator
+          unset($validators['file_validate_extensions']);
+        }
+      }
+      else {
+        $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.
@@ -1753,13 +1781,16 @@ function file_validate_name_length(stdClass $file) {
  *
  * @see hook_file_validate()
  */
-function file_validate_extensions(stdClass $file, $extensions) {
+function file_validate_extensions(stdClass $file, $extensions, $inclusive = FILE_ALLOW_EXTENSIONS_LISTED) {
   $errors = array();
 
   $regex = '/\.(' . preg_replace('/ +/', '|', preg_quote($extensions)) . ')$/i';
-  if (!preg_match($regex, $file->filename)) {
+  if ($inclusive == FILE_ALLOW_EXTENSIONS_LISTED && !preg_match($regex, $file->filename)) {
     $errors[] = t('Only files with the following extensions are allowed: %files-allowed.', array('%files-allowed' => $extensions));
   }
+  elseif ($inclusive == FILE_ALLOW_EXTENSIONS_NOTLISTED && preg_match($regex, $file->filename))  {
+    $errors[] = t('Files with the following extensions are not allowed: %files-allowed.', array('%files-allowed' => $extensions));
+  }
   return $errors;
 }
 
diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index a1a2ef9..298d0da 100644
--- a/core/modules/file/file.field.inc
+++ b/core/modules/file/file.field.inc
@@ -85,16 +85,21 @@ function file_field_instance_settings_form($field, $instance) {
 
   // Make the extension list a little more human-friendly by comma-separation.
   $extensions = str_replace(' ', ', ', $settings['file_extensions']);
+  $form['inclusion'] = array(
+    '#type' => 'radios',
+    '#title' => t('Allowed file extensions'),
+    '#options' => array(
+      FILE_ALLOW_EXTENSIONS_LISTED => t('Only the listed extensions'),
+      FILE_ALLOW_EXTENSIONS_NOTLISTED => t('All extensions except those listed'),
+    ),
+    '#default_value' => isset($settings['inclusion']) ? $settings['inclusion'] : FILE_ALLOW_EXTENSIONS_LISTED,
+  );
   $form['file_extensions'] = array(
     '#type' => 'textfield',
-    '#title' => t('Allowed file extensions'),
     '#default_value' => $extensions,
     '#description' => t('Separate extensions with a space or comma and do not include the leading dot.'),
     '#element_validate' => array('_file_generic_settings_extensions'),
     '#weight' => 1,
-    // By making this field required, we prevent a potential security issue
-    // that would allow files of any type to be uploaded.
-    '#required' => TRUE,
   );
 
   $form['max_filesize'] = array(
@@ -156,6 +161,9 @@ function _file_generic_settings_extensions($element, &$form_state) {
       form_set_value($element, $extensions, $form_state);
     }
   }
+  elseif ($form_state['values']['instance']['settings']['inclusion'] == FILE_ALLOW_EXTENSIONS_LISTED) {
+    form_error($element, t('You must provide a list of extensions. If you would like to allow all extensions, leave the list of extensions blank, and change the inclusion settings to "All extensions except those listed".'));
+  }
 }
 
 /**
@@ -544,14 +552,19 @@ function file_field_widget_upload_validators($field, $instance) {
     $max_filesize = parse_size($instance['settings']['max_filesize']);
   }
 
+  // by default make inclusion setting as secure as possible
+  if (!isset($instance['settings']['inclusion'])) {
+    $instance['settings']['inclusion'] = FILE_ALLOW_EXTENSIONS_LISTED;
+  }
+
   $validators = array();
 
   // There is always a file size limit due to the PHP server limit.
   $validators['file_validate_size'] = array($max_filesize);
 
   // Add the extension check if necessary.
-  if (!empty($instance['settings']['file_extensions'])) {
-    $validators['file_validate_extensions'] = array($instance['settings']['file_extensions']);
+  if (!empty($instance['settings']['file_extensions']) || $instance['settings']['inclusion'] == FILE_ALLOW_EXTENSIONS_NOTLISTED) {
+    $validators['file_validate_extensions'] = array($instance['settings']['file_extensions'], $instance['settings']['inclusion']);
   }
 
   return $validators;
@@ -947,8 +960,14 @@ function theme_file_upload_help($variables) {
   if (isset($upload_validators['file_validate_size'])) {
     $descriptions[] = t('Files must be less than !size.', array('!size' => '<strong>' . format_size($upload_validators['file_validate_size'][0]) . '</strong>'));
   }
-  if (isset($upload_validators['file_validate_extensions'])) {
-    $descriptions[] = t('Allowed file types: !extensions.', array('!extensions' => '<strong>' . check_plain($upload_validators['file_validate_extensions'][0]) . '</strong>'));
+  if (isset($upload_validators['file_validate_extensions']) && !empty($upload_validators['file_validate_extensions'][0])) {
+    if ($upload_validators['file_validate_extensions'][1] == FILE_ALLOW_EXTENSIONS_NOTLISTED) {
+      $inclusion = t('Disallowed');
+    }
+    else {
+      $inclusion = t('Allowed');
+    }
+    $descriptions[] = t('!inclusion file types: !extensions.', array('!inclusion' => $inclusion, '!extensions' => '<strong>' . check_plain($upload_validators['file_validate_extensions'][0]) . '</strong>'));
   }
   if (isset($upload_validators['file_validate_image_resolution'])) {
     $max = $upload_validators['file_validate_image_resolution'][0];
diff --git a/core/modules/file/file.js b/core/modules/file/file.js
index a934afe..189bb64 100644
--- a/core/modules/file/file.js
+++ b/core/modules/file/file.js
@@ -9,6 +9,9 @@
 
 (function ($) {
 
+var fileAllowExtensionsListed = 0;
+var fileAllowExtensionsNotListed = 1;
+
 /**
  * Attach behaviors to managed file element upload fields.
  */
@@ -21,7 +24,10 @@ Drupal.behaviors.fileValidateAutoAttach = {
       elements = settings.file.elements;
       for (selector in elements) {
         if (elements.hasOwnProperty(selector)) {
-          $context.find(selector).bind('change', {extensions: elements[selector]}, validateExtension);
+          var extensions = elements[selector][0];
+          var inclusion = elements[selector][1] || fileAllowExtensionsListed;
+          $(selector, context).bind('change', {extensions: extensions, inclusion: inclusion}, validateExtension);
+
         }
       }
     }
@@ -77,14 +83,19 @@ Drupal.file = Drupal.file || {
    * Client-side file input validation of file extensions.
    */
   validateExtension: function (event) {
+    // Avoid looping when the value is cleared.
+    if (this.value == '') {
+      return true;
+    }
     // Remove any previous errors.
     $('.file-upload-js-error').remove();
 
     // Add client side validation for the input[type=file].
+    var inclusion = event.data.inclusion;
     var extensionPattern = event.data.extensions.replace(/,\s*/g, '|');
     if (extensionPattern.length > 1 && this.value.length > 0) {
       var acceptableMatch = new RegExp('\\.(' + extensionPattern + ')$', 'gi');
-      if (!acceptableMatch.test(this.value)) {
+      if (inclusion == fileAllowExtensionsListed && !acceptableMatch.test(this.value)) {
         var error = Drupal.t("The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.", {
           '%filename': this.value,
           '%extensions': extensionPattern.replace(/\|/g, ', ')
@@ -93,6 +104,15 @@ Drupal.file = Drupal.file || {
         this.value = '';
         return false;
       }
+      else if (inclusion == fileAllowExtensionsNotListed && acceptableMatch.test(this.value)) {
+        var error = Drupal.t("The selected file %filename cannot be uploaded. Files with the following extensions are not allowed: %extensions.", {
+          '%filename': this.value,
+          '%extensions': extensionPattern.replace(/\|/g, ', ')
+        });
+        $(this).closest('div.form-managed-file').prepend('<div class="messages error file-upload-js-error">' + error + '</div>');
+        this.value = '';
+        return false;
+      }
     }
   },
   /**
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index a2a5a80..81f36d6 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -458,12 +458,24 @@ function file_managed_file_process($element, &$form_state, $form) {
   }
 
   // Add the extension list to the page as JavaScript settings.
-  if (isset($element['#upload_validators']['file_validate_extensions'][0])) {
-    $extension_list = implode(',', array_filter(explode(' ', $element['#upload_validators']['file_validate_extensions'][0])));
+  if (isset($element['#upload_validators']['file_validate_extensions'])) {
+    $extension_list = '';
+    if (!empty($element['#upload_validators']['file_validate_extensions'])) {
+      $extension_list = implode(',', array_filter(explode(' ', $element['#upload_validators']['file_validate_extensions'][0])));
+    }
     $element['upload']['#attached']['js'] = array(
       array(
         'type' => 'setting',
-        'data' => array('file' => array('elements' => array('#' . $element['#id'] . '-upload' => $extension_list)))
+        'data' => array(
+          'file' => array(
+            'elements' => array(
+              '#' . $element['#id'] . '-upload' => array(
+                $extension_list,
+                $element['#upload_validators']['file_validate_extensions'][1]
+              )
+            )
+          )
+        )
       )
     );
   }
diff --git a/core/modules/system/tests/file.test b/core/modules/system/tests/file.test
index c5eced1..9c6cacb 100644
--- a/core/modules/system/tests/file.test
+++ b/core/modules/system/tests/file.test
@@ -764,7 +764,7 @@ class FileSaveUploadTest extends FileHookTestCase {
 
     $this->drupalPost('file-test/upload', $edit, t('Submit'));
     $this->assertResponse(200, t('Received a 200 response for posted test file.'));
-    $message = t('For security reasons, your upload has been renamed to') . ' <em class="placeholder">' . $this->phpfile->filename . '.txt' . '</em>';
+    $message = t('For security reasons, your upload has been renamed to') . ' <em class="placeholder">' . $this->phpfile->filename . '_.txt' . '</em>';
     $this->assertRaw($message, t('Dangerous file was renamed.'));
     $this->assertRaw(t('File MIME type is text/plain.'), t('Dangerous file\'s MIME type was changed.'));
     $this->assertRaw(t('You WIN!'), t('Found the success message.'));
@@ -2575,7 +2575,7 @@ class FileNameMungingTest extends FileTestCase {
   function testMunging() {
     // Disable insecure uploads.
     variable_set('allow_insecure_uploads', 0);
-    $munged_name = file_munge_filename($this->name, '', TRUE);
+    $munged_name = file_munge_filename($this->name, '');
     $messages = drupal_get_messages();
     $this->assertTrue(in_array(t('For security reasons, your upload has been renamed to %filename.', array('%filename' => $munged_name)), $messages['status']), t('Alert properly set when a file is renamed.'));
     $this->assertNotEqual($munged_name, $this->name, t('The new filename (%munged) has been modified from the original (%original)', array('%munged' => $munged_name, '%original' => $this->name)));
@@ -2604,7 +2604,7 @@ class FileNameMungingTest extends FileTestCase {
    * Ensure that unmunge gets your name back.
    */
   function testUnMunge() {
-    $munged_name = file_munge_filename($this->name, '', FALSE);
+    $munged_name = file_munge_filename($this->name, '', FALSE, FILE_ALLOW_EXTENSIONS_LISTED);
     $unmunged_name = file_unmunge_filename($munged_name);
     $this->assertIdentical($unmunged_name, $this->name, t('The unmunged (%unmunged) filename matches the original (%original)', array('%unmunged' => $unmunged_name, '%original' => $this->name)));
   }
