diff --git a/config/install/seckit.settings.yml b/config/install/seckit.settings.yml
index 7c7d11b..1332862 100644
--- a/config/install/seckit.settings.yml
+++ b/config/install/seckit.settings.yml
@@ -39,3 +39,13 @@ seckit_various:
   from_origin_destination: same
   from_origin_destination: ''
   disable_autocomplete: FALSE
+seckit_advanced:
+  disable_seckit: FALSE
+  unlimited_csp_reports: TRUE
+  csp_limits:
+    max_size: 4096
+    flood:
+      limit_user: 100
+      window_user: 900
+      limit_global: 1000
+      window_global: 3600
diff --git a/config/schema/seckit.schema.yml b/config/schema/seckit.schema.yml
index 35e5644..5907aa6 100644
--- a/config/schema/seckit.schema.yml
+++ b/config/schema/seckit.schema.yml
@@ -133,3 +133,36 @@ seckit.settings:
         disable_autocomplete:
           type: boolean
           label: 'Disable autocomplete'
+    seckit_advanced:
+      type: mapping
+      label: 'Advanced'
+      mapping:
+        disable_seckit:
+          type: boolean
+          lablel: 'Disable Seckit'
+        unlimited_csp_reports:
+          type: boolean
+          label: 'Unlimited CSP reports'
+        csp_limits:
+          type: mapping
+          label: 'CSP Violation reporting limits'
+          mapping:
+            max_size:
+              type: integer
+              label: 'Maximum report size (bytes)'
+            flood:
+              type: mapping
+              label: 'Flood Settings'
+              mapping:
+                limit_user:
+                  type: integer
+                  label: 'Maximum reports per IP address'
+                window_user:
+                  type: integer
+                  label: 'Time window for per IP address flood detection'
+                limit_global:
+                  type: integer
+                  label: 'Maximum reports globally (ie. irrespective of IP address)'
+                window_global:
+                  type: integer
+                  label: 'Time window for global flood detection'
diff --git a/seckit.module b/seckit.module
index 5a2cb15..d914fba 100644
--- a/seckit.module
+++ b/seckit.module
@@ -20,6 +20,15 @@ define('SECKIT_X_FRAME_ALLOW_FROM', 3); // set X-Frame-Options HTTP header to Al
 define('SECKIT_CSP_REPORT_URL', 'report-csp-violation');
 
 /**
++ * Default limits for CSP violation reports.
++ */
+define('SECKIT_CSP_REPORT_MAX_SIZE', 4096); // Max accepted byte count
+define('SECKIT_CSP_REPORT_FLOOD_LIMIT_USER', 100); // Max reports per IP address...
+define('SECKIT_CSP_REPORT_FLOOD_WINDOW_USER', 900); // ...per time window (in seconds)
+define('SECKIT_CSP_REPORT_FLOOD_LIMIT_GLOBAL', 1000); // Max reports globally...
+define('SECKIT_CSP_REPORT_FLOOD_WINDOW_GLOBAL', 3600); // ...per time window (in seconds)
+
+/**
  * Implements hook_form_FORM_ID_alter() for 'user_login'.
  */
 function seckit_form_user_login_form_alter(&$form, FormStateInterface &$form_state) {
@@ -45,3 +54,55 @@ function _seckit_form_alter_login_form(&$form, FormStateInterface &$form_state)
     }
   }
 }
