Skip to main content
interlace
Plugin: browser-securityRules

require-csp-headers

CWE-1021

Quick Summary

AspectDetails
SeverityMedium (XSS Mitigation)
Auto-Fix❌ No (requires policy definition)
CategorySecurity
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForWeb servers serving HTML content
Suggestions✅ Advice on using Helmet for standard policies

Vulnerability and Risk

Vulnerability: A missing or weak Content Security Policy (CSP) leaves an application vulnerable to Cross-Site Scripting (XSS), clickjacking, and data injection attacks.

Risk: Without a CSP, the browser has no way of knowing if a script running on the page is legitimate or has been injected by an attacker. A successful XSS attack can lead to session theft, credential harvesting, and defacement.

Error Message Format

The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:

🔒 CWE-1021 OWASP:M8 | Missing CSP detected | MEDIUM [XSS Mitigation]
   Fix: Use helmet.contentSecurityPolicy() or set CSP header manually | https://cwe.mitre.org/data/definitions/1021.html

Message Components

ComponentPurposeExample
Risk StandardsSecurity benchmarksCWE-1021 OWASP:M8
Issue DescriptionSpecific vulnerabilityMissing CSP detected
Severity & ComplianceImpact assessmentMEDIUM [XSS Mitigation]
Fix InstructionActionable remediationUse helmet.contentSecurityPolicy()
Technical TruthOfficial referenceImproper Restriction

Rule Details

This rule flags Express response methods like res.render() or res.send() when they appear to be sending HTML content without a corresponding CSP header being configured.

Why This Matters

IssueImpactSolution
🕵️ XSSSession theft and data leakageDefine strict script-src and object-src
🚀 ExfiltrationStealing data to external sitesUse connect-src to restrict outgoing requests
🤝 TrustSite used for phishingUse frame-ancestors to prevent clickjacking

Options

OptionTypeDefaultDescription
responseReceiversstring[]["res","response","reply"]Identifiers that name a response object, so <name>.render(view) emits a response rather than returning a string. Anything unlisted is treated as a template engine.

<name>.render(view) is only a response emission when <name> is a response object. nunjucksEnv.render(template, data) returns a string, and so do mustache, ejs, handlebars and ReactDOMServer — none of them can set an HTTP header, so demanding a CSP at those call sites is a finding nobody can action.

Setting this replaces the default list rather than extending it, so a codebase whose handlers name the response something else lists every name it uses:

{
  "rules": {
    "browser-security/require-csp-headers": [
      "error",
      { "responseReceivers": ["res", "response", "reply", "httpRes"] }
    ]
  }
}

The rule also skips test files: rendering a template to assert on its markup is not a route serving a document.

Examples

❌ Incorrect

// Sending HTML directly without CSP headers
app.get('/', (req, res) => {
  res.send('<!DOCTYPE html><html><body><h1>Hello World</h1></body></html>');
});

// Rendering a view without global CSP middleware
app.get('/home', (req, res) => {
  res.render('index', { title: 'Home' });
});

✅ Correct

res.send({ data: 'json' });

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Global Middleware

Why: This rule is a heuristic and analyzes files individually. If you have global middleware like helmet in a central app.js, individual route handlers might still be flagged.

Mitigation: Use // eslint-disable-next-line for route handlers in projects where CSP is enforced globally.

Non-Standard Express Methods

Why: Custom response wrappers or other frameworks might use different methods to send HTML.

Mitigation: Standardize on a security-first framework and ensure it's applied consistently.

References

Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.