<?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: Armaan Saxena</title>
    <description>The latest articles on DEV Community by Armaan Saxena (@armaan_saxena_d0e2d40c14e).</description>
    <link>https://dev.to/armaan_saxena_d0e2d40c14e</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%2F3765797%2Faade80c5-64ee-4315-8dc9-18e6d9429681.png</url>
      <title>DEV Community: Armaan Saxena</title>
      <link>https://dev.to/armaan_saxena_d0e2d40c14e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/armaan_saxena_d0e2d40c14e"/>
    <language>en</language>
    <item>
      <title>Title: Hardening Open Source Apps: Preventing Stored XSS in User-Injected Code</title>
      <dc:creator>Armaan Saxena</dc:creator>
      <pubDate>Wed, 11 Feb 2026 08:33:30 +0000</pubDate>
      <link>https://dev.to/armaan_saxena_d0e2d40c14e/title-hardening-open-source-apps-preventing-stored-xss-in-user-injected-code-39ok</link>
      <guid>https://dev.to/armaan_saxena_d0e2d40c14e/title-hardening-open-source-apps-preventing-stored-xss-in-user-injected-code-39ok</guid>
      <description>&lt;h2&gt;
  
  
  The Challenge: Flexibility vs. Security
&lt;/h2&gt;

&lt;p&gt;In the world of monitoring tools and status pages, branding is everything. Users want the ability to inject custom CSS for their brand colors, custom HTML for their footers, and JavaScript for third-party analytics like Google Tag Manager or Intercom.&lt;/p&gt;

&lt;p&gt;However, as a developer, this creates a massive security headache: &lt;strong&gt;Stored Cross-Site Scripting (XSS).&lt;/strong&gt; If an admin account is compromised, or if a platform is multi-tenant, allowing a user to save raw &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags or unsanitized HTML can lead to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session Hijacking:&lt;/strong&gt; Stealing login cookies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Exfiltration:&lt;/strong&gt; Sending sensitive user data to an attacker's server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phishing:&lt;/strong&gt; Injecting fake login forms over the legitimate UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Solution: A Layered Defense
&lt;/h2&gt;

&lt;p&gt;While working on a major feature for the open-source project &lt;strong&gt;Checkmate&lt;/strong&gt;, I implemented a three-layered defense to allow customization while maintaining a high security bar.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. HTML Sanitization with DOMPurify
&lt;/h3&gt;

&lt;p&gt;React’s &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt; is the primary way to render raw HTML, but it is aptly named. To allow custom headers and footers safely, I integrated &lt;strong&gt;DOMPurify&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Before rendering any user-provided HTML, the string is passed through a sanitizer that strips out dangerous event handlers (like &lt;code&gt;onclick&lt;/code&gt; or &lt;code&gt;onerror&lt;/code&gt;) and malicious tags, while preserving safe layout elements like &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&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="c1"&gt;// Sanitizing before rendering&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; 
  &lt;span class="nx"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="o"&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;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;statusPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headerHTML&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="p"&gt;}}&lt;/span&gt; 
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Hardening CSS Injection
&lt;/h3&gt;

&lt;p&gt;CSS is often overlooked as a security vector. Malicious CSS can use &lt;code&gt;@import&lt;/code&gt; to load external scripts or &lt;code&gt;url()&lt;/code&gt; with complex selectors to exfiltrate sensitive data via background images (CSS-based keylogging).&lt;/p&gt;

&lt;p&gt;I implemented a &lt;strong&gt;Regex-based CSS Hardener&lt;/strong&gt; to block these specific patterns before the style tag is injected into the document head.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;safeCSS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;customCSS&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/url&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="sr"&gt;/gi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blocked(&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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/@import/gi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/* blocked */&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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/javascript&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*:/gi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blocked:&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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/-moz-binding&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*:/gi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blocked:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Injecting the hardened CSS&lt;/span&gt;
&lt;span class="nx"&gt;styleElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;safeCSS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. The "Risk Acceptance" UI Gate
&lt;/h3&gt;

&lt;p&gt;Security is as much about the UI as it is about the code. To prevent accidental or unauthorized script execution, I built a &lt;strong&gt;"Gatekeeper"&lt;/strong&gt; component. &lt;/p&gt;

&lt;p&gt;The JavaScript input field remains &lt;strong&gt;disabled by default&lt;/strong&gt;. To unlock it, the Admin must strictly check a &lt;strong&gt;"Risk Acceptance"&lt;/strong&gt; checkbox. This ensures that the user is making a conscious, informed decision to execute custom logic on their public page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it Matters
&lt;/h2&gt;

&lt;p&gt;In Open Source, we often prioritize features to grow the user base. But features that compromise security eventually hurt the community. By implementing these guardrails, we give users the branding power they need without leaving the door wide open for attackers.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>opensource</category>
      <category>security</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