+
+/**
+ * Check for CSP violation report flooding.
+ *
+ * @return (bool)
+ *   TRUE if flooding is detected (report logging should be inhibited).
+ *   FALSE if it is safe to proceed with logging the report.
+ */
+function _seckit_csp_report_flooding_detected() {
+  $flood_service = \Drupal::service('flood');
+  $config = \Drupal::config('seckit.settings');
+
+  // The global limit provides some DDOS protection.
+  $global_limit = $config->get('seckit_advanced.csp_limits.flood.limit_global');
+  $global_window = $config->get('seckit_advanced.csp_limits.flood.window_global');
+
+  try {
+    // flood_is_allowed() does not presently allow us to ignore the identifier,
+    // meaning we would need to log two flood events per CSP report in order to
+    // check both the global and per-user counts using the API function. This
+    // query enables us to do this while only registering one event per report.
+    // @see https://www.drupal.org/node/2472941
+    $connection = \Drupal::database();
+    $global_count = $connection->select('flood', 'f')
+      ->condition('event', 'seckit_csp_report')
+      ->condition('timestamp', REQUEST_TIME - $global_window, '>')
+      ->countQuery()
+      ->execute()
+      ->fetchField();
+  }
+  catch (\Exception $e) {
+    // Table could not exist
+    $global_count = 0;
+    \Drupal::logger('seckit')->warning("Exeption trying to get global count: @message", array('@message' => $e->getMessage()));
+  }
+
+  if ($global_count >= $global_limit) {
+    return TRUE; // Flooding is in effect
+  }
+
+  // Per-user limit.
+  $user_limit = $config->get('seckit_advanced.csp_limits.flood.limit_user');
+  $user_window = $config->get('seckit_advanced.csp_limits.flood.window_user');
+  if (!$flood_service->isAllowed('seckit_csp_report', $user_limit, $user_window)) {
+    return TRUE; // Flooding is in effect
+  }
+
+  // Flooding is not in effect. Log this event, and return the status.
+  $flood_service->register('seckit_csp_report', $user_window);
+
+  return FALSE; // No flooding
+}
diff --git a/src/Controller/SeckitExportController.php b/src/Controller/SeckitExportController.php
index 114f676..e34ffb2 100644
--- a/src/Controller/SeckitExportController.php
+++ b/src/Controller/SeckitExportController.php
@@ -5,6 +5,7 @@ namespace Drupal\seckit\Controller;
 use Drupal\Core\Access\AccessResult;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
 /**
@@ -16,6 +17,11 @@ class SeckitExportController {
    * Reports CSP violations.
    */
   public function export(Request $request) {
+    $config = \Drupal::config('seckit.settings');
+    if ($config->get('seckit_advanced.disable_seckit')) {
+      throw new NotFoundHttpException();
+    }
+
     // Only allow POST data with Content-Type application/csp-report
     // or application/json (the latter to support older user agents).
     // n.b. The CSP spec (1.0, 1.1) mandates this Content-Type header/value.
@@ -32,8 +38,30 @@ class SeckitExportController {
       throw new NotFoundHttpException();
     }
 
+    $config = \Drupal::config('seckit.settings');
+    $unlimited_reports = $config->get('seckit_advanced.unlimited_csp_reports');
+
+    // Check for flooding.
+    if (!$unlimited_reports && _seckit_csp_report_flooding_detected()) {
+      // An exception gets logged, if we are preventing for performance reasons
+      // we don't want this logged because it could cause a db write if dblog
+      // is enabled.
+      return new Response();
+    }
+
     // Get and parse report.
     $reports = file_get_contents('php://input');
+
+    if (!$unlimited_reports) {
+      $max_size = $config->get('seckit_advanced.csp_limits.max_size');
+      if (strlen($reports) > $max_size)  {
+        // An exception gets logged, if we are preventing for performance reasons
+        // we don't want this logged because it could cause a db write if dblog
+        // is enabled.
+        return new Response();
+      }
+    }
+
     $reports = json_decode($reports);
     if (!is_object($reports)) {
       throw new NotFoundHttpException();
@@ -52,8 +80,6 @@ class SeckitExportController {
       \Drupal::logger('seckit')->warning('CSP: Directive @directive violated.<br /> Blocked URI: @blocked_uri.<br /> <pre>Data: @data</pre>', $info);
     }
 
-    $response['status'] = 'ok';
-
     return new Response();
   }
 }
