diff --git a/modules/playground/components/playground-editor.tsx b/modules/playground/components/playground-editor.tsx index 1434060a..847be471 100644 --- a/modules/playground/components/playground-editor.tsx +++ b/modules/playground/components/playground-editor.tsx @@ -329,6 +329,18 @@ const PlaygroundEditor = ({ .padEnd(6, "0") : "#30bced"; + const sanitizeForCss = (value: unknown): string => + typeof value === "string" + ? value.replace(/[^a-zA-Z0-9 _\-#.]/g, "") + : ""; + + const SAFE_HEX_COLOR = /^[0-9a-fA-F]{6}$/; + const sanitizeColor = (value: unknown, fallback: string): string => { + const raw = typeof value === "string" ? value : ""; + const stripped = raw.replace(/^#/, ""); + return SAFE_HEX_COLOR.test(stripped) ? `#${stripped}` : fallback; + }; + provider.awareness.setLocalStateField("user", { name: session?.user?.name || "Anonymous", color: userColor, @@ -350,8 +362,8 @@ const PlaygroundEditor = ({ for (const [clientId, state] of states) { if (state.user) { - const color = state.user.color || "orange"; - const name = state.user.name || "Anonymous"; + const color = sanitizeColor(state.user.color, "#30bced"); + const name = sanitizeForCss(state.user.name) || "Anonymous"; css += ` .yRemoteSelection-${clientId} { @@ -388,7 +400,7 @@ const PlaygroundEditor = ({ `; } } - styleEl.innerHTML = css; + styleEl.textContent = css; }; provider.awareness.on("update", handleAwarenessUpdate);