Java, Newline, Script — JavaScript Bug Hunt

Modelled on the Samy worm on MySpace (October 2005): MySpace's profile filter removed the word javascript, but some browsers still ran a CSS url() in which…

  • Language: JavaScript
  • Layer: Frontend
  • Difficulty: Medium
  • Concepts: Security, Parsing
  • Modelled on: MySpace · Samy worm 2005
  • Visible tests: an https background is allowed; a scheme split by a newline is still refused
  • Reward: 50 XP for a complete fix

Briefing

Modelled on the Samy worm on MySpace (October 2005): MySpace's profile filter removed the word javascript, but some browsers still ran a CSS url() in which the word was split by a newline — java\nscript:. Samy Kamkar's profile used that gap to add him as a friend of everyone who viewed it, and the worm reached over a million profiles in about a day.

This project is a reconstruction. sanitize.js decides whether a URL may go into a profile's background style by searching for a forbidden word.

Fix isSafeUrl so the check is made on what the browser will actually see, and only known-safe schemes pass.

Bug report

BUG-SAMY · Priority: Critical (stored XSS) · Reported by: security

isSafeUrl(url):

  • first remove every character with code <= 32 (spaces, tabs, newlines and other control characters) and code 127, then lower-case the result
  • if what remains starts with a scheme (a letter, then letters, digits, "+", "-" or ".", then ":"), the URL is safe ONLY when that scheme is http or https
  • a URL with no scheme (e.g. "/img/bg.png", "img/bg.png") is relative and safe

render.backgroundStyle uses it to decide whether a URL is emitted.

Observed: "java<newline>script:…" passes the filter and runs in the viewer's browser.

Logs

[profile] saved style for user 11851658 (filter: ok)
[profile] friend count for user 11851658 growing without user action

The code as shipped

src/profile/sanitize.js (editable)

// Decides whether a user-supplied URL may appear in a profile style.
exports.isSafeUrl = function (url) {
  return String(url).toLowerCase().indexOf("javascript") === -1;
};

Read-only context: src/profile/render.js.

Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More JavaScript bug hunts.