{"record":{"id":"51f943d2fa384e00","repo":"Budibase/budibase","slug":"color-is-invalid","errorCode":null,"errorMessage":"Color is invalid.","messagePattern":"Color is invalid\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/shared-core/src/helpers/colors.ts","lineNumber":7,"sourceCode":"export const normaliseSafeCssColor = (color?: string) => {\n  if (color == null || color.trim() === \"\") {\n    return undefined\n  }\n  const trimmed = color.trim()\n  if (trimmed.includes(\";\") || /\\burl\\s*\\(/i.test(trimmed)) {\n    throw new Error(\"Color is invalid.\")\n  }\n  return trimmed\n}\n","sourceCodeStart":1,"sourceCodeEnd":11,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/shared-core/src/helpers/colors.ts#L1-L11","documentation":"normaliseSafeCssColor in packages/shared-core/src/helpers/colors.ts trims a color string and throws \"Color is invalid.\" if it contains a semicolon or a url( pattern. This is an anti-injection guard: since the value is used in CSS, semicolons could terminate a declaration and inject extra CSS, and url() could load external resources, so such inputs are rejected rather than sanitised.","triggerScenarios":"Passing a user-supplied color like \"red; background:url(evil)\" or any string containing \";\" or \"url(\" to helpers/components that normalise CSS colors, e.g. theming or chart color configuration.","commonSituations":"End users pasting multi-part CSS into a color field in the builder; API/automation values carrying CSS shorthand; copy-pasted CSS values like \"rgb(0,0,0); opacity:0.5\".","solutions":["Pass only a single CSS color value (hex, rgb(), hsl(), or named color) without any semicolons.","Strip/validate user input on your side before assigning it to the color property.","If multiple declarations were intended, split them and use only the color portion.","Use the library's color picker UI rather than free-text where possible."],"exampleFix":"// before\nconst color = normaliseSafeCssColor(\"#ff0000; border: 1px\")\n// after\nconst color = normaliseSafeCssColor(\"#ff0000\")","handlingStrategy":"validation","validationCode":"function safeColor(input?: string): string | undefined {\n  if (input == null || !input.trim()) return undefined\n  const t = input.trim()\n  if (t.includes(\";\") || /\\burl\\s*\\(/i.test(t)) return undefined\n  return t\n}\nconst color = safeColor(userColor) ?? \"#000000\"","typeGuard":"function isSafeCssColor(v: unknown): v is string {\n  return typeof v === \"string\" && v.trim() !== \"\" &&\n    !v.includes(\";\") && !/\\burl\\s*\\(/i.test(v)\n}","tryCatchPattern":"let color: string | undefined\ntry {\n  color = normaliseSafeCssColor(userColor)\n} catch {\n  color = undefined // falls back to default theme color\n}","preventionTips":["Only pass single color values (hex/rgb/hsl/named) — never CSS declarations","Sanitise any user-facing color input before it reaches the helper","Use the color picker UI rather than free-text fields","Treat semicolons and url( in color inputs as a sign of copy-pasted CSS and strip them"],"tags":["css","validation","security","sanitization"],"backgroundTag":"css-injection-rejected","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}