Fix low-severity security issues: headers, body limit, log redaction, telemetry validation

- Add X-Content-Type-Options, X-Frame-Options, and Referrer-Policy headers to all responses
- Cap express.json() body to 50kb to prevent memory exhaustion via large payloads
- Redact credentials from MQTT broker URL before logging (ws://user:pass@host pattern)
- Whitelist telemetry event kind field instead of accepting arbitrary strings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
BenandClaude Sonnet 4.6 committed 2026-03-08 03:44:09 +00:00
1 parent bbadebd761
commit 0e8dba2b3d
3 files changed
+15 -3

No files matched your search

+4 -1
View File
@@ -1136,11 +1136,14 @@ router.post('/telemetry/frontend-error', async (req, res) => {
return;
}
const ALLOWED_KINDS = new Set(['error', 'warning', 'unhandledrejection', 'crash']);
const kind = ALLOWED_KINDS.has(String(body.kind)) ? String(body.kind) : 'error';
await query(
`INSERT INTO frontend_error_events (kind, message, stack, page, user_agent)
VALUES ($1, $2, $3, $4, $5)`,
[
String(body.kind ?? 'error').slice(0, 40),
kind,
message,
body.stack ? String(body.stack).slice(0, 4000) : null,
body.page ? String(body.page).slice(0, 300) : null,
+9 -1
View File
@@ -80,7 +80,15 @@ async function main() {
},
}));
app.use(express.json());
// Security headers
app.use((_req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Referrer-Policy', 'no-referrer');
next();
});
app.use(express.json({ limit: '50kb' }));
// Rate limit: 120 requests / IP / minute on all API endpoints
app.use('/api', rateLimit({
+2 -1
View File
@@ -227,7 +227,8 @@ function buildAdvertFallbackPayload(originId: string, originName?: string): Reco
export function startMqttClient(): void {
const brokerUrl = process.env['MQTT_BROKER_URL'] ?? 'ws://mosquitto:9001';
console.log(`[mqtt] connecting to ${brokerUrl}`);
const redactedUrl = brokerUrl.replace(/\/\/[^@]*@/, '//***:***@');
console.log(`[mqtt] connecting to ${redactedUrl}`);
console.log(`[mqtt] channels: ${channelEntries.map((e) => e.name).join(', ')}`);
console.log(`[mqtt] topic prefixes: ${Array.from(TOPIC_PREFIXES).join(', ')}`);