Skip to content

Conversation

@KariraLakshya
Copy link
Contributor

@KariraLakshya KariraLakshya commented Dec 24, 2025

Description

This PR adds a baseline set of HTTP security headers to improve the security posture of the AsyncAPI website.

Changes

  • Configured standard security headers via netlify.toml
  • Added Content-Security-Policy in report-only mode to safely observe violations without breaking the site
  • Added HSTS, Referrer Policy, Permissions Policy, and content-type protections

Notes

  • CSP is intentionally added in report-only mode.
  • preload is intentionally omitted from HSTS and can be considered in a follow-up PR.

Fixes #4724

Summary by CodeRabbit

  • Chores

    • Updated site security header configuration: removed legacy headers and replaced them with a stronger set of security-focused headers.
  • New Features

    • Enforced stricter content and transport security with reporting enabled to help detect and mitigate policy violations.
    • Added a lightweight endpoint to receive Content Security Policy violation reports and acknowledge them without returning content.

✏️ Tip: You can customize this high-level summary in your review settings.

@netlify
Copy link

netlify bot commented Dec 24, 2025

Deploy Preview for asyncapi-website ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 77777fe
🔍 Latest deploy log https://app.netlify.com/projects/asyncapi-website/deploys/694eede3ed7c7e0008bf3341
😎 Deploy Preview https://deploy-preview-4769--asyncapi-website.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 24, 2025

📝 Walkthrough

Walkthrough

Replaced two response headers with multiple security-focused headers in Netlify config and added a Netlify Function that accepts POSTed CSP violation reports, attempts to parse and log them, and always returns HTTP 204 No Content.

Changes

Cohort / File(s) Summary
Security headers (Netlify config)
netlify.toml
Replaced X-Frame-Options and Access-Control-Allow-Origin with X-Content-Type-Options, Referrer-Policy, Permissions-Policy, Strict-Transport-Security, and Content-Security-Policy-Report-Only.
CSP report endpoint (Netlify Function)
netlify/functions/csp-report.ts
Added export const handler: Handler that only allows POST (405 otherwise), tries to parse event.body JSON, logs the report or parse error with a timestamp, and responds with HTTP 204 No Content.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor Browser
    participant CDN as "Site / CDN"
    participant CSPFn as "Netlify Function\n/netlify/functions/csp-report"
    participant Logs as "Server Console / Logs"

    Browser->>CDN: Request page (receives security headers)
    Note right of CDN: CSP-Report-Only header present
    Browser->>CSPFn: POST CSP violation (JSON)
    activate CSPFn
    CSPFn->>CSPFn: try parse event.body
    alt parse success
        CSPFn->>Logs: log timestamp + parsed report
    else parse error
        CSPFn->>Logs: log timestamp + parse error
    end
    CSPFn-->>Browser: HTTP 204 No Content
    deactivate CSPFn
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nibbled toml and set a robust fence,
Headers standing guard in quiet defense.
When a rogue script trips and sends a small report,
I log the tale, then close the door with a soft 204. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The CSP report endpoint function (csp-report.ts) extends beyond the baseline header configuration scope defined in issue #4724, introducing reporting infrastructure not part of the original requirements. Either remove the CSP reporting endpoint from this PR and address it separately as a follow-up, or clarify that reporting infrastructure is now in-scope for this issue.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly references adding HTTP security headers via Netlify configuration, which directly matches the main changeset focus on netlify.toml security header updates.
Linked Issues check ✅ Passed The PR successfully implements all required security headers from issue #4724: CSP (report-only), X-Content-Type-Options, frame-ancestors via CSP, Referrer-Policy, Permissions-Policy, and HSTS.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Dec 24, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (785c358) to head (77777fe).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #4769   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           22        22           
  Lines          798       798           
  Branches       146       146           
=========================================
  Hits           798       798           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
netlify.toml (2)

7-7: Remove trailing semicolon from HSTS header.

The trailing semicolon after includeSubDomains; is unnecessary and non-standard, though it shouldn't cause issues with most browsers.

🔎 Suggested fix
-    Strict-Transport-Security = "max-age=63072000; includeSubDomains;"
+    Strict-Transport-Security = "max-age=63072000; includeSubDomains"

4-8: Consider adding X-Frame-Options as a fallback for older browsers.

While frame-ancestors 'none' in your CSP provides clickjacking protection, older browsers that don't support CSP Level 2 (including some legacy enterprise browsers) won't enforce it. Adding X-Frame-Options = "DENY" alongside the CSP directive ensures broader compatibility.

🔎 Suggested addition
     X-Content-Type-Options = "nosniff"
+    X-Frame-Options = "DENY"
     Referrer-Policy = "strict-origin-when-cross-origin"
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e917b0d and 4fa03fb.

