title: Django-CSP - AJAX request with vanilla JS blocked by CSP
body: <p>I have a Django-based D&amp;D-wiki webpage that I'm working on in my free time which I'm using to learn more about web development.
  I recently implemented a Content-Security-Policy using <a href="https://django-csp.readthedocs.io/en/latest/" rel="nofollow noreferrer">django-csp.</a> That went well and the switch was fairly painless, given that I only had 20 or so templates to deal with. Here my CSP settings:</p>
  <pre><code>//Django settings.py
  CSP_DEFAULT_SRC = (&quot;'none'&quot;,)
  CSP_STYLE_SRC = (&quot;'self'&quot;, 'stackpath.bootstrapcdn.com', 'fonts.googleapis.com', &quot;'unsafe-inline'&quot;, 'cdn.jsdelivr.net', 'cdnjs.cloudflare.com', 'rawcdn.githack.com', 'maxcdn.bootstrapcdn.com',)
  CSP_SCRIPT_SRC = (&quot;'self'&quot;, 'localhost', &quot;default-src&quot;, 'stackpath.bootstrapcdn.com', 'code.jquery.com', 'cdn.jsdelivr.net', 'cdnjs.cloudflare.com','maxcdn.bootstrapcdn.com',)
  CSP_IMG_SRC = (&quot;'self'&quot;, 'ipw3.org', 'data:', 'cdn.jsdelivr.net', 'cdnjs.cloudflare.com', 'i.imgur.com',)
  CSP_FONT_SRC = (&quot;'self'&quot;, 'fonts.gstatic.com', 'maxcdn.bootstrapcdn.com',)
  CSP_MEDIA_SRC = (&quot;'self'&quot;,)
  CSP_INCLUDE_NONCE_IN = ('style-src',)
  </code></pre>
  <p>Even more recently started learning about AJAX requests and wanted to implement a simple POST request.
  Sadly, my CSP blocks this request, which I believe should be allowed given that I allowed self and localhost in CSP_SCRIPT_SRC:</p>
  <pre><code>//JS Event Listener that creates and sends the AJAX request
      document.getElementById('create-timstamp').addEventListener('click', function(event){ 
          const isValid = validateForm();
          if (isValid){
              xhr = new XMLHttpRequest();
              xhr.open('POST', getCreateTimestampURL(), true);            
              xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
              const csrf = document.querySelector('input[name=&quot;csrfmiddlewaretoken&quot;]').value;
              xhr.setRequestHeader(&quot;X-CSRF-TOKEN&quot;, csrf);
  
              xhr.onload = function(){
                  document.querySelector('.timestamp-create-box').remove();
              }
  
              const timestampForm = document.forms['timestamp-form'];
              const timestamp_seconds = toTimeInt(timestampForm['time'].value);
              const timestamp_name = timestampForm['name'].value;
              const data = `name=${timestamp_name}&amp;time=${timestamp_seconds}`;
  
              xhr.send(data);
              
              return false;
          }
  
  
  //For completion's sake here also the helper methods used by the event listener
  function getCreateTimestampURL(){
      return document.querySelector('#add-timestamp').dataset.timestampcreateurl;
  }
  
  function toTimeInt(timestampString){
      const hours = parseInt(timestampString.substring(0,2));
      const minutes = parseInt(timestampString.substring(3,5));
      const seconds = parseInt(timestampString.substring(6,8));
      return 3600*hours + 60*minutes + seconds;
  }
  </code></pre>
  <p>And here the browser's response:</p>
  <pre><code>//Webbrowser console output after triggering the event
  Content Security Policy: The page’s settings blocked the loading of a resource at http://localhost:8002/files/timestamp/1/17/new (“default-src”).
  </code></pre>
  <p>So I know I'm doing something wrong, but I'm not sure what. I know I need to adjust my CSP settings somehow, but I'm already allowing localhost-scripts, what else is required?</p>