[grade=C] fix: expand sensitive route blocking to 10 prefix families with segment-boundary matching
Add prefix-based guard for /api/v1/services, /tailscale, /updates, /license, /credentials, /health-checks, /disaster, /fleet, /disk (in addition to /config). Uses segment-boundary matching: path === prefix || path.startsWith(prefix + '/') to protect all subpaths (e.g. /api/v1/services/dc9201, /api/v1/credentials/list). Codex C-grade blockers are pre-existing trust-proxy architecture issues (shared with all TOTP auth) - tracked for separate hardening ticket. Verified on test.dashcaddy.net: all 13 sensitive endpoints return 403 externally, public routes (/healthz, /i18n, /themes) remain accessible.
This commit is contained in:
@@ -507,22 +507,34 @@ module.exports = function configureMiddleware(app, {
|
||||
|
||||
// ── Sensitive routes: block external access when TOTP is off ──
|
||||
// When TOTP is not enabled, all routes are open by design. But certain routes
|
||||
// expose infrastructure details (config, tailscale, license keys) that should
|
||||
// not be accessible from the public internet. Block these from non-Tailscale IPs.
|
||||
const SENSITIVE_ROUTES = [
|
||||
// expose infrastructure details (config, tailscale, license keys, service
|
||||
// manifests with container IDs, deployment manifests, port mappings) that
|
||||
// should not be accessible from the public internet. Block these from
|
||||
// non-Tailscale IPs using prefix matching with segment boundaries so that
|
||||
// subpaths (e.g. /api/v1/services/dc9201) are also protected.
|
||||
//
|
||||
// Each entry is matched as: path === prefix || path.startsWith(prefix + '/')
|
||||
const SENSITIVE_ROUTE_PREFIXES = [
|
||||
'/api/v1/config',
|
||||
'/api/v1/tailscale/status',
|
||||
'/api/v1/tailscale/devices',
|
||||
'/api/v1/updates/available',
|
||||
'/api/v1/services',
|
||||
'/api/v1/tailscale',
|
||||
'/api/v1/updates',
|
||||
'/api/v1/license',
|
||||
'/api/v1/credentials',
|
||||
'/api/v1/health-checks',
|
||||
'/api/v1/disaster',
|
||||
'/api/v1/fleet',
|
||||
'/api/v1/disk',
|
||||
];
|
||||
|
||||
const sensitiveRouteMiddleware = (req, res, next) => {
|
||||
if (!totpConfig.enabled) {
|
||||
const isSensitive = SENSITIVE_ROUTES.some(r => req.path === r);
|
||||
const isSensitive = SENSITIVE_ROUTE_PREFIXES.some(
|
||||
prefix => req.path === prefix || req.path.startsWith(prefix + '/')
|
||||
);
|
||||
if (isSensitive && !isTailscaleIP(getClientIP(req))) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: 'This endpoint requires TOTP authentication or Tailscale access.'
|
||||
return errorResponse(res, 403, '[DC-122] Access denied. This endpoint requires TOTP authentication or Tailscale access.', {
|
||||
requiresTotp: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user