Skip to content

[P2][Security/Privacy] Raster image tools should not accept raw SVG through generic image policies #311

Description

@baixiangcpp

Summary

Generic raster image policies currently allow SVG files in image-standard, image-compact, and image-logo. Those policies are used by tools such as Image Resizer, Photo Censor, Image Cropper, Image Filters, Color Picker, and Caption Generator.

The project already treats SVG as a special security surface in dedicated SVG/Markdown guards and sanitizers. Generic raster image tools should not ingest raw SVG through unsanitized object URLs unless the SVG path has an explicit sanitizer/rasterization boundary.

Why this matters

SVG is not the same risk class as PNG/JPEG/WebP/GIF/AVIF:

  • SVG is XML/markup, not a pure raster image.
  • SVG can contain links, embedded references, styles, metadata, and other markup-like surfaces.
  • Browser behavior differs depending on whether SVG is loaded as <img>, object URL, data URL, canvas source, or parsed text.
  • The site's privacy claim depends on avoiding accidental external-resource loads and avoiding ambiguous rendering boundaries.

Dedicated SVG tools already use explicit sanitization paths. Generic raster tools should either reject SVG or route it through an explicit sanitized SVG-to-raster path.

Current behavior

Relevant policy:

"image-standard": {accept: "image/*",allowedMimePrefixes: ["image/"],allowedExtensions: [".png",".jpg",".jpeg",".webp",".gif",".svg",".avif"],}

Similar .svg entries exist in image-compact and image-logo.

Example path:

  • src/features/tools/image-resizer/browser-actions.ts
    • validates with FILE_INPUT_POLICIES["image-standard"];
    • creates URL.createObjectURL(file);
    • loads it into an Image() via loadImageElement();
    • later renders it to canvas/worker.

There is no SVG sanitizer in this generic image path.

Expected behavior

Choose one of these approaches.

Preferred option: exclude SVG from generic raster image policies

  • Remove .svg and image/svg+xml acceptance from image-standard, image-compact, and image-logo.
  • Keep SVG only in the dedicated svg policy.
  • Point users to SVG Optimizer / SVG to PNG / SVG converter tools for SVG workflows.

Alternative option: explicit sanitized SVG raster path

  • Detect SVG uploads in generic image tools.
  • Sanitize SVG using the shared sanitizer before preview/rasterization.
  • Prevent external references from loading.
  • Rasterize through a controlled data URL/blob path.
  • Add tests proving dangerous SVG payloads are sanitized and no external references remain.

Suggested implementation plan

  1. Audit every consumer of:
    • FILE_INPUT_POLICIES["image-standard"]
    • FILE_INPUT_POLICIES["image-compact"]
    • FILE_INPUT_POLICIES["image-logo"]
  2. Remove .svg from generic image policies unless a consumer has an explicit sanitizer/raster path.
  3. Keep FILE_INPUT_POLICIES.svg for SVG-specific tools.
  4. Update upload copy so users understand SVG should use SVG tools.
  5. Add guard tests:
    • generic raster policies do not include .svg;
    • dedicated SVG policy still accepts .svg;
    • image-resizer/photo-censor/cropper/filter tools do not silently accept SVG through raster policy.
  6. If supporting SVG in raster tools is intentionally required, add sanitizer tests with malicious SVG fixtures.

Acceptance criteria

  • Generic raster image policies do not accept raw SVG unless an explicit sanitized SVG raster path exists.
  • Dedicated SVG tools continue to accept and sanitize SVG.
  • Upload UI copy points SVG users to SVG-specific tools or describes the sanitized path.
  • Tests cover policy separation between raster image inputs and SVG inputs.
  • Existing image tool tests still pass.
  • npm test -- --run tests/unit/file-input-policy.test.ts tests/component/bf-025-bf-031-image-file-safety.test.tsx tests/guards/html-injection-surface-guard.test.ts passes if updated.
  • npm run check:types and npm run lint pass.

Related code pointers

  • src/core/files/file-input-policy.ts
  • src/core/utils/image-canvas-utils.ts
  • src/features/tools/image-resizer/browser-actions.ts
  • src/core/security/sanitize.ts
  • tests/guards/html-injection-surface-guard.test.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions