Repository navigation
Add an escaping Html template to effect/http - #9061
adam-r-kowalski wants to merge 4 commits into
Conversation
🦋 Changeset detectedLatest commit: 28e05d2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 32 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Bundle Size AnalysisGenerated from PR build output; treat the content below as untrusted.
|
Brand Html with a symbol so JSON-parsed data cannot pass as trusted markup, rename raw to rawUnsafe, document where escaping does not make an interpolation safe, and keep succeeded interpolations synchronous.
|
I have a design concern about shipping Html.make`<a href="${url}">link</a>` // javascript: URLs pass through
Html.make`<iframe srcdoc="${markup}"></iframe>` // entities are decoded, then parsed as HTMLEvent-handler attributes have a similar problem: HTML entity escaping does not escape the JavaScript that runs after attribute decoding. The module documents these limits, but ordinary-looking template usage can still introduce XSS without an explicit unsafe call. The resulting I would avoid shipping this template tag as the recommended way to render untrusted input. A better direction is to use an established renderer with context-specific handling and pass its output to |
Problem
HttpServerResponse.htmlas a template tag does not escape what it interpolates, so untrusted text reaches the page as markup:Changing the tag to escape would break code that interpolates markup strings, so this adds a new module instead.
Change
effect/httpgetsHtml:Html.makeis a template tag returningEffect<Html, E, R>. Interpolated strings are escaped (& < > " '). Numbers and booleans are rendered,nullandundefinedrender nothing, and arrays are rendered element by element.OptionandEffectinterpolations work as inTemplate.make: effects are awaited and the result keeps their errors and services. Arrays of effects are not awaited; the docs show combining them withEffect.all.Htmlvalues (frommake, orHtml.rawUnsafefor trusted markup) are inserted as they are, so components compose without double escaping. The brand is a symbol key, so objects fromJSON.parsecannot pass asHtml.Html.escapeandHtml.isHtmlare exported.HttpServerResponse.htmlaccepts anHtmlvalue as well as a string. The tag form is unchanged and still does not escape.Safety
Escaping makes an interpolation safe in element text and in quoted values of ordinary attributes. It does not make it safe in URL attributes (
javascript:passes through, so validate URLs separately), event handler,styleorsrcdocattributes,scriptandstyleelements, comments, unquoted attribute values, or tag and attribute names. The module documents these limits.Tests
test/http/Html.test.tscovers escaping in text and quoted attributes, rendering of primitives, arrays andOption, composition withrawUnsafe, effect services, errors and ordering, rejection of a JSON-forgedHtmlvalue, and the exported helpers.test/http/HttpServerResponse.test.tscovers sending anHtmlvalue and the unchanged unescaped tag.pnpm check,pnpm lint,pnpm jsdocs --checkand the Html, HttpServerResponse and Template suites pass.Changeset
effectpatch, matching other additions to@stability unstablemodules.Closes EFF-2021