Skip to content

Conversation

@lydell
Copy link

@lydell lydell commented Nov 11, 2025

Closes elm/html#246 together with elm/html#281.

Simpler alternative to #190. That PR allows srcdoc but disallows script execution via careful management of sandbox. That’s quite complicated, while this PR is very simple. It turns out that a GitHub search immediately reveals people (ab)using srcdoc to execute scripts, so that careful sandbox handling isn’t backwards compatible for them anyway. I asked on Slack on how people use srcdoc:

  • Most people said they don’t use it.
  • Some people said they use it to execute some JavaScript code.
  • One person had a legit use case without JavaScript execution.

In all cases it’s possible to wrap the iframe in a web component to achieve the same thing. So it’s fairly easy to migrate.

All that makes it seem like it’s more worth keeping things simple and disallow srcdoc. Instead of silently disallowing script tags (silently breaking people’s code), we show a warning with a link to documentation on how to use a web component instead – see elm/html#281.

Demo/tests:

module IframeSrcdocDemoMinimal2 exposing (main)

import Browser
import Html
import Html.Attributes
import Html.Events
import Json.Encode
import VirtualDom


type CustomElementState
    = Srcdoc1
    | Srcdoc2
    | NoSrcdoc


main =
    Browser.sandbox
        { init = Srcdoc1
        , update =
            \() customElementState ->
                case customElementState of
                    Srcdoc1 ->
                        Srcdoc2

                    Srcdoc2 ->
                        NoSrcdoc

                    NoSrcdoc ->
                        Srcdoc1
        , view = view
        }


view customElementState =
    Html.div []
        [ Html.iframe [ Html.Attributes.srcdoc "<script>window.parent.document.body.append('[Injected 1]')</script>" ] []
        , Html.iframe [ Html.Attributes.property "srcdoc" (Json.Encode.string "<script>window.parent.document.body.append('[Injected 2]')</script>") ] []
        , Html.iframe [ Html.Attributes.attribute "srcdoc" "<script>window.parent.document.body.append('[Injected 3]')</script>" ] []
        , Html.iframe [ Html.Attributes.attribute "SRCDOC" "<script>window.parent.document.body.append('[Injected 4]')</script>" ] []
        , Html.iframe [ Html.Attributes.attribute "SrcDoc" "<script>window.parent.document.body.append('[Injected 5]')</script>" ] []

        -- Test of the custom element documented in: https://github.com/elm/html/pull/281
        , Html.node "my-iframe"
            (case customElementState of
                Srcdoc1 ->
                    [ Html.Attributes.attribute "html" "<elm>Hello 1</em><script>window.parent.document.body.append('[Injected 6]')</script>" ]

                Srcdoc2 ->
                    [ Html.Attributes.attribute "html" "<elm>Hello 2</em>" ]

                NoSrcdoc ->
                    []
            )
            []
        , Html.button [ Html.Events.onClick () ] [ Html.text "Cycle my-iframe content" ]
        ]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Iframe's srcDoc allow arbitrary scripts which can result in unsafe packages published

1 participant