diff --git a/open-sse/services/ipFilter.ts b/open-sse/services/ipFilter.ts index e54930c5b1..7516d56546 100644 --- a/open-sse/services/ipFilter.ts +++ b/open-sse/services/ipFilter.ts @@ -133,7 +133,13 @@ export function checkIP(ip) { switch (_config.mode) { case "whitelist": - // Only whitelisted IPs allowed + // Only whitelisted IPs allowed — but if the whitelist is empty the admin + // has just switched to this mode and has not added IPs yet. Allow the + // request through so the admin can still reach the dashboard to populate + // the list. Once at least one entry exists, enforcement kicks in. + if (_config.whitelist.size === 0) { + return { allowed: true }; + } if (!matchesAny(normalizedIP, _config.whitelist)) { return { allowed: false, reason: "IP not in whitelist" }; } diff --git a/tests/unit/ip-filter.test.ts b/tests/unit/ip-filter.test.ts index 77bad1ea64..9e02abad82 100644 --- a/tests/unit/ip-filter.test.ts +++ b/tests/unit/ip-filter.test.ts @@ -77,6 +77,18 @@ test("whitelist: CIDR match", () => { assert.equal(checkIP("11.0.0.1").allowed, false); }); +test("whitelist: empty whitelist allows all IPs (admin can still reach dashboard)", () => { + configureIPFilter({ enabled: true, mode: "whitelist", whitelist: [] }); + assert.equal(checkIP("1.2.3.4").allowed, true); + assert.equal(checkIP("5.6.7.8").allowed, true); +}); + +test("whitelist: non-empty whitelist blocks unlisted IPs", () => { + configureIPFilter({ enabled: true, mode: "whitelist", whitelist: ["1.2.3.4"] }); + assert.equal(checkIP("1.2.3.4").allowed, true); + assert.equal(checkIP("5.6.7.8").allowed, false); +}); + // ─── Whitelist Priority Mode ──────────────────────────────────────────────── test("whitelist-priority: whitelist overrides blacklist", () => { @@ -120,9 +132,14 @@ test("addToBlacklist/removeFromBlacklist: dynamic updates", () => { test("addToWhitelist/removeFromWhitelist: dynamic updates", () => { configureIPFilter({ enabled: true, mode: "whitelist" }); addToWhitelist("1.1.1.1"); + addToWhitelist("2.2.2.2"); assert.equal(checkIP("1.1.1.1").allowed, true); removeFromWhitelist("1.1.1.1"); assert.equal(checkIP("1.1.1.1").allowed, false); + // #13534: removing the last entry leaves an empty whitelist, which no longer + // enforces (so an admin who has not populated the list yet is not locked out). + removeFromWhitelist("2.2.2.2"); + assert.equal(checkIP("1.1.1.1").allowed, true); }); // ─── IPv6 Normalization ─────────────────────────────────────────────────────