fix(security): fail closed on gateway bind fallback and tighten canvas IP fallback

This commit is contained in:
Peter Steinberger
2026-02-19 14:36:39 +01:00
parent a40c10d3e2
commit 08a7967936
4 changed files with 247 additions and 32 deletions

View File

@@ -152,5 +152,84 @@ describe("resolveGatewayRuntimeConfig", () => {
}),
).rejects.toThrow("refusing to bind gateway");
});
it("should reject loopback mode if host resolves to non-loopback", async () => {
const cfg = {
gateway: {
bind: "loopback" as const,
auth: {
mode: "none" as const,
},
},
};
await expect(
resolveGatewayRuntimeConfig({
cfg,
port: 18789,
host: "0.0.0.0",
}),
).rejects.toThrow("gateway bind=loopback resolved to non-loopback host");
});
it("should reject custom bind without customBindHost", async () => {
const cfg = {
gateway: {
bind: "custom" as const,
auth: {
mode: "token" as const,
token: "test-token-123",
},
},
};
await expect(
resolveGatewayRuntimeConfig({
cfg,
port: 18789,
}),
).rejects.toThrow("gateway.bind=custom requires gateway.customBindHost");
});
it("should reject custom bind with invalid customBindHost", async () => {
const cfg = {
gateway: {
bind: "custom" as const,
customBindHost: "192.168.001.100",
auth: {
mode: "token" as const,
token: "test-token-123",
},
},
};
await expect(
resolveGatewayRuntimeConfig({
cfg,
port: 18789,
}),
).rejects.toThrow("gateway.bind=custom requires a valid IPv4 customBindHost");
});
it("should reject custom bind if resolved host differs from configured host", async () => {
const cfg = {
gateway: {
bind: "custom" as const,
customBindHost: "192.168.1.100",
auth: {
mode: "token" as const,
token: "test-token-123",
},
},
};
await expect(
resolveGatewayRuntimeConfig({
cfg,
port: 18789,
host: "0.0.0.0",
}),
).rejects.toThrow("gateway bind=custom requested 192.168.1.100 but resolved 0.0.0.0");
});
});
});