Bug 1392955, r=dimi
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Sat, 02 Mar 2019 00:01:26 +0000
changeset 519938 45b70e8a557b8e179ab87a66ade201eed0257196
parent 519937 8ffa5f870efb9ae97f73072bafb3a870b3cbec73
child 519939 c6197e7ad760cac9d691482130fa8ea72e7fd8de
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdimi
bugs1392955
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1392955, r=dimi Differential Revision: https://phabricator.services.mozilla.com/D19475
toolkit/components/reputationservice/ApplicationReputation.cpp
toolkit/components/reputationservice/ApplicationReputation.h
toolkit/components/reputationservice/moz.build
toolkit/components/reputationservice/test/gtest/TestExecutableLists.cpp
toolkit/components/reputationservice/test/gtest/moz.build
xpcom/io/moz.build
xpcom/io/nsLocalFileCommon.cpp
xpcom/io/nsLocalFileCommon.h
xpcom/io/nsLocalFileWin.cpp
--- a/toolkit/components/reputationservice/ApplicationReputation.cpp
+++ b/toolkit/components/reputationservice/ApplicationReputation.cpp
@@ -38,16 +38,17 @@
 #include "mozilla/TimeStamp.h"
 #include "mozilla/intl/LocaleService.h"
 
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsDependentSubstring.h"
 #include "nsError.h"
+#include "nsLocalFileCommon.h"
 #include "nsNetCID.h"
 #include "nsReadableUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
 
 #include "nsIContentPolicy.h"
@@ -96,16 +97,426 @@ using safe_browsing::ClientDownloadReque
 // MOZ_LOG=ApplicationReputation:5
 mozilla::LazyLogModule ApplicationReputationService::prlog(
     "ApplicationReputation");
 #define LOG(args) \
   MOZ_LOG(ApplicationReputationService::prlog, mozilla::LogLevel::Debug, args)
 #define LOG_ENABLED() \
   MOZ_LOG_TEST(ApplicationReputationService::prlog, mozilla::LogLevel::Debug)
 
