Skip to content

Escape coverage gap: theme furniture geometry and the ECharts background option reach the SVG output unescaped #129

Description

Where escaping is applied today

Both render backends escape data-derived bytes before they reach SVG output: a category/title/tooltip string carrying <img> markup lands as &lt;img… in both the Vega-Lite and the ECharts SVG serializers. That control covers the data path.

Where it is not applied

  1. packages/flint-js/src/vegalite/canvas-furniture.ts L59-63 — canvasFurnitureMarkup interpolates x, y, width, height into the <rect> markup raw; escapeAttr is applied only to the fill/color attribute. applyCanvasFurniture (packages/flint-js/src/vegalite/theme.ts L5716+, with item.width ?? 40 / item.height ?? 2 at ~L5729-5730) copies the authored width/height through with no type check, and the MCP boundary accepts theme_spec as z.union([z.string(), z.record(z.string(), z.any())]) (packages/flint-mcp/src/tools/schemas.ts L105-106), so the width?: number; height?: number contract in core/theme/types.ts (~L409-410) is never enforced at runtime. A string authored into furniture[].width or furniture[].height therefore lands verbatim inside the <rect ...> markup of the exported or injected SVG — an attribute breakout out of the rect element. (Authored x/y values do not reach the rect; the geometry is computed.)
  2. The background render option — packages/flint-mcp/src/render/index.ts L59 passes options.background through, and packages/flint-mcp/src/render/echarts.ts L31 sets it as backgroundColor before renderToSVGString(). ECharts' SSR string builder writes the background fill="…" attribute unescaped, so a non-color string in that option lands verbatim in the same way. Validating the option as a color at renderChart entry is the natural flint-side fix, since the fill attribute itself is written by zrender's string builder.

Both sites ship in the published flint-chart / flint-chart-mcp 0.5.1 dist — the server render path and the app UI bundle carry the identical markup functions.

Suggested change

  • In canvasFurnitureMarkup, coerce all geometry with Number.isFinite and run escapeAttr over every attribute (or build the rect via DOM APIs instead of string concatenation).
  • Enforce the numeric contract for furniture width/height at the trust boundary — reject non-number values in resolveThemeSpec/grounding, matching the existing unknown-preset throw.
  • Validate the background render option as a color at renderChart entry.
  • A regression test that puts hostile strings into furniture[].width and the background option and asserts they do not appear verbatim in the toSVG output would lock the coverage in place.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions