Comprehensive 6-domain security audit addressing 8 Critical, 17 Important,
and 5 Low findings. Key fixes:
Critical:
- Strip PII from unauthenticated ticket lookup (IDOR)
- Add role+permission checks to event check-in routes
- Validate tier-to-event ownership on update/delete (IDOR)
- Fix path traversal in video replace (resolve + prefix check)
- Enable MongoDB authentication for Rocket.Chat
- Disable Grafana anonymous access
- Sanitize CSV exports against formula injection (payments)
- Apply DOMPurify to richDescription on public event page (XSS)
Important:
- Require current password for self-service password changes
- Atomic password reset token consumption (race condition fix)
- Scope postMessage to specific origin (not wildcard)
- Validate redirect parameter against open redirect
- Replace weak temp passwords (5760 values → crypto.randomBytes)
- Move shift capacity check inside transaction (TOCTOU fix)
- Fix EVENTS_ADMIN privilege inversion in ticketed events
- Make ENCRYPTION_KEY required (remove optional fallback)
- Add internal Prometheus metrics endpoint for Docker scraping
- Add nginx-level rate limiting (limit_req_zone)
- Fix X-Forwarded-For to use $remote_addr (prevents spoofing)
- Replace CSP stripping with frame-ancestors in embed proxies
- Remove error.message from Fastify 500 responses
- Strip PII from volunteer canvass address data
- Wrap GrapesJS output in {% raw %} to prevent Jinja2 SSTI
- Scope SSE token query param to /sse path only
- Sanitize Listmonk email query against injection
Bunker Admin
61 lines
2.5 KiB
TypeScript
61 lines
2.5 KiB
TypeScript
import { Router } from 'express';
|
|
import { authenticate } from '../../middleware/auth.middleware';
|
|
import { requireRole } from '../../middleware/rbac.middleware';
|
|
import { SOCIAL_ROLES } from '../../utils/roles';
|
|
import { friendshipRouter } from './friendship.routes';
|
|
import { blockRouter } from './block.routes';
|
|
import { privacyRouter } from './privacy.routes';
|
|
import { notificationRouter } from './notification.routes';
|
|
import { profileRouter } from './profile.routes';
|
|
import { feedRouter } from './feed.routes';
|
|
import { suggestionsRouter } from './suggestions.routes';
|
|
import { pokeRouter } from './poke.routes';
|
|
import { recommendationRouter } from './recommendation.routes';
|
|
import { integrationRouter } from './integration.routes';
|
|
import { groupRouter } from './group.routes';
|
|
import { achievementsRouter } from './achievements.routes';
|
|
import { sseRouter } from './sse.routes';
|
|
import { socialAdminRouter } from './social-admin.routes';
|
|
import { referralRouter } from './referral.routes';
|
|
import { impactStoriesRouter } from './impact-stories.routes';
|
|
import { spotlightRouter } from './spotlight.routes';
|
|
import { challengeRouter } from './challenge.routes';
|
|
|
|
const router = Router();
|
|
|
|
// EventSource (SSE) doesn't support custom headers — accept token via query param
|
|
// Scoped to /sse path only to limit token-in-URL exposure to where it's truly needed
|
|
router.use((req, _res, next) => {
|
|
if (req.query.token && !req.headers.authorization && req.path.startsWith('/sse')) {
|
|
req.headers.authorization = `Bearer ${req.query.token}`;
|
|
}
|
|
next();
|
|
});
|
|
|
|
// All social routes require authentication
|
|
router.use(authenticate);
|
|
|
|
// Admin sub-router (requires admin role)
|
|
router.use('/admin', requireRole(...SOCIAL_ROLES), socialAdminRouter);
|
|
|
|
// Sub-routers
|
|
router.use('/friends', friendshipRouter);
|
|
router.use('/blocks', blockRouter);
|
|
router.use('/privacy', privacyRouter);
|
|
router.use('/notifications', notificationRouter);
|
|
router.use('/profile', profileRouter);
|
|
router.use('/feed', feedRouter);
|
|
router.use('/suggestions', suggestionsRouter);
|
|
router.use('/pokes', pokeRouter);
|
|
router.use('/recommendations', recommendationRouter);
|
|
router.use('/integration', integrationRouter);
|
|
router.use('/groups', groupRouter);
|
|
router.use('/achievements', achievementsRouter);
|
|
router.use('/sse', sseRouter);
|
|
router.use('/referrals', referralRouter);
|
|
router.use('/stories', impactStoriesRouter);
|
|
router.use('/spotlight', spotlightRouter);
|
|
router.use('/challenges', challengeRouter);
|
|
|
|
export { router as socialRouter };
|