📒 Files selected for processing (1)
  • netlify.toml
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Redirect rules - asyncapi-website
  • GitHub Check: Header rules - asyncapi-website
  • GitHub Check: Pages changed - asyncapi-website
  • GitHub Check: Test NodeJS PR - windows-latest
  • GitHub Check: Lighthouse CI
🔇 Additional comments (2)
netlify.toml (2)

4-6: LGTM! Strong baseline security headers.

These three headers are correctly configured:

  • X-Content-Type-Options prevents MIME-sniffing attacks
  • Referrer-Policy provides good privacy/security balance
  • Permissions-Policy blocks risky features by default

1-9: No changes needed; the removal of Access-Control-Allow-Origin is appropriate.

The AsyncAPI website repository contains no CORS-related code, cross-origin API calls, or references to Access-Control headers. The architecture uses static site generation (SSG) with Netlify serverless functions for backend operations, which does not require CORS headers for client-side cross-origin requests. The header removal is intentional security hardening.

Likely an incorrect or invalid review comment.

netlify.toml Outdated
Referrer-Policy = "strict-origin-when-cross-origin"
Permissions-Policy = "camera=(), microphone=(), geolocation=()"
Strict-Transport-Security = "max-age=63072000; includeSubDomains;"
Content-Security-Policy-Report-Only = "default-src 'self'; frame-ancestors 'none'; script-src 'self' https: 'unsafe-inline' 'unsafe-eval'; style-src 'self' https: 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https: data:; connect-src 'self' https:;"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

CSP baseline is too permissive to be effective, even in report-only mode.

The current Content-Security-Policy-Report-Only contains several directives that significantly weaken protection against XSS and other attacks:

  • 'unsafe-inline' in script-src and style-src allows inline scripts/styles (primary XSS vector)
  • 'unsafe-eval' in script-src permits eval() and similar constructs (another XSS vector)
  • Broad https: sources allow loading from any HTTPS origin

While report-only mode is appropriate for initial deployment, these directives are so permissive they won't generate meaningful violation reports to help you harden the policy later. Consider tightening the baseline to at least remove 'unsafe-eval' and restrict sources to specific trusted domains, then use the violation reports to iteratively refine.

Additionally, missing commonly recommended directives:

  • object-src 'none' - blocks plugins
  • base-uri 'self' - prevents base tag injection
  • form-action 'self' - restricts form submissions
🔎 Suggested improved baseline (still permissive but more useful for monitoring)
-    Content-Security-Policy-Report-Only = "default-src 'self'; frame-ancestors 'none'; script-src 'self' https: 'unsafe-inline' 'unsafe-eval'; style-src 'self' https: 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https: data:; connect-src 'self' https:;"
+    Content-Security-Policy-Report-Only = "default-src 'self'; script-src 'self' 'unsafe-inline' https://trusted-cdn.example.com; style-src 'self' 'unsafe-inline' https://trusted-cdn.example.com; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https:; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none';"

Replace https://trusted-cdn.example.com with your actual CDN/third-party script domains. This removes 'unsafe-eval' and tightens sources while keeping 'unsafe-inline' for compatibility during the monitoring phase.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Content-Security-Policy-Report-Only = "default-src 'self'; frame-ancestors 'none'; script-src 'self' https: 'unsafe-inline' 'unsafe-eval'; style-src 'self' https: 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https: data:; connect-src 'self' https:;"
Content-Security-Policy-Report-Only = "default-src 'self'; script-src 'self' 'unsafe-inline' https://trusted-cdn.example.com; style-src 'self' 'unsafe-inline' https://trusted-cdn.example.com; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https:; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none';"

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4fa03fb and 41fb20f.

📒 Files selected for processing (1)
  • netlify.toml
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Redirect rules - asyncapi-website
  • GitHub Check: Header rules - asyncapi-website
  • GitHub Check: Pages changed - asyncapi-website
  • GitHub Check: Test NodeJS PR - windows-latest
🔇 Additional comments (2)
netlify.toml (2)

4-7: Excellent baseline security header configuration!

The security headers are well-configured:

  • X-Content-Type-Options prevents MIME type sniffing attacks
  • Referrer-Policy provides a good balance between privacy and functionality
  • Permissions-Policy appropriately restricts sensitive browser features
  • Strict-Transport-Security enforces HTTPS with a 2-year max-age and subdomain coverage

8-8: Good progress addressing previous feedback on CSP directives!

The CSP has been significantly improved from the previous version:

  • Removed 'unsafe-eval' from script-src (eliminates a major XSS vector)
  • Added object-src 'none' (blocks plugins)
  • Added base-uri 'self' (prevents base tag injection)
  • Added form-action 'self' (restricts form submissions)

These changes directly address the concerns raised in the previous review.

