Conversation
A form definition loaded from an untrusted source (e.g. the demo's URL hash) could specify inputTag "iframe" with attributes.srcdoc to render <iframe srcdoc="<script>...</script>">. Elm's VirtualDom only rewrites on*/formAction keys and blanks javascript:/data:text/html, value prefixes, so srcdoc slipped through — the iframe runs inline HTML in the embedder's origin. Sanitize at decode time: - inputTag must be "input" or a valid hyphenated custom-element name; anything else falls back to "input" (blocks iframe, object, embed, meta, script, etc.). - Drop attributes whose keys are srcdoc, sandbox, allow, csp, http-equiv, or background (defense in depth against the remaining script-execution / boundary-loosening attributes). Applied in decodeCustomElement and decodeInputTagAttributes. Covered by tests/XssDefenseTest.elm (19 cases).
ChooseMultipleField.Validate counted len(value) directly against
MinRequired and MaxAllowed. A raw POST body can repeat the same
name=value pair ("colors=Red&colors=Red&colors=Red"), which satisfied
"pick at least N" with one real selection. Browsers don't submit
checkboxes that way and the Elm frontend dedupes, so this only
surfaces on hand-crafted HTTP submissions, but the Go validator is
the server-side backstop and shouldn't be fooled by it.
Dedupe via a new uniqueStrings helper before evaluating MinRequired,
MaxAllowed, and the per-value choice check. Behavior for well-formed
(non-duplicate) submissions is unchanged. New tests cover duplicate
submissions failing minRequired, passing maxAllowed when collapsed,
and the normal happy paths.
✅ Deploy Preview for tiny-form-fields ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
wynn987
approved these changes
Apr 16, 2026
Comment on lines
+341
to
+345
| // Count distinct submissions. A raw POST body can repeat the same value | ||
| // (e.g. "color=Red&color=Red&color=Red"), which would otherwise let a | ||
| // caller satisfy MinRequired with a single distinct choice or inflate | ||
| // the count past MaxAllowed inspection. | ||
| distinct := uniqueStrings(value) |
There was a problem hiding this comment.
👍 shouldnt break legitimate users on goventry since a real browser form submission wouldnt have dup checkbox values
Comment on lines
+4069
to
+4076
| -- XSS defense. Elm's VirtualDom rewrites on*/formAction keys and blanks | ||
| -- javascript:/data:text/html, values, but leaves the tag name and other | ||
| -- attributes untouched. A form definition can reach both, so we normalize | ||
| -- here: reject any inputTag that isn't the default "input" or a valid | ||
| -- custom-element name (must contain a hyphen per the HTML spec; that alone | ||
| -- rules out iframe/object/embed/meta/etc.), and drop attributes whose | ||
| -- name or value can still produce script execution or boundary-loosening | ||
| -- on the native tags we do allow. |
There was a problem hiding this comment.
shouldnt break goventry too since all our input tags and attributes matches the allowed list
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two independent security hardenings found during a manual review of the form-definition decode path and the Go server-side validator.
1. Custom-element tag + attribute sanitization (XSS hardening)
A form definition loaded from an untrusted source (e.g. the demo's URL hash in index.html) could specify inputTag: "iframe" with attributes: { "srcdoc": "<script>…</script>" }. Elm's VirtualDom only rewrites on* / formAction attribute keys and only blanks values starting with javascript: or data:text/html,, so srcdoc slipped through both filters. The iframe runs its inline HTML in the embedder's origin, yielding same-origin script execution (cookies, CSRF, DOM takeover).
Fix (src/Main.elm): sanitize at decode time.
Impact of the change on existing usage: no known legitimate use in this repo or the demo is affected. Native input and hyphenated custom elements like validated-input pass through unchanged. style is not in the denylist — inline styling continues to work.
Tests: tests/XssDefenseTest.elm — 19 cases covering tag allowlist (input, validated-input, iframe, IFrame, object, embed, meta, script, -foo, my!tag), attribute denylist (srcdoc, sandbox, allow, http-equiv, case-insensitive), benign pass-through (type/pattern/maxlength/placeholder/style), and end-to-end neutralization of the exact iframe+srcdoc PoC.
2. ChooseMultiple dedup in Go validator
ChooseMultipleField.Validate counted len(value) directly against MinRequired and MaxAllowed. A raw POST body can repeat the same name=value pair (colors=Red&colors=Red&colors=Red), which satisfied a "pick at least 3" rule with one real selection. Browsers don't submit checkboxes that way and the Elm frontend dedupes, so this only surfaces on hand-crafted HTTP requests — but the Go validator is the server-side backstop and shouldn't be fooled by it.
Fix (go/validate.go): new uniqueStrings helper; dedupe before evaluating MinRequired, MaxAllowed, and the per-value choice check. Behavior on well-formed (non-duplicate) submissions is unchanged.
Tests (go/validate_test.go):