fix(security): drop URLhaus feed, validate CIDR ranges, pass unknown client IPs
Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 31s
CI / tests-integration (push) Successful in 1m42s
CI / tests-unit (push) Successful in 1m46s
CI / tests-ui (push) Successful in 2m35s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 1m40s
Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 31s
CI / tests-integration (push) Successful in 1m42s
CI / tests-unit (push) Successful in 1m46s
CI / tests-ui (push) Successful in 2m35s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 1m40s
This commit is contained in:
1 parent
7392b843ad
commit
7f6febf906
4 files changed
+78
-12
No files matched your search
@@ -248,6 +248,15 @@ describe("anti-DDoS automatic CrowdSec blocks", () => {
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("passes the unknown-IP sentinel through even when a stale block key exists", async () => {
|
||||
state.map.set("antiddos:block:0.0.0.0", "1");
|
||||
|
||||
const decision = await enforceDdosRateLimit(directRequest("0.0.0.0"));
|
||||
|
||||
expect(decision.outcome).toBe("pass");
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("blocks immediately on a local LAPI ban decision (app-layer bouncer)", async () => {
|
||||
vi.stubEnv("CROWDSEC_LOCAL_ENABLED", "true");
|
||||
vi.stubEnv("CROWDSEC_LAPI_URL", "http://127.0.0.1:18080");
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { NextRequest } from "next/server";
|
||||
import { NextResponse } from "next/server";
|
||||
import { env } from "@/env";
|
||||
import { getAntiddosConfig } from "@/lib/antiddos-config";
|
||||
import { resolveClientIp } from "@/lib/client-ip";
|
||||
import { resolveClientIp, UNKNOWN_CLIENT_IP } from "@/lib/client-ip";
|
||||
import { isCloudflareProxied } from "@/lib/cloudflare";
|
||||
import { maybeAutoBlockCloudflare } from "@/lib/cloudflare-api";
|
||||
import { maybeAutoBlockCrowdsec } from "@/lib/crowdsec-api";
|
||||
@@ -71,6 +71,12 @@ export async function enforceDdosRateLimit(
|
||||
}
|
||||
|
||||
const ip = resolveClientIp(req.headers);
|
||||
// A trusted ingress always resolves a real client address. `0.0.0.0` is the
|
||||
// sentinel for header-less loopback traffic (health checks, CI browser
|
||||
// gates, monitoring). If it were rate-limited or blocked it would occupy a
|
||||
// single shared key, and any burst of synthetic local traffic could then
|
||||
// shed all origin-verified requests — exactly what broke CI smoke tests.
|
||||
if (ip === UNKNOWN_CLIENT_IP) return { outcome: "pass" };
|
||||
const blockKey = `antiddos:block:${ip}`;
|
||||
if (redis) {
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user