{"id":92,"date":"2026-10-27T08:00:00","date_gmt":"2026-10-27T07:00:00","guid":{"rendered":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/"},"modified":"2026-10-16T14:00:12","modified_gmt":"2026-10-16T12:00:12","slug":"content-security-policy-in-typo3-v13-and-v14","status":"publish","type":"post","link":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/","title":{"rendered":"Content Security Policy in TYPO3 v13 and v14"},"content":{"rendered":"<p>A Content Security Policy (CSP) tells the browser which sources a page may load scripts, styles, images and frames from. If an attacker manages to inject a <code>&lt;script&gt;<\/code> into your page, a good policy stops the browser from running it. It is one of the most useful security headers, and also one of the easiest to get wrong.<\/p>\n<p>The classic mistake I see in TYPO3 projects: somebody copies a policy into the root <code>.htaccess<\/code> with <code>Header set Content-Security-Policy \u2026<\/code>. The frontend looks fine. Then an editor calls, because the backend shows a white page or buttons do nothing. In this post I explain why that happens and show the core API that TYPO3 has for this since v12.3.<\/p>\n<h2>Why the .htaccess header breaks the backend<\/h2>\n<p>The TYPO3 backend already sends its own policy. Since v13 that is not even optional: the feature flag <code>security.backend.enforceContentSecurityPolicy<\/code> was removed in 13.0, and the backend always protects itself. On my v14 site a request to <code>\/typo3\/<\/code> answers with a header starting like this:<\/p>\n<pre><code class=\"language-text\">content-security-policy: default-src 'self'; script-src 'self' 'nonce-\u2026' 'report-sample'; style-src 'self' 'unsafe-inline' 'report-sample'; \u2026<\/code><\/pre>\n<p>The nonce is a random value per request, and the backend puts the same value on its own inline scripts. When Apache adds a second <code>Content-Security-Policy<\/code> header from <code>.htaccess<\/code>, the browser does not choose one. It enforces <em>both<\/em>, and a resource must pass every policy. Your hand-written policy does not know the nonce, so the backend&#8217;s scripts are blocked. White page.<\/p>\n<p>The fix is not a smarter regex in <code>.htaccess<\/code>. It is to let TYPO3 build the policy, because TYPO3 knows the nonce, knows the site, and knows which extensions need which sources.<\/p>\n<h2>Step 1: switch on the frontend policy<\/h2>\n<p>For the frontend, two feature flags exist, both off by default:<\/p>\n<ul>\n<li><code>security.frontend.enforceContentSecurityPolicy<\/code> sends a <code>Content-Security-Policy<\/code> header.<\/li>\n<li><code>security.frontend.reportContentSecurityPolicy<\/code> sends <code>Content-Security-Policy-Report-Only<\/code>: violations are reported, nothing is blocked.<\/li>\n<\/ul>\n<p>Always start with report-only. In v13 you set it in <code>config\/system\/settings.php<\/code> or <code>additional.php<\/code>:<\/p>\n<pre><code class=\"language-php\">$GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['security.frontend.reportContentSecurityPolicy'] = true;<\/code><\/pre>\n<p>Since v14.2 there is also a console command for it (<code>Feature-108815<\/code>):<\/p>\n<pre><code class=\"language-bash\">ddev exec vendor\/bin\/typo3 configuration:set SYS\/features\/security.frontend.reportContentSecurityPolicy true --json<\/code><\/pre>\n<p>The core already provides a sensible default frontend policy in EXT:frontend&#8217;s <code>Configuration\/ContentSecurityPolicies.php<\/code>: <code>default-src 'self'<\/code>, scripts with a nonce, <code>data:<\/code> images, and a few YouTube and Vimeo hosts for media embeds.<\/p>\n<h2>Step 2: per-site rules in csp.yaml<\/h2>\n<p>Each site can have a <code>csp.yaml<\/code> next to its <code>config.yaml<\/code>. Since 12.4.x it can set the disposition per site, so you do not need the global flags at all if you prefer this. Here a site that enforces the default policy, plus one external host for embedded maps, and at the same time tests a stricter <code>img-src<\/code> in report-only mode:<\/p>\n<pre><code class=\"language-yaml\"># config\/sites\/main\/csp.yaml\nenforce:\n  inheritDefault: true\n  includeResolutions: true\n  mutations:\n    - mode: extend\n      directive: 'frame-src'\n      sources:\n        - 'https:\/\/maps.example.org'\nreport:\n  inheritDefault: true\n  mutations:\n    - mode: set\n      directive: 'img-src'\n      sources:\n        - \"'self'\"<\/code><\/pre>\n<p><code>extend<\/code> takes the parent directive (here <code>default-src 'self'<\/code>) and adds sources. <code>set<\/code> replaces the directive completely. And <code>active: false<\/code> switches CSP off for one site, which is handy when one site of a multi-site installation is not ready yet.<\/p>\n<h2>Step 3: rules that belong to an extension<\/h2>\n<p>If your extension embeds a third-party widget, the extension should bring its own rule. Then every site that uses the extension gets it, and you do not repeat it in every <code>csp.yaml<\/code>. The file is <code>Configuration\/ContentSecurityPolicies.php<\/code> in the extension:<\/p>\n<pre><code class=\"language-php\">&lt;?php\n\ndeclare(strict_types=1);\n\nuse TYPO3CMSCoreSecurityContentSecurityPolicyDirective;\nuse TYPO3CMSCoreSecurityContentSecurityPolicyMutation;\nuse TYPO3CMSCoreSecurityContentSecurityPolicyMutationCollection;\nuse TYPO3CMSCoreSecurityContentSecurityPolicyMutationMode;\nuse TYPO3CMSCoreSecurityContentSecurityPolicyScope;\nuse TYPO3CMSCoreSecurityContentSecurityPolicyUriValue;\nuse TYPO3CMSCoreTypeMap;\n\nreturn Map::fromEntries([\n    Scope::frontend(),\n    new MutationCollection(\n        new Mutation(MutationMode::Extend, Directive::FrameSrc, new UriValue('https:\/\/maps.example.org')),\n        new Mutation(MutationMode::Extend, Directive::ImgSrc, new UriValue('https:\/\/tiles.maps.example.org')),\n    ),\n]);<\/code><\/pre>\n<p>A site can drop the rules of one package again with the <code>packages<\/code> key in <code>csp.yaml<\/code>, if it does not want them.<\/p>\n<h2>Step 4: inline scripts and nonces in Fluid<\/h2>\n<p>The default policy allows scripts from your own host and scripts with the current nonce. Inline scripts without the nonce are blocked. The best fix is to move the script into a file. Where that is not possible, the asset ViewHelpers handle it for you. In v14.2 and later:<\/p>\n<pre><code class=\"language-html\">&lt;f:asset.script identifier=\"consent-init\" csp=\"1\"&gt;\n    document.documentElement.classList.add('js');\n&lt;\/f:asset.script&gt;<\/code><\/pre>\n<p>In v13 the same argument is called <code>useNonce=\"1\"<\/code>. It still works in v14, but since 14.2 it writes a deprecation and will be removed in v15 (<code>Deprecation-100887<\/code>). If you write the tag yourself, v14 has <code>{f:security.nonce(directive: 'script-src')}<\/code> for the attribute value.<\/p>\n<p>One thing to know: a nonce makes the response uncacheable for proxies, because the value changes per request. TYPO3 already avoids nonces when a page does not need them (an important change in 13.4.x). And v14.2 added hash-based CSP as an opt-in per site, with <code>behavior.useHash: true<\/code> and <code>useNonce: false<\/code> in <code>csp.yaml<\/code>, so fully cached pages can keep a strict policy (<code>Feature-100887<\/code>).<\/p>\n<h2>Step 5: read the violation reports<\/h2>\n<p>With the core reporting endpoint, violations are stored in the table <code>sys_http_report<\/code> and shown in the backend module &#8220;Content Security Policy&#8221;. In v13 you find it under Admin Tools, in v14 under System. The module groups the reports and can even suggest a resolution, which is stored and applied at runtime (that is what <code>includeResolutions<\/code> above refers to). I prefer to copy a good resolution into <code>csp.yaml<\/code> or the extension file, because then it is in git and reviewed.<\/p>\n<p>My routine: report-only for a week or two, clear out the expected noise (browser extensions inject a lot), fix the real ones, then switch the site to <code>enforce<\/code>.<\/p>\n<p>For my own site hoja.in, the frontend flag is still off, I have to admit. The site loads no third-party resources anymore after the rebuild, so it is a good candidate for the default policy. Report-only comes first, as described above. Practise what you preach, Hoja.<\/p>\n<p>Cheers, and keep the backend working!<\/p>\n<h2>Further reading<\/h2>\n<ul>\n<li><a href=\"https:\/\/docs.typo3.org\/m\/typo3\/reference-coreapi\/main\/en-us\/ApiOverview\/ContentSecurityPolicy\/Index.html\">TYPO3 documentation: Content Security Policy<\/a><\/li>\n<li><a href=\"https:\/\/docs.typo3.org\/permalink\/changelog:important-104549-1723461851\">Important: #104549 \u2013 Site-specific CSP disposition<\/a><\/li>\n<li><a href=\"https:\/\/docs.typo3.org\/permalink\/changelog:feature-100887-1773012077\">Feature: #100887 \u2013 Prefer CSP hash values over nonce values<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Guides\/CSP\">MDN: Content Security Policy<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>A CSP header set by hand in .htaccess fights with the one TYPO3 already sends for the backend. Use the core API instead: feature flags, csp.yaml per site, extension mutations and nonces.<\/p>\n","protected":false},"author":1,"featured_media":93,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20],"tags":[13,43,33,24],"class_list":["post-92","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-development","tag-fluid","tag-security","tag-typo3-v13","tag-typo3-v14"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Content Security Policy in TYPO3 v13 and v14<\/title>\n<meta name=\"description\" content=\"Use the TYPO3 core CSP API, not .htaccess headers: frontend flags, csp.yaml per site, ContentSecurityPolicies.php, nonces in Fluid, violation reports.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Content Security Policy in TYPO3 v13 and v14\" \/>\n<meta property=\"og:description\" content=\"Use the TYPO3 core CSP API, not .htaccess headers: frontend flags, csp.yaml per site, ContentSecurityPolicies.php, nonces in Fluid, violation reports.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/\" \/>\n<meta property=\"og:site_name\" content=\"Hoja Mustaffa Abdul Latheef \u2013 Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-27T07:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/content-security-policy-in-typo3-v13-and-v14.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Hoja Mustaffa Abdul Latheef\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@hojaonline\" \/>\n<meta name=\"twitter:site\" content=\"@hojaonline\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Hoja Mustaffa Abdul Latheef\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/\"},\"author\":{\"name\":\"Hoja Mustaffa Abdul Latheef\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#\\\/schema\\\/person\\\/e6fbd54c2061674d8ea3e7861d858c7b\"},\"headline\":\"Content Security Policy in TYPO3 v13 and v14\",\"datePublished\":\"2026-10-27T07:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/\"},\"wordCount\":827,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#\\\/schema\\\/person\\\/e6fbd54c2061674d8ea3e7861d858c7b\"},\"image\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/hoja.in\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/content-security-policy-in-typo3-v13-and-v14.jpg\",\"keywords\":[\"fluid\",\"Security\",\"TYPO3 v13\",\"TYPO3 v14\"],\"articleSection\":[\"Web development\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/\",\"url\":\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/\",\"name\":\"Content Security Policy in TYPO3 v13 and v14\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/hoja.in\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/content-security-policy-in-typo3-v13-and-v14.jpg\",\"datePublished\":\"2026-10-27T07:00:00+00:00\",\"description\":\"Use the TYPO3 core CSP API, not .htaccess headers: frontend flags, csp.yaml per site, ContentSecurityPolicies.php, nonces in Fluid, violation reports.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/#primaryimage\",\"url\":\"https:\\\/\\\/hoja.in\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/content-security-policy-in-typo3-v13-and-v14.jpg\",\"contentUrl\":\"https:\\\/\\\/hoja.in\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/content-security-policy-in-typo3-v13-and-v14.jpg\",\"width\":1200,\"height\":630,\"caption\":\"CSP the TYPO3 way\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/content-security-policy-in-typo3-v13-and-v14\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/hoja.in\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Content Security Policy in TYPO3 v13 and v14\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/hoja.in\\\/blog\\\/\",\"name\":\"Hoja Mustaffa Abdul Latheef \u2013 Blog\",\"description\":\"Notes from daily work with TYPO3, PHP and AI-assisted engineering\",\"publisher\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#\\\/schema\\\/person\\\/e6fbd54c2061674d8ea3e7861d858c7b\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/hoja.in\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#\\\/schema\\\/person\\\/e6fbd54c2061674d8ea3e7861d858c7b\",\"name\":\"Hoja Mustaffa Abdul Latheef\",\"logo\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#\\\/schema\\\/person\\\/image\\\/\"},\"description\":\"Senior TYPO3 Developer at jweiland.net, TYPO3 CMS Certified Developer. I write about TYPO3 upgrades, extension development, PHP and AI-assisted engineering with Claude Code.\",\"sameAs\":[\"https:\\\/\\\/hoja.in\\\/\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Content Security Policy in TYPO3 v13 and v14","description":"Use the TYPO3 core CSP API, not .htaccess headers: frontend flags, csp.yaml per site, ContentSecurityPolicies.php, nonces in Fluid, violation reports.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/","og_locale":"en_US","og_type":"article","og_title":"Content Security Policy in TYPO3 v13 and v14","og_description":"Use the TYPO3 core CSP API, not .htaccess headers: frontend flags, csp.yaml per site, ContentSecurityPolicies.php, nonces in Fluid, violation reports.","og_url":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/","og_site_name":"Hoja Mustaffa Abdul Latheef \u2013 Blog","article_published_time":"2026-10-27T07:00:00+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/content-security-policy-in-typo3-v13-and-v14.jpg","type":"image\/jpeg"}],"author":"Hoja Mustaffa Abdul Latheef","twitter_card":"summary_large_image","twitter_creator":"@hojaonline","twitter_site":"@hojaonline","twitter_misc":{"Written by":"Hoja Mustaffa Abdul Latheef","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/#article","isPartOf":{"@id":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/"},"author":{"name":"Hoja Mustaffa Abdul Latheef","@id":"https:\/\/hoja.in\/blog\/#\/schema\/person\/e6fbd54c2061674d8ea3e7861d858c7b"},"headline":"Content Security Policy in TYPO3 v13 and v14","datePublished":"2026-10-27T07:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/"},"wordCount":827,"commentCount":0,"publisher":{"@id":"https:\/\/hoja.in\/blog\/#\/schema\/person\/e6fbd54c2061674d8ea3e7861d858c7b"},"image":{"@id":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/#primaryimage"},"thumbnailUrl":"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/content-security-policy-in-typo3-v13-and-v14.jpg","keywords":["fluid","Security","TYPO3 v13","TYPO3 v14"],"articleSection":["Web development"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/","url":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/","name":"Content Security Policy in TYPO3 v13 and v14","isPartOf":{"@id":"https:\/\/hoja.in\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/#primaryimage"},"image":{"@id":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/#primaryimage"},"thumbnailUrl":"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/content-security-policy-in-typo3-v13-and-v14.jpg","datePublished":"2026-10-27T07:00:00+00:00","description":"Use the TYPO3 core CSP API, not .htaccess headers: frontend flags, csp.yaml per site, ContentSecurityPolicies.php, nonces in Fluid, violation reports.","breadcrumb":{"@id":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/#primaryimage","url":"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/content-security-policy-in-typo3-v13-and-v14.jpg","contentUrl":"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/content-security-policy-in-typo3-v13-and-v14.jpg","width":1200,"height":630,"caption":"CSP the TYPO3 way"},{"@type":"BreadcrumbList","@id":"https:\/\/hoja.in\/blog\/content-security-policy-in-typo3-v13-and-v14\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/hoja.in\/blog\/"},{"@type":"ListItem","position":2,"name":"Content Security Policy in TYPO3 v13 and v14"}]},{"@type":"WebSite","@id":"https:\/\/hoja.in\/blog\/#website","url":"https:\/\/hoja.in\/blog\/","name":"Hoja Mustaffa Abdul Latheef \u2013 Blog","description":"Notes from daily work with TYPO3, PHP and AI-assisted engineering","publisher":{"@id":"https:\/\/hoja.in\/blog\/#\/schema\/person\/e6fbd54c2061674d8ea3e7861d858c7b"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/hoja.in\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/hoja.in\/blog\/#\/schema\/person\/e6fbd54c2061674d8ea3e7861d858c7b","name":"Hoja Mustaffa Abdul Latheef","logo":{"@id":"https:\/\/hoja.in\/blog\/#\/schema\/person\/image\/"},"description":"Senior TYPO3 Developer at jweiland.net, TYPO3 CMS Certified Developer. I write about TYPO3 upgrades, extension development, PHP and AI-assisted engineering with Claude Code.","sameAs":["https:\/\/hoja.in\/"]}]}},"_links":{"self":[{"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/posts\/92","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/comments?post=92"}],"version-history":[{"count":1,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/posts\/92\/revisions"}],"predecessor-version":[{"id":169,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/posts\/92\/revisions\/169"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/media\/93"}],"wp:attachment":[{"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/media?parent=92"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/categories?post=92"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/tags?post=92"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}