diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties b/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties
index d0395d6a1af9b3129c4a10a0feab3230af9304a1..bd06716288dd34cc480b2c4ae540220ef0714b54 100644
--- a/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties
@@ -24,5 +24,3 @@ CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text=
 EULADialog.cancelButton.text=Cancel
 EULADialog.acceptButton.text=Accept
 EULADialog.title=Cyber Triage End User License Agreement
-CTMalwareScannerOptionsPanel.fileUploadCheckbox.text=Upload file if hash lookup produces no results
-CTMalwareScannerOptionsPanel.fileUploadPanel.border.title=File Upload
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties-MERGED b/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties-MERGED
index 18e60839f3f3f38106cff8b0507a623af5221106..ccd4780aae1390257815a1be6383327f41a7383f 100644
--- a/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties-MERGED
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties-MERGED
@@ -62,5 +62,3 @@ CTOPtionsPanel_loadMalwareScansInfo_loading=Loading...
 EULADialog.cancelButton.text=Cancel
 EULADialog.acceptButton.text=Accept
 EULADialog.title=Cyber Triage End User License Agreement
-CTMalwareScannerOptionsPanel.fileUploadCheckbox.text=Upload file if hash lookup produces no results
-CTMalwareScannerOptionsPanel.fileUploadPanel.border.title=File Upload
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.form b/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.form
index 8557f946d95770c3e1462ce2345afdbd4d85f0d5..407f55844a6525143efd5865ab9039cb72e8870f 100644
--- a/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.form
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.form
@@ -16,49 +16,6 @@
 
   <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
   <SubComponents>
-    <Container class="javax.swing.JPanel" name="fileUploadPanel">
-      <Properties>
-        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
-          <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
-            <TitledBorder title="File Upload">
-              <ResourceString PropertyName="titleX" bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.fileUploadPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-            </TitledBorder>
-          </Border>
-        </Property>
-      </Properties>
-      <AuxValues>
-        <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
-        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
-      </AuxValues>
-      <Constraints>
-        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
-          <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
-        </Constraint>
-      </Constraints>
-
-      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
-      <SubComponents>
-        <Component class="javax.swing.JCheckBox" name="fileUploadCheckbox">
-          <Properties>
-            <Property name="selected" type="boolean" value="true"/>
-            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-              <ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.fileUploadCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-            </Property>
-            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
-              <Dimension value="[32767, 20]"/>
-            </Property>
-          </Properties>
-          <Events>
-            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="fileUploadCheckboxActionPerformed"/>
-          </Events>
-          <Constraints>
-            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
-              <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="1.0"/>
-            </Constraint>
-          </Constraints>
-        </Component>
-      </SubComponents>
-    </Container>
     <Container class="javax.swing.JPanel" name="licenseInfoPanel">
       <Properties>
         <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.java
