[{"data":1,"prerenderedAt":669},["ShallowReactive",2],{"guide-iframe-sandbox-security":3},{"id":4,"title":5,"body":6,"date":661,"description":662,"extension":663,"meta":664,"navigation":132,"path":665,"readingTime":169,"seo":666,"stem":667,"__hash__":668},"guides\u002Fguides\u002Fiframe-sandbox-security.md","Iframe Sandbox Attribute Guide",{"type":7,"value":8,"toc":654},"minimark",[9,22,27,33,70,76,205,209,212,366,370,387,394,397,434,438,443,524,533,538,576,579,584,621,624,628,641,650],[10,11,12,13,17,18,21],"p",{},"Embedding untrusted HTML in a page—whether for a live preview, a third-party widget, or user-submitted content—carries significant risk. Without restrictions, an embedded frame can redirect the parent page, access cookies, trigger downloads, or run popup windows. The ",[14,15,16],"code",{},"sandbox"," attribute on ",[14,19,20],{},"\u003Ciframe>"," elements applies the principle of least privilege, granting only the permissions an embedded document genuinely needs.",[23,24,26],"h2",{"id":25},"the-sandbox-security-model","The Sandbox Security Model",[10,28,29,30,32],{},"When you add the ",[14,31,16],{}," attribute to an iframe, the embedded document is placed under the strictest possible restrictions. It cannot:",[34,35,36,40,43,46,49,52,55],"ul",{},[37,38,39],"li",{},"Submit forms",[37,41,42],{},"Run scripts",[37,44,45],{},"Navigate the parent page",[37,47,48],{},"Access same-origin resources (cookies, localStorage, DOM)",[37,50,51],{},"Open popups or new windows",[37,53,54],{},"Trigger modal dialogs (alert, prompt, confirm)",[37,56,57,58,61,62,65,66,69],{},"Use the ",[14,59,60],{},"pointerlock",", ",[14,63,64],{},"autoplay",", or ",[14,67,68],{},"payment"," APIs",[10,71,72,73,75],{},"Every permission must be explicitly granted through a token added to the ",[14,74,16],{}," value. This deny-by-default model ensures that forgetting a restriction is safe—only forgetting to grant a permission causes functionality to break, and breakage is visible.",[77,78,83],"pre",{"className":79,"code":80,"language":81,"meta":82,"style":82},"language-html shiki shiki-themes github-light github-dark","\u003C!-- Maximum lockdown: no scripts, no forms, no navigation -->\n\u003Ciframe sandbox src=\"https:\u002F\u002Funtrusted.example.com\u002Fembed\">\u003C\u002Fiframe>\n\n\u003C!-- Allow scripts but nothing else -->\n\u003Ciframe sandbox=\"allow-scripts\" src=\"\u002Fpreview\u002Fuser-code\">\u003C\u002Fiframe>\n\n\u003C!-- Allow scripts and same-origin access -->\n\u003Ciframe sandbox=\"allow-scripts allow-same-origin\" src=\"\u002Fwidget\">\u003C\u002Fiframe>\n","html","",[14,84,85,94,127,134,140,167,172,178],{"__ignoreMap":82},[86,87,90],"span",{"class":88,"line":89},"line",1,[86,91,93],{"class":92},"sJ8bj","\u003C!-- Maximum lockdown: no scripts, no forms, no navigation -->\n",[86,95,97,101,105,109,112,115,119,122,124],{"class":88,"line":96},2,[86,98,100],{"class":99},"sVt8B","\u003C",[86,102,104],{"class":103},"s9eBZ","iframe",[86,106,108],{"class":107},"sScJk"," sandbox",[86,110,111],{"class":107}," src",[86,113,114],{"class":99},"=",[86,116,118],{"class":117},"sZZnC","\"https:\u002F\u002Funtrusted.example.com\u002Fembed\"",[86,120,121],{"class":99},">\u003C\u002F",[86,123,104],{"class":103},[86,125,126],{"class":99},">\n",[86,128,130],{"class":88,"line":129},3,[86,131,133],{"emptyLinePlaceholder":132},true,"\n",[86,135,137],{"class":88,"line":136},4,[86,138,139],{"class":92},"\u003C!-- Allow scripts but nothing else -->\n",[86,141,143,145,147,149,151,154,156,158,161,163,165],{"class":88,"line":142},5,[86,144,100],{"class":99},[86,146,104],{"class":103},[86,148,108],{"class":107},[86,150,114],{"class":99},[86,152,153],{"class":117},"\"allow-scripts\"",[86,155,111],{"class":107},[86,157,114],{"class":99},[86,159,160],{"class":117},"\"\u002Fpreview\u002Fuser-code\"",[86,162,121],{"class":99},[86,164,104],{"class":103},[86,166,126],{"class":99},[86,168,170],{"class":88,"line":169},6,[86,171,133],{"emptyLinePlaceholder":132},[86,173,175],{"class":88,"line":174},7,[86,176,177],{"class":92},"\u003C!-- Allow scripts and same-origin access -->\n",[86,179,181,183,185,187,189,192,194,196,199,201,203],{"class":88,"line":180},8,[86,182,100],{"class":99},[86,184,104],{"class":103},[86,186,108],{"class":107},[86,188,114],{"class":99},[86,190,191],{"class":117},"\"allow-scripts allow-same-origin\"",[86,193,111],{"class":107},[86,195,114],{"class":99},[86,197,198],{"class":117},"\"\u002Fwidget\"",[86,200,121],{"class":99},[86,202,104],{"class":103},[86,204,126],{"class":99},[23,206,208],{"id":207},"sandbox-token-reference","Sandbox Token Reference",[10,210,211],{},"Each token grants a specific capability. Combine multiple tokens as a space-separated list.",[213,214,215,231],"table",{},[216,217,218],"thead",{},[219,220,221,225,228],"tr",{},[222,223,224],"th",{},"Token",[222,226,227],{},"Grants",[222,229,230],{},"Risk Level",[232,233,234,248,261,274,291,304,316,329,342,354],"tbody",{},[219,235,236,242,245],{},[237,238,239],"td",{},[14,240,241],{},"allow-scripts",[237,243,244],{},"JavaScript execution",[237,246,247],{},"High — scripts combined with same-origin can escape the sandbox",[219,249,250,255,258],{},[237,251,252],{},[14,253,254],{},"allow-same-origin",[237,256,257],{},"Access to parent's cookies and storage",[237,259,260],{},"High — see warning below",[219,262,263,268,271],{},[237,264,265],{},[14,266,267],{},"allow-forms",[237,269,270],{},"Form submission",[237,272,273],{},"Medium — forms can send data to external servers",[219,275,276,281,288],{},[237,277,278],{},[14,279,280],{},"allow-popups",[237,282,283,284,287],{},"Opening ",[14,285,286],{},"window.open"," links",[237,289,290],{},"Medium — popups escape sandbox restrictions",[219,292,293,298,301],{},[237,294,295],{},[14,296,297],{},"allow-popups-to-escape-sandbox",[237,299,300],{},"Popups inherit parent privileges",[237,302,303],{},"Low — popups get full permissions",[219,305,306,311,313],{},[237,307,308],{},[14,309,310],{},"allow-top-navigation",[237,312,45],{},[237,314,315],{},"High — can redirect users away",[219,317,318,323,326],{},[237,319,320],{},[14,321,322],{},"allow-top-navigation-by-user-activation",[237,324,325],{},"Navigate parent only on user click",[237,327,328],{},"Medium — safer than unrestricted navigation",[219,330,331,336,339],{},[237,332,333],{},[14,334,335],{},"allow-downloads",[237,337,338],{},"Download files",[237,340,341],{},"Low",[219,343,344,349,352],{},[237,345,346],{},[14,347,348],{},"allow-modals",[237,350,351],{},"Use alert\u002Fconfirm\u002Fprompt",[237,353,341],{},[219,355,356,361,364],{},[237,357,358],{},[14,359,360],{},"allow-presentation",[237,362,363],{},"Use Presentation API",[237,365,341],{},[23,367,369],{"id":368},"the-scripts-same-origin-trap","The Scripts + Same-Origin Trap",[10,371,372,373,383,384,386],{},"The most critical security consideration: ",[374,375,376,377,379,380,382],"strong",{},"never combine ",[14,378,241],{}," and ",[14,381,254],{}," on the same iframe that loads untrusted content."," When both tokens are present, the embedded document can use JavaScript to remove its own ",[14,385,16],{}," attribute from the parent's DOM, effectively escaping all restrictions.",[10,388,389,390,393],{},"This combination is safe only when the embedded content is fully trusted (such as a same-domain widget) or when the iframe's ",[14,391,392],{},"src"," is a data URI or blob URL that has no origin to align with the parent.",[10,395,396],{},"For HTML preview tools—the exact use case that demands both tokens—you must use additional defenses:",[34,398,399,415,428],{},[37,400,401,408,409,411,412,414],{},[374,402,403,404,407],{},"Set the iframe's ",[14,405,406],{},"srcdoc"," attribute"," instead of a URL. Content in ",[14,410,406],{}," is treated as a unique opaque origin that never matches the parent, even with ",[14,413,254],{},".",[37,416,417,420,421,424,425,414],{},[374,418,419],{},"Use a separate subdomain"," with its own origin. Serve preview content from ",[14,422,423],{},"preview.yourapp.com"," while the parent runs on ",[14,426,427],{},"app.yourapp.com",[37,429,430,433],{},[374,431,432],{},"Deploy Content Security Policy (CSP)"," headers within the iframe to further restrict script behavior.",[23,435,437],{"id":436},"practical-examples","Practical Examples",[10,439,440],{},[374,441,442],{},"Secure live preview for a code playground:",[77,444,446],{"className":79,"code":445,"language":81,"meta":82,"style":82},"\u003Ciframe\n  sandbox=\"allow-scripts\"\n  srcdoc=\"\u003Chtml>\u003Cbody>\u003Ch1>Hello\u003C\u002Fh1>\u003Cscript>document.body.style.color='red'\u003C\u002Fscript>\u003C\u002Fbody>\u003C\u002Fhtml>\"\n>\u003C\u002Fiframe>\n",[14,447,448,455,465,516],{"__ignoreMap":82},[86,449,450,452],{"class":88,"line":89},[86,451,100],{"class":99},[86,453,454],{"class":103},"iframe\n",[86,456,457,460,462],{"class":88,"line":96},[86,458,459],{"class":107},"  sandbox",[86,461,114],{"class":99},[86,463,464],{"class":117},"\"allow-scripts\"\n",[86,466,467,470,472,475,478,481,483,486,488,491,493,496,498,501,503,506,508,511,513],{"class":88,"line":129},[86,468,469],{"class":107},"  srcdoc",[86,471,114],{"class":99},[86,473,474],{"class":117},"\"",[86,476,100],{"class":477},"s7hpK",[86,479,480],{"class":117},"html>",[86,482,100],{"class":477},[86,484,485],{"class":117},"body>",[86,487,100],{"class":477},[86,489,490],{"class":117},"h1>Hello",[86,492,100],{"class":477},[86,494,495],{"class":117},"\u002Fh1>",[86,497,100],{"class":477},[86,499,500],{"class":117},"script>document.body.style.color='red'",[86,502,100],{"class":477},[86,504,505],{"class":117},"\u002Fscript>",[86,507,100],{"class":477},[86,509,510],{"class":117},"\u002Fbody>",[86,512,100],{"class":477},[86,514,515],{"class":117},"\u002Fhtml>\"\n",[86,517,518,520,522],{"class":88,"line":136},[86,519,121],{"class":99},[86,521,104],{"class":103},[86,523,126],{"class":99},[10,525,526,527,529,530,532],{},"Here, ",[14,528,406],{}," ensures the content has a unique origin. Scripts run but cannot access the parent page. No ",[14,531,254],{}," token is needed.",[10,534,535],{},[374,536,537],{},"Embedding a trusted internal widget:",[77,539,541],{"className":79,"code":540,"language":81,"meta":82,"style":82},"\u003Ciframe\n  sandbox=\"allow-scripts allow-same-origin allow-forms\"\n  src=\"\u002Fwidgets\u002Fanalytics-dashboard\"\n>\u003C\u002Fiframe>\n",[14,542,543,549,558,568],{"__ignoreMap":82},[86,544,545,547],{"class":88,"line":89},[86,546,100],{"class":99},[86,548,454],{"class":103},[86,550,551,553,555],{"class":88,"line":96},[86,552,459],{"class":107},[86,554,114],{"class":99},[86,556,557],{"class":117},"\"allow-scripts allow-same-origin allow-forms\"\n",[86,559,560,563,565],{"class":88,"line":129},[86,561,562],{"class":107},"  src",[86,564,114],{"class":99},[86,566,567],{"class":117},"\"\u002Fwidgets\u002Fanalytics-dashboard\"\n",[86,569,570,572,574],{"class":88,"line":136},[86,571,121],{"class":99},[86,573,104],{"class":103},[86,575,126],{"class":99},[10,577,578],{},"Safe because the source is same-origin and fully controlled.",[10,580,581],{},[374,582,583],{},"Embedding a third-party video player:",[77,585,587],{"className":79,"code":586,"language":81,"meta":82,"style":82},"\u003Ciframe\n  sandbox=\"allow-scripts allow-presentation\"\n  src=\"https:\u002F\u002Fvideos.example.com\u002Fembed\u002Fabc123\"\n>\u003C\u002Fiframe>\n",[14,588,589,595,604,613],{"__ignoreMap":82},[86,590,591,593],{"class":88,"line":89},[86,592,100],{"class":99},[86,594,454],{"class":103},[86,596,597,599,601],{"class":88,"line":96},[86,598,459],{"class":107},[86,600,114],{"class":99},[86,602,603],{"class":117},"\"allow-scripts allow-presentation\"\n",[86,605,606,608,610],{"class":88,"line":129},[86,607,562],{"class":107},[86,609,114],{"class":99},[86,611,612],{"class":117},"\"https:\u002F\u002Fvideos.example.com\u002Fembed\u002Fabc123\"\n",[86,614,615,617,619],{"class":88,"line":136},[86,616,121],{"class":99},[86,618,104],{"class":103},[86,620,126],{"class":99},[10,622,623],{},"Scripts run for playback, but no forms, no navigation, no same-origin access.",[23,625,627],{"id":626},"testing-your-sandbox-configuration","Testing Your Sandbox Configuration",[10,629,630,631,61,634,637,638,640],{},"Always test sandbox configurations with deliberate escape attempts. Create a test page that tries ",[14,632,633],{},"parent.document",[14,635,636],{},"top.location.href",", and ",[14,639,286],{}," to verify that restrictions hold. Browser developer tools show the active sandbox flags in the iframe's security properties.",[10,642,643,644,649],{},"For quick sandbox attribute generation and testing, the ",[645,646,648],"a",{"href":647},"\u002Ftools\u002Fhtml-preview","HTML Preview tool"," renders code snippets in a sandboxed environment with configurable permissions.",[651,652,653],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7hpK, html code.shiki .s7hpK{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}",{"title":82,"searchDepth":96,"depth":96,"links":655},[656,657,658,659,660],{"id":25,"depth":96,"text":26},{"id":207,"depth":96,"text":208},{"id":368,"depth":96,"text":369},{"id":436,"depth":96,"text":437},{"id":626,"depth":96,"text":627},"2026-05-28","Understanding sandbox restrictions for secure HTML preview and embedded content.","md",{},"\u002Fguides\u002Fiframe-sandbox-security",{"title":5,"description":662},"guides\u002Fiframe-sandbox-security","8c3YyKdU6-awMyc5Bm0cPUgQxGAhmgAq1mQzCWTv3rA",1780401334552]