frontpage.
newsnewestaskshowjobs

Made with ♥ by @iamnishanth

Open Source @Github

Open in hackernews

How to safely escape JSON inside HTML SCRIPT elements

https://sirre.al/2025/08/06/safe-json-in-script-tags-how-not-to-break-a-site/
36•dmsnell•10h ago

Comments

dmsnell•10h ago
Discussing why parsing HTML SCRIPT elements is so complicated, the history of why it became the way it is, and how to safely and securely embed JSON content inside of a SCRIPT element today.
dmsnell•4h ago
This was my first submission, and the above comment was what I added to the text box. It wasn’t clear to me what the purpose was, but it seemed like it would want an excerpt. I only discovered after submitting that it created this comment.

I guess people just generally don’t add those?

Still, to help me out, could someone clarify why this was down-voted? I don’t want to mess up again if I did, but I don't understand what that was.

shakna•3h ago
> Leave url blank to submit a question for discussion. If there is no url, text will appear at the top of the thread. If there is a url, text is optional.

Most people will opt for text to be optional with a link - unless they're showing their own product (Show HN). Because there is an expectation that you will attempt to read an article, before conversing about it.

flomo•3h ago
I don't know, but I see early posts which look like AI bot summaries (presumably to collect karma). Probably not necessary for a link.
bawolff•2h ago
I think its just because as a comment it looks pretty random and somewhat off topic since its a summary of the article instead of an opinion on it.

I think most of the time people dont add a comment to submissions, but if they do its more of the form: I found X interesting because of [insert non obvious reason why X is interesting] or some additional non-obvious context needed.

In any case, i don't think there is any reason to worry too much. There was no ill intent and at the end of the day its all just fake internet points.

comex•6h ago
If you're evaluating JSON as JavaScript, you also need to make sure none of the objects have a key named "__proto__", or else you can end up with some strange results.

(This is related to the 'prototype pollution' attack, although searching that phrase will mostly give you information about the more-dangerous variant where two objects are being merged together with some JS library. If __proto__ is just part of a literal, the behavior is not as dangerous, but still surprising.)

o11c•5h ago
But note that there's also `<script type="application/json">` these days (usually only useful with `id=`) ... and `importmap` I guess.
themafia•1h ago
It's even more general:

    type

    This attribute indicates the type of script represented. The value of this attribute will be one of the following:

    [...]

    Any other value
    
    The embedded content is treated as a data block, and won't be processed by the browser. Developers must use a valid MIME type that is not a JavaScript MIME type to denote data blocks. All of the other attributes will be ignored, including the src attribute.
Although 'importmap' has specific functionality, as does 'speculationrules', although they operate similarly. My favorite is type="module" which competes with the higher level attribute nomodule="true". Anyways it looks like <script> has taken a lot of abuse over the years:

https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/...

masklinn•37m ago
> My favorite is type="module" which competes with the higher level attribute nomodule="true". Anyways it looks like <script> has taken a lot of abuse over the years:

It "conflicts" in the same way noscript[1] and script "conflict" no? They're basically related features, but can't really be made exclusive because the mere act of trying to do so wouldn't work: as the link indicates, executing code in a !module browser reserves the type (requires a specific set of types) so you can't use that as a way to opt in !module browsers.

[1] an other fun element with wonky parsing rules besides

themafia•25m ago
You can write:

    <script nomodule="true" type="module"></script>
Which is a little weird. At the very least I'd expect the type="module" documentation to say that `charset`, `defer` and `nomodule` attributes have no effect.
dullcrisp•5h ago
Wait can someone explain why a script tag inside a comment inside a script tag needs to be closed, while a script tag inside a script tag without a comment does not? They explained why comments inside script tags are a thing, but nothing further than that.
AdieuToLogic•4h ago
From the post:

  Everything until the tag closer </script> is inside
  the script element.
And:

  In fact, script tags can contain any language (not 
  necessarily JavaScript) or even arbitrary data. In order to 
  support this behavior, script tags have special parsing 
  rules. For the most part, the browser accepts whatever is 
  inside the script tag until it finds the script close tag 
  </script>.
Note the sentence fragment "even arbitrary data." This explains the second part of your question as to why nested script tags without HTML comments do not require matching closing tags. Similar compatibility hacks exist for other closing tags (search for Chrome closing tags being optional for a fun ride down a rabbit hole).

As to:

  why a script tag inside a comment inside a script tag needs
  to be closed ...
