{"record":{"id":"b44bd66c01cd5418","repo":"apache/superset","slug":"security-error","errorCode":"security_error","errorMessage":"Unsafe node type \"${nodeType}\" at path: ${path.join('.')}. Only static data structures are allowed.","messagePattern":"Unsafe node type \"(.+?)\" at path: (.+?)\\. Only static data structures are allowed\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"superset-frontend/plugins/plugin-chart-echarts/src/utils/safeEChartOptionsParser.ts","lineNumber":220,"sourceCode":"  'require',\n  'import',\n  'module',\n  'exports',\n]);\n\n/**\n * Recursively validates that an AST node contains only safe constructs.\n * Throws an error if any unsafe patterns are detected.\n */\nfunction validateNode(node: Node, path: string[] = []): void {\n  if (!node || typeof node !== 'object') {\n    return;\n  }\n\n  const nodeType = node.type;\n\n  if (!SAFE_NODE_TYPES.has(nodeType)) {\n    throw new Error(\n      `Unsafe node type \"${nodeType}\" at path: ${path.join('.')}. ` +\n        `Only static data structures are allowed.`,\n    );\n  }\n\n  switch (nodeType) {\n    case 'Identifier': {\n      const identNode = node as Node & { name: string };\n      if (DANGEROUS_IDENTIFIERS.has(identNode.name)) {\n        throw new Error(\n          `Dangerous identifier \"${identNode.name}\" detected at path: ${path.join('.')}`,\n        );\n      }\n      break;\n    }\n\n    case 'UnaryExpression': {\n      const unaryNode = node as Node & { operator: string; argument: Node };","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset-frontend/plugins/plugin-chart-echarts/src/utils/safeEChartOptionsParser.ts#L202-L238","documentation":"The same /redirect/ route aborts 400 'Invalid URL scheme' when urlparse(target_url).scheme.lower() is in DANGEROUS_SCHEMES = {javascript, data, vbscript, file} (superset/views/redirect.py:39,67). This blocks script-execution and local-file schemes from being bounced through Superset's redirector — a defense against attackers crafting malicious links inside alert/report content. The block is logged at warning level with the first 80 chars of the URL.","triggerScenarios":"GET /redirect/?url=javascript:alert(1), url=data:text/html;base64,..., url=file:///etc/passwd, or url=vbscript:... — including mixed-case scheme variants (JAVASCRIPT:, Java​Script:) since the check lowercases the parsed scheme.","commonSituations":"User-controlled dashboard text or alert payloads being interpolated into redirect targets; security testing/pen-test scans of the email links; legitimate file:// links in internal tooling that must be removed because Superset will never allow them.","solutions":["Use only http:// or https:// (or relative/internal) URLs as redirect targets","Sanitize user-supplied link fields at the point of storage (dashboard markdown, alert text) with an allowlist of schemes","Treat occurrences in logs as hostile-content signals: trace which alert/report produced the link"],"exampleFix":"# before\nlink = user_provided_url  # may be 'javascript:...' -> 400 + security log\n\n# after\nfrom urllib.parse import urlparse\nif urlparse(user_provided_url).scheme.lower() not in (\"http\", \"https\", \"\"):\n    link = None  # drop or reject","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\nDANGEROUS = {\"javascript\", \"data\", \"vbscript\", \"file\"}\n\ndef scheme_allowed(url: str) -> bool:\n    return urlparse(url).scheme.lower() not in DANGEROUS","typeGuard":"const DANGEROUS = new Set([\"javascript\", \"data\", \"vbscript\", \"file\"]);\nconst isSafeScheme = (u: string): boolean =>\n  !DANGEROUS.has(new URL(u, \"https://example.invalid\").protocol.replace(\":\", \"\").toLowerCase());","tryCatchPattern":null,"preventionTips":["Allowlist schemes (http/https/relative) on any user-supplied link stored in Superset content","Never put user-controlled values directly into redirect targets; log occurrences — they usually indicate injected content"],"tags":["superset","security","xss","redirect","http-400","alerts-reports"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}