@KariraLakshya
Copy link
Contributor Author

Thanks for the review feedback.

I agree that CSP report-only mode is most effective when paired with a reporting endpoint.
I intentionally kept this PR limited to baseline security headers, since adding report-uri / report-to requires choosing and maintaining reporting infrastructure (Netlify function or third-party service).

Happy to extend this with a reporting endpoint in a follow-up PR once maintainers confirm the preferred approach.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
netlify/functions/csp-report.ts (2)

3-7: Consider adding request validation.

The handler accepts any request method and content-type. CSP reports are sent as POST requests with application/csp-report or application/json content-type. Adding validation improves security and debugging.

🔎 Add basic request validation
 export const handler: Handler = async (event) => {
+  // Validate request method
+  if (event.httpMethod !== 'POST') {
+    return {
+      statusCode: 405,
+      body: 'Method Not Allowed'
+    };
+  }
+
+  // Validate content-type (CSP reports can be application/csp-report or application/json)
+  const contentType = event.headers['content-type'] || '';
+  if (!contentType.includes('application/csp-report') && !contentType.includes('application/json')) {
+    return {
+      statusCode: 415,
+      body: 'Unsupported Media Type'
+    };
+  }
+
   // Log CSP violation reports
   console.log('[CSP Violation Report]', {
     body: event.body,
     timestamp: new Date().toISOString()
   });
   
   return {
     statusCode: 204,
   };
 };

3-3: Remove unnecessary async keyword.

The function doesn't perform any asynchronous operations. The async keyword is unnecessary unless you plan to add async logging/storage later.