+/**
+ * Our detection of executable/binary files uses 3 lists:
+ * - kNonBinaryExecutables (below)
+ * - kBinaryFileExtensions (below)
+ * - sExecutableExts (in nsLocalFileCommon)
+ *
+ * On Windows, the `sExecutableExts` list is used to determine whether files
+ * count as executable. For executable files, we will not offer an "open with"
+ * option when downloading, only "save as".
+ *
+ * On all platforms, the combination of these lists is used to determine
+ * whether files should be subject to application reputation checks.
+ * Specifically, all files with extensions that:
+ * - are in kBinaryFileExtensions, or
+ * - are in sExecutableExts **and not in kNonBinaryExecutables**
+ *
+ * will be subject to checks.
+ *
+ * There are tests that verify that these lists are sorted and that extensions
+ * never appear in both the sExecutableExts and kBinaryFileExtensions lists.
+ *
+ * When adding items to any lists:
+ * - please prefer adding to sExecutableExts unless it is imperative users can
+ *   (potentially automatically!) open such files with a helper application
+ *   without first saving them (and that outweighs any associated risk).
+ * - if adding executable items that shouldn't be submitted to apprep servers,
+ *   add them to sExecutableExts and also to kNonBinaryExecutables.
+ * - always add an associated comment in the kBinaryFileExtensions list. Add
+ *   a commented-out entry with an `exec` annotation if you add the actual
+ *   entry in sExecutableExts.
+ *
+ * When removing items please consider whether items should still be in the
+ * sExecutableExts list even if removing them from the kBinaryFileExtensions
+ * list, and vice versa.
+ *
+ * Note that there is a GTest that does its best to check some of these
+ * invariants that you'll likely need to update if you're modifying these
+ * lists.
+ */
+
+// Items that are in sExecutableExts but shouldn't be submitted for application
+// reputation checks.
+/* static */
+const char* const ApplicationReputationService::kNonBinaryExecutables[] = {
+    ".ad",
+    ".air",
+};
+
+// Items that should be submitted for application reputation checks that users
+// are able to open immediately (without first saving and then finding the
+// file). If users shouldn't be able to open them immediately, add to
+// sExecutableExts instead (see also the docstring comment above!).
+/* static */
+const char* const ApplicationReputationService::kBinaryFileExtensions[] = {
+    // Originally extracted from the "File Type Policies" Chrome extension
+    // Items listed with an `exec` comment are in the sExecutableExts list in
+    // nsLocalFileCommon.h .
+    //".001",
+    //".7z",
+    //".ace",
+    //".action", // Mac script
+    //".ad", exec // Windows
+    //".ade", exec  // MS Access
+    //".adp", exec // MS Access
+    //".air", exec // Adobe AIR installer; excluded from apprep checks.
+    ".apk",  // Android package
+    //".app", exec  // Executable application
+    ".applescript",
+    //".application", exec // MS ClickOnce
+    ".appref-ms",    // MS ClickOnce
+    //".arc",
+    //".arj",
+    ".as",   // Mac archive
+    //".asp", exec  // Windows Server script
+    ".asx",  // Windows Media Player
+    //".b64",
+    //".balz",
+    //".bas", exec  // Basic script
+    ".bash",  // Linux shell
+    //".bat", exec  // Windows shell
+    //".bhx",
+    ".bin",
+    ".btapp",      // uTorrent and Transmission
+    ".btinstall",  // uTorrent and Transmission
+    ".btkey",      // uTorrent and Transmission
+    ".btsearch",   // uTorrent and Transmission
+    ".btskin",     // uTorrent and Transmission
+    ".bz",         // Linux archive (bzip)
+    ".bz2",        // Linux archive (bzip2)
+    ".bzip2",      // Linux archive (bzip2)
+    ".cab",        // Windows archive
+    ".cdr",        // Mac disk image
+    ".cfg",        // Windows
+    ".chi",        // Windows Help
+    //".chm", exec // Windows Help
+    ".class",      // Java
+    //".cmd", exec // Windows executable
+    //".com", exec // Windows executable
+    ".command",    // Mac script
+    ".cpgz",       // Mac archive
+    ".cpi",        // Control Panel Item. Executable used for adding icons
+                   // to Control Panel
+    //".cpio",
+    //".cpl", exec  // Windows executable
+    //".crt", exec  // Windows signed certificate
+    ".crx",  // Chrome extensions
+    ".csh",  // Linux shell
+    //".csv",
+    ".dart",        // Mac disk image
+    ".dc42",        // Apple DiskCopy Image
+    ".deb",         // Linux package
+    ".desktop",     // A shortcut that runs other files
+    ".dex",         // Android
+    ".dht",         // HTML
+    ".dhtm",        // HTML
+    ".dhtml",       // HTML
+    ".diskcopy42",  // Apple DiskCopy Image
+    ".dll",         // Windows executable
+    ".dmg",         // Mac disk image
+    ".dmgpart",     // Mac disk image
+    ".doc",         // MS Office
+    ".docb",        // MS Office
+    ".docm",        // MS Word
+    ".docx",        // MS Word
+    ".dot",         // MS Word
+    ".dotm",        // MS Word
+    ".dott",        // MS Office
+    ".dotx",        // MS Word
+    ".drv",         // Windows driver
+    ".dvdr",        // Mac Disk image
+    ".efi",         // Firmware
+    ".eml",         // MS Outlook
+    //".exe", exec // Windows executable
+    //".fat",
+    ".fon",     // Windows font
+    //".fxp", exec // MS FoxPro
+    ".gadget",  // Windows
+    //".gif",
+    ".grp",   // Windows
+    ".gz",    // Linux archive (gzip)
+    ".gzip",  // Linux archive (gzip)
+    ".hfs",   // Mac disk image
+    //".hlp", exec // Windows Help
+    ".hqx",   // Mac archive
+    //".hta", exec // HTML trusted application
+    ".htm", ".html",
+    ".htt",  // MS HTML template
+    //".ica",
+    ".img",      // Mac disk image
+    ".imgpart",  // Mac disk image
+    //".inf", exec // Windows installer
+    ".ini",      // Generic config file
+    //".ins", exec // IIS config
+    //".inx", // InstallShield
+    ".iso",  // CD image
+    //".isp", exec // IIS config
+    //".isu", // InstallShield
+    //".jar", exec // Java
+    //".jnlp", exec // Java
+    //".job", // Windows
+    //".jpg",
+    //".jpeg",
+    //".js", exec  // JavaScript script
+    //".jse", exec // JScript
+    ".ksh",  // Linux shell
+    //".lha",
+    //".lnk", exec // Windows
+    ".local",  // Windows
+    //".lpaq1",
+    //".lpaq5",
+    //".lpaq8",
+    //".lzh",
+    //".lzma",
+    //".mad", exec  // MS Access
+    //".maf", exec  // MS Access
+    //".mag", exec  // MS Access
+    //".mam", exec  // MS Access
+    ".manifest",  // Windows
+    //".maq", exec  // MS Access
+    //".mar", exec  // MS Access
+    //".mas", exec  // MS Access
+    //".mat", exec  // MS Access
+    //".mau", exec  // Media attachment
+    //".mav", exec  // MS Access
+    //".maw", exec  // MS Access
+    //".mda", exec  // MS Access
+    //".mdb", exec  // MS Access
+    //".mde", exec  // MS Access
+    //".mdt", exec  // MS Access
+    //".mdw", exec  // MS Access
+    //".mdz", exec  // MS Access
+    ".mht",       // MS HTML
+    ".mhtml",     // MS HTML
+    ".mim",       // MS Mail
+    //".mkv",
+    ".mmc",  // MS Office
+    ".mof",  // Windows
+    //".mov",
+    //".mp3",
+    //".mp4",
+    ".mpkg",     // Mac installer
+    //".msc", exec  // Windows executable
+    ".msg",      // MS Outlook
+    //".msh", exec  // Windows shell
+    //".msh1", exec // Windows shell
+    //".msh1xml", exec  // Windows shell
+    //".msh2", exec // Windows shell
+    //".msh2xml", exec // Windows shell
+    //".mshxml", exec // Windows
+    //".msi", exec  // Windows installer
+    //".msp", exec  // Windows installer
+    //".mst", exec  // Windows installer
+    ".ndif",     // Mac disk image
+    //".ntfs", // 7z
+    ".ocx",   // ActiveX
+    //".ops", exec  // MS Office
+    ".osas",  // AppleScript
+    ".osax",  // AppleScript
+    //".out", // Linux binary
+    ".oxt",  // OpenOffice extension, can execute arbitrary code
+    //".package",
+    //".paf", // PortableApps package
+    //".paq8f",
+    //".paq8jd",
+    //".paq8l",
+    //".paq8o",
+    ".partial",  // Downloads
+    ".pax",      // Mac archive
+    //".pcd", exec     // Microsoft Visual Test
+    ".pdf",      // Adobe Acrobat
+    //".pea",
+    ".pet",  // Linux package
+    //".pif", exec // Windows
+    ".pkg",  // Mac installer
+    ".pl",   // Perl script
+    //".plg", exec // MS Visual Studio
+    //".png",
+    ".pot",     // MS PowerPoint
+    ".potm",    // MS PowerPoint
+    ".potx",    // MS PowerPoint
+    ".ppam",    // MS PowerPoint
+    ".pps",     // MS PowerPoint
+    ".ppsm",    // MS PowerPoint
+    ".ppsx",    // MS PowerPoint
+    ".ppt",     // MS PowerPoint
+    ".pptm",    // MS PowerPoint
+    ".pptx",    // MS PowerPoint
+    //".prf", exec // MS Outlook
+    //".prg", exec // Windows
+    ".ps1",     // Windows shell
+    ".ps1xml",  // Windows shell
+    ".ps2",     // Windows shell
+    ".ps2xml",  // Windows shell
+    ".psc1",    // Windows shell
+    ".psc2",    // Windows shell
+    //".pst", exec // MS Outlook
+    ".pup",     // Linux package
+    ".py",      // Python script
+    ".pyc",     // Python binary
+    ".pyd",     // Equivalent of a DLL, for python libraries
+    ".pyo",     // Compiled python code
+    ".pyw",     // Python GUI
+    //".quad",
+    //".r00",
+    //".r01",
+    //".r02",
+    //".r03",
+    //".r04",
+    //".r05",
+    //".r06",
+    //".r07",
+    //".r08",
+    //".r09",
+    //".r10",
+    //".r11",
+    //".r12",
+    //".r13",
+    //".r14",
+    //".r15",
+    //".r16",
+    //".r17",
+    //".r18",
+    //".r19",
+    //".r20",
+    //".r21",
+    //".r22",
+    //".r23",
+    //".r24",
+    //".r25",
+    //".r26",
+    //".r27",
+    //".r28",
+    //".r29",
+    //".rar",
+    ".rb",    // Ruby script
+    //".reg", exec  // Windows Registry
+    ".rels",  // MS Office
+    //".rgs", // Windows Registry
+    ".rpm",  // Linux package
+    ".rtf",  // MS Office
+    //".run", // Linux shell
+    //".scf", exec         // Windows shell
+    ".scpt",               // AppleScript
+    ".scptd",              // AppleScript
+    //".scr", exec         // Windows
+    //".sct", exec         // Windows shell
+    ".search-ms",          // Windows
+    ".seplugin",           // AppleScript
+    //".settingcontent-ms", exec // Windows settings
+    ".sh",                 // Linux shell
+    ".shar",               // Linux shell
+    //".shb", exec         // Windows
+    //".shs", exec         // Windows shell
+    ".sht",                // HTML
+    ".shtm",               // HTML
+    ".shtml",              // HTML
+    ".sldm",               // MS PowerPoint
+    ".sldx",               // MS PowerPoint
+    ".slk",                // MS Excel
+    ".slp",                // Linux package
+    ".smi",                // Mac disk image
+    ".sparsebundle",       // Mac disk image
+    ".sparseimage",        // Mac disk image
+    ".spl",                // Adobe Flash
+    //".squashfs",
+    ".svg",
+    ".swf",   // Adobe Flash
+    ".swm",   // Windows Imaging
+    ".sys",   // Windows
+    ".tar",   // Linux archive
+    ".taz",   // Linux archive (bzip2)
+    ".tbz",   // Linux archive (bzip2)
+    ".tbz2",  // Linux archive (bzip2)
+    ".tcsh",  // Linux shell
+    //".tif",
+    ".tgz",  // Linux archive (gzip)
+    //".toast", // Roxio disk image
+    ".torrent",  // Bittorrent
+    ".tpz",      // Linux archive (gzip)
+    //".txt",
+    ".txz",  // Linux archive (xz)
+    ".tz",   // Linux archive (gzip)
+    //".u3p", // U3 Smart Apps
+    ".udf",   // MS Excel
+    ".udif",  // Mac disk image
+    //".url", exec  // Windows
+    //".uu",
+    //".uue",
+    //".vb", exec  // Visual Basic script
+    //".vbe", exec // Visual Basic script
+    //".vbs", exec // Visual Basic script
+    //".vbscript", // Visual Basic script
+    //".vdx", exec // MS Visio
+    ".vhd",       // Windows virtual hard drive
+    ".vhdx",      // Windows virtual hard drive
+    ".vmdk",      // VMware virtual disk
+    //".vsd", exec  // MS Visio
+    //".vsdm", exec // MS Visio
+    //".vsdx", exec // MS Visio
+    //".vsmacros", exec  // MS Visual Studio
+    //".vss",  exec  // MS Visio
+    //".vssm", exec  // MS Visio
+    //".vssx", exec  // MS Visio
+    //".vst",  exec  // MS Visio
+    //".vstm", exec  // MS Visio
+    //".vstx", exec  // MS Visio
+    //".vsw",  exec  // MS Visio
+    //".vsx",  exec  // MS Visio
+    //".vtx",  exec  // MS Visio
+    //".wav",
+    //".webp",
+    ".website",  // Windows
+    ".wim",      // Windows Imaging
+    //".workflow", // Mac Automator
+    //".wrc", // FreeArc archive
+    //".ws",  exec  // Windows script
+    //".wsc", exec  // Windows script
+    //".wsf", exec  // Windows script
+    //".wsh", exec  // Windows script
+    ".xar",   // MS Excel
+    ".xbap",  // XAML Browser Application
+    ".xht", ".xhtm", ".xhtml",
+    ".xip",     // Mac archive
+    ".xla",     // MS Excel
+    ".xlam",    // MS Excel
+    ".xldm",    // MS Excel
+    ".xll",     // MS Excel
+    ".xlm",     // MS Excel
+    ".xls",     // MS Excel
+    ".xlsb",    // MS Excel
+    ".xlsm",    // MS Excel
+    ".xlsx",    // MS Excel
+    ".xlt",     // MS Excel
+    ".xltm",    // MS Excel
+    ".xltx",    // MS Excel
+    ".xlw",     // MS Excel
+    ".xml",     // MS Excel
+    ".xnk",     // MS Exchange
+    ".xrm-ms",  // Windows
+    ".xsl",     // XML Stylesheet
+    //".xxe",
+    ".xz",     // Linux archive (xz)
+    ".z",      // InstallShield
+#ifdef XP_WIN  // disable on Mac/Linux, see 1167493
+    ".zip",    // Generic archive
+#endif
+    ".zipx",  // WinZip
+              //".zpaq",
+};
+
 enum class LookupType { AllowlistOnly, BlocklistOnly, BothLists };
 
 // Define the reasons that download protection service accepts or blocks this
 // download. This is now used for telemetry purposes and xpcshell test. Please
 // also update the xpcshell-test if a reason is added.
 //
 // LocalWhitelist       : URL is found in the local whitelist
 // LocalBlocklist       : URL is found in the local blocklist
