{"record":{"id":"e4cd786ec9f9716a","repo":"apache/superset","slug":"css-contains-a-disallowed-construct-label","errorCode":null,"errorMessage":"CSS contains a disallowed construct ({label}).","messagePattern":"CSS contains a disallowed construct \\((.+?)\\)\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":422,"severity":"error","filePath":"superset/dashboards/schemas.py","lineNumber":173,"sourceCode":"\n    Lightweight input hardening for the user-supplied ``css`` field, which is\n    persisted and re-served into the dashboard page. Blocks ``expression(``,\n    script-scheme URIs (e.g. ``javascript:``), ``@import``, and ``url(...)``\n    referencing a script scheme, while leaving ordinary styling intact.\n\n    CSS escape sequences (e.g. ``\\\\6a avascript:``) are not expanded before\n    matching, so this validator is a first-line filter and not a complete XSS\n    sanitiser; it should not be treated as a substitute for other defences.\n    \"\"\"\n    if not value:\n        return\n    if isinstance(value, (bytes, bytearray)):\n        text = value.decode(\"utf-8\", errors=\"ignore\")\n    else:\n        text = value\n    for label, pattern in _DANGEROUS_CSS_PATTERNS:\n        if pattern.search(text):\n            raise ValidationError(f\"CSS contains a disallowed construct ({label}).\")\n\n\nclass SharedLabelsColorsField(fields.Field):\n    \"\"\"\n    A custom field that accepts either a list of strings or a dictionary.\n    \"\"\"\n\n    def _deserialize(\n        self,\n        value: Union[list[str], dict[str, str]],\n        attr: Union[str, None],\n        data: Union[Mapping[str, Any], None],\n        **kwargs: dict[str, Any],\n    ) -> list[str]:\n        if isinstance(value, list):\n            if all(isinstance(item, str) for item in value):\n                return value\n        elif isinstance(value, dict):","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/dashboards/schemas.py#L155-L191","documentation":"Custom CSS validator on dashboards: stored CSS is re-served into the dashboard page, so constructs that can execute script or load remote resources are rejected at validation time. Matching patterns include script schemes (javascript:, vbscript:, livescript:, mocha:), legacy IE expression(), and remote url() imports. The error names the offending construct label.","triggerScenarios":"PUT/POST a dashboard with css containing 'expression(' anywhere, a javascript:/vbscript: scheme token, or a url() pointing at a remote stylesheet (e.g. @import url(https://evil.com/x.css)).","commonSituations":"Pasting CSS from old IE-era snippets; attempting to load web fonts or external stylesheets via url(); obfuscated CSS where a scheme string appears inside a comment or string value (the check is textual, so false positives are possible).","solutions":["Remove the construct named in the error message label (e.g. drop the expression() rule or the javascript: URL).","Host assets locally or use data: URIs / relative paths for images, which the validator explicitly allows.","If a false positive (the pattern appears in an innocent comment/string), reword the comment or remove the literal token.","Note the documented limitation: CSS escapes are not expanded, so treat this as a first-line filter and keep CSP as a defence in depth."],"exampleFix":"/* before */\n.chart { width: expression(document.body.clientWidth); background: url(javascript:alert(1)); }\n\n/* after */\n.chart { width: 95%; background: url('/static/img/bg.png'); }","handlingStrategy":"validation","validationCode":"import re\n_BAD = [re.compile(r\"expression\\s*\\(\", re.I), re.compile(r\"(?:javascript|vbscript|livescript|mocha)\\s*:\")]\ndef css_looks_safe(css: str) -> bool:\n    return not any(p.search(css) for p in _BAD)","typeGuard":null,"tryCatchPattern":"from marshmallow import ValidationError\ntry:\n    validate_css(css)\nexcept ValidationError as ex:\n    label = str(ex.messages)  # names the disallowed construct\n    raise ValueError(f\"remove forbidden CSS construct: {label}\")","preventionTips":["Never put javascript:/vbscript: or expression( in dashboard CSS, even in comments.","Use relative paths or data: URIs for background images.","Keep CSP enabled as a second layer — the validator is a first-line filter only."],"tags":["css","xss","validation","dashboard","security"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}