Well, this again is due to maximizing backward compatibility in order to support broken browsers (thanks IE4, you bastard!). As the article states:

  When JavaScript was first introduced, many browsers did not 
  support it. So they would render the content of the script 
  tag – the JavaScript code itself. The normal way to get 
  around that was to put the script into a comment ...
HTH
dullcrisp•18m ago
So did these older browsers also check for the presence of a comment before turning on double-escaping mode?

Or did they always have two levels of script tag escaping but that behavior only got preserved when inside an HTML comment?

No other JavaScript behavior is different inside an HTML comment, and I’m still missing the connection between the HTML comment and the embedded </script> not closing the tag besides that they were two things that older browsers might have done.

dmsnell•4h ago
The other comment explains this, but I think it can also be viewed differently.

It’s helpful to recognize that the inner script tags are not actual script tags. Yes, once entering a script element, the browser switches parsers and wants to skip everything until a closing script tag appears. The STYLE element, TITLE, TEXTAREA, and a few others do this. Once they chop up the HTML like this they send the contents to the separate inner parser (in this case, the JS engine). SCRIPT is unique due to the legacy behavior^1.

HTML5 specifies these “inner” tags as transitions into escape modes. The entire goal is to allow JavaScript to contain the string “</script>” without it leaking to the outer parser. The early pattern of hiding inside an HTML comment is what determined the escaping mechanism rather than making some special syntax (which today does exist as noted in the post).

The opening script tag inside the comment is actually what triggers the escaping mode, and so it’s less an HTML tag and more some kind of pseudo JS syntax. The inner closing tag is therefore the escaped string value and simultaneously closes the escaped mode.

Consider the use of double quotes inside a string. We have to close the outer quote, but if the inner quote is escaped like `\”` then we don’t have to close it — it’s merely data and not syntax.

There is only one level of nesting, and eight opening tags would still be “closed” by the single closing tag.

^1: (edit) This is one reason HTML and XML (XHTML) are incompatible. The content of SCRIPT and STYLE elements are essentially just bytes. In XML they must be well-formed markup. XML parsers cannot parse HTML.

tannhaeuser•1h ago
Whoever the idiot was who came up with piling inline CSS and JS into the already heavy SGML syntax of HTML should've considered his career choices. It would've be perfectly adequate to require script and CSS to be put into external "resources" linked via src/href, especially since the spec proposals operated under the assumption there would be multiple script and styling languages going forward (like, hey, if we have one markup and styling language, why not have two or multiple?). When in fact the rules were quite simple: in SGML, text rendered to the reader goes into content, everything else, including formatting properties, goes into atttibutes. The reason for introducing this inlining misfeature was probably the desire to avoid network roundtrip, which would've later been made bogusly obsolete by Google's withdrawn HTTP/2 push spec, but also the bizarre idea anyone except webdev bloggers would be editing HTML+CSS by hand. To think there was a committee overviewing such blunders as "W3C recommendations" - actually, they screwed up again with CSS when they allowed unencoded inline data URLs such as used for SVG backgrounds and the like. The alarm bells should've been ringing at the latest the moment they seriously considered storing markup within CSS like with the abovementioned misfeature but also with the "content:" CSS property. You know, as in "recommendation" which is how W3C final stage specs were called.
dullcrisp•4m ago
Huh, it’s still confusing to me why they would have this double-escaping behavior only inside an HTML comment. Why not have it always behave one way or the other? At what point did the parsing behavior inside and outside HTML comments split and why?
TOGoS•3h ago
> Not so fast, things are about to get messy

That ship sailed several paragraphs ago, when <script> got special treatment by the HTML parser. Too bad we couldn't all agree to parse <![CDATA[...]]> consistently, or, you know, just &-escape the text like we do /everywhere else/ in HTML.

forty•1h ago
What's wrong with CDATA? Do you have concrete examples when that would not work?

I want everything local – Building my offline AI workspace

https://instavm.io/blog/building-my-offline-ai-workspace
728•mkagenius•15h ago•196 comments

Tribblix – The Retro Illumos Distribution

http://www.tribblix.org/
35•bilegeek•2h ago•1 comments

What the windsurf sale means for the AI coding ecosystem

https://ethanding.substack.com/p/windsurf-gets-margin-called
99•whoami_nr•5h ago•22 comments

I bought a £16 smartwatch just because it used USB-C

https://shkspr.mobi/blog/2025/08/i-bought-a-16-smartwatch-just-because-it-used-usb-c/
157•blenderob•2d ago•73 comments