@@ -169,17 +580,17 @@ class PendingLookup final : public nsISt
     SERVER_RESPONSE_FAILED = 1,
     SERVER_RESPONSE_INVALID = 2,
   };
 
   // The target filename for the downloaded file.
   nsCString mFileName;
 
   // True if extension of this file matches any extension in the
-  // kBinaryFileExtensions list.
+  // kBinaryFileExtensions or sExecutableExts list.
   bool mIsBinaryFile;
 
   // Number of blocklist and allowlist hits we have seen.
   uint32_t mBlocklistCount;
   uint32_t mAllowlistCount;
 
   // The query containing metadata about the downloaded file.
   nsCOMPtr<nsIApplicationReputationQuery> mQuery;
@@ -435,370 +846,16 @@ PendingLookup::PendingLookup(nsIApplicat
       mCallback(aCallback) {
   LOG(("Created pending lookup [this = %p]", this));
 }
 
 PendingLookup::~PendingLookup() {
   LOG(("Destroying pending lookup [this = %p]", this));
 }
 
-static const char* const kBinaryFileExtensions[] = {
-    // Extracted from the "File Type Policies" Chrome extension
-    //".001",
-    //".7z",
-    //".ace",
-    //".action", // Mac script
-    //".ad", // Windows
-    ".ade",  // MS Access
-    ".adp",  // MS Access
-    ".apk",  // Android package
-    ".app",  // Executable application
-    ".applescript",
-    ".application",  // MS ClickOnce
-    ".appref-ms",    // MS ClickOnce
-    //".arc",
-    //".arj",
-    ".as",   // Mac archive
-    ".asp",  // Windows Server script
-    ".asx",  // Windows Media Player
-    //".b64",
-    //".balz",
-    ".bas",   // Basic script
-    ".bash",  // Linux shell
-    ".bat",   // Windows shell
-    //".bhx",
-    ".bin",
-    ".btapp",      // uTorrent and Transmission
-    ".btinstall",  // uTorrent and Transmission
-    ".btkey",      // uTorrent and Transmission
-    ".btsearch",   // uTorrent and Transmission
-    ".btskin",     // uTorrent and Transmission
-    ".bz",         // Linux archive (bzip)
-    ".bz2",        // Linux archive (bzip2)
-    ".bzip2",      // Linux archive (bzip2)
-    ".cab",        // Windows archive
-    ".cdr",        // Mac disk image
-    ".cfg",        // Windows
-    ".chi",        // Windows Help
-    ".chm",        // Windows Help
-    ".class",      // Java
-    ".cmd",        // Windows executable
-    ".com",        // Windows executable
-    ".command",    // Mac script
-    ".cpgz",       // Mac archive
-    ".cpi",        // Control Panel Item. Executable used for adding icons
-                   // to Control Panel
-    //".cpio",
-    ".cpl",  // Windows executable
-    ".crt",  // Windows signed certificate
-    ".crx",  // Chrome extensions
-    ".csh",  // Linux shell
-    //".csv",
-    ".dart",        // Mac disk image
-    ".dc42",        // Apple DiskCopy Image
-    ".deb",         // Linux package
-    ".desktop",     // A shortcut that runs other files
-    ".dex",         // Android
-    ".dhtml",       // HTML
-    ".dhtm",        // HTML
-    ".dht",         // HTML
-    ".diskcopy42",  // Apple DiskCopy Image
-    ".dll",         // Windows executable
-    ".dmg",         // Mac disk image
-    ".dmgpart",     // Mac disk image
-    ".doc",         // MS Office
-    ".docb",        // MS Office
-    ".docm",        // MS Word
-    ".docx",        // MS Word
-    ".dot",         // MS Word
-    ".dotm",        // MS Word
-    ".dott",        // MS Office
-    ".dotx",        // MS Word
-    ".drv",         // Windows driver
-    ".dvdr",        // Mac Disk image
-    ".efi",         // Firmware
-    ".eml",         // MS Outlook
-    ".exe",         // Windows executable
-    //".fat",
-    ".fon",     // Windows font
-    ".fxp",     // MS FoxPro
-    ".gadget",  // Windows
-    //".gif",
-    ".grp",   // Windows
-    ".gz",    // Linux archive (gzip)
-    ".gzip",  // Linux archive (gzip)
-    ".hfs",   // Mac disk image
-    ".hlp",   // Windows Help
-    ".hqx",   // Mac archive
-    ".hta",   // HTML trusted application
-    ".htm", ".html",
-    ".htt",  // MS HTML template
-    //".ica",
-    ".img",      // Mac disk image
-    ".imgpart",  // Mac disk image
-    ".inf",      // Windows installer
-    ".ini",      // Generic config file
-    ".ins",      // IIS config
-    //".inx", // InstallShield
-    ".iso",  // CD image
-    ".isp",  // IIS config
-    //".isu", // InstallShield
-    ".jar",   // Java
-    ".jnlp",  // Java
-    //".job", // Windows
-    //".jpg",
-    //".jpeg",
-    ".js",   // JavaScript script
-    ".jse",  // JScript
-    ".ksh",  // Linux shell
-    //".lha",
-    ".lnk",    // Windows
-    ".local",  // Windows
-    //".lpaq1",
-    //".lpaq5",
-    //".lpaq8",
-    //".lzh",
-    //".lzma",
-    ".mad",       // MS Access
-    ".maf",       // MS Access
-    ".mag",       // MS Access
-    ".mam",       // MS Access
-    ".manifest",  // Windows
-    ".maq",       // MS Access
-    ".mar",       // MS Access
-    ".mas",       // MS Access
-    ".mat",       // MS Access
-    ".mau",       // Media attachment
-    ".mav",       // MS Access
-    ".maw",       // MS Access
-    ".mda",       // MS Access
-    ".mdb",       // MS Access
-    ".mde",       // MS Access
-    ".mdt",       // MS Access
-    ".mdw",       // MS Access
-    ".mdz",       // MS Access
-    ".mht",       // MS HTML
-    ".mhtml",     // MS HTML
-    ".mim",       // MS Mail
-    //".mkv",
-    ".mmc",  // MS Office
-    ".mof",  // Windows
-    //".mov",
-    //".mp3",
-    //".mp4",
-    ".mpkg",     // Mac installer
-    ".msc",      // Windows executable
-    ".msg",      // MS Outlook
-    ".msh",      // Windows shell
-    ".msh1",     // Windows shell
-    ".msh1xml",  // Windows shell
-    ".msh2",     // Windows shell
-    ".msh2xml",  // Windows shell
-    ".mshxml",   // Windows
-    ".msi",      // Windows installer
-    ".msp",      // Windows installer
-    ".mst",      // Windows installer
-    ".ndif",     // Mac disk image
-    //".ntfs", // 7z
-    ".ocx",   // ActiveX
-    ".ops",   // MS Office
-    ".osas",  // AppleScript
-    ".osax",  // AppleScript
-    //".out", // Linux binary
-    ".oxt",  // OpenOffice extension, can execute arbitrary code
-    //".package",
-    //".paf", // PortableApps package
-    //".paq8f",
-    //".paq8jd",
-    //".paq8l",
-    //".paq8o",
-    ".partial",  // Downloads
-    ".pax",      // Mac archive
-    ".pcd",      // Microsoft Visual Test
-    ".pdf",      // Adobe Acrobat
-    //".pea",
-    ".pet",  // Linux package
-    ".pif",  // Windows
-    ".pkg",  // Mac installer
-    ".pl",   // Perl script
-    ".plg",  // MS Visual Studio
-    //".png",
-    ".pot",     // MS PowerPoint
-    ".potm",    // MS PowerPoint
-    ".potx",    // MS PowerPoint
-    ".ppam",    // MS PowerPoint
-    ".pps",     // MS PowerPoint
-    ".ppsm",    // MS PowerPoint
-    ".ppsx",    // MS PowerPoint
-    ".ppt",     // MS PowerPoint
-    ".pptm",    // MS PowerPoint
-    ".pptx",    // MS PowerPoint
-    ".prf",     // MS Outlook
-    ".prg",     // Windows
-    ".ps1",     // Windows shell
-    ".ps1xml",  // Windows shell
-    ".ps2",     // Windows shell
-    ".ps2xml",  // Windows shell
-    ".psc1",    // Windows shell
-    ".psc2",    // Windows shell
-    ".pst",     // MS Outlook
-    ".pup",     // Linux package
-    ".py",      // Python script
-    ".pyc",     // Python binary
-    ".pyd",     // Equivalent of a DLL, for python libraries
-    ".pyo",     // Compiled python code
-    ".pyw",     // Python GUI
-    //".quad",
-    //".r00",
-    //".r01",
-    //".r02",
-    //".r03",
-    //".r04",
-    //".r05",
-    //".r06",
-    //".r07",
-    //".r08",
-    //".r09",
-    //".r10",
-    //".r11",
-    //".r12",
-    //".r13",
-    //".r14",
-    //".r15",
-    //".r16",
-    //".r17",
-    //".r18",
-    //".r19",
-    //".r20",
-    //".r21",
-    //".r22",
-    //".r23",
-    //".r24",
-    //".r25",
-    //".r26",
-    //".r27",
-    //".r28",
-    //".r29",
-    //".rar",
-    ".rb",    // Ruby script
-    ".reg",   // Windows Registry
-    ".rels",  // MS Office
-    //".rgs", // Windows Registry
-    ".rpm",  // Linux package
-    ".rtf",  // MS Office
-    //".run", // Linux shell
-    ".scf",                // Windows shell
-    ".scpt",               // AppleScript
-    ".scptd",              // AppleScript
-    ".scr",                // Windows
-    ".sct",                // Windows shell
-    ".search-ms",          // Windows
-    ".seplugin",           // AppleScript
-    ".settingcontent-ms",  // Windows settings
-    ".sh",                 // Linux shell
-    ".shar",               // Linux shell
-    ".shb",                // Windows
-    ".shs",                // Windows shell
-    ".shtml",              // HTML
-    ".shtm",               // HTML
-    ".sht",                // HTML
-    ".sldm",               // MS PowerPoint
-    ".sldx",               // MS PowerPoint
-    ".slk",                // MS Excel
-    ".slp",                // Linux package
-    ".smi",                // Mac disk image
-    ".sparsebundle",       // Mac disk image
-    ".sparseimage",        // Mac disk image
-    ".spl",                // Adobe Flash
-    //".squashfs",
-    ".svg",
-    ".swf",   // Adobe Flash
-    ".swm",   // Windows Imaging
-    ".sys",   // Windows
-    ".tar",   // Linux archive
-    ".taz",   // Linux archive (bzip2)
-    ".tbz",   // Linux archive (bzip2)
-    ".tbz2",  // Linux archive (bzip2)
-    ".tcsh",  // Linux shell
-    //".tif",
-    ".tgz",  // Linux archive (gzip)
-    //".toast", // Roxio disk image
-    ".torrent",  // Bittorrent
-    ".tpz",      // Linux archive (gzip)
-    //".txt",
-    ".txz",  // Linux archive (xz)
-    ".tz",   // Linux archive (gzip)
-    //".u3p", // U3 Smart Apps
-    ".udf",   // MS Excel
-    ".udif",  // Mac disk image
-    ".url",   // Windows
-    //".uu",
-    //".uue",
-    ".vb",   // Visual Basic script
-    ".vbe",  // Visual Basic script
-    ".vbs",  // Visual Basic script
-    //".vbscript", // Visual Basic script
-    ".vdx",       // MS Visio
-    ".vhd",       // Windows virtual hard drive
-    ".vhdx",      // Windows virtual hard drive
-    ".vmdk",      // VMware virtual disk
-    ".vsd",       // MS Visio
-    ".vsdm",      // MS Visio
-    ".vsdx",      // MS Visio
-    ".vsmacros",  // MS Visual Studio
-    ".vss",       // MS Visio
-    ".vssm",      // MS Visio
-    ".vssx",      // MS Visio
-    ".vst",       // MS Visio
-    ".vstm",      // MS Visio
-    ".vstx",      // MS Visio
-    ".vsw",       // MS Visio
-    ".vsx",       // MS Visio
-    ".vtx",       // MS Visio
-    //".wav",
-    //".webp",
-    ".website",  // Windows
-    ".wim",      // Windows Imaging
-    //".workflow", // Mac Automator
-    //".wrc", // FreeArc archive
-    ".ws",    // Windows script
-    ".wsc",   // Windows script
-    ".wsf",   // Windows script
-    ".wsh",   // Windows script
-    ".xar",   // MS Excel
-    ".xbap",  // XAML Browser Application
-    ".xhtml", ".xhtm", ".xht",
-    ".xip",     // Mac archive
-    ".xla",     // MS Excel
-    ".xlam",    // MS Excel
-    ".xldm",    // MS Excel
-    ".xll",     // MS Excel
-    ".xlm",     // MS Excel
-    ".xls",     // MS Excel
-    ".xlsb",    // MS Excel
-    ".xlsm",    // MS Excel
-    ".xlsx",    // MS Excel
-    ".xlt",     // MS Excel
-    ".xltm",    // MS Excel
-    ".xltx",    // MS Excel
-    ".xlw",     // MS Excel
-    ".xml",     // MS Excel
-    ".xnk",     // MS Exchange
-    ".xrm-ms",  // Windows
-    ".xsl",     // XML Stylesheet
-    //".xxe",
-    ".xz",     // Linux archive (xz)
-    ".z",      // InstallShield
-#ifdef XP_WIN  // disable on Mac/Linux, see 1167493
-    ".zip",    // Generic archive
-#endif
-    ".zipx",  // WinZip
-              //".zpaq",
-};
-
 static const char* const kDmgFileExtensions[] = {
     ".cdr",          ".dart",        ".dc42",  ".diskcopy42",
     ".dmg",          ".dmgpart",     ".dvdr",  ".img",
     ".imgpart",      ".iso",         ".ndif",  ".smi",
     ".sparsebundle", ".sparseimage", ".toast", ".udif",
 };
 
 static const char* const kRarFileExtensions[] = {
@@ -819,27 +876,50 @@ static const char* GetFileExt(const nsAC
   for (size_t i = 0; i < aLength; ++i) {
     if (StringEndsWith(aFilename, nsDependentCString(aFileExtensions[i]))) {
       return aFileExtensions[i];
     }
   }
   return nullptr;
 }
 
+static const char* GetFileExt(const nsACString& aFilename) {
+#define _GetFileExt(_f, _l) GetFileExt(_f, _l, ArrayLength(_l))
+  const char* ext = _GetFileExt(
+      aFilename, ApplicationReputationService::kBinaryFileExtensions);
+  if (ext == nullptr &&
+      !_GetFileExt(aFilename,
+                   ApplicationReputationService::kNonBinaryExecutables)) {
+    ext = _GetFileExt(aFilename, sExecutableExts);
+  }
+  return ext;
+}
+
 // Returns true if the file extension matches one in the given array.
 static bool IsFileType(const nsACString& aFilename,
                        const char* const aFileExtensions[],
                        const size_t aLength) {
   return GetFileExt(aFilename, aFileExtensions, aLength) != nullptr;
 }
 
+static bool IsBinary(const nsACString& aFilename) {
+  return IsFileType(aFilename,
+                    ApplicationReputationService::kBinaryFileExtensions,
+                    ArrayLength(
+                        ApplicationReputationService::kBinaryFileExtensions)) ||
+         (!IsFileType(
+              aFilename, ApplicationReputationService::kNonBinaryExecutables,
+              ArrayLength(
+                  ApplicationReputationService::kNonBinaryExecutables)) &&
+          IsFileType(aFilename, sExecutableExts, ArrayLength(sExecutableExts)));
+}
+
 ClientDownloadRequest::DownloadType PendingLookup::GetDownloadType(
     const nsACString& aFilename) {
-  MOZ_ASSERT(IsFileType(aFilename, kBinaryFileExtensions,
-                        ArrayLength(kBinaryFileExtensions)));
+  MOZ_ASSERT(IsBinary(aFilename));
 
   // From
   // https://cs.chromium.org/chromium/src/chrome/common/safe_browsing/download_protection_util.cc?l=17
   if (StringEndsWith(aFilename, NS_LITERAL_CSTRING(".zip"))) {
     return ClientDownloadRequest::ZIPPED_EXECUTABLE;
   } else if (StringEndsWith(aFilename, NS_LITERAL_CSTRING(".apk"))) {
     return ClientDownloadRequest::ANDROID_APK;
   } else if (StringEndsWith(aFilename, NS_LITERAL_CSTRING(".app")) ||
@@ -1285,18 +1365,17 @@ nsresult PendingLookup::DoLookupInternal
   if (redirects) {
     AddRedirects(redirects);
   } else {
     LOG(("ApplicationReputation: Got no redirects [this=%p]", this));
   }
 
   rv = mQuery->GetSuggestedFileName(mFileName);
   if (NS_SUCCEEDED(rv) && !mFileName.IsEmpty()) {
-    mIsBinaryFile = IsFileType(mFileName, kBinaryFileExtensions,
-                               ArrayLength(kBinaryFileExtensions));
+    mIsBinaryFile = IsBinary(mFileName);
     LOG(("Suggested filename: %s [binary = %d, this = %p]", mFileName.get(),
          mIsBinaryFile, this));
   } else {
     nsAutoCString errorName;
     mozilla::GetErrorName(rv, errorName);
     LOG(("No suggested filename [rv = %s, this = %p]", errorName.get(), this));
     mFileName = EmptyCString();
   }
@@ -1443,16 +1522,19 @@ nsresult PendingLookup::ParseCertificate
   }
   if (mRequest.signature().certificate_chain_size() > 0) {
     mRequest.mutable_signature()->set_trusted(true);
   }
   return NS_OK;
 }
 
 nsresult PendingLookup::SendRemoteQuery() {
+  MOZ_ASSERT(!IsFileType(
+      mFileName, ApplicationReputationService::kNonBinaryExecutables,
+      ArrayLength(ApplicationReputationService::kNonBinaryExecutables)));
   Reason reason = Reason::NotSet;
   nsresult rv = SendRemoteQueryInternal(reason);
   if (NS_FAILED(rv)) {
     return OnComplete(nsIApplicationReputationService::VERDICT_SAFE, reason,
                       rv);
   }
   // SendRemoteQueryInternal has fired off the query and we call OnComplete in
   // the nsIStreamListener.onStopRequest.
@@ -1765,19 +1847,19 @@ nsresult PendingLookup::OnStopRequestInt
              SERVER_RESPONSE_VALID);
   AccumulateCategorical(
       mozilla::Telemetry::LABELS_APPLICATION_REPUTATION_SERVER_2::
           ResponseValid);
 
   // Clamp responses 0-7, we only know about 0-4 for now.
   Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SERVER_VERDICT,
              std::min<uint32_t>(response.verdict(), 7));
+  const char* ext = GetFileExt(mFileName);
   AccumulateCategoricalKeyed(
-      nsCString(GetFileExt(mFileName, kBinaryFileExtensions,
-                           ArrayLength(kBinaryFileExtensions))),
+      nsCString(ext),
       VerdictToLabel(std::min<uint32_t>(response.verdict(), 7)));
   switch (response.verdict()) {
     case safe_browsing::ClientDownloadResponse::DANGEROUS:
       aVerdict = nsIApplicationReputationService::VERDICT_DANGEROUS;
       aReason = Reason::VerdictDangerous;
       break;
     case safe_browsing::ClientDownloadResponse::DANGEROUS_HOST:
       aVerdict = nsIApplicationReputationService::VERDICT_DANGEROUS_HOST;
--- a/toolkit/components/reputationservice/ApplicationReputation.h
+++ b/toolkit/components/reputationservice/ApplicationReputation.h
@@ -22,16 +22,22 @@ class PendingLookup;
 
 class ApplicationReputationService final
     : public nsIApplicationReputationService {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIAPPLICATIONREPUTATIONSERVICE
 
  public:
+  static const char* const kNonBinaryExecutables[2];
+#ifdef XP_WIN
+  static const char* const kBinaryFileExtensions[175];
+#else
+  static const char* const kBinaryFileExtensions[174];
+#endif
   static already_AddRefed<ApplicationReputationService> GetSingleton();
 
  private:
   friend class PendingLookup;
   friend class PendingDBLookup;
   /**
    * Global singleton object for holding this factory service.
    */
--- a/toolkit/components/reputationservice/moz.build
+++ b/toolkit/components/reputationservice/moz.build
@@ -38,8 +38,12 @@ LOCAL_INCLUDES += [
 
 DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True
 DEFINES['GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER'] = True
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-shadow']
 
 include('/ipc/chromium/chromium-config.mozbuild')
+
+
+if CONFIG['ENABLE_TESTS']:
+    DIRS += ['test/gtest']
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/toolkit/components/reputationservice/test/gtest/TestExecutableLists.cpp
@@ -0,0 +1,347 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/3.0/ */
+
+#include "gtest/gtest.h"
+#include "mozilla/ArrayUtils.h"
+#include "nsLocalFileCommon.h"
+#include "ApplicationReputation.h"
+
+// PLEASE read the comment in ApplicationReputation.cpp before modifying this list.
+static const char* const kTestFileExtensions[] = {
+    ".ad",   // Windows (ignored for app rep)
+    ".ade",  // MS Access
+    ".adp",  // MS Access
+    ".air",  // Adobe Air (ignored for app rep)
+    ".apk",  // Android package
+    ".app",  // Executable application
+    ".applescript",
+    ".application",  // MS ClickOnce
+    ".appref-ms",    // MS ClickOnce
+    ".as",           // Mac archive
+    ".asp",          // Windows Server script
+    ".asx",          // Windows Media Player
+    ".bas",          // Basic script
+    ".bash",         // Linux shell
+    ".bat",          // Windows shell
+    ".bin",
+    ".btapp",        // uTorrent and Transmission
+    ".btinstall",    // uTorrent and Transmission
+    ".btkey",        // uTorrent and Transmission
+    ".btsearch",     // uTorrent and Transmission
+    ".btskin",       // uTorrent and Transmission
+    ".bz",           // Linux archive (bzip)
+    ".bz2",          // Linux archive (bzip2)
+    ".bzip2",        // Linux archive (bzip2)
+    ".cab",          // Windows archive
+    ".cdr",          // Mac disk image
+    ".cfg",          // Windows
+    ".chi",          // Windows Help
+    ".chm",          // Windows Help
+    ".class",        // Java
+    ".cmd",          // Windows executable
+    ".com",          // Windows executable
+    ".command",      // Mac script
+    ".cpgz",         // Mac archive
+    ".cpi",          // Control Panel Item. Executable used for adding icons
+                     // to Control Panel
+    ".cpl",          // Windows executable
+    ".crt",          // Windows signed certificate
+    ".crx",          // Chrome extensions
+    ".csh",          // Linux shell
+    ".dart",         // Mac disk image
+    ".dc42",         // Apple DiskCopy Image
+    ".deb",          // Linux package
+    ".desktop",      // A shortcut that runs other files
+    ".dex",          // Android
+    ".dht",          // HTML
+    ".dhtm",         // HTML
+    ".dhtml",        // HTML
+    ".diskcopy42",   // Apple DiskCopy Image
+    ".dll",          // Windows executable
+    ".dmg",          // Mac disk image
+    ".dmgpart",      // Mac disk image
+    ".doc",          // MS Office
+    ".docb",         // MS Office
+    ".docm",         // MS Word
+    ".docx",         // MS Word
+    ".dot",          // MS Word
+    ".dotm",         // MS Word
+    ".dott",         // MS Office
+    ".dotx",         // MS Word
+    ".drv",          // Windows driver
+    ".dvdr",         // Mac Disk image
+    ".efi",          // Firmware
+    ".eml",          // MS Outlook
+    ".exe",          // Windows executable
+    ".fon",          // Windows font
+    ".fxp",          // MS FoxPro
+    ".gadget",       // Windows
+    ".grp",          // Windows
+    ".gz",           // Linux archive (gzip)
+    ".gzip",         // Linux archive (gzip)
+    ".hfs",          // Mac disk image
+    ".hlp",          // Windows Help
+    ".hqx",          // Mac archive
+    ".hta",          // HTML trusted application
+    ".htm", ".html",
+    ".htt",                // MS HTML template
+    ".img",                // Mac disk image
+    ".imgpart",            // Mac disk image
+    ".inf",                // Windows installer
+    ".ini",                // Generic config file
+    ".ins",                // IIS config
+    ".iso",                // CD image
+    ".isp",                // IIS config
+    ".jar",                // Java
+    ".jnlp",               // Java
+    ".js",                 // JavaScript script
+    ".jse",                // JScript
+    ".ksh",                // Linux shell
+    ".lnk",                // Windows
+    ".local",              // Windows
+    ".mad",                // MS Access
+    ".maf",                // MS Access
+    ".mag",                // MS Access
+    ".mam",                // MS Access
+    ".manifest",           // Windows
+    ".maq",                // MS Access
+    ".mar",                // MS Access
+    ".mas",                // MS Access
+    ".mat",                // MS Access
+    ".mau",                // Media attachment
+    ".mav",                // MS Access
+    ".maw",                // MS Access
+    ".mda",                // MS Access
+    ".mdb",                // MS Access
+    ".mde",                // MS Access
+    ".mdt",                // MS Access
+    ".mdw",                // MS Access
+    ".mdz",                // MS Access
+    ".mht",                // MS HTML
+    ".mhtml",              // MS HTML
+    ".mim",                // MS Mail
+    ".mmc",                // MS Office
+    ".mof",                // Windows
+    ".mpkg",               // Mac installer
+    ".msc",                // Windows executable
+    ".msg",                // MS Outlook
+    ".msh",                // Windows shell
+    ".msh1",               // Windows shell
+    ".msh1xml",            // Windows shell
+    ".msh2",               // Windows shell
+    ".msh2xml",            // Windows shell
+    ".mshxml",             // Windows
+    ".msi",                // Windows installer
+    ".msp",                // Windows installer
+    ".mst",                // Windows installer
+    ".ndif",               // Mac disk image
+    ".ocx",                // ActiveX
+    ".ops",                // MS Office
+    ".osas",               // AppleScript
+    ".osax",               // AppleScript
+    ".oxt",                // OpenOffice extension, can execute arbitrary code
+    ".partial",            // Downloads
+    ".pax",                // Mac archive
+    ".pcd",                // Microsoft Visual Test
+    ".pdf",                // Adobe Acrobat
+    ".pet",                // Linux package
+    ".pif",                // Windows
+    ".pkg",                // Mac installer
+    ".pl",                 // Perl script
+    ".plg",                // MS Visual Studio
+    ".pot",                // MS PowerPoint
+    ".potm",               // MS PowerPoint
+    ".potx",               // MS PowerPoint
+    ".ppam",               // MS PowerPoint
+    ".pps",                // MS PowerPoint
+    ".ppsm",               // MS PowerPoint
+    ".ppsx",               // MS PowerPoint
+    ".ppt",                // MS PowerPoint
+    ".pptm",               // MS PowerPoint
+    ".pptx",               // MS PowerPoint
+    ".prf",                // MS Outlook
+    ".prg",                // Windows
+    ".ps1",                // Windows shell
+    ".ps1xml",             // Windows shell
+    ".ps2",                // Windows shell
+    ".ps2xml",             // Windows shell
+    ".psc1",               // Windows shell
+    ".psc2",               // Windows shell
+    ".pst",                // MS Outlook
+    ".pup",                // Linux package
+    ".py",                 // Python script
+    ".pyc",                // Python binary
+    ".pyd",                // Equivalent of a DLL, for python libraries
+    ".pyo",                // Compiled python code
+    ".pyw",                // Python GUI
+    ".rb",                 // Ruby script
+    ".reg",                // Windows Registry
+    ".rels",               // MS Office
+    ".rpm",                // Linux package
+    ".rtf",                // MS Office
+    ".scf",                // Windows shell
+    ".scpt",               // AppleScript
+    ".scptd",              // AppleScript
+    ".scr",                // Windows
+    ".sct",                // Windows shell
+    ".search-ms",          // Windows
+    ".seplugin",           // AppleScript
+    ".settingcontent-ms",  // Windows settings
+    ".sh",                 // Linux shell
+    ".shar",               // Linux shell
+    ".shb",                // Windows
+    ".shs",                // Windows shell
+    ".sht",                // HTML
+    ".shtm",               // HTML
+    ".shtml",              // HTML
+    ".sldm",               // MS PowerPoint
+    ".sldx",               // MS PowerPoint
+    ".slk",                // MS Excel
+    ".slp",                // Linux package
+    ".smi",                // Mac disk image
+    ".sparsebundle",       // Mac disk image
+    ".sparseimage",        // Mac disk image
+    ".spl",                // Adobe Flash
+    ".svg",
+    ".swf",       // Adobe Flash
+    ".swm",       // Windows Imaging
+    ".sys",       // Windows
+    ".tar",       // Linux archive
+    ".taz",       // Linux archive (bzip2)
+    ".tbz",       // Linux archive (bzip2)
+    ".tbz2",      // Linux archive (bzip2)
+    ".tcsh",      // Linux shell
+    ".tgz",       // Linux archive (gzip)
+    ".torrent",   // Bittorrent
+    ".tpz",       // Linux archive (gzip)
+    ".txz",       // Linux archive (xz)
+    ".tz",        // Linux archive (gzip)
+    ".udf",       // MS Excel
+    ".udif",      // Mac disk image
+    ".url",       // Windows
+    ".vb",        // Visual Basic script
+    ".vbe",       // Visual Basic script
+    ".vbs",       // Visual Basic script
+    ".vdx",       // MS Visio
+    ".vhd",       // Windows virtual hard drive
+    ".vhdx",      // Windows virtual hard drive
+    ".vmdk",      // VMware virtual disk
+    ".vsd",       // MS Visio
+    ".vsdm",      // MS Visio
+    ".vsdx",      // MS Visio
+    ".vsmacros",  // MS Visual Studio
+    ".vss",       // MS Visio
+    ".vssm",      // MS Visio
+    ".vssx",      // MS Visio
+    ".vst",       // MS Visio
+    ".vstm",      // MS Visio
+    ".vstx",      // MS Visio
+    ".vsw",       // MS Visio
+    ".vsx",       // MS Visio
+    ".vtx",       // MS Visio
+    ".website",   // Windows
+    ".wim",       // Windows Imaging
+    ".ws",        // Windows script
+    ".wsc",       // Windows script
+    ".wsf",       // Windows script
+    ".wsh",       // Windows script
+    ".xar",       // MS Excel
+    ".xbap",      // XAML Browser Application
+    ".xht", ".xhtm", ".xhtml",
+    ".xip",     // Mac archive
+    ".xla",     // MS Excel
+    ".xlam",    // MS Excel
+    ".xldm",    // MS Excel
+    ".xll",     // MS Excel
+    ".xlm",     // MS Excel
+    ".xls",     // MS Excel
+    ".xlsb",    // MS Excel
+    ".xlsm",    // MS Excel
+    ".xlsx",    // MS Excel
+    ".xlt",     // MS Excel
+    ".xltm",    // MS Excel
+    ".xltx",    // MS Excel
+    ".xlw",     // MS Excel
+    ".xml",     // MS Excel
+    ".xnk",     // MS Exchange
+    ".xrm-ms",  // Windows
+    ".xsl",     // XML Stylesheet
+    ".xz",      // Linux archive (xz)
+    ".z",       // InstallShield
+#ifdef XP_WIN   // disable on Mac/Linux, see 1167493
+    ".zip",     // Generic archive
+#endif
+    ".zipx",  // WinZip
+};
+
+#define CheckListSorted(_list)                                   \
+  {                                                              \
+    for (size_t i = 1; i < mozilla::ArrayLength(_list); ++i) {   \
+      nsDependentCString str1((_list)[i - 1]);                   \
+      nsDependentCString str2((_list)[i]);                       \
+      EXPECT_LE(Compare(str1, str2), -1)                         \
+          << "Expected " << str1.get() << " to be sorted after " \
+          << str2.get();                                         \
+    }                                                            \
+  }
+
+// First, verify that the 2 lists are both sorted. This helps when checking for
+// duplicates manually, ensures we could start doing more efficient lookups if
+// we felt that was necessary (e.g. if the lists get much bigger), and that it's
+// easy for humans to find things...
+TEST(TestExecutableLists, ListsAreSorted) {
+  CheckListSorted(sExecutableExts);
+  CheckListSorted(ApplicationReputationService::kBinaryFileExtensions);
+  CheckListSorted(ApplicationReputationService::kNonBinaryExecutables);
+  CheckListSorted(kTestFileExtensions);
+}
+
+bool _IsInList(const char* ext, const char* const _list[], const size_t len) {
+  nsDependentCString extStr(ext);
+  for (size_t i = 0; i < len; ++i) {
+    if (extStr.EqualsASCII(_list[i])) {
+      return true;
+    }
+  }
+  return false;
+}
+
+#define IsInList(_ext, _list) \
+  _IsInList(_ext, _list, mozilla::ArrayLength(_list))
+
+TEST(TestExecutableLists, NonBinariesInExecutablesList) {
+  for (auto nonBinary : ApplicationReputationService::kNonBinaryExecutables) {
+    EXPECT_TRUE(IsInList(nonBinary, sExecutableExts))
+        << "Expected " << nonBinary << " to be part of sExecutableExts list";
+  }
+}
+
+TEST(TestExecutableLists, AllExtensionsInTestList) {
+  for (auto ext : ApplicationReputationService::kBinaryFileExtensions) {
+    EXPECT_TRUE(IsInList(ext, kTestFileExtensions))
+        << "Expected binary extension " << ext
+        << " to be listed in the test extension list";
+  }
+
+  for (auto ext : sExecutableExts) {
+    EXPECT_TRUE(IsInList(ext, kTestFileExtensions))
+        << "Expected executable extension " << ext
+        << " to be listed in the test extension list";
+  }
+
+  for (auto ext : ApplicationReputationService::kNonBinaryExecutables) {
+    EXPECT_TRUE(IsInList(ext, kTestFileExtensions))
+        << "Expected non-binary executable extension " << ext
+        << " to be listed in the test extension list";
+  }
+}
+
+TEST(TestExecutableLists, TestListExtensionsExistSomewhere) {
+  for (auto ext : kTestFileExtensions) {
+    EXPECT_TRUE(
+        IsInList(ext, ApplicationReputationService::kBinaryFileExtensions) !=
+        IsInList(ext, sExecutableExts))
+        << "Expected test extension " << ext
+        << " to be in exactly one of the other lists.";
+  }
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/reputationservice/test/gtest/moz.build
@@ -0,0 +1,19 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+LOCAL_INCLUDES += [
+    '../..',
+]
+
+DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True
+DEFINES['GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER'] = True
+
+UNIFIED_SOURCES += [
+  'TestExecutableLists.cpp'
+]
+
+FINAL_LIBRARY = 'xul-gtest'
+
--- a/xpcom/io/moz.build
+++ b/xpcom/io/moz.build
@@ -70,16 +70,17 @@ EXPORTS += [
     'nsAnonymousTemporaryFile.h',
     'nsAppDirectoryServiceDefs.h',
     'nsDirectoryService.h',
     'nsDirectoryServiceDefs.h',
     'nsDirectoryServiceUtils.h',
     'nsEscape.h',
     'nsLinebreakConverter.h',
     'nsLocalFile.h',
+    'nsLocalFileCommon.h',
     'nsMultiplexInputStream.h',
     'nsNativeCharsetUtils.h',
     'nsScriptableInputStream.h',
     'nsStorageStream.h',
     'nsStreamUtils.h',
     'nsStringStream.h',
     'nsUnicharInputStream.h',
     'nsWildCard.h',
--- a/xpcom/io/nsLocalFileCommon.cpp
+++ b/xpcom/io/nsLocalFileCommon.cpp
@@ -11,21 +11,122 @@
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsReadableUtils.h"
 #include "nsPrintfCString.h"
 #include "nsCRT.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsUTF8Utils.h"
 #include "nsArray.h"
+#include "nsLocalFileCommon.h"
 
 #ifdef XP_WIN
 #  include <string.h>
 #endif
 
+// Extensions that should be considered 'executable', ie will not allow users
+// to open immediately without first saving to disk, and potentially provoke
+// other warnings. PLEASE read the longer comment in
+// toolkit/components/reputationservice/ApplicationReputation.h
+// before modifying this list!
+/* static */
+const char* const sExecutableExts[] = {
+    // clang-format off
+  ".ad",
+  ".ade",         // access project extension
+  ".adp",
+  ".air",         // Adobe AIR installer
+  ".app",         // executable application
+  ".application", // from bug 348763
+  ".asp",
+  ".bas",
+  ".bat",
+  ".chm",
+  ".cmd",
+  ".com",
+  ".cpl",
+  ".crt",
+  ".exe",
+  ".fxp",         // FoxPro compiled app
+  ".hlp",
+  ".hta",
+  ".inf",
+  ".ins",
+  ".isp",
+  ".jar",         // java application bundle
+  ".jnlp",
+  ".js",
+  ".jse",
+  ".lnk",
+  ".mad",         // Access Module Shortcut
+  ".maf",         // Access
+  ".mag",         // Access Diagram Shortcut
+  ".mam",         // Access Macro Shortcut
+  ".maq",         // Access Query Shortcut
+  ".mar",         // Access Report Shortcut
+  ".mas",         // Access Stored Procedure
+  ".mat",         // Access Table Shortcut
+  ".mau",         // Media Attachment Unit
+  ".mav",         // Access View Shortcut
+  ".maw",         // Access Data Access Page
+  ".mda",         // Access Add-in, MDA Access 2 Workgroup
+  ".mdb",
+  ".mde",
+  ".mdt",         // Access Add-in Data
+  ".mdw",         // Access Workgroup Information
+  ".mdz",         // Access Wizard Template
+  ".msc",
+  ".msh",         // Microsoft Shell
+  ".msh1",        // Microsoft Shell
+  ".msh1xml",     // Microsoft Shell
+  ".msh2",        // Microsoft Shell
+  ".msh2xml",     // Microsoft Shell
+  ".mshxml",      // Microsoft Shell
+  ".msi",
+  ".msp",
+  ".mst",
+  ".ops",         // Office Profile Settings
+  ".pcd",
+  ".pif",
+  ".plg",         // Developer Studio Build Log
+  ".prf",         // windows system file
+  ".prg",
+  ".pst",
+  ".reg",
+  ".scf",         // Windows explorer command
+  ".scr",
+  ".sct",
+  ".settingcontent-ms",
+  ".shb",
+  ".shs",
+  ".url",
+  ".vb",
+  ".vbe",
+  ".vbs",
+  ".vdx",
+  ".vsd",
+  ".vsdm",
+  ".vsdx",
+  ".vsmacros",    // Visual Studio .NET Binary-based Macro Project
+  ".vss",
+  ".vssm",
+  ".vssx",
+  ".vst",
+  ".vstm",
+  ".vstx",
+  ".vsw",
+  ".vsx",
+  ".vtx",
+  ".ws",
+  ".wsc",
+  ".wsf",
+  ".wsh"
+    // clang-format on
+};
+
 #if !defined(MOZ_WIDGET_COCOA) && !defined(XP_WIN)
 NS_IMETHODIMP
 nsLocalFile::InitWithFile(nsIFile* aFile) {
   if (NS_WARN_IF(!aFile)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsAutoCString path;
new file mode 100644
--- /dev/null
+++ b/xpcom/io/nsLocalFileCommon.h
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _NS_LOCAL_FILE_COMMON_H_
+#define _NS_LOCAL_FILE_COMMON_H_
+
+extern const char* const sExecutableExts[89];
+
+#endif
--- a/xpcom/io/nsLocalFileWin.cpp
+++ b/xpcom/io/nsLocalFileWin.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/UniquePtrExtensions.h"
 
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsMemory.h"
 #include "GeckoProfiler.h"
 
 #include "nsLocalFile.h"
+#include "nsLocalFileCommon.h"
 #include "nsIDirectoryEnumerator.h"
 #include "nsNativeCharsetUtils.h"
 
 #include "nsSimpleEnumerator.h"
 #include "nsIComponentManager.h"
 #include "prio.h"
 #include "private/pprio.h"  // To get PR_ImportFile
 #include "nsHashKeys.h"
@@ -2735,99 +2736,19 @@ nsLocalFile::IsExecutable(bool* aResult)
   int32_t dotIdx = path.RFindChar(char16_t('.'));
   if (dotIdx != kNotFound) {
     // Convert extension to lower case.
     char16_t* p = path.BeginWriting();
     for (p += dotIdx + 1; *p; ++p) {
       *p += (*p >= L'A' && *p <= L'Z') ? 'a' - 'A' : 0;
     }
 
-    // Search for any of the set of executable extensions.
-    static const char* const executableExts[] = {
-        // clang-format off
-      "ad",
-      "ade",         // access project extension
-      "adp",
-      "air",         // Adobe AIR installer
-      "app",         // executable application
-      "application", // from bug 348763
-      "asp",
-      "bas",
-      "bat",
-      "chm",
-      "cmd",
-      "com",
-      "cpl",
-      "crt",
-      "exe",
-      "fxp",         // FoxPro compiled app
-      "hlp",
-      "hta",
-      "inf",
-      "ins",
-      "isp",
-      "jar",         // java application bundle
-      "js",
-      "jse",
-      "lnk",
-      "mad",         // Access Module Shortcut
-      "maf",         // Access
-      "mag",         // Access Diagram Shortcut
-      "mam",         // Access Macro Shortcut
-      "maq",         // Access Query Shortcut
-      "mar",         // Access Report Shortcut
-      "mas",         // Access Stored Procedure
-      "mat",         // Access Table Shortcut
-      "mau",         // Media Attachment Unit
-      "mav",         // Access View Shortcut
-      "maw",         // Access Data Access Page
-      "mda",         // Access Add-in, MDA Access 2 Workgroup
-      "mdb",
-      "mde",
-      "mdt",         // Access Add-in Data
-      "mdw",         // Access Workgroup Information
-      "mdz",         // Access Wizard Template
-      "msc",
-      "msh",         // Microsoft Shell
-      "mshxml",      // Microsoft Shell
-      "msi",
-      "msp",
-      "mst",
-      "ops",         // Office Profile Settings
-      "pcd",
-      "pif",
-      "plg",         // Developer Studio Build Log
-      "prf",         // windows system file
-      "prg",
-      "pst",
-      "reg",
-      "scf",         // Windows explorer command
-      "scr",
-      "sct",
-      "settingcontent-ms",
-      "shb",
-      "shs",
-      "url",
-      "vb",
-      "vbe",
-      "vbs",
-      "vsd",
-      "vsmacros",    // Visual Studio .NET Binary-based Macro Project
-      "vss",
-      "vst",
-      "vsw",
-      "ws",
-      "wsc",
-      "wsf",
-      "wsh"
-        // clang-format on
-    };
-    nsDependentSubstring ext = Substring(path, dotIdx + 1);
-    for (size_t i = 0; i < ArrayLength(executableExts); ++i) {
-      if (ext.EqualsASCII(executableExts[i])) {
+    nsDependentSubstring ext = Substring(path, dotIdx);
+    for (size_t i = 0; i < ArrayLength(sExecutableExts); ++i) {
+      if (ext.EqualsASCII(sExecutableExts[i])) {
         // Found a match.  Set result and quit.
         *aResult = true;
         break;
       }
     }
   }
 
   return NS_OK;