Skip to content

Commit e1a585d

Browse files
committed
security: add real security headers middleware
- 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
1 parent 46af09f commit e1a585d

3 files changed

Lines changed: 26 additions & 5 deletions

File tree

packages/core/src/app.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
import { getCoreVersion } from './utils/version'
3232
import { bootstrapMiddleware } from './middleware/bootstrap'
3333
import { metricsMiddleware } from './middleware/metrics'
34+
import { securityHeadersMiddleware } from './middleware/security-headers'
3435
import { createDatabaseToolsAdminRoutes } from './plugins/core-plugins/database-tools-plugin/admin-routes'
3536
import { createSeedDataAdminRoutes } from './plugins/core-plugins/seed-data-plugin/admin-routes'
3637
import { emailPlugin } from './plugins/core-plugins/email-plugin'
@@ -171,10 +172,7 @@ export function createSonicJSApp(config: SonicJSConfig = {}): SonicJSApp {
171172
})
172173

173174
// Security middleware
174-
app.use('*', async (_c, next) => {
175-
// Security headers, CORS, etc.
176-
await next()
177-
})
175+
app.use('*', securityHeadersMiddleware())
178176

179177
// Custom middleware - after auth
180178
if (config.middleware?.afterAuth) {

packages/core/src/middleware/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const securityLoggingMiddleware: any = () => async (_c: any, next: any) =
3737
export const performanceLoggingMiddleware: any = () => async (_c: any, next: any) => await next()
3838
export const cacheHeaders: any = () => async (_c: any, next: any) => await next()
3939
export const compressionMiddleware: any = async (_c: any, next: any) => await next()
40-
export const securityHeaders: any = () => async (_c: any, next: any) => await next()
40+
export { securityHeadersMiddleware as securityHeaders } from './security-headers'
4141

4242
// Other stubs
4343
export const PermissionManager: any = {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Context, Next } from 'hono'
2+
3+
/**
4+
* Security headers middleware.
5+
* Sets standard security headers on every response.
6+
* Skips HSTS in development to avoid local dev issues.
7+
*/
8+
export const securityHeadersMiddleware = () => {
9+
return async (c: Context, next: Next) => {
10+
await next()
11+
12+
c.header('X-Content-Type-Options', 'nosniff')
13+
c.header('X-Frame-Options', 'SAMEORIGIN')
14+
c.header('Referrer-Policy', 'strict-origin-when-cross-origin')
15+
c.header('Permissions-Policy', 'camera=(), microphone=(), geolocation=()')
16+
17+
// Only set HSTS in non-development environments
18+
const environment = (c.env as any)?.ENVIRONMENT
19+
if (environment !== 'development') {
20+
c.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains')
21+
}
22+
}
23+
}

0 commit comments

Comments
 (0)