feat: private hostname guard for authenticated/private mode

Reject requests from unrecognised Host headers when running
authenticated/private. Adds server middleware, CLI `allowed-hostname`
command, config-schema field, and prompt support for configuring
allowed hostnames during onboard/configure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Forgotten
2026-02-23 19:43:52 -06:00
parent 076092685e
commit 85c0b9a3dc
15 changed files with 385 additions and 8 deletions

View File

@@ -33,6 +33,7 @@ export interface Config {
deploymentExposure: DeploymentExposure;
host: string;
port: number;
allowedHostnames: string[];
authBaseUrlMode: AuthBaseUrlMode;
authPublicBaseUrl: string | undefined;
databaseMode: DatabaseMode;
@@ -131,12 +132,23 @@ export function loadConfig(): Config {
authBaseUrlModeFromEnv ??
fileConfig?.auth?.baseUrlMode ??
(authPublicBaseUrl ? "explicit" : "auto");
const allowedHostnamesFromEnvRaw = process.env.PAPERCLIP_ALLOWED_HOSTNAMES;
const allowedHostnamesFromEnv = allowedHostnamesFromEnvRaw
? allowedHostnamesFromEnvRaw
.split(",")
.map((value) => value.trim().toLowerCase())
.filter((value) => value.length > 0)
: null;
const allowedHostnames = Array.from(
new Set((allowedHostnamesFromEnv ?? fileConfig?.server.allowedHostnames ?? []).map((value) => value.trim().toLowerCase()).filter(Boolean)),
);
return {
deploymentMode,
deploymentExposure,
host: process.env.HOST ?? fileConfig?.server.host ?? "127.0.0.1",
port: Number(process.env.PORT) || fileConfig?.server.port || 3100,
allowedHostnames,
authBaseUrlMode,
authPublicBaseUrl,
databaseMode: fileDatabaseMode,