Skip to content
Back to skills

Cors Security Headers

ASecurity

CORS configuration and HTTP security headers. CORS middleware, preflight requests, Content-Security-Policy, CSRF protection, Helmet.js, and secure cookie configuration. USE WHEN: user mentions "CORS", "cross-origin", "CSP", "Content-Security-Policy", "CSRF", "security headers", "Helmet", "preflight", "Access-Control" DO NOT USE FOR: authentication tokens - use `jwt` or `oauth2`; encryption - use `cryptography`

  • 31 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 8, 2026
ai-agentstypescriptjavaexpressspringapisecurity

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 8, 2026

npx -y skills add claude-dev-suite/claude-dev-suite --skill cors-security-headers --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cors Security Headers?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cors Security Headers
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/claude-dev-suite-cors-security-headers/badge)](https://www.skillsdirectory.com/skills/claude-dev-suite-cors-security-headers)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cors-security-headers
description: |
  CORS configuration and HTTP security headers. CORS middleware, preflight
  requests, Content-Security-Policy, CSRF protection, Helmet.js, and
  secure cookie configuration.

  USE WHEN: user mentions "CORS", "cross-origin", "CSP", "Content-Security-Policy",
  "CSRF", "security headers", "Helmet", "preflight", "Access-Control"

  DO NOT USE FOR: authentication tokens - use `jwt` or `oauth2`;
  encryption - use `cryptography`
allowed-tools: Read, Grep, Glob, Write, Edit
---
# CORS & Security Headers

## CORS (Express)

```typescript
import cors from 'cors';

// Restrictive (recommended)
app.use(cors({
  origin: ['https://myapp.com', 'https://admin.myapp.com'],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400, // Preflight cache: 24h
}));

// Dynamic origin
app.use(cors({
  origin: (origin, callback) => {
    const allowed = ALLOWED_ORIGINS.includes(origin!) || !origin; // !origin = same-origin
    callback(null, allowed ? origin : false);
  },
  credentials: true,
}));
```

## Security Headers (Helmet.js)

```typescript
import helmet from 'helmet';

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", "'unsafe-inline'", 'https://cdn.example.com'],
      styleSrc: ["'self'", "'unsafe-inline'"],
      imgSrc: ["'self'", 'data:', 'https:'],
      connectSrc: ["'self'", 'https://api.example.com'],
      frameSrc: ["'none'"],
      objectSrc: ["'none'"],
    },
  },
  hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
  referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
}));
```

## CSRF Protection

```typescript
import csrf from 'csurf';

// For server-rendered forms (session-based apps)
app.use(csrf({ cookie: true }));
app.get('/form', (req, res) => {
  res.render('form', { csrfToken: req.csrfToken() });
});

// For SPAs: use SameSite cookies + custom header
// No csrf library needed — rely on:
// 1. SameSite=Strict/Lax cookies
// 2. Check Origin/Referer header matches
// 3. Custom header requirement (X-Requested-With)
```

## Secure Cookies

```typescript
app.use(session({
  cookie: {
    httpOnly: true,        // No JS access
    secure: true,          // HTTPS only
    sameSite: 'lax',       // CSRF protection
    maxAge: 24 * 60 * 60 * 1000,
    domain: '.myapp.com',  // Shared across subdomains
  },
}));
```

## Spring Boot Security Headers

```java
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .cors(cors -> cors.configurationSource(corsConfig()))
        .headers(headers -> headers
            .contentSecurityPolicy(csp -> csp.policyDirectives("default-src 'self'"))
            .referrerPolicy(ref -> ref.policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN))
            .frameOptions(frame -> frame.deny())
        )
        .csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
        .build();
}

@Bean
CorsConfigurationSource corsConfig() {
    var config = new CorsConfiguration();
    config.setAllowedOrigins(List.of("https://myapp.com"));
    config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
    config.setAllowCredentials(true);
    var source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return source;
}
```

## Key Headers Reference

| Header | Purpose | Recommended Value |
|--------|---------|------------------|
| `Strict-Transport-Security` | Force HTTPS | `max-age=31536000; includeSubDomains` |
| `Content-Security-Policy` | Restrict resource loading | `default-src 'self'` + specifics |
| `X-Content-Type-Options` | Prevent MIME sniffing | `nosniff` |
| `X-Frame-Options` | Prevent clickjacking | `DENY` |
| `Referrer-Policy` | Control referrer info | `strict-origin-when-cross-origin` |
| `Permissions-Policy` | Restrict browser features | `camera=(), microphone=()` |

## Anti-Patterns

| Anti-Pattern | Fix |
|--------------|-----|
| `Access-Control-Allow-Origin: *` with credentials | Specify exact origins |
| No CSP header | Add Content-Security-Policy |
| CSRF token in URL query params | Use header or hidden form field |
| `SameSite=None` without `Secure` | Always pair SameSite=None with Secure |
| Missing HSTS | Enable with long max-age and preload |

## Production Checklist

- [ ] CORS: specific origins, no wildcard with credentials
- [ ] Helmet.js (or equivalent) for all security headers
- [ ] CSP configured and tested
- [ ] HSTS with preload
- [ ] Secure, HttpOnly, SameSite cookies
- [ ] CSRF protection for state-changing requests

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.