You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2026/06/01 22:26:18 UTC

(superset) 01/01: fix(embedded-sdk): validate embedded dashboard id format before use

This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch fix/embedded-sdk-id-format-validation
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 4f2fe420444220b0dd316aee91d652e144786f31
Author: Claude Code <no...@anthropic.com>
AuthorDate: Mon Jun 1 15:25:54 2026 -0700

    fix(embedded-sdk): validate embedded dashboard id format before use
    
    Add defense-in-depth format validation for the embedded dashboard id
    before it is interpolated into the iframe URL. The id is a
    Superset-generated UUID (hexadecimal characters and hyphens), so a new
    exported `validateEmbeddedDashboardId` helper rejects any value that does
    not match that format.
    
    This is a minor behavior change: a malformed id now throws instead of
    being used as-is. A unit test file covers the helper, and a jest config
    is added so the switchboard ES module is transformed during testing.
    
    Co-Authored-By: Claude Opus 4.8 <no...@anthropic.com>
---
 superset-embedded-sdk/jest.config.js    | 24 +++++++++++++++++
 superset-embedded-sdk/src/index.test.ts | 46 +++++++++++++++++++++++++++++++++
 superset-embedded-sdk/src/index.ts      | 17 +++++++++++-
 3 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/superset-embedded-sdk/jest.config.js b/superset-embedded-sdk/jest.config.js
new file mode 100644
index 00000000000..a49b796ab5b
--- /dev/null
+++ b/superset-embedded-sdk/jest.config.js
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+module.exports = {
+  // @superset-ui/switchboard ships ES module syntax, so it must be
+  // transformed by babel rather than ignored as a node_modules dependency.
+  transformIgnorePatterns: ["/node_modules/(?!@superset-ui/switchboard)"],
+};
diff --git a/superset-embedded-sdk/src/index.test.ts b/superset-embedded-sdk/src/index.test.ts
new file mode 100644
index 00000000000..77aee04715c
--- /dev/null
+++ b/superset-embedded-sdk/src/index.test.ts
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { validateEmbeddedDashboardId } from "./index";
+
+describe("validateEmbeddedDashboardId", () => {
+  it("accepts a canonical uuid", () => {
+    expect(() =>
+      validateEmbeddedDashboardId("f4787a4f-2541-4f8a-9b5e-1e2d3c4b5a6f")
+    ).not.toThrow();
+  });
+
+  it("accepts a simple hexadecimal id", () => {
+    expect(() => validateEmbeddedDashboardId("abc123")).not.toThrow();
+  });
+
+  it.each([
+    ["../../evil"],
+    ["a/b"],
+    ["x?foo=bar"],
+    ["x#frag"],
+    ["a@b.com"],
+    ["foo bar"],
+    ["http://evil.com"],
+    [""],
+    ["%2e%2e"],
+  ])("rejects an id with an unexpected format: %p", (id) => {
+    expect(() => validateEmbeddedDashboardId(id)).toThrow();
+  });
+});
diff --git a/superset-embedded-sdk/src/index.ts b/superset-embedded-sdk/src/index.ts
index 2eb9f37181a..01fd9be930c 100644
--- a/superset-embedded-sdk/src/index.ts
+++ b/superset-embedded-sdk/src/index.ts
@@ -50,7 +50,9 @@ export type UiConfigType = {
 };
 
 export type EmbedDashboardParams = {
-  /** The id provided by the embed configuration UI in Superset */
+  /** The id provided by the embed configuration UI in Superset.
+   * This is the UUID generated by Superset's embed configuration and is
+   * expected to contain only hexadecimal characters and hyphens. */
   id: string;
   /** The domain where Superset can be located, with protocol, such as: https://superset.example.com */
   supersetDomain: string;
@@ -112,6 +114,17 @@ export type EmbeddedDashboard = {
   setThemeMode: (mode: ThemeMode) => void;
 };
 
+/**
+ * Validates that an embedded dashboard id has the expected format
+ * (the UUID produced by Superset's embed configuration). Throws on
+ * anything containing characters that are not part of that format.
+ */
+export function validateEmbeddedDashboardId(id: string): void {
+  if (typeof id !== 'string' || !/^[a-f0-9-]+$/i.test(id)) {
+    throw new Error('Invalid dashboard id format');
+  }
+}
+
 /**
  * Embeds a Superset dashboard into the page using an iframe.
  */
@@ -128,6 +141,8 @@ export async function embedDashboard({
   referrerPolicy,
   resolvePermalinkUrl,
 }: EmbedDashboardParams): Promise<EmbeddedDashboard> {
+  validateEmbeddedDashboardId(id);
+
   function log(...info: unknown[]) {
     if (debug) {
       console.debug(`[superset-embedded-sdk][dashboard ${id}]`, ...info);