Skip to contentExploitQuest

Lesson 1 of 1 in Encoding Is Contextual

Four Different Problems

"Escaping the output" is not one job. The same value needs four different treatments depending on where it lands.

3 min read

Not yet reviewed

Most frameworks escape for HTML by default, and most developers conclude the problem is handled. It is handled in one of four places. The other three are where cross-site scripting still lives.

The same value, four destinations

<p>Hello, NAME</p>
<img alt="NAME">
<script>const u = "NAME"</script>
<a href="/search?q=NAME">
  1. Line 1HTML text. Escape < > &. This is the one every framework does for you, and the reason people believe the problem is solved.
  2. Line 2An attribute. Now quotes matter too — an unescaped " closes the attribute and the rest becomes markup. Always quote attributes.
  3. Line 3Inside a script. HTML escaping does nothing useful here; you are writing JavaScript source, and </script> inside the value ends the block whatever you did to the angle brackets.
  4. Line 4A URL. Needs percent-encoding, and the scheme needs checking — javascript: in an href is script execution with no angle bracket anywhere.

Note

The mistake is not forgetting to escape. It is escaping for the wrong context, which looks correct in review and in every test, because the output is escaped — just not for where it landed.

The rule that avoids all four

Do not put data into a document by building the document as a string. Let the templating layer place the value, so it knows what surrounds it — and when you genuinely must build markup, put the value somewhere the parser treats as data rather than as syntax.

The value becomes markup

el.innerHTML = '<p>' + name + '</p>'

The value stays data

el.textContent = name

textContent cannot produce an element whatever the string contains. This is the same shape as the previous chapter: stop the data being part of the sentence, rather than sanitising it so it survives being part of one.

Serving data into a script

The commonest remaining hole is handing server data to client JavaScript by writing it into a <script> block. Even correct JSON encoding is not enough, because the HTML parser reaches the content before the JavaScript parser does and stops the block at the first </script> it sees.

Take care

If you must inline data, put it in a <script type="application/json"> block and read it with JSON.parse — and still escape < in the payload. The parser reads that block as text rather than as code, which removes the execution question entirely.

What this platform does instead

Lesson content here is structured data, never markup. A lesson body is a validated tree of typed blocks, and the renderer decides what element each becomes — so an author cannot supply an element at all, and there is no context for a value to escape the wrong way from.

Note

That is a stronger guarantee than escaping, and it is available more often than people think. Accepting markup and cleaning it is a permanent commitment to being better at parsing than an attacker; accepting structure and rendering it is a decision you make once.

A username is HTML-escaped and placed inside `<img alt=NAME>` with no quotes around the attribute. Is it safe?