CVE-2023-26140 (Other, published 2023-08-16T05:15Z)
Description: value: Versions of the package @excalidraw/excalidraw from 0.0.0 are vulnerable to Cross-site Scripting (XSS) via embedded links in whiteboard objects due to improper input sanitization.
Severity: nan (CVSS v3 base score: 6.1)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Repository: https://github.com/excalidraw/excalidraw
Files changed:
package.json
src/components/App.tsx
src/data/restore.ts
src/data/url.test.tsx
src/data/url.ts
src/element/Hyperlink.tsx
src/packages/excalidraw/CHANGELOG.md
src/packages/excalidraw/index.tsx
src/renderer/renderElement.ts
yarn.lock
Commit message: fix: stronger enforcement of normalizeLink (#6728)

Co-authored-by: dwelle <luzar.david@gmail.com>


Vulnerable code:
  normalizeLink,
  isLocalLink,
      const url = this.hitLinkElement.link;
          this.props.onLinkOpen(this.hitLinkElement, customEvent);
            newWindow.location = normalizeLink(url);
    link: element.link ?? null,
          href={element.link || ""}
              onLinkOpen(element, customEvent);
export const normalizeLink = (link: string) => {
  link = link.trim();
  if (link) {
    // prefix with protocol if not fully-qualified
    if (!link.includes("://") && !/^[[\\/]/.test(link)) {
      link = `https://${link}`;
    }
  }
  return link;
};

export const isLocalLink = (link: string | null) => {
  return !!(link?.includes(location.origin) || link?.startsWith("/"));
};

    anchorTag.setAttribute("href", element.link);

Fixed code:
    "@braintree/sanitize-url": "6.0.2",
import { isLocalLink, normalizeLink } from "../data/url";
      let url = this.hitLinkElement.link;
        url = normalizeLink(url);
          this.props.onLinkOpen(
            {
              ...this.hitLinkElement,
              link: url,
            },
            customEvent,
          );
            newWindow.location = url;
import { normalizeLink } from "./url";
    link: element.link ? normalizeLink(element.link) : null,
import { normalizeLink } from "./url";

describe("normalizeLink", () => {
  // NOTE not an extensive XSS test suite, just to check if we're not
  // regressing in sanitization
  it("should sanitize links", () => {
    expect(
      // eslint-disable-next-line no-script-url
      normalizeLink(`javascript://%0aalert(document.domain)`).startsWith(
        // eslint-disable-next-line no-script-url
        `javascript:`,
      ),
    ).toBe(false);
    expect(normalizeLink("ola")).toBe("ola");
    expect(normalizeLink(" ola")).toBe("ola");

    expect(normalizeLink("https://www.excalidraw.com")).toBe(
      "https://www.excalidraw.com",
    );
    expect(normalizeLink("www.excalidraw.com")).toBe("www.excalidraw.com");
    expect(normalizeLink("/ola")).toBe("/ola");
    expect(normalizeLink("http://test")).toBe("http://test");
    expect(normalizeLink("ftp://test")).toBe("ftp://test");
    expect(normalizeLink("file://")).toBe("file://");
    expect(normalizeLink("file://")).toBe("file://");
    expect(normalizeLink("[test](https://test)")).toBe("[test](https://test)");
    expect(normalizeLink("[[test]]")).toBe("[[test]]");
    expect(normalizeLink("<test>")).toBe("<test>");
  });
});
import { sanitizeUrl } from "@braintree/sanitize-url";

export const normalizeLink = (link: string) => {
  return sanitizeUrl(link);
};

export const isLocalLink = (link: string | null) => {
  return !!(link?.includes(location.origin) || link?.startsWith("/"));
};
import { isLocalLink, normalizeLink } from "../data/url";
          href={normalizeLink(element.link || "")}
              onLinkOpen(
                {
                  ...element,
                  link: normalizeLink(element.link),
                },
                customEvent,
              );
- Properly sanitize element `link` urls. [#6728](https://github.com/excalidraw/excalidraw/pull/6728).

export { normalizeLink } from "../../data/url";
import { normalizeLink } from "../data/url";
    anchorTag.setAttribute("href", normalizeLink(element.link));
"@braintree/sanitize-url@6.0.2":
  version "6.0.2"
  resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz#6110f918d273fe2af8ea1c4398a88774bb9fc12f"
  integrity sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg==