VYPR
High severity8.3NVD Advisory· Published Mar 31, 2026· Updated Apr 2, 2026

CVE-2026-34504

CVE-2026-34504

Description

OpenClaw before 2026.3.28 contains a server-side request forgery vulnerability in the fal provider image-generation-provider.ts component that allows attackers to fetch internal URLs. A malicious or compromised fal relay can exploit unguarded image download fetches to expose internal service metadata and responses through the image pipeline.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
openclawnpm
< 2026.3.282026.3.28

Affected products

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

Patches

1
80d1e8a11a2a

fal: guard image fetches (#55948)

https://github.com/openclaw/openclawJacob TomlinsonMar 27, 2026via ghsa
2 files changed · +386 117
  • extensions/fal/image-generation-provider.test.ts+225 70 modified
    @@ -1,34 +1,43 @@
     import * as providerAuth from "openclaw/plugin-sdk/provider-auth";
    -import { afterEach, describe, expect, it, vi } from "vitest";
    -import { buildFalImageGenerationProvider } from "./image-generation-provider.js";
    +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
     
    -function expectFalJsonPost(
    -  fetchMock: ReturnType<typeof vi.fn>,
    -  params: {
    -    call: number;
    -    url: string;
    -    body: Record<string, unknown>;
    -  },
    -) {
    -  expect(fetchMock).toHaveBeenNthCalledWith(
    +const { fetchWithSsrFGuardMock } = vi.hoisted(() => ({
    +  fetchWithSsrFGuardMock: vi.fn(),
    +}));
    +
    +import {
    +  _setFalFetchGuardForTesting,
    +  buildFalImageGenerationProvider,
    +} from "./image-generation-provider.js";
    +
    +function expectFalJsonPost(params: { call: number; url: string; body: Record<string, unknown> }) {
    +  expect(fetchWithSsrFGuardMock).toHaveBeenNthCalledWith(
         params.call,
    -    params.url,
         expect.objectContaining({
    -      method: "POST",
    -      headers: expect.objectContaining({
    -        Authorization: "Key fal-test-key",
    -        "Content-Type": "application/json",
    +      url: params.url,
    +      init: expect.objectContaining({
    +        method: "POST",
    +        headers: expect.objectContaining({
    +          Authorization: "Key fal-test-key",
    +          "Content-Type": "application/json",
    +        }),
           }),
    +      auditContext: "fal-image-generate",
         }),
       );
     
    -  const request = fetchMock.mock.calls[params.call - 1]?.[1];
    +  const request = fetchWithSsrFGuardMock.mock.calls[params.call - 1]?.[0];
       expect(request).toBeTruthy();
    -  expect(JSON.parse(String(request?.body))).toEqual(params.body);
    +  expect(JSON.parse(String(request?.init?.body))).toEqual(params.body);
     }
     
     describe("fal image-generation provider", () => {
    +  beforeEach(() => {
    +    vi.clearAllMocks();
    +  });
    +
       afterEach(() => {
    +    _setFalFetchGuardForTesting(null);
         vi.restoreAllMocks();
       });
     
    @@ -38,26 +47,35 @@ describe("fal image-generation provider", () => {
           source: "env",
           mode: "api-key",
         });
    -    const fetchMock = vi
    -      .fn()
    +    _setFalFetchGuardForTesting(fetchWithSsrFGuardMock);
    +    const releaseRequest = vi.fn(async () => {});
    +    const releaseDownload = vi.fn(async () => {});
    +    fetchWithSsrFGuardMock
           .mockResolvedValueOnce({
    -        ok: true,
    -        json: async () => ({
    -          images: [
    -            {
    -              url: "https://v3.fal.media/files/example/generated.png",
    -              content_type: "image/png",
    -            },
    -          ],
    -          prompt: "draw a cat",
    -        }),
    +        response: new Response(
    +          JSON.stringify({
    +            images: [
    +              {
    +                url: "https://v3.fal.media/files/example/generated.png",
    +                content_type: "image/png",
    +              },
    +            ],
    +            prompt: "draw a cat",
    +          }),
    +          {
    +            status: 200,
    +            headers: { "Content-Type": "application/json" },
    +          },
    +        ),
    +        release: releaseRequest,
           })
           .mockResolvedValueOnce({
    -        ok: true,
    -        headers: new Headers({ "content-type": "image/png" }),
    -        arrayBuffer: async () => Buffer.from("png-data"),
    +        response: new Response(Buffer.from("png-data"), {
    +          status: 200,
    +          headers: { "content-type": "image/png" },
    +        }),
    +        release: releaseDownload,
           });
    -    vi.stubGlobal("fetch", fetchMock);
     
         const provider = buildFalImageGenerationProvider();
         const result = await provider.generateImage({
    @@ -69,7 +87,7 @@ describe("fal image-generation provider", () => {
           size: "1536x1024",
         });
     
    -    expectFalJsonPost(fetchMock, {
    +    expectFalJsonPost({
           call: 1,
           url: "https://fal.run/fal-ai/flux/dev",
           body: {
    @@ -79,10 +97,16 @@ describe("fal image-generation provider", () => {
             output_format: "png",
           },
         });
    -    expect(fetchMock).toHaveBeenNthCalledWith(
    +    expect(fetchWithSsrFGuardMock).toHaveBeenNthCalledWith(
           2,
    -      "https://v3.fal.media/files/example/generated.png",
    +      expect.objectContaining({
    +        url: "https://v3.fal.media/files/example/generated.png",
    +        auditContext: "fal-image-download",
    +        policy: undefined,
    +      }),
         );
    +    expect(releaseRequest).toHaveBeenCalledTimes(1);
    +    expect(releaseDownload).toHaveBeenCalledTimes(1);
         expect(result).toEqual({
           images: [
             {
    @@ -102,20 +126,27 @@ describe("fal image-generation provider", () => {
           source: "env",
           mode: "api-key",
         });
    -    const fetchMock = vi
    -      .fn()
    +    _setFalFetchGuardForTesting(fetchWithSsrFGuardMock);
    +    fetchWithSsrFGuardMock
           .mockResolvedValueOnce({
    -        ok: true,
    -        json: async () => ({
    -          images: [{ url: "https://v3.fal.media/files/example/edited.png" }],
    -        }),
    +        response: new Response(
    +          JSON.stringify({
    +            images: [{ url: "https://v3.fal.media/files/example/edited.png" }],
    +          }),
    +          {
    +            status: 200,
    +            headers: { "Content-Type": "application/json" },
    +          },
    +        ),
    +        release: vi.fn(async () => {}),
           })
           .mockResolvedValueOnce({
    -        ok: true,
    -        headers: new Headers({ "content-type": "image/png" }),
    -        arrayBuffer: async () => Buffer.from("edited-data"),
    +        response: new Response(Buffer.from("edited-data"), {
    +          status: 200,
    +          headers: { "content-type": "image/png" },
    +        }),
    +        release: vi.fn(async () => {}),
           });
    -    vi.stubGlobal("fetch", fetchMock);
     
         const provider = buildFalImageGenerationProvider();
         await provider.generateImage({
    @@ -133,7 +164,7 @@ describe("fal image-generation provider", () => {
           ],
         });
     
    -    expectFalJsonPost(fetchMock, {
    +    expectFalJsonPost({
           call: 1,
           url: "https://fal.run/fal-ai/flux/dev/image-to-image",
           body: {
    @@ -152,20 +183,27 @@ describe("fal image-generation provider", () => {
           source: "env",
           mode: "api-key",
         });
    -    const fetchMock = vi
    -      .fn()
    +    _setFalFetchGuardForTesting(fetchWithSsrFGuardMock);
    +    fetchWithSsrFGuardMock
           .mockResolvedValueOnce({
    -        ok: true,
    -        json: async () => ({
    -          images: [{ url: "https://v3.fal.media/files/example/wide.png" }],
    -        }),
    +        response: new Response(
    +          JSON.stringify({
    +            images: [{ url: "https://v3.fal.media/files/example/wide.png" }],
    +          }),
    +          {
    +            status: 200,
    +            headers: { "Content-Type": "application/json" },
    +          },
    +        ),
    +        release: vi.fn(async () => {}),
           })
           .mockResolvedValueOnce({
    -        ok: true,
    -        headers: new Headers({ "content-type": "image/png" }),
    -        arrayBuffer: async () => Buffer.from("wide-data"),
    +        response: new Response(Buffer.from("wide-data"), {
    +          status: 200,
    +          headers: { "content-type": "image/png" },
    +        }),
    +        release: vi.fn(async () => {}),
           });
    -    vi.stubGlobal("fetch", fetchMock);
     
         const provider = buildFalImageGenerationProvider();
         await provider.generateImage({
    @@ -176,7 +214,7 @@ describe("fal image-generation provider", () => {
           aspectRatio: "16:9",
         });
     
    -    expectFalJsonPost(fetchMock, {
    +    expectFalJsonPost({
           call: 1,
           url: "https://fal.run/fal-ai/flux/dev",
           body: {
    @@ -194,20 +232,27 @@ describe("fal image-generation provider", () => {
           source: "env",
           mode: "api-key",
         });
    -    const fetchMock = vi
    -      .fn()
    +    _setFalFetchGuardForTesting(fetchWithSsrFGuardMock);
    +    fetchWithSsrFGuardMock
           .mockResolvedValueOnce({
    -        ok: true,
    -        json: async () => ({
    -          images: [{ url: "https://v3.fal.media/files/example/portrait.png" }],
    -        }),
    +        response: new Response(
    +          JSON.stringify({
    +            images: [{ url: "https://v3.fal.media/files/example/portrait.png" }],
    +          }),
    +          {
    +            status: 200,
    +            headers: { "Content-Type": "application/json" },
    +          },
    +        ),
    +        release: vi.fn(async () => {}),
           })
           .mockResolvedValueOnce({
    -        ok: true,
    -        headers: new Headers({ "content-type": "image/png" }),
    -        arrayBuffer: async () => Buffer.from("portrait-data"),
    +        response: new Response(Buffer.from("portrait-data"), {
    +          status: 200,
    +          headers: { "content-type": "image/png" },
    +        }),
    +        release: vi.fn(async () => {}),
           });
    -    vi.stubGlobal("fetch", fetchMock);
     
         const provider = buildFalImageGenerationProvider();
         await provider.generateImage({
    @@ -219,7 +264,7 @@ describe("fal image-generation provider", () => {
           aspectRatio: "9:16",
         });
     
    -    expectFalJsonPost(fetchMock, {
    +    expectFalJsonPost({
           call: 1,
           url: "https://fal.run/fal-ai/flux/dev",
           body: {
    @@ -272,4 +317,114 @@ describe("fal image-generation provider", () => {
           }),
         ).rejects.toThrow("does not support aspectRatio overrides");
       });
    +
    +  it("blocks private-network image download URLs through the SSRF guard", async () => {
    +    vi.spyOn(providerAuth, "resolveApiKeyForProvider").mockResolvedValue({
    +      apiKey: "fal-test-key",
    +      source: "env",
    +      mode: "api-key",
    +    });
    +    _setFalFetchGuardForTesting(fetchWithSsrFGuardMock);
    +    const blocked = new Error("Blocked: resolves to private/internal/special-use IP address");
    +    fetchWithSsrFGuardMock
    +      .mockResolvedValueOnce({
    +        response: new Response(
    +          JSON.stringify({
    +            images: [{ url: "http://169.254.169.254/latest/meta-data/iam/security-credentials/" }],
    +          }),
    +          {
    +            status: 200,
    +            headers: { "Content-Type": "application/json" },
    +          },
    +        ),
    +        release: vi.fn(async () => {}),
    +      })
    +      .mockRejectedValueOnce(blocked);
    +
    +    const provider = buildFalImageGenerationProvider();
    +    await expect(
    +      provider.generateImage({
    +        provider: "fal",
    +        model: "fal-ai/flux/dev",
    +        prompt: "draw a cat",
    +        cfg: {},
    +      }),
    +    ).rejects.toThrow(blocked.message);
    +
    +    expect(fetchWithSsrFGuardMock).toHaveBeenNthCalledWith(
    +      2,
    +      expect.objectContaining({
    +        url: "http://169.254.169.254/latest/meta-data/iam/security-credentials/",
    +        auditContext: "fal-image-download",
    +        policy: undefined,
    +      }),
    +    );
    +  });
    +
    +  it("allows trusted private relay hosts derived from configured baseUrl", async () => {
    +    vi.spyOn(providerAuth, "resolveApiKeyForProvider").mockResolvedValue({
    +      apiKey: "fal-test-key",
    +      source: "env",
    +      mode: "api-key",
    +    });
    +    _setFalFetchGuardForTesting(fetchWithSsrFGuardMock);
    +    const relayPolicy = {
    +      allowPrivateNetwork: true,
    +      hostnameAllowlist: ["relay.internal", "*.relay.internal"],
    +    };
    +    fetchWithSsrFGuardMock
    +      .mockResolvedValueOnce({
    +        response: new Response(
    +          JSON.stringify({
    +            images: [{ url: "http://media.relay.internal/files/generated.png" }],
    +          }),
    +          {
    +            status: 200,
    +            headers: { "Content-Type": "application/json" },
    +          },
    +        ),
    +        release: vi.fn(async () => {}),
    +      })
    +      .mockResolvedValueOnce({
    +        response: new Response(Buffer.from("png-data"), {
    +          status: 200,
    +          headers: { "content-type": "image/png" },
    +        }),
    +        release: vi.fn(async () => {}),
    +      });
    +
    +    const provider = buildFalImageGenerationProvider();
    +    await provider.generateImage({
    +      provider: "fal",
    +      model: "fal-ai/flux/dev",
    +      prompt: "draw a cat",
    +      cfg: {
    +        models: {
    +          providers: {
    +            fal: {
    +              baseUrl: "http://relay.internal:8080",
    +              models: [],
    +            },
    +          },
    +        },
    +      },
    +    });
    +
    +    expect(fetchWithSsrFGuardMock).toHaveBeenNthCalledWith(
    +      1,
    +      expect.objectContaining({
    +        url: "http://relay.internal:8080/fal-ai/flux/dev",
    +        auditContext: "fal-image-generate",
    +        policy: relayPolicy,
    +      }),
    +    );
    +    expect(fetchWithSsrFGuardMock).toHaveBeenNthCalledWith(
    +      2,
    +      expect.objectContaining({
    +        url: "http://media.relay.internal/files/generated.png",
    +        auditContext: "fal-image-download",
    +        policy: relayPolicy,
    +      }),
    +    );
    +  });
     });
    
  • extensions/fal/image-generation-provider.ts+161 47 modified
    @@ -2,6 +2,12 @@ import type {
       GeneratedImageAsset,
       ImageGenerationProvider,
     } from "openclaw/plugin-sdk/image-generation";
    +import {
    +  buildHostnameAllowlistPolicyFromSuffixAllowlist,
    +  fetchWithSsrFGuard,
    +  type SsrFPolicy,
    +  ssrfPolicyFromAllowPrivateNetwork,
    +} from "openclaw/plugin-sdk/infra-runtime";
     import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/provider-auth";
     
     const DEFAULT_FAL_BASE_URL = "https://fal.run";
    @@ -28,6 +34,81 @@ type FalImageGenerationResponse = {
     };
     
     type FalImageSize = string | { width: number; height: number };
    +type FalNetworkPolicy = {
    +  apiPolicy?: SsrFPolicy;
    +  trustedDownloadHostSuffix?: string;
    +  trustedDownloadPolicy?: SsrFPolicy;
    +};
    +
    +let falFetchGuard = fetchWithSsrFGuard;
    +
    +export function _setFalFetchGuardForTesting(impl: typeof fetchWithSsrFGuard | null): void {
    +  falFetchGuard = impl ?? fetchWithSsrFGuard;
    +}
    +
    +function mergeSsrFPolicies(...policies: Array<SsrFPolicy | undefined>): SsrFPolicy | undefined {
    +  const merged: SsrFPolicy = {};
    +  for (const policy of policies) {
    +    if (!policy) {
    +      continue;
    +    }
    +    if (policy.allowPrivateNetwork) {
    +      merged.allowPrivateNetwork = true;
    +    }
    +    if (policy.dangerouslyAllowPrivateNetwork) {
    +      merged.dangerouslyAllowPrivateNetwork = true;
    +    }
    +    if (policy.allowRfc2544BenchmarkRange) {
    +      merged.allowRfc2544BenchmarkRange = true;
    +    }
    +    if (policy.allowedHostnames?.length) {
    +      merged.allowedHostnames = Array.from(
    +        new Set([...(merged.allowedHostnames ?? []), ...policy.allowedHostnames]),
    +      );
    +    }
    +    if (policy.hostnameAllowlist?.length) {
    +      merged.hostnameAllowlist = Array.from(
    +        new Set([...(merged.hostnameAllowlist ?? []), ...policy.hostnameAllowlist]),
    +      );
    +    }
    +  }
    +  return Object.keys(merged).length > 0 ? merged : undefined;
    +}
    +
    +function matchesTrustedHostSuffix(hostname: string, trustedSuffix: string): boolean {
    +  const normalizedHost = hostname.trim().toLowerCase();
    +  const normalizedSuffix = trustedSuffix.trim().toLowerCase();
    +  return normalizedHost === normalizedSuffix || normalizedHost.endsWith(`.${normalizedSuffix}`);
    +}
    +
    +function resolveFalNetworkPolicy(
    +  cfg: Parameters<typeof resolveApiKeyForProvider>[0]["cfg"],
    +): FalNetworkPolicy {
    +  const baseUrl = resolveFalBaseUrl(cfg);
    +  const explicitBaseUrl = cfg?.models?.providers?.fal?.baseUrl?.trim();
    +  let parsedBaseUrl: URL;
    +  try {
    +    parsedBaseUrl = new URL(baseUrl);
    +  } catch {
    +    return {};
    +  }
    +
    +  const hostSuffix = parsedBaseUrl.hostname.trim().toLowerCase();
    +  if (!hostSuffix) {
    +    return {};
    +  }
    +
    +  const hostPolicy = buildHostnameAllowlistPolicyFromSuffixAllowlist([hostSuffix]);
    +  const privateNetworkPolicy = explicitBaseUrl
    +    ? ssrfPolicyFromAllowPrivateNetwork(true)
    +    : undefined;
    +  const trustedHostPolicy = mergeSsrFPolicies(hostPolicy, privateNetworkPolicy);
    +  return {
    +    apiPolicy: trustedHostPolicy,
    +    trustedDownloadHostSuffix: explicitBaseUrl ? hostSuffix : undefined,
    +    trustedDownloadPolicy: explicitBaseUrl ? trustedHostPolicy : undefined,
    +  };
    +}
     
     function resolveFalBaseUrl(cfg: Parameters<typeof resolveApiKeyForProvider>[0]["cfg"]): string {
       const direct = cfg?.models?.providers?.fal?.baseUrl?.trim();
    @@ -174,17 +255,41 @@ function fileExtensionForMimeType(mimeType: string | undefined): string {
       return slashIndex >= 0 ? normalized.slice(slashIndex + 1) || "png" : "png";
     }
     
    -async function fetchImageBuffer(url: string): Promise<{ buffer: Buffer; mimeType: string }> {
    -  const response = await fetch(url);
    -  if (!response.ok) {
    -    const text = await response.text().catch(() => "");
    -    throw new Error(
    -      `fal image download failed (${response.status}): ${text || response.statusText}`,
    -    );
    +async function fetchImageBuffer(
    +  url: string,
    +  networkPolicy?: FalNetworkPolicy,
    +): Promise<{ buffer: Buffer; mimeType: string }> {
    +  const downloadPolicy = (() => {
    +    const trustedSuffix = networkPolicy?.trustedDownloadHostSuffix;
    +    const trustedPolicy = networkPolicy?.trustedDownloadPolicy;
    +    if (!trustedSuffix || !trustedPolicy) {
    +      return undefined;
    +    }
    +    try {
    +      const parsed = new URL(url);
    +      return matchesTrustedHostSuffix(parsed.hostname, trustedSuffix) ? trustedPolicy : undefined;
    +    } catch {
    +      return undefined;
    +    }
    +  })();
    +  const { response, release } = await falFetchGuard({
    +    url,
    +    policy: downloadPolicy,
    +    auditContext: "fal-image-download",
    +  });
    +  try {
    +    if (!response.ok) {
    +      const text = await response.text().catch(() => "");
    +      throw new Error(
    +        `fal image download failed (${response.status}): ${text || response.statusText}`,
    +      );
    +    }
    +    const mimeType = response.headers.get("content-type")?.trim() || "image/png";
    +    const arrayBuffer = await response.arrayBuffer();
    +    return { buffer: Buffer.from(arrayBuffer), mimeType };
    +  } finally {
    +    await release();
       }
    -  const mimeType = response.headers.get("content-type")?.trim() || "image/png";
    -  const arrayBuffer = await response.arrayBuffer();
    -  return { buffer: Buffer.from(arrayBuffer), mimeType };
     }
     
     export function buildFalImageGenerationProvider(): ImageGenerationProvider {
    @@ -236,6 +341,7 @@ export function buildFalImageGenerationProvider(): ImageGenerationProvider {
             hasInputImages,
           });
           const model = ensureFalModelPath(req.model, hasInputImages);
    +      const networkPolicy = resolveFalNetworkPolicy(req.cfg);
           const requestBody: Record<string, unknown> = {
             prompt: req.prompt,
             num_images: req.count ?? 1,
    @@ -253,50 +359,58 @@ export function buildFalImageGenerationProvider(): ImageGenerationProvider {
             requestBody.image_url = toDataUri(input.buffer, input.mimeType);
           }
     
    -      const response = await fetch(`${resolveFalBaseUrl(req.cfg)}/${model}`, {
    -        method: "POST",
    -        headers: {
    -          Authorization: `Key ${auth.apiKey}`,
    -          "Content-Type": "application/json",
    +      const { response, release } = await falFetchGuard({
    +        url: `${resolveFalBaseUrl(req.cfg)}/${model}`,
    +        init: {
    +          method: "POST",
    +          headers: {
    +            Authorization: `Key ${auth.apiKey}`,
    +            "Content-Type": "application/json",
    +          },
    +          body: JSON.stringify(requestBody),
             },
    -        body: JSON.stringify(requestBody),
    +        policy: networkPolicy.apiPolicy,
    +        auditContext: "fal-image-generate",
           });
    +      try {
    +        if (!response.ok) {
    +          const text = await response.text().catch(() => "");
    +          throw new Error(
    +            `fal image generation failed (${response.status}): ${text || response.statusText}`,
    +          );
    +        }
     
    -      if (!response.ok) {
    -        const text = await response.text().catch(() => "");
    -        throw new Error(
    -          `fal image generation failed (${response.status}): ${text || response.statusText}`,
    -        );
    -      }
    +        const payload = (await response.json()) as FalImageGenerationResponse;
    +        const images: GeneratedImageAsset[] = [];
    +        let imageIndex = 0;
    +        for (const entry of payload.images ?? []) {
    +          const url = entry.url?.trim();
    +          if (!url) {
    +            continue;
    +          }
    +          const downloaded = await fetchImageBuffer(url, networkPolicy);
    +          imageIndex += 1;
    +          images.push({
    +            buffer: downloaded.buffer,
    +            mimeType: downloaded.mimeType,
    +            fileName: `image-${imageIndex}.${fileExtensionForMimeType(
    +              downloaded.mimeType || entry.content_type,
    +            )}`,
    +          });
    +        }
     
    -      const payload = (await response.json()) as FalImageGenerationResponse;
    -      const images: GeneratedImageAsset[] = [];
    -      let imageIndex = 0;
    -      for (const entry of payload.images ?? []) {
    -        const url = entry.url?.trim();
    -        if (!url) {
    -          continue;
    +        if (images.length === 0) {
    +          throw new Error("fal image generation response missing image data");
             }
    -        const downloaded = await fetchImageBuffer(url);
    -        imageIndex += 1;
    -        images.push({
    -          buffer: downloaded.buffer,
    -          mimeType: downloaded.mimeType,
    -          fileName: `image-${imageIndex}.${fileExtensionForMimeType(
    -            downloaded.mimeType || entry.content_type,
    -          )}`,
    -        });
    -      }
     
    -      if (images.length === 0) {
    -        throw new Error("fal image generation response missing image data");
    +        return {
    +          images,
    +          model,
    +          metadata: payload.prompt ? { prompt: payload.prompt } : undefined,
    +        };
    +      } finally {
    +        await release();
           }
    -
    -      return {
    -        images,
    -        model,
    -        metadata: payload.prompt ? { prompt: payload.prompt } : undefined,
    -      };
         },
       };
     }
    

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.