unsloth/studio/frontend
Darshan Poudel 256d17e2e1
fix(studio): block arbitrary external image URLs in markdown renderer (#5602)
* fix(studio): block arbitrary external image URLs in markdown renderer

Model-emitted <img src="http://attacker.com/..."> tags were causing the
browser to issue HTTP requests to arbitrary origins, leaking the user's
IP address, User-Agent, and Referer header to any domain a prompt-injected
model could emit (tracking-pixel vector, issue #5596).

Add a urlTransform function passed to <Streamdown> that only allows:
  - data: URIs  (inline images, mermaid SVG, user attachments)
  - blob: URIs  (locally generated object URLs)
  - relative paths without a scheme (same-origin assets)

All other schemes (http:, https:, ftp:, etc.) return null, causing
Streamdown to omit the <img> element entirely.

Existing iframes are already stripped by Streamdown's default sanitizer;
event-handler attributes (onerror, onload, etc.) are also stripped by
the default schema.

* fix(studio): strip control chars and block backslash URL variants

Two bypass vectors found after review:

1. Backslash-normalised URLs: \\attacker.com\pixel has no colon and does
   not start with // so the earlier guards allowed it as a relative path.
   Browsers normalise leading backslash pairs to // before resolving, so
   the request still reaches the external origin.

2. Embedded control characters: /\n/attacker.com passes trim() unchanged,
   startsWith("//") is false, and no-colon check passes it as relative.
   Browsers strip ASCII controls (U+0000-U+001F, U+007F) before URL
   resolution, so the value resolves to the attacker origin.

Fix: strip all ASCII control characters from the raw URL before any guard,
then block any URL whose normalized form starts with two chars from [/\\]
to cover //, \\, /\, and \/ in one regex.

* fix(studio): delegate non-image URLs to defaultUrlTransform

Returning the raw URL for non-img nodes bypassed Streamdown's built-in
link sanitization, allowing model-emitted javascript: hrefs to reach the
DOM unfiltered. Pass non-image URLs through defaultUrlTransform so the
library's own javascript:/data: sanitization stays active for links.

* fix(studio): use scheme regex instead of includes() for colon check

A colon anywhere in the URL (e.g. /api/image?id=model:v2 or
/snapshots/2026-06-04T12:00:00Z.png) was incorrectly treated as an
explicit scheme and the URL was dropped. Replace the includes(':') check
with a proper scheme regex that only matches when a valid scheme token
appears before any path separator.

* Studio: shorten safeImageUrl comments in markdown renderer

---------

Co-authored-by: Daniel Han <danielhanchen@gmail.com>
2026-06-10 00:32:31 -07:00
..
public feat(studio): Hub + Download Manager (#5916) 2026-06-09 04:11:24 -07:00
src fix(studio): block arbitrary external image URLs in markdown renderer (#5602) 2026-06-10 00:32:31 -07:00
.gitignore perf(studio): upgrade to Vite 8 + auto-install bun for faster frontend builds (#4522) 2026-03-25 04:27:41 -07:00
.gitkeep add studio root folder 2026-02-02 09:14:35 +00:00
.npmrc security: NOT affected by Mini Shai-Hulud (May-12 wave) -- forward-looking hardening only (#5397) 2026-05-13 04:58:12 -07:00
biome.json feat: add seed dataset support with configuration, preview, and builder utilities 2026-02-14 18:44:38 +01:00
components.json add studio root folder 2026-02-02 09:14:35 +00:00
data-designer.openapi (1).yaml save and import, and fixes 2026-02-04 14:32:49 +01:00
eslint.config.js Final cleanup 2026-03-12 18:28:04 +00:00
index.html Final cleanup 2026-03-12 18:28:04 +00:00
package-lock.json Studio: clean-room compact RAG (knowledge bases, hybrid search, fast indexing) (#5910) 2026-06-09 21:17:04 -07:00
package.json Studio: clean-room compact RAG (knowledge bases, hybrid search, fast indexing) (#5910) 2026-06-09 21:17:04 -07:00
tsconfig.app.json Relax frontend unused local check (#4388) 2026-03-17 16:04:11 -07:00
tsconfig.json cleanup 2026-02-04 13:28:39 +01:00
tsconfig.node.json cleanup 2026-02-04 13:28:39 +01:00
vite.config.ts Fix Install commands for Windows + 1 line installs (#4447) 2026-03-19 02:09:09 -07:00