🔎 Remove async if not needed
-export const handler: Handler = async () => {
+export const handler: Handler = () => {
   return {
     statusCode: 204,
   };
 };

Or keep it if you expect to add async operations based on the previous suggestions.

netlify.toml (2)

8-8: CSP policy remains very permissive for eventual enforcement.

While report-only mode is appropriate for initial deployment, the current policy is extremely permissive:

  • https: in multiple directives allows loading from any HTTPS origin
  • 'unsafe-inline' in script-src and style-src permits inline scripts/styles (primary XSS vector)

These directives are so broad that the reports may not provide useful insights for tightening the policy later. Once you've collected initial reports, consider progressively restricting:

  1. Replace https: with specific trusted domains (CDNs, analytics, etc.)
  2. Remove 'unsafe-inline' in favor of nonces or hashes for inline scripts/styles
🔎 Example of moderately tightened policy for the next iteration
-    Content-Security-Policy-Report-Only = "default-src 'self'; script-src 'self' https: 'unsafe-inline'; style-src 'self' https: 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https:; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; report-uri /.netlify/functions/csp-report;"
+    Content-Security-Policy-Report-Only = "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.example.com https://analytics.example.com; style-src 'self' 'unsafe-inline' https://cdn.example.com; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https://api.example.com; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; report-uri /.netlify/functions/csp-report;"

Replace placeholder domains with actual third-party services used by the site. This keeps 'unsafe-inline' during monitoring but restricts source origins to generate more actionable violation reports.


7-7: Trailing semicolon in HSTS header is unusual but should work.

The trailing semicolon after includeSubDomains; is syntactically valid but non-standard (typically omitted). Most implementations will handle it correctly, but you might consider removing it for consistency with common formatting.

🔎 Remove trailing semicolon
-    Strict-Transport-Security = "max-age=63072000; includeSubDomains;"
+    Strict-Transport-Security = "max-age=63072000; includeSubDomains"
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41fb20f and ea72be9.

📒 Files selected for processing (2)
  • netlify.toml
  • netlify/functions/csp-report.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Redirect rules - asyncapi-website
  • GitHub Check: Header rules - asyncapi-website
  • GitHub Check: Pages changed - asyncapi-website
  • GitHub Check: Test NodeJS PR - windows-latest
🔇 Additional comments (2)
netlify.toml (2)

4-8: Security headers look good overall.

The baseline security headers are well-configured:

  • X-Content-Type-Options: nosniff prevents MIME sniffing
  • Referrer-Policy: strict-origin-when-cross-origin balances privacy and functionality
  • Permissions-Policy restricts powerful features
  • Strict-Transport-Security enforces HTTPS with 2-year max-age and subdomain coverage
  • frame-ancestors 'none' in CSP prevents clickjacking
  • report-uri now present (addresses previous critical issue)

8-8: Verify the CSP reporting endpoint functions correctly after deployment.

Ensure that:

  1. The Netlify function deploys successfully at /.netlify/functions/csp-report
  2. Browsers can reach the endpoint (check for CORS or authentication issues)
  3. CSP violation reports are being generated and logged (once you implement logging per the suggestion on csp-report.ts)

Test by visiting the site and checking browser DevTools Console for CSP violations, then verifying the function logs in Netlify dashboard.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
netlify/functions/csp-report.ts (1)

5-6: Consider adding Content-Type validation and size limits.

For improved reliability and to prevent potential abuse:

  1. Validate the Content-Type header (CSP reports typically use application/csp-report or application/json)
  2. Add a size limit check to prevent processing excessively large payloads
🔎 Suggested defensive checks
+  const contentType = event.headers['content-type'] || '';
+  if (!contentType.includes('application/csp-report') && !contentType.includes('application/json')) {
+    return {
+      statusCode: 415,
+      body: 'Unsupported Media Type',
+    };
+  }
+
   try {
     if (event.body) {
+      // Reject overly large payloads (e.g., > 10KB)
+      if (event.body.length > 10240) {
+        console.warn('[CSP Report] Rejected oversized payload');
+        return { statusCode: 413 };
+      }
+
       const report = JSON.parse(event.body);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea72be9 and f8cf009.

📒 Files selected for processing (1)
  • netlify/functions/csp-report.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test NodeJS PR - windows-latest
🔇 Additional comments (1)
netlify/functions/csp-report.ts (1)

3-20: Good implementation of CSP report logging.

The function now properly logs CSP violation reports with timestamps and handles parsing errors gracefully. This addresses the previous review feedback and provides the necessary observability for refining the CSP policy.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
netlify/functions/csp-report.ts (3)

5-10: Fix indentation inconsistency.

Lines 5 and 8-10 have inconsistent indentation that doesn't match the rest of the file. This should be caught and fixed by your linter/formatter.

🔎 Proposed fix for indentation
   // CSP reports are sent via POST
-  if (event.httpMethod !== 'POST') {
+  if (event.httpMethod !== 'POST') {
     return {
       statusCode: 405,
       headers: {
-      Allow: 'POST',
-    },
+        Allow: 'POST',
+      },
       body: 'Method Not Allowed',
     };
   }

5-13: Consider validating Content-Type header.

Browsers typically send CSP reports with Content-Type: application/csp-report or application/json. Validating the Content-Type would prevent processing of unexpected payloads and improve security posture.

🔎 Proposed fix to add Content-Type validation
   // CSP reports are sent via POST
   if (event.httpMethod !== 'POST') {
     return {
       statusCode: 405,
       headers: {
         Allow: 'POST',
       },
       body: 'Method Not Allowed',
     };
   }
+
+  const contentType = event.headers['content-type'] || '';
+  if (!contentType.includes('application/csp-report') && !contentType.includes('application/json')) {
+    return {
+      statusCode: 415,
+      body: 'Unsupported Media Type',
+    };
+  }

14-25: Excellent implementation of CSP report logging.

The code successfully addresses the previous review feedback by logging CSP violations and handling parse errors. Using console.warn for violations and console.error for parse errors provides good log-level differentiation.

💡 Optional: Log when body is missing

For easier debugging, consider logging when event.body is missing:

   try {
     if (event.body) {
       const report = JSON.parse(event.body);

       console.warn('[CSP Violation Report]', {
         report,
         timestamp: new Date().toISOString(),
       });
+    } else {
+      console.warn('[CSP Report] Received POST with empty body');
     }
   } catch (error) {
     console.error('[CSP Report Parse Error]', error);
   }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f8cf009 and 8c10cce.

📒 Files selected for processing (1)
  • netlify/functions/csp-report.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test NodeJS PR - windows-latest
🔇 Additional comments (2)
netlify/functions/csp-report.ts (2)

1-2: LGTM!

The import is correct and uses the appropriate type from @netlify/functions.


27-29: LGTM!

Returning 204 No Content is the correct response for CSP report endpoints.

@KariraLakshya
Copy link
Contributor Author

The remaining CI failure appears to be related to the Lighthouse Best Practices
threshold. The changes in this PR intentionally focus on adding a safe,
non-breaking security baseline (CSP in report-only mode with logging).

Further improving the Lighthouse score would likely require one of the following:

  • Adding cross-origin isolation headers (COOP/COEP), which would be a breaking
    change and require auditing all third-party resources
  • Removing or replacing existing third-party scripts/resources that affect the
    Best Practices score
  • Adjusting or relaxing the Lighthouse Best Practices threshold in the workflow
    to better align with the current site architecture

Please let me know which approach you’d prefer:

  • updating the Lighthouse configuration, or
  • addressing additional Lighthouse-specific hardening in a separate follow-up PR

Happy to proceed based on your guidance.

@KariraLakshya
Copy link
Contributor Author

@anshgoyalevil Should I add isolation headers (COOP/COEP), to fix the remaining CI failure??
I have not added till now because it would require auditing of third party resouces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Add comprehensive security headers to improve website protection

1 participant