From 248a7697b5e7d076dcde40e40f7421d41bccbb32 Mon Sep 17 00:00:00 2001 From: Jonas Elfering Date: Thu, 15 Oct 2026 11:43:07 +0200 Subject: [PATCH 1/3] fix(media): apply CSP to all static asset responses --- 6.7/rootfs/etc/varnish/default.vcl | 4 +++ 6.8/rootfs/etc/varnish/default.vcl | 4 +++ README.md | 13 ++++++++++ tests/static-assets.sh | 40 ++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 tests/static-assets.sh diff --git a/6.7/rootfs/etc/varnish/default.vcl b/6.7/rootfs/etc/varnish/default.vcl index 0241e40..60e2d25 100644 --- a/6.7/rootfs/etc/varnish/default.vcl +++ b/6.7/rootfs/etc/varnish/default.vcl @@ -175,6 +175,10 @@ sub vcl_backend_response { } sub vcl_deliver { + if (req.url ~ "^/(media|thumbnail|theme|bundles)/") { + set resp.http.Content-Security-Policy = "script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'"; + } + ## we don't want the client to cache anything except assets and store-api responses if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(theme|media|thumbnail|bundles|store-api)/") { set resp.http.Pragma = "no-cache"; diff --git a/6.8/rootfs/etc/varnish/default.vcl b/6.8/rootfs/etc/varnish/default.vcl index b126f4e..0d41284 100644 --- a/6.8/rootfs/etc/varnish/default.vcl +++ b/6.8/rootfs/etc/varnish/default.vcl @@ -145,6 +145,10 @@ sub vcl_backend_response { } sub vcl_deliver { + if (req.url ~ "^/(media|thumbnail|theme|bundles)/") { + set resp.http.Content-Security-Policy = "script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'"; + } + unset resp.http.xkey; unset resp.http.X-Varnish; unset resp.http.Via; diff --git a/README.md b/README.md index d2812c7..51deb53 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,19 @@ The image bases on the official [Varnish image](https://hub.docker.com/_/varnish) and contains the Shopware default VCL. The containing VCL is for the usage with xkeys. +## Static asset Content Security Policy + +Responses under `/media/`, `/thumbnail/`, `/theme/` and `/bundles/` receive `Content-Security-Policy: script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'`, including cache hits and error responses. This applies to every file type in these directories. Bundled HTML applications cannot execute scripts, submit forms or embed documents. Application responses outside these paths retain their existing policy. + +Run the regression checks against either version's image: + +```sh +docker build -t shopware-varnish-csp-test 6.7 +docker run --rm --entrypoint sh -v "$PWD":/source:ro -w /source shopware-varnish-csp-test tests/static-assets.sh 6.7/rootfs/etc/varnish/default.vcl +``` + +Use `6.8` in both paths to check that version. +
Config for Shopware 6.7 diff --git a/tests/static-assets.sh b/tests/static-assets.sh new file mode 100644 index 0000000..e781ab7 --- /dev/null +++ b/tests/static-assets.sh @@ -0,0 +1,40 @@ +#!/bin/sh +set -eu + +# Run inside the image: sh tests/static-assets.sh /source/6.7/rootfs/etc/varnish/default.vcl +test_dir=$(mktemp -d) +test_file=$test_dir/static-assets.vtc +trap 'rm -rf "$test_dir"' EXIT +policy="script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'" + +{ + echo 'varnishtest "Asset CSP covers every file type and preserves application policies"' + echo 'server s1 {' + # The first asset is requested twice; the second request must be a cache hit. + for status in 200 200 200 200 200 200 200 200 200 200 404; do + echo 'rxreq' + echo "txresp -status $status -hdr \"Cache-Control: public, max-age=3600\" -hdr \"Content-Security-Policy: default-src 'self'\" -body response" + done + echo '} -start' + echo 'varnish v1 -vcl {' + sed -e "s/__SHOPWARE_BACKEND_HOST__/\${s1_addr}/g" \ + -e "s/__SHOPWARE_BACKEND_PORT__/\${s1_port}/g" \ + -e 's/__SHOPWARE_ALLOWED_PURGER_IP__/"127.0.0.1"/g' "$1" + echo '} -start' + echo 'client c1 {' + for path in /media/test.html /media/test.html /thumbnail/test.svg /theme/app.js /bundles/app/index.html /media/image.png /media/no-extension /media/test.html?download=1 /admin /application/rendered.html /media-other/test.html /media/missing.html; do + expected_policy=$policy + case "$path" in + /admin|/application/*|/media-other/*) expected_policy="default-src 'self'" ;; + esac + status=200 + [ "$path" != /media/missing.html ] || status=404 + echo "txreq -url \"$path\"" + echo 'rxresp' + echo "expect resp.status == $status" + echo "expect resp.http.Content-Security-Policy == \"$expected_policy\"" + done + echo '} -run' + echo 'varnish v1 -expect MAIN.cache_hit == 1' +} > "$test_file" +varnishtest "$test_file" From 9dde4c8e89f21062cfcb9766422a7efb7697ffca Mon Sep 17 00:00:00 2001 From: Jonas Elfering Date: Thu, 15 Oct 2026 11:46:39 +0200 Subject: [PATCH 2/3] chore(tests): remove static asset test harness --- README.md | 9 --------- tests/static-assets.sh | 40 ---------------------------------------- 2 files changed, 49 deletions(-) delete mode 100644 tests/static-assets.sh diff --git a/README.md b/README.md index 51deb53..1ad4e35 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,6 @@ The containing VCL is for the usage with xkeys. Responses under `/media/`, `/thumbnail/`, `/theme/` and `/bundles/` receive `Content-Security-Policy: script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'`, including cache hits and error responses. This applies to every file type in these directories. Bundled HTML applications cannot execute scripts, submit forms or embed documents. Application responses outside these paths retain their existing policy. -Run the regression checks against either version's image: - -```sh -docker build -t shopware-varnish-csp-test 6.7 -docker run --rm --entrypoint sh -v "$PWD":/source:ro -w /source shopware-varnish-csp-test tests/static-assets.sh 6.7/rootfs/etc/varnish/default.vcl -``` - -Use `6.8` in both paths to check that version. -
Config for Shopware 6.7 diff --git a/tests/static-assets.sh b/tests/static-assets.sh deleted file mode 100644 index e781ab7..0000000 --- a/tests/static-assets.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh -set -eu - -# Run inside the image: sh tests/static-assets.sh /source/6.7/rootfs/etc/varnish/default.vcl -test_dir=$(mktemp -d) -test_file=$test_dir/static-assets.vtc -trap 'rm -rf "$test_dir"' EXIT -policy="script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'" - -{ - echo 'varnishtest "Asset CSP covers every file type and preserves application policies"' - echo 'server s1 {' - # The first asset is requested twice; the second request must be a cache hit. - for status in 200 200 200 200 200 200 200 200 200 200 404; do - echo 'rxreq' - echo "txresp -status $status -hdr \"Cache-Control: public, max-age=3600\" -hdr \"Content-Security-Policy: default-src 'self'\" -body response" - done - echo '} -start' - echo 'varnish v1 -vcl {' - sed -e "s/__SHOPWARE_BACKEND_HOST__/\${s1_addr}/g" \ - -e "s/__SHOPWARE_BACKEND_PORT__/\${s1_port}/g" \ - -e 's/__SHOPWARE_ALLOWED_PURGER_IP__/"127.0.0.1"/g' "$1" - echo '} -start' - echo 'client c1 {' - for path in /media/test.html /media/test.html /thumbnail/test.svg /theme/app.js /bundles/app/index.html /media/image.png /media/no-extension /media/test.html?download=1 /admin /application/rendered.html /media-other/test.html /media/missing.html; do - expected_policy=$policy - case "$path" in - /admin|/application/*|/media-other/*) expected_policy="default-src 'self'" ;; - esac - status=200 - [ "$path" != /media/missing.html ] || status=404 - echo "txreq -url \"$path\"" - echo 'rxresp' - echo "expect resp.status == $status" - echo "expect resp.http.Content-Security-Policy == \"$expected_policy\"" - done - echo '} -run' - echo 'varnish v1 -expect MAIN.cache_hit == 1' -} > "$test_file" -varnishtest "$test_file" From 26244fb536a5d933622e5139ebcfbab45984cf5a Mon Sep 17 00:00:00 2001 From: Jonas Elfering Date: Thu, 15 Oct 2026 13:00:52 +0200 Subject: [PATCH 3/3] fix(media): restrict Varnish CSP to uploaded media paths --- 6.7/rootfs/etc/varnish/default.vcl | 2 +- 6.8/rootfs/etc/varnish/default.vcl | 2 +- README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/6.7/rootfs/etc/varnish/default.vcl b/6.7/rootfs/etc/varnish/default.vcl index 60e2d25..7fd22d0 100644 --- a/6.7/rootfs/etc/varnish/default.vcl +++ b/6.7/rootfs/etc/varnish/default.vcl @@ -175,7 +175,7 @@ sub vcl_backend_response { } sub vcl_deliver { - if (req.url ~ "^/(media|thumbnail|theme|bundles)/") { + if (req.url ~ "^/(media|thumbnail)/") { set resp.http.Content-Security-Policy = "script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'"; } diff --git a/6.8/rootfs/etc/varnish/default.vcl b/6.8/rootfs/etc/varnish/default.vcl index 0d41284..433c13b 100644 --- a/6.8/rootfs/etc/varnish/default.vcl +++ b/6.8/rootfs/etc/varnish/default.vcl @@ -145,7 +145,7 @@ sub vcl_backend_response { } sub vcl_deliver { - if (req.url ~ "^/(media|thumbnail|theme|bundles)/") { + if (req.url ~ "^/(media|thumbnail)/") { set resp.http.Content-Security-Policy = "script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'"; } diff --git a/README.md b/README.md index 1ad4e35..d783322 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ The containing VCL is for the usage with xkeys. ## Static asset Content Security Policy -Responses under `/media/`, `/thumbnail/`, `/theme/` and `/bundles/` receive `Content-Security-Policy: script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'`, including cache hits and error responses. This applies to every file type in these directories. Bundled HTML applications cannot execute scripts, submit forms or embed documents. Application responses outside these paths retain their existing policy. +Responses under `/media/` and `/thumbnail/` receive `Content-Security-Policy: script-src 'none'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'none'`, including cache hits and error responses. This applies to every file type in these directories. HTML documents in these paths cannot execute scripts, submit forms or embed documents. Responses outside these paths retain their existing policy.
Config for Shopware 6.7