diff --git a/spec/file_caching_test.js b/spec/file_caching_test.js
index 7a30e60ecb5595ccecfdb863010107800fc94c06..180b25be34408a687ce5e9d69788117d64900220 100644
--- a/spec/file_caching_test.js
+++ b/spec/file_caching_test.js
@@ -56,6 +56,7 @@ describe('File caching service', () => {
     expect(response.statusCode).toBe(200)
     expect(response.headers['content-type']).toBe('application/javascript; charset=utf-8')
     expect(response.text).toBe('this is example')
+    expect(response.headers['content-security-policy']).toContain('sha256-NzZhMTE2Njc2YTgyNTZmZTdlZGVjZDU3YTNmYzRjNmM1OWZkMTI2NjRkYzZmMWM3YTkwMGU3ZTdhNDlhZmVlMwo=')
     const response2 = await request(app).get('/test.txt')
     expect(response2.statusCode).toBe(200)
     expect(response2.headers['content-type']).toBe('text/plain; charset=utf-8')
@@ -66,6 +67,7 @@ describe('File caching service', () => {
     const response = await request(app).get('/main.css')
     expect(response.statusCode).toBe(200)
     expect(response.headers['content-type']).toBe('text/css; charset=utf-8')
+    expect(response.headers['content-security-policy']).toContain('sha256-YjRiYWRlYTVhYmM5ZTZkNjE2ZGM4YjcwZWRlNzUxMmU0YjgxY2UxMWExOTI2ZjM1NzM1M2Y2MWJjNmUwMmZjMwo=')
   })
 
   it('serves / as index.html', async () => {
diff --git a/src/createApp.js b/src/createApp.js
index ffdaa7800eec5ef5f2f64fefb328d266b9c020d3..5fab09652ee2578647440cfb4485dc094e5bae5b 100644
--- a/src/createApp.js
+++ b/src/createApp.js
@@ -38,7 +38,19 @@ export function createApp () {
 
   // Application-level middleware
   app.use(httpLogger)
-  app.use(helmet())
+  app.use((req, res, next) => {
+    const { sha256Sum } = fileCache.get(req.path)
+    res.locals.sha256Sum = sha256Sum
+    next()
+  })
+  app.use(helmet({
+    contentSecurityPolicy: {
+      useDefaults: true,
+      directives: {
+        defaultSrc: ["'self'", (req, res) => res.locals.sha256Sum ? `'sha256-${res.locals.sha256Sum}'` : '']
+      }
+    }
+  }))
   app.use('/healthy', health.LivenessEndpoint(healthCheck))
   app.use('/ready', health.ReadinessEndpoint(healthCheck))
   app.use(metricsMiddleware)
diff --git a/src/files.js b/src/files.js
index 9d2c45b3bd9f5253b26f94ac00d7e889ab535bf0..b059dc3c83f0dfbb9a739012d8f4e11aaea608e6 100644
--- a/src/files.js
+++ b/src/files.js
@@ -1,6 +1,11 @@
 import fetch from 'node-fetch'
+import crypto from 'crypto'
 
 class FileCache {
+  constructor () {
+    this._cache = {}
+  }
+
   async warmUp (manifests, deps) {
     const cache = Object.fromEntries(await (async function () {
       const files = Object.keys(deps)
@@ -20,9 +25,12 @@ class FileCache {
             }
             const response = await fetch(new URL(file, manifest.meta.baseUrl))
             if (!response.ok) return null
+            const content = await response.buffer()
+            const sha256Sum = crypto.createHash('sha256').update(content).digest('base64')
             return [file, {
               'content-type': response.headers.get('content-type'),
-              content: await response.buffer()
+              sha256Sum,
+              content
             }]
           } catch (e) { console.error(e) }
         }))).filter(data => Array.isArray(data) && data.length === 2))