Skip to content

Comments

security: add real security headers middleware#663

Open
mmcintosh wants to merge 1 commit intoSonicJs-Org:mainfrom
mmcintosh:hotfix/security-headers
Open

security: add real security headers middleware#663
mmcintosh wants to merge 1 commit intoSonicJs-Org:mainfrom
mmcintosh:hotfix/security-headers

Conversation

@mmcintosh
Copy link
Contributor

Security: Add Real Security Headers Middleware

Summary

Replaces the no-op security headers placeholder with real security headers on every response. Prevents clickjacking, MIME-type sniffing, referrer leakage, and enforces HTTPS in production.

Changes

1. Security Headers Middleware

  • Sets 5 security headers on every response (applied after route handler via await next())
  • HSTS skipped in development to avoid breaking local dev with forced HTTPS

2. Headers Set

Header Value Purpose
X-Content-Type-Options nosniff Prevent MIME-type sniffing
X-Frame-Options SAMEORIGIN Prevent clickjacking
Referrer-Policy strict-origin-when-cross-origin Limit referrer leakage
Permissions-Policy camera=(), microphone=(), geolocation=() Disable sensitive browser APIs
Strict-Transport-Security max-age=31536000; includeSubDomains Force HTTPS (production only)

3. Replaces No-Op Stub

  • The existing securityHeaders export in middleware/index.ts was a no-op pass-through
  • Now re-exports the real securityHeadersMiddleware implementation
  • app.ts mounts the real middleware where the empty placeholder was

Technical Details

New File:

  • packages/core/src/middleware/security-headers.ts -- securityHeadersMiddleware() factory function

Updated Files:

  • packages/core/src/middleware/index.ts -- Re-exports real implementation instead of stub
  • packages/core/src/app.ts -- Imports and mounts securityHeadersMiddleware() on * (replacing the no-op)

Testing

  • Unit Tests: PASSED
  • E2E Tests: PASSED (3/3 shards green)

Performance Impact

No measurable impact -- setting 5 response headers adds negligible overhead.

Breaking Changes

  • X-Frame-Options: SAMEORIGIN will prevent embedding SonicJS admin pages in iframes from other domains. This is intentional.
  • HSTS will enforce HTTPS for 1 year once a browser sees the header. Only applied in non-development environments.

Migration Notes

No action required. Headers are applied automatically on all responses.

Known Issues

None.

Demo / Screenshots

N/A -- no UI changes. Headers visible in browser DevTools Network tab.

Related Issues

(Security hardening -- no linked issue)

Checklist

  • Code follows project coding standards
  • Tests added/updated and passing
  • Documentation updated
  • No breaking changes
  • Backward compatible

}

it('valid key with matching scope — calls next()', async () => {
const hash = await hashApiKey(TOKEN)

Check notice

Code scanning / CodeQL

Unused variable, import, function or class

Unused variable hash.
})

const mw = requireApiKey('search:read')
const result = await mw(ctx, mockNext)

Check notice

Code scanning / CodeQL

Unused variable, import, function or class

Unused variable result.
- Create security-headers.ts middleware replacing pass-through stub
- Set X-Content-Type-Options: nosniff (prevents MIME sniffing)
- Set X-Frame-Options: SAMEORIGIN (blocks external framing)
- Set Referrer-Policy: strict-origin-when-cross-origin
- Set Permissions-Policy: camera=(), microphone=(), geolocation=()
- Set HSTS (1 year) in non-development environments
- Apply middleware in app.ts security slot
- Replace stub export in middleware/index.ts

Fixes VULN-005
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.

1 participant