index 2a09c1ed5518cf3a69d834610c371b93ce16b404..1abd64b2d9d9c39aa9aa22fd800ae938d587e1e2 100644
--- a/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.java
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.java
@@ -141,15 +141,13 @@ private synchronized LicenseResponse getLicenseInfo() {
     }
 
     private MalwareIngestSettings getIngestSettings() {
-        return new MalwareIngestSettings()
-                .setUploadFiles(this.fileUploadCheckbox.isSelected());
+        return new MalwareIngestSettings();
     }
 
     private void setIngestSettings(MalwareIngestSettings ingestSettings) {
         if (ingestSettings == null) {
             ingestSettings = new MalwareIngestSettings();
         }
-        this.fileUploadCheckbox.setSelected(ingestSettings.isUploadFiles());
     }
 
     private synchronized void setLicenseDisplay(LicenseInfo licenseInfo, String licenseMessage) {
@@ -220,8 +218,6 @@ private synchronized void loadMalwareScansInfo(LicenseInfo licenseInfo) {
     private void initComponents() {
         java.awt.GridBagConstraints gridBagConstraints;
 
-        javax.swing.JPanel fileUploadPanel = new javax.swing.JPanel();
-        fileUploadCheckbox = new javax.swing.JCheckBox();
         javax.swing.JPanel licenseInfoPanel = new javax.swing.JPanel();
         licenseInfoMessageLabel = new javax.swing.JLabel();
         licenseInfoUserLabel = new javax.swing.JLabel();
@@ -238,35 +234,6 @@ private void initComponents() {
 
         setLayout(new java.awt.GridBagLayout());
 
-        fileUploadPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.fileUploadPanel.border.title"))); // NOI18N
-        fileUploadPanel.setLayout(new java.awt.GridBagLayout());
-
-        fileUploadCheckbox.setSelected(true);
-        org.openide.awt.Mnemonics.setLocalizedText(fileUploadCheckbox, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.fileUploadCheckbox.text")); // NOI18N
-        fileUploadCheckbox.setMaximumSize(new java.awt.Dimension(32767, 20));
-        fileUploadCheckbox.addActionListener(new java.awt.event.ActionListener() {
-            public void actionPerformed(java.awt.event.ActionEvent evt) {
-                fileUploadCheckboxActionPerformed(evt);
-            }
-        });
-        gridBagConstraints = new java.awt.GridBagConstraints();
-        gridBagConstraints.gridx = 0;
-        gridBagConstraints.gridy = 0;
-        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
-        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
-        gridBagConstraints.weightx = 1.0;
-        gridBagConstraints.weighty = 1.0;
-        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
-        fileUploadPanel.add(fileUploadCheckbox, gridBagConstraints);
-
-        gridBagConstraints = new java.awt.GridBagConstraints();
-        gridBagConstraints.gridx = 0;
-        gridBagConstraints.gridy = 0;
-        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
-        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
-        gridBagConstraints.weightx = 1.0;
-        add(fileUploadPanel, gridBagConstraints);
-
         licenseInfoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoPanel.border.title"))); // NOI18N
         licenseInfoPanel.setLayout(new java.awt.GridBagLayout());
 
@@ -427,10 +394,6 @@ private void licenseInfoAddButtonActionPerformed(java.awt.event.ActionEvent evt)
         }
     }//GEN-LAST:event_licenseInfoAddButtonActionPerformed
 
-    private void fileUploadCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileUploadCheckboxActionPerformed
-        this.firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
-    }//GEN-LAST:event_fileUploadCheckboxActionPerformed
-
     @NbBundle.Messages({
         "# {0} - userName",
         "# {1} - email",
@@ -691,7 +654,6 @@ protected void done() {
 
     // Variables declaration - do not modify//GEN-BEGIN:variables
     private javax.swing.JLabel countersResetLabel;
-    private javax.swing.JCheckBox fileUploadCheckbox;
     private javax.swing.JLabel fileUploadsRemainingLabel;
     private javax.swing.JLabel hashLookupsRemainingLabel;
     private javax.swing.JButton licenseInfoAddButton;
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties
new file mode 100644
index 0000000000000000000000000000000000000000..e9fdcb1cb54558342fc3c773008a4300170573a4
--- /dev/null
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties
@@ -0,0 +1,7 @@
+MalwareScanIngestSettingsPanel.uploadFilesCheckbox.AccessibleContext.accessibleName=Upload file content for files that do not have results
+MalwareScanIngestSettingsPanel.uploadFilesCheckbox.label=Upload file content for files that do not have results
+MalwareScanIngestSettingsPanel.uploadFilesCheckbox.text=Upload file content for files that do not have results
+DataSourceIntegrityIngestSettingsPanel.queryFilesTextArea.text=Query file existing results using file\u2019s hash
+MalwareScanIngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings
+MalwareScanIngestSettingsPanel.paidLicenseTextArea.text=This module requires a paid license. \nSee the Global Options panel for details
+MalwareScanIngestSettingsPanel.queryFilesCheckbox.text=Query for existing results using file\u2019s hash
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties-MERGED b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties-MERGED
index 4380a9607c8ce4600aabba5cd89473c2aca49e73..3b886d02cb0bee0184d225eeb75d4bd809c1bba9 100644
--- a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties-MERGED
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties-MERGED
@@ -38,6 +38,13 @@ MalwareScanIngestModule_uploadFile_noRemainingFileUploads_title=No Remaining Fil
 # {0} - objectId
 MalwareScanIngestModule_uploadFile_notUploadable_desc=A file did not meet requirements for upload (object id: {0}).
 MalwareScanIngestModule_uploadFile_notUploadable_title=Not Able to Upload
-MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the Cyber Triage cloud API for any possible malicious executables.
+MalwareScanIngestModuleFactory_description=Identifies executable files with malware.
 MalwareScanIngestModuleFactory_displayName=Cyber Triage Malware Scanner
 MalwareScanIngestModuleFactory_version=1.0.0
+MalwareScanIngestSettingsPanel.uploadFilesCheckbox.AccessibleContext.accessibleName=Upload file content for files that do not have results
+MalwareScanIngestSettingsPanel.uploadFilesCheckbox.label=Upload file content for files that do not have results
+MalwareScanIngestSettingsPanel.uploadFilesCheckbox.text=Upload file content for files that do not have results
+DataSourceIntegrityIngestSettingsPanel.queryFilesTextArea.text=Query file existing results using file\u2019s hash
+MalwareScanIngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings
+MalwareScanIngestSettingsPanel.paidLicenseTextArea.text=This module requires a paid license. \nSee the Global Options panel for details
+MalwareScanIngestSettingsPanel.queryFilesCheckbox.text=Query for existing results using file\u2019s hash
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle_ar.properties b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle_ar.properties
new file mode 100644
index 0000000000000000000000000000000000000000..7a6ad43a3eeca38110aa9e58feb73a9387bd005e
--- /dev/null
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle_ar.properties
@@ -0,0 +1 @@
+MalwareScanIngestSettingsPanel.ingestSettingsLabel.text=Configuracion de Ingesta
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle_ja.properties b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle_ja.properties
new file mode 100644
index 0000000000000000000000000000000000000000..cff7aa2e8d4fc8680cb0c317c8ce19a7d57369c2
--- /dev/null
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle_ja.properties
@@ -0,0 +1 @@
+MalwareScanIngestSettingsPanel.ingestSettingsLabel.text=\u53d6\u8fbc\u307f\u8a2d\u5b9a
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModule.java b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModule.java
index c52e72a350db8f8c6267460ec4531e6d19082912..190b1412ce1909d71f8b3d901379df0cadf8cad4 100644
--- a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModule.java
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModule.java
@@ -72,10 +72,17 @@
 class MalwareScanIngestModule implements FileIngestModule {
 
     private static final SharedProcessing sharedProcessing = new SharedProcessing();
-
+    private boolean uploadFiles;
+    private boolean queryFiles;
+    
+    MalwareScanIngestModule(MalwareScanIngestSettings settings) {
+        uploadFiles = settings.shouldUploadFiles();
+        queryFiles = settings.shouldQueryFiles();  
+    }
+    
     @Override
     public void startUp(IngestJobContext context) throws IngestModuleException {
-        sharedProcessing.startUp(context);
+        sharedProcessing.startUp(context, uploadFiles);
     }
 
     @Override
@@ -123,7 +130,7 @@ private static class SharedProcessing {
                 "application/msdos-windows",//NON-NLS
                 "application/x-msdos-program"//NON-NLS
         ).collect(Collectors.toSet());
-
+        
         private static final String MALWARE_TYPE_NAME = "TSK_MALWARE";
         private static final String MALWARE_CONFIG = "Cyber Triage Cloud";
 
@@ -153,14 +160,14 @@ private static class SharedProcessing {
             "MalwareScanIngestModule_ShareProcessing_lowUploadsLimitWarning_title=File Uploads Limit Low",
             "# {0} - remainingUploads",
             "MalwareScanIngestModule_ShareProcessing_lowUploadsLimitWarning_desc=This license only has {0} file uploads remaining.",})
-        synchronized void startUp(IngestJobContext context) throws IngestModuleException {
+        synchronized void startUp(IngestJobContext context, boolean uploadFiles) throws IngestModuleException {
             // only run this code once per startup
             if (ingestJobState != null) {
                 return;
             }
 
             try {
-                ingestJobState = getNewJobState(context);
+                ingestJobState = getNewJobState(context, uploadFiles);
             } catch (Exception ex) {
                 ingestJobState = IngestJobState.DISABLED;
                 throw new IngestModuleException("An exception occurred on MalwareScanIngestModule startup", ex);
@@ -175,7 +182,7 @@ synchronized void startUp(IngestJobContext context) throws IngestModuleException
          * parameters required for the job.
          * @throws Exception
          */
-        private IngestJobState getNewJobState(IngestJobContext context) throws Exception {
+        private IngestJobState getNewJobState(IngestJobContext context, boolean uploadFiles) throws Exception {
             // get saved license
             Optional<LicenseInfo> licenseInfoOpt = ctSettingsPersistence.loadLicenseInfo();
             if (licenseInfoOpt.isEmpty() || licenseInfoOpt.get().getDecryptedLicense() == null) {
@@ -207,7 +214,6 @@ private IngestJobState getNewJobState(IngestJobContext context) throws Exception
             }
 
             // determine lookups remaining
-            boolean uploadFiles = ctSettingsPersistence.loadMalwareIngestSettings().isUploadFiles();
             if (uploadFiles) {
                 long uploadsRemaining = remaining(authTokenResponse.getFileUploadLimit(), authTokenResponse.getFileUploadCount());
                 if (uploadsRemaining <= 0) {
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModuleFactory.java b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModuleFactory.java
index e1381160363d093f7daff876c69d2b7febca2d9b..83cb93f689c8c2b7545bcee863c5e32a2689cb0f 100644
--- a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModuleFactory.java
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModuleFactory.java
@@ -25,6 +25,8 @@
 import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
 import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
 import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
+import org.sleuthkit.autopsy.ingest.NoIngestModuleIngestJobSettings;
 
 /**
  * Factory for malware scan ingest modules.
@@ -32,7 +34,7 @@
 @ServiceProvider(service = org.sleuthkit.autopsy.ingest.IngestModuleFactory.class)
 @Messages({
     "MalwareScanIngestModuleFactory_displayName=Cyber Triage Malware Scanner",
-    "MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the Cyber Triage cloud API for any possible malicious executables.",
+    "MalwareScanIngestModuleFactory_description=Identifies executable files with malware.",
     "MalwareScanIngestModuleFactory_version=1.0.0"
 })
 public class MalwareScanIngestModuleFactory extends IngestModuleFactoryAdapter {
@@ -66,7 +68,7 @@ public boolean isFileIngestModuleFactory() {
 
     @Override
     public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings ingestOptions) {
-        return new MalwareScanIngestModule();
+        return new MalwareScanIngestModule((MalwareScanIngestSettings) ingestOptions);
     }
 
     @Override
@@ -81,4 +83,23 @@ public IngestModuleGlobalSettingsPanel getGlobalSettingsPanel() {
         return optionsPanel;
     }
 
+    @Override
+    public boolean hasIngestJobSettingsPanel() {
+        return true;
+    }
+
+    @Override
+    public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) {
+        if (settings instanceof MalwareScanIngestSettings) {
+            return new MalwareScanIngestSettingsPanel((MalwareScanIngestSettings) settings);
+        }
+        /*
+         * Compatibility check for older versions.
+         */
+        if (settings instanceof NoIngestModuleIngestJobSettings) {
+            return new MalwareScanIngestSettingsPanel(new MalwareScanIngestSettings());
+        }
+        
+        throw new IllegalArgumentException("Expected settings argument to be an instance of IngestSettings");
+    }
 }
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestSettings.java b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestSettings.java
new file mode 100644
index 0000000000000000000000000000000000000000..158e9677457664b8f0793df023b4f5845ec2e878
--- /dev/null
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestSettings.java
@@ -0,0 +1,96 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2023 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.basistech.df.cybertriage.autopsy.malwarescan;
+
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
+
+/**
+ * Ingest job settings for the Malware scanner module.
+ */
+final class MalwareScanIngestSettings implements IngestModuleIngestJobSettings {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final boolean DEFAULT_QUERY_FILES = true;
+    private static final boolean DEFAULT_UPLOAD_FILES = true;
+    
+    public boolean queryFiles;
+    public boolean uploadFiles;
+
+    /**
+     * Instantiate the ingest job settings with default values.
+     */
+    MalwareScanIngestSettings() {
+        this.queryFiles = DEFAULT_QUERY_FILES;
+        this.uploadFiles = DEFAULT_UPLOAD_FILES;
+    }
+
+    /**
+     * Instantiate the ingest job settings.
+     * 
+     * @param computeHashes  Compute hashes if none are present
+     * @param verifyHashes   Verify hashes if any are present
+     */
+    MalwareScanIngestSettings(boolean queryFiles, boolean uploadFiles) {
+        this.queryFiles = queryFiles;
+        this.uploadFiles = uploadFiles;
+    }
+
+    @Override
+    public long getVersionNumber() {
+        return serialVersionUID;
+    }
+    
+    /**
+     * Should files be queried?
+     * 
+     * @return true if files should be queried, false otherwise
+     */
+    public boolean shouldQueryFiles() {
+        return queryFiles;
+    }
+    
+    /**
+     * Set whether files should be queried.
+     * 
+     * @param queryFiles true if files should be queried
+     */
+    void setqueryFiles(boolean queryFiles) {
+        this.queryFiles = queryFiles;
+    }
+    
+    
+    /**
+     * Should files be uploaded?
+     * 
+     * @return true if files should be uploaded, false otherwise
+     */
+    public boolean shouldUploadFiles() {
+        return uploadFiles;
+    }    
+    
+    /**
+     * Set whether files should be uploaded.
+     * 
+     * @param uploadFiles true if files should be uploaded
+     */
+    void setUploadFiles(boolean uploadFiles) {
+        this.uploadFiles = uploadFiles;
+    }
+}
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestSettingsPanel.form b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestSettingsPanel.form
new file mode 100644
index 0000000000000000000000000000000000000000..46a928c98eda4ef9d1cd9bbdc70f65efd976632c
--- /dev/null
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestSettingsPanel.form
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <Properties>
+    <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[300, 155]"/>
+    </Property>
+  </Properties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <EmptySpace min="6" pref="6" max="-2" attributes="0"/>
+                      <Component id="ingestSettingsLabel" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" attributes="0">
+                      <EmptySpace min="6" pref="6" max="-2" attributes="0"/>
+                      <Component id="uploadFilesCheckbox" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="queryFilesCheckbox" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
+                      <Component id="paidLicenseTextArea" min="-2" pref="243" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+              <EmptySpace min="-2" pref="185" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="ingestSettingsLabel" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
+              <Component id="queryFilesCheckbox" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="uploadFilesCheckbox" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
+              <Component id="paidLicenseTextArea" min="-2" pref="32" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JCheckBox" name="queryFilesCheckbox">
+      <Properties>
+        <Property name="selected" type="boolean" value="true"/>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.queryFilesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="enabled" type="boolean" value="false"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JCheckBox" name="uploadFilesCheckbox">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.uploadFilesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="focusable" type="boolean" value="false"/>
+        <Property name="label" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.uploadFilesCheckbox.label" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <AccessibilityProperties>
+        <Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.uploadFilesCheckbox.AccessibleContext.accessibleName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </AccessibilityProperties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="ingestSettingsLabel">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
+          <FontInfo relative="true">
+            <Font bold="true" component="ingestSettingsLabel" property="font" relativeSize="true" size="0"/>
+          </FontInfo>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.ingestSettingsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextArea" name="paidLicenseTextArea">
+      <Properties>
+        <Property name="columns" type="int" value="20"/>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+          <Font name="Segoe UI" size="12" style="1"/>
+        </Property>
+        <Property name="rows" type="int" value="5"/>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.paidLicenseTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="wrapStyleWord" type="boolean" value="true"/>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="null"/>
+        </Property>
+        <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
+          <Color id="Default Cursor"/>
+        </Property>
+        <Property name="focusable" type="boolean" value="false"/>
+        <Property name="opaque" type="boolean" value="false"/>
+        <Property name="requestFocusEnabled" type="boolean" value="false"/>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestSettingsPanel.java b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestSettingsPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..a418de0f833cb32fb9fc3b81c21cc9f9342b8de0
--- /dev/null
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestSettingsPanel.java
@@ -0,0 +1,149 @@
+/*
+ * Autopsy Browser
+ *
+ * Copyright 2023 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.basistech.df.cybertriage.autopsy.malwarescan;
+
+import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo;
+import com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud.CTLicensePersistence;
+import java.util.Optional;
+import org.sleuthkit.autopsy.modules.dataSourceIntegrity.*;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
+
+/**
+ * Ingest job settings panel for the Malware scanner ingest.
+ */
+@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
+final class MalwareScanIngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
+
+    private final CTLicensePersistence ctPersistence = CTLicensePersistence.getInstance();
+    
+    MalwareScanIngestSettingsPanel(MalwareScanIngestSettings settings) {
+        initComponents();
+        customizeComponents(settings);
+    }
+
+    /**
+     * Update components with values from the ingest job settings.
+     *
+     * @param settings The ingest job settings.
+     */
+    private void customizeComponents(MalwareScanIngestSettings settings) {
+        Optional<LicenseInfo> licenseInfoOpt = ctPersistence.loadLicenseInfo();
+        LicenseInfo licenseInfo = licenseInfoOpt.orElse(null);
+        if (licenseInfo != null) {
+            this.paidLicenseTextArea.setVisible(false);
+            this.queryFilesCheckbox.setVisible(true);
+            this.queryFilesCheckbox.setEnabled(false);
+            this.uploadFilesCheckbox.setVisible(true);
+            this.queryFilesCheckbox.setSelected(true);
+            this.uploadFilesCheckbox.setSelected(settings.shouldUploadFiles());
+        } else {
+            this.paidLicenseTextArea.setVisible(true);
+            this.queryFilesCheckbox.setVisible(false);
+            this.uploadFilesCheckbox.setVisible(false);       
+        }
+    }
+    
+    @Override
+    public IngestModuleIngestJobSettings getSettings() {
+        return new MalwareScanIngestSettings(queryFilesCheckbox.isSelected(), uploadFilesCheckbox.isSelected());
+    }
+
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        queryFilesCheckbox = new javax.swing.JCheckBox();
+        uploadFilesCheckbox = new javax.swing.JCheckBox();
+        ingestSettingsLabel = new javax.swing.JLabel();
+        paidLicenseTextArea = new javax.swing.JTextArea();
+
+        setPreferredSize(new java.awt.Dimension(300, 155));
+
+        queryFilesCheckbox.setSelected(true);
+        org.openide.awt.Mnemonics.setLocalizedText(queryFilesCheckbox, org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.queryFilesCheckbox.text")); // NOI18N
+        queryFilesCheckbox.setEnabled(false);
+
+        org.openide.awt.Mnemonics.setLocalizedText(uploadFilesCheckbox, org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.uploadFilesCheckbox.text")); // NOI18N
+        uploadFilesCheckbox.setFocusable(false);
+        uploadFilesCheckbox.setLabel(org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.uploadFilesCheckbox.label")); // NOI18N
+
+        ingestSettingsLabel.setFont(ingestSettingsLabel.getFont().deriveFont(ingestSettingsLabel.getFont().getStyle() | java.awt.Font.BOLD));
+        org.openide.awt.Mnemonics.setLocalizedText(ingestSettingsLabel, org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.ingestSettingsLabel.text")); // NOI18N
+
+        paidLicenseTextArea.setColumns(20);
+        paidLicenseTextArea.setFont(new java.awt.Font("Segoe UI", 1, 12)); // NOI18N
+        paidLicenseTextArea.setRows(5);
+        paidLicenseTextArea.setText(org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.paidLicenseTextArea.text")); // NOI18N
+        paidLicenseTextArea.setWrapStyleWord(true);
+        paidLicenseTextArea.setBorder(null);
+        paidLicenseTextArea.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
+        paidLicenseTextArea.setFocusable(false);
+        paidLicenseTextArea.setOpaque(false);
+        paidLicenseTextArea.setRequestFocusEnabled(false);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(layout.createSequentialGroup()
+                        .addGap(6, 6, 6)
+                        .addComponent(ingestSettingsLabel))
+                    .addGroup(layout.createSequentialGroup()
+                        .addGap(6, 6, 6)
+                        .addComponent(uploadFilesCheckbox))
+                    .addGroup(layout.createSequentialGroup()
+                        .addContainerGap()
+                        .addComponent(queryFilesCheckbox))
+                    .addGroup(layout.createSequentialGroup()
+                        .addGap(5, 5, 5)
+                        .addComponent(paidLicenseTextArea, javax.swing.GroupLayout.PREFERRED_SIZE, 243, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                .addGap(185, 185, 185))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(ingestSettingsLabel)
+                .addGap(18, 18, 18)
+                .addComponent(queryFilesCheckbox)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(uploadFilesCheckbox)
+                .addGap(18, 18, 18)
+                .addComponent(paidLicenseTextArea, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE))
+        );
+
+        uploadFilesCheckbox.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.uploadFilesCheckbox.AccessibleContext.accessibleName")); // NOI18N
+    }// </editor-fold>//GEN-END:initComponents
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JLabel ingestSettingsLabel;
+    private javax.swing.JTextArea paidLicenseTextArea;
+    private javax.swing.JCheckBox queryFilesCheckbox;
+    private javax.swing.JCheckBox uploadFilesCheckbox;
+    // End of variables declaration//GEN-END:variables
+
+}