Breaking the Sorting Barrier for Directed Single-Source Shortest Paths

https://arxiv.org/abs/2504.17033
47•pentestercrab•3h ago•1 comments

Ultrathin business card runs a fluid simulation

https://github.com/Nicholas-L-Johnson/flip-card
976•wompapumpum•21h ago•197 comments

Sandstorm- self-hostable web productivity suite

https://sandstorm.org/
33•nalinidash•3h ago•9 comments

Partially Matching Zig Enums

https://matklad.github.io/2025/08/08/partially-matching-zig-enums.html
4•ingve•31m ago•0 comments

Engineer restores pay phones for free public use

https://www.npr.org/2025/08/04/nx-s1-5484013/engineer-restores-pay-phones-for-free-public-use
110•andsoitis•3d ago•37 comments

Tor: How a military project became a lifeline for privacy

https://thereader.mitpress.mit.edu/the-secret-history-of-tor-how-a-military-project-became-a-lifeline-for-privacy/
317•anarbadalov•17h ago•150 comments

Car has more than 1.2M km on it – and it's still going strong

https://www.cbc.ca/news/canada/nova-scotia/1985-toyota-tercel-high-mileage-1.7597168
10•Sgt_Apone•3d ago•5 comments

Representing Python notebooks as dataflow graphs

https://marimo.io/blog/dataflow
19•akshayka•3d ago•0 comments

A SPARC makes a little fire

https://www.leadedsolder.com/2025/08/05/sparcstation-scsi-termination-fix-magic-smoke.html
17•zdw•3d ago•0 comments

Getting good results from Claude Code

https://www.dzombak.com/blog/2025/08/getting-good-results-from-claude-code/
347•ingve•19h ago•137 comments

Efrit: A native elisp coding agent running in Emacs

https://github.com/steveyegge/efrit
120•simonpure•14h ago•18 comments

How we replaced Elasticsearch and MongoDB with Rust and RocksDB

https://radar.com/blog/high-performance-geocoding-in-rust
237•j_kao•20h ago•63 comments

Hacking Diffusion into Qwen3 for the Arc Challenge

https://www.matthewnewton.com/blog/arc-challenge-diffusion
86•mattnewton•3d ago•7 comments

Jim Lovell, Apollo 13 commander, has died

https://www.nasa.gov/news-release/acting-nasa-administrator-reflects-on-legacy-of-astronaut-jim-lovell/
494•LorenDB•14h ago•100 comments

Ask HN: How can ChatGPT serve 700M users when I can't run one GPT-4 locally?

412•superasn•13h ago•273 comments

Let's properly analyze an AI article for once

https://nibblestew.blogspot.com/2025/08/lets-properly-analyze-ai-article-for.html
63•pabs3•6h ago•38 comments

Astronomy Photographer of the Year 2025 shortlist

https://www.rmg.co.uk/whats-on/astronomy-photographer-year/galleries/2025-shortlist
208•speckx•18h ago•31 comments

Our European search index goes live

https://blog.ecosia.org/launching-our-european-search-index/
51•maelito•12h ago•7 comments

Unmasking the Sea Star Killer

https://www.biographic.com/unmasking-the-sea-star-killer/
62•sohkamyung•3d ago•11 comments

Window Activation

https://blog.broulik.de/2025/08/on-window-activation/
200•LorenDB•4d ago•114 comments

How to safely escape JSON inside HTML SCRIPT elements

https://sirre.al/2025/08/06/safe-json-in-script-tags-how-not-to-break-a-site/
36•dmsnell•10h ago•18 comments

The surprise deprecation of GPT-4o for ChatGPT consumers

https://simonwillison.net/2025/Aug/8/surprise-deprecation-of-gpt-4o/
359•tosh•15h ago•346 comments

Debugging a mysterious HTTP streaming issue

https://mintlify.com/blog/debugging-a-mysterious-http-streaming-issue-when-cloudflare-compression-breaks-everything
10•skeptrune•3d ago•4 comments

Fire hazard of WHY2025 badge due to 18650 Li-Ion cells

https://wiki.why2025.org/Badge/Fire_hazard
95•fjfaase•3d ago•87 comments

Build durable workflows with Postgres

https://www.dbos.dev/blog/why-postgres-durable-execution
130•KraftyOne•13h ago•47 comments

A robust, open-source framework for Spiking Neural Networks on low-end FPGAs

https://arxiv.org/abs/2507.07284
60•PaulHoule•4d ago•5 comments