diff --git a/src/EventSubscriber/SecKitEventSubscriber.php b/src/EventSubscriber/SecKitEventSubscriber.php
index 999e57b..e56139e 100644
--- a/src/EventSubscriber/SecKitEventSubscriber.php
+++ b/src/EventSubscriber/SecKitEventSubscriber.php
@@ -32,6 +32,11 @@ class SecKitEventSubscriber implements EventSubscriberInterface {
   }
 
   public function onKernelRequest(GetResponseEvent $event) {
+    $config = \Drupal::config('seckit.settings');
+    if ($config->get('seckit_advanced.disable_seckit')) {
+      return;
+    }
+
     $this->request = $event->getRequest();
 
     // execute necessary functions
@@ -41,6 +46,11 @@ class SecKitEventSubscriber implements EventSubscriberInterface {
   }
 
   public function onKernelResponse(FilterResponseEvent $event) {
+    $config = \Drupal::config('seckit.settings');
+    if ($config->get('seckit_advanced.disable_seckit')) {
+      return;
+    }
+
     $this->response = $event->getResponse();
 
     // execute necessary functions
@@ -106,7 +116,6 @@ class SecKitEventSubscriber implements EventSubscriberInterface {
     }
 
     // Allow requests from whitelisted Origins.
-    global $base_root;
     global $base_url;
 
     $whitelist = explode(',', $this->config->get('seckit_csrf.origin_whitelist'));
@@ -131,7 +140,6 @@ class SecKitEventSubscriber implements EventSubscriberInterface {
     );
 
     $message = 'Possible CSRF attack was blocked. IP address: @ip, Origin: @origin.';
-    $warning = t($message, $args);
     \Drupal::logger('seckit')->warning($message, $args);
 
     $event->setResponse(new Response(t('Access denied'), Response::HTTP_FORBIDDEN));
diff --git a/src/Form/SecKitSettingsForm.php b/src/Form/SecKitSettingsForm.php
index 945a676..78bf3c0 100644
--- a/src/Form/SecKitSettingsForm.php
+++ b/src/Form/SecKitSettingsForm.php
@@ -206,6 +206,23 @@ class SecKitSettingsForm extends ConfigFormBase {
       '#description' => t("Specify a URL (relative to the Drupal root) for a file containing the (entire) policy. <strong>All other directives will be omitted</strong> by Security Kit, as <code>policy-uri</code> may only be defined in the <em>absence</em> of other policy definitions in the <code>X-Content-Security-Policy</code> HTTP header. The MIME type for this URI <strong>must</strong> be <code>text/x-content-security-policy</code>, otherwise user-agents will enforce the policy <code>allow 'none'</code>  instead."),
     );
 
+    $args = array(
+      ':adv' => '#edit-seckit-advanced',
+      '@adv' => 'Advanced_options',
+    );
+
+    $title = "<strong>" . t('CSP violation reporting limits are currently disabled. See <a href=":adv">@adv</a> below.', $args) . '</strong><br />';
+    $description = t("Reporting limits should be enabled once your CSP is production-ready, to prevent excessive report logging should the violation report URL be flooded.");
+    $form['seckit_xss']['csp']['csp_limits'] = array(
+      '#type' => 'markup',
+      '#markup' => $title . $description,
+      '#states' => array(
+        'visible' => array(
+          ':input[name="seckit_advanced[unlimited_csp_reports]"]' => array('checked' => TRUE),
+        ),
+      ),
+    );
+
     // fieldset for X-XSS-Protection
     $form['seckit_xss']['x_xss'] = array(
       '#type' => 'details',
@@ -522,6 +539,94 @@ class SecKitSettingsForm extends ConfigFormBase {
       '#description' => t('Prevent the browser from populating login/registration form fields using its autocomplete functionality. This as populated fields may contain sensitive information, facilitating unauthorized access.'),
     );
 
+    // Advanced / developer options.
+    $form['seckit_advanced'] = array(
+      '#type' => 'details',
+      '#title' => t('Advanced options'),
+      '#collapsible' => TRUE,
+      '#open' => TRUE,
+      '#tree' => TRUE,
+    );
+
+    $form['seckit_advanced']['disable_seckit'] = array(
+      '#type' => 'checkbox',
+      '#default_value' => $config->get('seckit_advanced.disable_seckit'),
+      '#title' => t('Disable Security Kit'),
+      '#description' => t('Prevent the module from doing anything.'),
+    );
+
+    $request = \Drupal::request();
+    if ($config->get('seckit_advanced.disable_seckit') && empty($request->getContent())) {
+      drupal_set_message(t("Security Kit is currently disabled in the Advanced options (below)."), 'warning');
+    }
+
+    // CSP report limits
+    $form['seckit_advanced']['unlimited_csp_reports'] = array(
+      '#type' => 'checkbox',
+      '#default_value' => $config->get('seckit_advanced.unlimited_csp_reports'),
+      '#title' => t('Unlimited CSP reports'),
+      '#description' => t('Ignore restrictions on the size and quantity of CSP violation reports. This should be disabled once the CSP is production-ready.'),
+    );
+
+    $form['seckit_advanced']['csp_limits'] = array(
+      '#type' => 'details',
+      '#title' => t('CSP violation reporting limits'),
+      '#description' => t("Reports breaching these limits will not be logged."),
+      '#collapsible' => TRUE,
+      '#open' => TRUE,
+      '#states' => array(
+        'visible' => array(
+          ':input[name="seckit_advanced[unlimited_csp_reports]"]' => array('checked' => FALSE),
+        ),
+      ),
+    );
+
+    $form['seckit_advanced']['csp_limits']['max_size'] = array(
+      '#title' => t('Maximum report size (bytes)'),
+      '#type' => 'textfield',
+      '#maxlength'=> 16,
+      '#default_value' => $config->get('seckit_advanced.csp_limits.max_size'),
+    );
+
+    $form['seckit_advanced']['csp_limits']['flood'] = array(
+      '#type' => 'details',
+      '#title' => t('Flood settings'),
+      '#collapsible' => TRUE,
+      '#open' => TRUE,
+    );
+
+    $form['seckit_advanced']['csp_limits']['flood']['limit_user'] = array(
+      '#title' => t('Maximum reports per IP address'),
+      '#description' => t('Applicable within the given time window'),
+      '#type' => 'textfield',
+      '#maxlength'=> 16,
+      '#default_value' => $config->get('seckit_advanced.csp_limits.flood.limit_user'),
+    );
+
+    $form['seckit_advanced']['csp_limits']['flood']['window_user'] = array(
+      '#title' => t('Time window for per IP address flood detection'),
+      '#description' => t('Duration in seconds'),
+      '#type' => 'textfield',
+      '#maxlength'=> 16,
+      '#default_value' => $config->get('seckit_advanced.csp_limits.flood.window_user'),
+    );
+
+    $form['seckit_advanced']['csp_limits']['flood']['limit_global'] = array(
+      '#title' => t('Maximum reports globally (i.e. irrespective of IP address)'),
+      '#description' => t('Applicable within the given time window'),
+      '#type' => 'textfield',
+      '#maxlength'=> 16,
+      '#default_value' => $config->get('seckit_advanced.csp_limits.flood.limit_global'),
+    );
+
+    $form['seckit_advanced']['csp_limits']['flood']['window_global'] = array(
+      '#title' => t('Time window for global flood detection'),
+      '#description' => t('Duration in seconds'),
+      '#type' => 'textfield',
+      '#maxlength'=> 16,
+      '#default_value' => $config->get('seckit_advanced.csp_limits.flood.window_global'),
+    );
+
     return parent::buildForm($form, $form_state);
   }
 
