VYPR
Medium severity5.3NVD Advisory· Published Apr 23, 2026· Updated Apr 28, 2026

CVE-2026-41337

CVE-2026-41337

Description

OpenClaw before 2026.3.31 contains a callback origin mutation vulnerability in Plivo voice-call replay that allows attackers to mutate in-process callback origin before replay rejection. Attackers with captured valid callbacks for live calls can exploit this to manipulate callback origins during the replay process.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
openclawnpm
< 2026.3.312026.3.31

Affected products

1
  • cpe:2.3:a:openclaw:openclaw:*:*:*:*:*:node.js:*:*
    Range: <2026.3.31

Patches

1
efe9183f9d2f

fix(voice-call): pin plivo callback origins (#58238)

https://github.com/openclaw/openclawVincent KocMar 31, 2026via ghsa
3 files changed · +34 0
  • CHANGELOG.md+1 0 modified
    @@ -78,6 +78,7 @@ Docs: https://docs.openclaw.ai
     - Memory/QMD: keep `memory_search` session-hit paths roundtrip-safe when exported session markdown lives under the workspace `qmd/` directory, so `memory_get` can read the exact returned path instead of failing on the generic `qmd/sessions/...` alias. (#43519) Thanks @holgergruenhagen and @vincentkoc.
     - Memory/QMD: treat null-byte collection corruption the same when QMD surfaces it as `ENOENT`, so managed-collection repair still rebuilds and retries instead of leaving QMD stuck on a broken path. Thanks @vincentkoc.
     - Memory/QMD: stop rewriting Han/CJK BM25 queries before `qmd search`, so OpenClaw search semantics match direct QMD results for mixed and spaced Chinese queries. Thanks @vincentkoc.
    +- Voice call/Plivo: pin stored callback bases to the configured public webhook URL so later call-control redirects stay on the intended origin even if webhook transport metadata differs. Thanks @zsxsoft and @vincentkoc.
     - Agents/memory flush: keep daily memory flush files append-only during embedded attempts so compaction writes do not overwrite earlier notes. (#53725) Thanks @HPluseven.
     - Web UI/markdown: stop bare auto-links from swallowing adjacent CJK text while preserving valid mixed-script path and query characters in rendered links. (#48410) Thanks @jnuyao.
     - BlueBubbles/iMessage: coalesce URL-only inbound messages with their link-preview balloon again so sharing a bare link no longer drops the URL from agent context. Thanks @vincentkoc.
    
  • extensions/voice-call/src/providers/plivo.test.ts+26 0 modified
    @@ -64,4 +64,30 @@ describe("PlivoProvider", () => {
           "plivo:v3:verified",
         );
       });
    +
    +  it("pins stored callback bases to publicUrl instead of request Host", () => {
    +    const provider = new PlivoProvider(
    +      {
    +        authId: "MA000000000000000000",
    +        authToken: "test-token",
    +      },
    +      {
    +        publicUrl: "https://voice.openclaw.ai/voice/webhook?provider=plivo",
    +      },
    +    );
    +
    +    provider.parseWebhookEvent({
    +      headers: { host: "attacker.example" },
    +      rawBody:
    +        "CallUUID=call-uuid&CallStatus=in-progress&Direction=outbound&From=%2B15550000000&To=%2B15550000001&Event=StartApp",
    +      url: "https://attacker.example/voice/webhook?provider=plivo&flow=answer&callId=internal-call-id",
    +      method: "POST",
    +      query: { provider: "plivo", flow: "answer", callId: "internal-call-id" },
    +    });
    +
    +    const callbackMap = (provider as unknown as { callUuidToWebhookUrl: Map<string, string> })
    +      .callUuidToWebhookUrl;
    +
    +    expect(callbackMap.get("call-uuid")).toBe("https://voice.openclaw.ai/voice/webhook");
    +  });
     });
    
  • extensions/voice-call/src/providers/plivo.ts+7 0 modified
    @@ -544,6 +544,13 @@ export class PlivoProvider implements VoiceCallProvider {
     
       private baseWebhookUrlFromCtx(ctx: WebhookContext): string | null {
         try {
    +      if (this.options.publicUrl) {
    +        const base = new URL(this.options.publicUrl);
    +        const requestUrl = new URL(ctx.url);
    +        base.pathname = requestUrl.pathname;
    +        return `${base.origin}${base.pathname}`;
    +      }
    +
           const u = new URL(
             reconstructWebhookUrl(ctx, {
               allowedHosts: this.options.webhookSecurity?.allowedHosts,
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.