github-advanced-security[bot] commented on code in PR #39925:
URL: https://github.com/apache/superset/pull/39925#discussion_r3203571447
##########
superset-frontend/src/utils/navigationUtils.ts:
##########
@@ -16,8 +16,140 @@
* specific language governing permissions and limitations
* under the License.
*/
+import {
+ createElement,
+ type AnchorHTMLAttributes,
+ type ReactElement,
+} from 'react';
import { ensureAppRoot } from './pathUtils';
+//
=============================================================================
+// Channel-3 helpers (browser-direct sinks)
+//
=============================================================================
+//
+// Every helper in this section takes a *router-relative* path (the same shape
+// you'd pass to `<Link to>` or `history.push`) and applies the application
+// root internally before handing the URL to the browser. This keeps the rest
+// of the codebase decision-free: callers always write `/sqllab`, never
+// `${applicationRoot()}/sqllab`.
+//
+// Once migration is complete, `ensureAppRoot` and `makeUrl` are imported only
+// from this module. A static-invariant test (see
+// `navigationUtils.invariants.test.ts`) enforces that boundary.
+//
=============================================================================
+
+/**
+ * Features passed to `window.open` for new-tab navigation. `noopener` and
+ * `noreferrer` are mandatory — without them the opened page can drive the
+ * opener via `window.opener` (reverse tabnabbing) and read the referrer.
+ */
+const NEW_TAB_FEATURES = 'noopener noreferrer';
+
+/**
+ * Schemes that are safe to feed to `window.location` / `window.open` /
+ * anchor `href`. Anything outside this allow-list (`javascript:`, `data:`,
+ * `vbscript:`, etc.) can execute script in the current origin and is
+ * rejected by {@link assertSafeNavigationUrl}.
+ *
+ * The first two alternatives match relative URLs:
+ * - `^/(?!/)` — absolute path on this origin (`/foo`), but not a
+ * protocol-relative URL (`//host`). Protocol-relative is matched by the
+ * `\/\/` alternative instead.
+ * - `\/\/` — protocol-relative (`//cdn.example.com/foo`).
+ *
+ * Kept locally in `navigationUtils.ts` rather than imported from pathUtils
+ * so the safety property is checkable from this file alone — that's what
+ * CodeQL needs to clear the dataflow alert on the sinks below.
+ */
+const SAFE_NAVIGATION_URL_RE =
+ /^(?:\/(?!\/)|\/\/|https?:|ftp:|mailto:|tel:)/i;
+
+/**
+ * Validate that `url` uses a navigation-safe shape. `ensureAppRoot` already
+ * neutralises script-bearing schemes by prefixing them as relative paths
+ * (`javascript:alert(1)` → `/javascript:alert(1)`), but this assertion gives
+ * the property a single, locally-readable enforcement point and keeps the
+ * channel-3 sinks below from being flagged as untrusted-data flows.
+ */
+function assertSafeNavigationUrl(url: string): string {
+ if (!SAFE_NAVIGATION_URL_RE.test(url)) {
+ throw new Error(
+ `navigationUtils refused unsafe URL: only relative paths and ` +
+ `http(s):, ftp:, mailto:, tel: schemes are allowed.`,
+ );
+ }
+ return url;
+}
+
+/**
+ * Open a router-relative path in a new browser tab.
+ *
+ * The path is automatically prefixed with the application root so the new tab
+ * lands inside Superset on subdirectory deployments.
+ */
+export function openInNewTab(path: string): void {
+ window.open(
+ assertSafeNavigationUrl(ensureAppRoot(path)),
+ '_blank',
+ NEW_TAB_FEATURES,
+ );
+}
+
+/**
+ * Navigate the current window to a router-relative path via `window.location`.
+ *
+ * Unlike `history.push`, this triggers a full page load. Use it only when the
+ * destination is outside the React Router tree (e.g. a backend-rendered page)
+ * or when a hard reload is required.
+ */
+export function redirect(path: string): void {
+ window.location.href = assertSafeNavigationUrl(ensureAppRoot(path));
+}
+
+/**
+ * Replace the current entry in `window.history` with a router-relative path.
+ * No new history entry is pushed. Use sparingly — most navigation should go
+ * through React Router's `history.replace`.
+ */
+export function redirectReplace(path: string): void {
+ window.location.replace(assertSafeNavigationUrl(ensureAppRoot(path)));
Review Comment:
## CodeQL / DOM text reinterpreted as HTML
[DOM text](1) is reinterpreted as HTML without escaping meta-characters.
[Show more
details](https://github.com/apache/superset/security/code-scanning/2282)
##########
superset-frontend/src/utils/navigationUtils.ts:
##########
@@ -16,8 +16,140 @@
* specific language governing permissions and limitations
* under the License.
*/
+import {
+ createElement,
+ type AnchorHTMLAttributes,
+ type ReactElement,
+} from 'react';
import { ensureAppRoot } from './pathUtils';
+//
=============================================================================
+// Channel-3 helpers (browser-direct sinks)
+//
=============================================================================
+//
+// Every helper in this section takes a *router-relative* path (the same shape
+// you'd pass to `<Link to>` or `history.push`) and applies the application
+// root internally before handing the URL to the browser. This keeps the rest
+// of the codebase decision-free: callers always write `/sqllab`, never
+// `${applicationRoot()}/sqllab`.
+//
+// Once migration is complete, `ensureAppRoot` and `makeUrl` are imported only
+// from this module. A static-invariant test (see
+// `navigationUtils.invariants.test.ts`) enforces that boundary.
+//
=============================================================================
+
+/**
+ * Features passed to `window.open` for new-tab navigation. `noopener` and
+ * `noreferrer` are mandatory — without them the opened page can drive the
+ * opener via `window.opener` (reverse tabnabbing) and read the referrer.
+ */
+const NEW_TAB_FEATURES = 'noopener noreferrer';
+
+/**
+ * Schemes that are safe to feed to `window.location` / `window.open` /
+ * anchor `href`. Anything outside this allow-list (`javascript:`, `data:`,
+ * `vbscript:`, etc.) can execute script in the current origin and is
+ * rejected by {@link assertSafeNavigationUrl}.
+ *
+ * The first two alternatives match relative URLs:
+ * - `^/(?!/)` — absolute path on this origin (`/foo`), but not a
+ * protocol-relative URL (`//host`). Protocol-relative is matched by the
+ * `\/\/` alternative instead.
+ * - `\/\/` — protocol-relative (`//cdn.example.com/foo`).
+ *
+ * Kept locally in `navigationUtils.ts` rather than imported from pathUtils
+ * so the safety property is checkable from this file alone — that's what
+ * CodeQL needs to clear the dataflow alert on the sinks below.
+ */
+const SAFE_NAVIGATION_URL_RE =
+ /^(?:\/(?!\/)|\/\/|https?:|ftp:|mailto:|tel:)/i;
+
+/**
+ * Validate that `url` uses a navigation-safe shape. `ensureAppRoot` already
+ * neutralises script-bearing schemes by prefixing them as relative paths
+ * (`javascript:alert(1)` → `/javascript:alert(1)`), but this assertion gives
+ * the property a single, locally-readable enforcement point and keeps the
+ * channel-3 sinks below from being flagged as untrusted-data flows.
+ */
+function assertSafeNavigationUrl(url: string): string {
+ if (!SAFE_NAVIGATION_URL_RE.test(url)) {
+ throw new Error(
+ `navigationUtils refused unsafe URL: only relative paths and ` +
+ `http(s):, ftp:, mailto:, tel: schemes are allowed.`,
+ );
+ }
+ return url;
+}
+
+/**
+ * Open a router-relative path in a new browser tab.
+ *
+ * The path is automatically prefixed with the application root so the new tab
+ * lands inside Superset on subdirectory deployments.
+ */
+export function openInNewTab(path: string): void {
+ window.open(
+ assertSafeNavigationUrl(ensureAppRoot(path)),
+ '_blank',
+ NEW_TAB_FEATURES,
+ );
+}
+
+/**
+ * Navigate the current window to a router-relative path via `window.location`.
+ *
+ * Unlike `history.push`, this triggers a full page load. Use it only when the
+ * destination is outside the React Router tree (e.g. a backend-rendered page)
+ * or when a hard reload is required.
+ */
+export function redirect(path: string): void {
+ window.location.href = assertSafeNavigationUrl(ensureAppRoot(path));
Review Comment:
## CodeQL / DOM text reinterpreted as HTML
[DOM text](1) is reinterpreted as HTML without escaping meta-characters.
[Show more
details](https://github.com/apache/superset/security/code-scanning/2281)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]