fix(voice-call): close webhook in-flight limiter fail-open on empty remote address (#74453)

* fix(voice-call): close in-flight limiter fail-open on empty remote address

The webhook in-flight limiter (createWebhookInFlightLimiter in
src/plugin-sdk/webhook-request-guards.ts) returns true unconditionally
when tryAcquire is called with an empty key — that is its by-contract
fail-open path used to mean 'caller is opting out of the limiter'.

The voice-call webhook handler reached that path silently: it computed
'req.socket.remoteAddress ?? ""' and passed the empty string straight
into tryAcquire. Whenever req.socket.remoteAddress was absent (closed
socket, edge proxy quirk), the limiter became a no-op and the request
proceeded directly to readBody without any concurrency cap.

Fix: when remoteAddress is missing, log a warning and fall back to a
constant non-empty key ('__voice_call_no_remote__') so all such
requests share one in-flight bucket instead of bypassing the limiter
entirely. The bucket size stays maxInFlightPerKey (default 8), which
is the right defense-in-depth posture against slow-body attacks
arriving with stripped IP info.

Scoped to voice-call only. Other consumers of the SDK helper
(bluebubbles via openclaw/plugin-sdk/webhook-ingress) are not changed
to avoid drive-by edits to plugins this PR does not own. The shared
SDK contract (empty key = bypass) is left as-is and documented
implicitly by the fix's comment block.

The existing 8-concurrent test in webhook.test.ts continues to assert
the limiter engages on the happy path; no new test added since the
private handleRequest path is not unit-test exposed and the change is
two-line auditable from the diff alone.

* test(voice-call): cover missing webhook remote address limiter

* test: align changed package sdk routing

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
Fred blum
2026-04-30 04:02:14 +03:00
committed by GitHub
parent 10a9654674
commit 9b1bde2561
4 changed files with 92 additions and 5 deletions

View File

@@ -489,8 +489,8 @@ describe("scripts/test-projects changed-target routing", () => {
expect(plans).toEqual([
{
config: "test/vitest/vitest.unit.config.ts",
forwardedArgs: [],
includePatterns: ["packages/sdk/src/**/*.test.ts"],
forwardedArgs: ["packages/sdk/src/index.test.ts"],
includePatterns: null,
watchMode: false,
},
]);