<?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: Rishi</title>
    <description>The latest articles on DEV Community by Rishi (@rishi-hustler).</description>
    <link>https://dev.to/rishi-hustler</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%2F3684576%2F80e36486-6eda-47a9-b4f2-837fab12f7f8.png</url>
      <title>DEV Community: Rishi</title>
      <link>https://dev.to/rishi-hustler</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rishi-hustler"/>
    <language>en</language>
    <item>
      <title>Supply Chain Attack</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Tue, 30 Dec 2025 04:45:23 +0000</pubDate>
      <link>https://dev.to/rishi-hustler/supply-chain-attack-p01</link>
      <guid>https://dev.to/rishi-hustler/supply-chain-attack-p01</guid>
      <description>&lt;h2&gt;
  
  
  🏗️ Phase 1: The Anatomy of the Target
&lt;/h2&gt;

&lt;p&gt;In modern web development, we rarely write everything from scratch. We stand on the shoulders of "transitive dependencies."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Direct Dependency:&lt;/strong&gt; You install &lt;code&gt;useful-auth-lib&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transitive Dependency:&lt;/strong&gt; &lt;code&gt;useful-auth-lib&lt;/code&gt; depends on &lt;code&gt;small-string-helper&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Hidden Risk:&lt;/strong&gt; You might only have 10 packages in your &lt;code&gt;package.json&lt;/code&gt;, but your &lt;code&gt;node_modules&lt;/code&gt; folder contains 800+ packages. &lt;strong&gt;You are only as secure as the weakest link in that chain of 800.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🕵️ Phase 2: The Attack - "The Long Game"
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Target Selection
&lt;/h3&gt;

&lt;p&gt;The attacker doesn't target a massive library like &lt;em&gt;React&lt;/em&gt; (too many eyes). Instead, they find a &lt;strong&gt;"Deep Dependency"&lt;/strong&gt;—a small utility library that hasn't been updated in a year but is used by thousands of other popular packages.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Social Engineering (The "Trojan Horse")
&lt;/h3&gt;

&lt;p&gt;The attacker, using a fake but professional-looking GitHub profile, begins contributing helpful, legitimate code to the repository.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They fix a typo.&lt;/li&gt;
&lt;li&gt;They improve documentation.&lt;/li&gt;
&lt;li&gt;They optimize a loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result:&lt;/strong&gt; The original, overworked maintainer eventually grants them "Maintainer" status or "Publish" rights to the npm registry to help share the workload.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. The Injection
&lt;/h3&gt;

&lt;p&gt;The attacker releases version &lt;code&gt;v3.4.2&lt;/code&gt;. They ensure the code on &lt;strong&gt;GitHub&lt;/strong&gt; looks clean, but the code published to the &lt;strong&gt;npm registry&lt;/strong&gt; contains the malicious payload.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;br&gt;
&lt;strong&gt;Key Insight:&lt;/strong&gt; npm does not verify that the code in the &lt;code&gt;.tgz&lt;/code&gt; file on their registry matches the code in the GitHub repository. This is where the backdoor lives.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🚀 Phase 3: The Execution Flow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: The Automated Update
&lt;/h3&gt;

&lt;p&gt;A developer at a large FinTech firm runs a routine command to clear a vulnerability flag or add a new feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm update

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because of the &lt;strong&gt;Caret (^) symbol&lt;/strong&gt; in &lt;code&gt;package.json&lt;/code&gt; (e.g., &lt;code&gt;"small-string-helper": "^3.4.0"&lt;/code&gt;), npm automatically pulls the malicious &lt;code&gt;v3.4.2&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: The Lifecycle Hook
&lt;/h3&gt;

&lt;p&gt;The attacker uses npm "Lifecycle Scripts." In the malicious package's &lt;code&gt;package.json&lt;/code&gt;, they add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"postinstall"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node ./scripts/init.js"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The moment &lt;code&gt;npm install&lt;/code&gt; finishes, &lt;code&gt;init.js&lt;/code&gt; runs automatically with the &lt;strong&gt;same permissions&lt;/strong&gt; as the developer or the build server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Environment Fingerprinting
&lt;/h3&gt;

&lt;p&gt;The script doesn't attack immediately. It "fingerprints" the environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Is this a CI/CD server?&lt;/strong&gt; (Checks for variables like &lt;code&gt;GITHUB_ACTIONS&lt;/code&gt; or &lt;code&gt;JENKINS_URL&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does it have high-value targets?&lt;/strong&gt; (Looks for &lt;code&gt;.aws/credentials&lt;/code&gt;, &lt;code&gt;.env&lt;/code&gt; files, or &lt;code&gt;id_rsa&lt;/code&gt; SSH keys).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is it a production environment?&lt;/strong&gt; (Checks &lt;code&gt;NODE_ENV === 'production'&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: The Backdoor &amp;amp; Exfiltration
&lt;/h3&gt;

&lt;p&gt;If the conditions are right, the script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Injects a snippet&lt;/strong&gt; into the main application code that intercepts login forms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Opens a Reverse Shell:&lt;/strong&gt; It connects back to the attacker's server, allowing them to execute commands on your server remotely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Steals Secrets:&lt;/strong&gt; It sends your &lt;code&gt;.env&lt;/code&gt; variables to a remote API.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🛡️ Phase 4: The Modern Defense Strategy
&lt;/h2&gt;

&lt;p&gt;To combat this, a simple &lt;code&gt;npm audit&lt;/code&gt; is no longer enough. You need a multi-layered defense.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Dependency Pinning &amp;amp; Lockfiles
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lockfiles:&lt;/strong&gt; Always commit &lt;code&gt;package-lock.json&lt;/code&gt;. It forces the exact version and &lt;strong&gt;verifies the hash (integrity)&lt;/strong&gt; of the package to ensure it hasn't been tampered with since the last install.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pinning:&lt;/strong&gt; For high-security projects, use exact versions (e.g., &lt;code&gt;"library": "1.2.3"&lt;/code&gt;) instead of ranges (&lt;code&gt;^1.2.3&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Specialized Auditing Tools
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;npm audit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Basic check against known CVEs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Snyk / Socket.dev&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Analyzes the &lt;em&gt;behavior&lt;/em&gt; of code (e.g., "Why is this CSS library asking for network access?").&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;StepSecurity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Monitors CI/CD pipelines to see if they try to connect to unknown IP addresses.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  3. Network Isolation
&lt;/h3&gt;

&lt;p&gt;Run your build processes in a network-restricted environment. A build script should &lt;strong&gt;never&lt;/strong&gt; need to send data to an unknown external IP address in Russia or North Korea.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. SBOM (Software Bill of Materials)
&lt;/h3&gt;

&lt;p&gt;Generate an SBOM for every release. This is a comprehensive inventory of every piece of software used, making it easier to identify if a newly discovered vulnerability affects you.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 The Takeaway
&lt;/h2&gt;

&lt;p&gt;In the world of npm, you aren't just importing code; &lt;strong&gt;you are importing the security practices of every developer in your dependency tree.&lt;/strong&gt; Dependency auditing isn't a one-time task; it's a continuous process of verifying trust.&lt;/p&gt;

</description>
      <category>supplychain</category>
      <category>webdev</category>
      <category>attacks</category>
    </item>
    <item>
      <title>CORS: The Developer’s Nightmare: A Scenario-Based Guide to Fixing it Without *</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Mon, 29 Dec 2025 15:31:33 +0000</pubDate>
      <link>https://dev.to/rishi-hustler/cors-the-developers-nightmare-a-scenario-based-guide-to-fixing-it-without--2d3g</link>
      <guid>https://dev.to/rishi-hustler/cors-the-developers-nightmare-a-scenario-based-guide-to-fixing-it-without--2d3g</guid>
      <description>&lt;h2&gt;
  
  
  CORS: The Developer’s Nightmare: A Scenario-Based Guide to Fixing it Without &lt;code&gt;*&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;We’ve all been there. You’ve spent hours perfecting your Node.js API and your React frontend. You trigger your first &lt;code&gt;fetch()&lt;/code&gt; request, and instead of data, you get a wall of red text in the console:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Access to fetch at '&lt;a href="https://www.google.com/search?q=api.mysite.com" rel="noopener noreferrer"&gt;https://www.google.com/search?q=api.mysite.com&lt;/a&gt;' from origin 'mysite.com' has been blocked by CORS policy..."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a moment of frustration, many developers reach for the "nuclear option": setting &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; to &lt;code&gt;*&lt;/code&gt;. While this makes the error go away, it’s the security equivalent of leaving your front door wide open because the lock was sticking.&lt;/p&gt;

&lt;p&gt;Here is how to navigate the most common CORS nightmares like a pro.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is CORS actually doing?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cross-Origin Resource Sharing (CORS)&lt;/strong&gt; is not a bug; it is a browser security feature. It prevents a malicious website from making requests to your API on behalf of a user.&lt;/p&gt;

&lt;p&gt;The browser uses a &lt;strong&gt;Preflight Request&lt;/strong&gt; (an &lt;code&gt;OPTIONS&lt;/code&gt; call) to ask the server: "Hey, is this domain allowed to talk to you?" If the server doesn't explicitly say "Yes," the browser kills the request.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scenario 1: The "I have multiple environments" Problem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Setup:&lt;/strong&gt; You have a local development server (&lt;code&gt;localhost:3000&lt;/code&gt;), a staging site, and a production site. You need all of them to access your API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Wrong Fix:&lt;/strong&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="c1"&gt;// Hardcoding one domain breaks the others&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://mysite.com&lt;/span&gt;&lt;span class="dl"&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;strong&gt;The Pro Fix:&lt;/strong&gt;&lt;br&gt;
Create a "Whitelist" and check the incoming &lt;code&gt;Origin&lt;/code&gt; header against it.&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;whitelist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://staging.mysite.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://mysite.com&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;corsOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;whitelist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not allowed by CORS&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="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;em&gt;Note: &lt;code&gt;!origin&lt;/code&gt; allows tools like Postman or server-to-server requests to still function.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Scenario 2: The "I need to send Cookies" Problem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Setup:&lt;/strong&gt; You are using &lt;code&gt;credentials: 'include'&lt;/code&gt; in your fetch request because you need to send session cookies or HttpOnly JWTs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Nightmare:&lt;/strong&gt; When you use &lt;code&gt;credentials&lt;/code&gt;, the browser &lt;strong&gt;strictly forbids&lt;/strong&gt; the use of &lt;code&gt;*&lt;/code&gt;. If you try it, the request will fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt; 1.  &lt;strong&gt;Reflect the Origin:&lt;/strong&gt; You must echo back the specific origin of the requester.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Allow Credentials:&lt;/strong&gt; Set the &lt;code&gt;Access-Control-Allow-Credentials&lt;/code&gt; header to &lt;code&gt;true&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example in Express.js&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://mysite.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Scenario 3: The "Custom Headers" Problem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Setup:&lt;/strong&gt; You are sending a custom header for tracking or versioning, such as &lt;code&gt;X-API-Version: v1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Nightmare:&lt;/strong&gt; Even if the origin is allowed, the browser will block the request because it considers &lt;code&gt;X-API-Version&lt;/code&gt; a "non-standard" header.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt;&lt;br&gt;
You must explicitly tell the browser that this specific header is safe to read.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Access-Control-Allow-Headers: Content-Type, Authorization, X-API-Version

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Summary Checklist: Fixing CORS the Right Way
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Why?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Check the trailing slash&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;https://mysite.com&lt;/code&gt; and &lt;code&gt;https://mysite.com/&lt;/code&gt; are different origins.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Match the Protocol&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;http&lt;/code&gt; and &lt;code&gt;https&lt;/code&gt; are not the same in the eyes of CORS.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Verify Port Numbers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;localhost:3000&lt;/code&gt; is a different origin than &lt;code&gt;localhost:4000&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use a Middleware&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Use established libraries like the &lt;code&gt;cors&lt;/code&gt; npm package instead of manual headers to avoid typos.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The Ultimate Rule
&lt;/h2&gt;

&lt;p&gt;CORS is a &lt;strong&gt;browser-only&lt;/strong&gt; concept. If you are still seeing "Access Blocked" after following these steps, check your server-side logs. Sometimes a 500 Internal Server Error on your API causes the CORS headers not to be sent, leading the browser to report a CORS error instead of the actual backend crash.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>CSRF in the Modern Era: Do you actually need tokens in a decoupled React/Node app?</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Mon, 29 Dec 2025 15:09:42 +0000</pubDate>
      <link>https://dev.to/rishi-hustler/csrf-in-the-modern-era-do-you-actually-need-tokens-in-a-decoupled-reactnode-app-e5p</link>
      <guid>https://dev.to/rishi-hustler/csrf-in-the-modern-era-do-you-actually-need-tokens-in-a-decoupled-reactnode-app-e5p</guid>
      <description>&lt;h2&gt;
  
  
  CSRF in the Modern Era: Do you actually need tokens in a decoupled React/Node app?
&lt;/h2&gt;

&lt;p&gt;For years, the &lt;strong&gt;Cross-Site Request Forgery (CSRF)&lt;/strong&gt; token was the gold standard of web security. Every tutorial told you the same thing: if you have a form, you need a hidden &lt;code&gt;_csrf&lt;/code&gt; token.&lt;/p&gt;

&lt;p&gt;But as the web shifted from monolithic PHP or Rails apps to decoupled architectures—think a &lt;strong&gt;React/Vue&lt;/strong&gt; frontend talking to a &lt;strong&gt;Node/Python&lt;/strong&gt; API—the conversation changed. With the rise of &lt;code&gt;SameSite&lt;/code&gt; cookie attributes and the decline of traditional session cookies, many developers are asking: &lt;strong&gt;Is the CSRF token a relic of the past?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The short answer: &lt;strong&gt;It depends on how you handle your cookies.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What is CSRF anyway? (The Quick Refresh)
&lt;/h2&gt;

&lt;p&gt;CSRF is an attack that tricks a victim's browser into performing an unwanted action on a different website where the victim is currently authenticated.&lt;/p&gt;

&lt;p&gt;Imagine you are logged into &lt;code&gt;your-bank.com&lt;/code&gt;. You then visit a malicious site that has a hidden form:&lt;br&gt;
&lt;code&gt;&amp;lt;form action="https://your-bank.com/transfer" method="POST"&amp;gt;&lt;/code&gt;.&lt;br&gt;
As soon as you land on the page, the form submits. Because your browser automatically attaches your session cookies to requests sent to &lt;code&gt;your-bank.com&lt;/code&gt;, the bank thinks &lt;em&gt;you&lt;/em&gt; initiated the transfer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The "Modern" Shield: &lt;code&gt;SameSite&lt;/code&gt; Cookies
&lt;/h2&gt;

&lt;p&gt;The reason many claim CSRF is "dead" is the widespread adoption of the &lt;code&gt;SameSite&lt;/code&gt; cookie attribute. This tells the browser whether to send cookies with cross-site requests.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;SameSite=Strict&lt;/code&gt;&lt;/strong&gt;: Cookies are only sent if the request originates from the same site where the cookie was set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;SameSite=Lax&lt;/code&gt;&lt;/strong&gt;: (The modern browser default) Cookies are withheld on cross-site subrequests (like images or frames) but sent when a user navigates to the URL (like clicking a link).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If all modern browsers use &lt;code&gt;SameSite=Lax&lt;/code&gt; by default, why bother with tokens?&lt;/strong&gt; Because "Lax" still allows cookies to be sent on top-level &lt;code&gt;GET&lt;/code&gt; requests. While &lt;code&gt;GET&lt;/code&gt; requests &lt;em&gt;should&lt;/em&gt; be idempotent (read-only), a poorly designed API that allows state changes via &lt;code&gt;GET&lt;/code&gt; remains vulnerable. Furthermore, older browsers don't support &lt;code&gt;SameSite&lt;/code&gt;, leaving those users exposed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Decoupled Apps: JWTs vs. Cookies
&lt;/h2&gt;

&lt;p&gt;In a React/Node environment, your vulnerability depends entirely on your &lt;strong&gt;Authentication Strategy&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario A: You use Cookies (The Risk)
&lt;/h3&gt;

&lt;p&gt;If your Node.js API sends a &lt;code&gt;Set-Cookie&lt;/code&gt; header to store a session ID or a JWT in the browser's cookie storage, &lt;strong&gt;you are vulnerable to CSRF.&lt;/strong&gt; Even with a decoupled React frontend, the browser will try to attach that cookie to any request made to your API domain.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Verdict:&lt;/strong&gt; You &lt;strong&gt;DO&lt;/strong&gt; still need CSRF protection (tokens or Double Submit Cookies).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Scenario B: You use LocalStorage/SessionStorage (The Trade-off)
&lt;/h3&gt;

&lt;p&gt;If your React app stores a JWT in &lt;code&gt;localStorage&lt;/code&gt; and manually attaches it to the &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt; header, &lt;strong&gt;you are immune to CSRF.&lt;/strong&gt; Browsers do not automatically attach headers; they only automatically attach cookies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Catch:&lt;/strong&gt; While you solved CSRF, you opened the door to &lt;strong&gt;XSS (Cross-Site Scripting)&lt;/strong&gt;. If an attacker runs a malicious script on your page, they can steal that token from &lt;code&gt;localStorage&lt;/code&gt; instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verdict:&lt;/strong&gt; You don't need CSRF tokens, but your security risk has simply shifted elsewhere.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Modern Solution: The "Double Submit Cookie"
&lt;/h2&gt;

&lt;p&gt;If you want the security of &lt;code&gt;HttpOnly&lt;/code&gt; cookies (to prevent XSS) but don't want the overhead of managing CSRF tokens in a database on the server, the &lt;strong&gt;Double Submit Cookie&lt;/strong&gt; pattern is the industry favorite for React/Node apps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the user logs in, the server sends a random string in a &lt;strong&gt;non-HttpOnly&lt;/strong&gt; cookie (e.g., &lt;code&gt;csrf-token&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The React app reads this cookie using JavaScript.&lt;/li&gt;
&lt;li&gt;For every "state-changing" request (POST/PUT/DELETE), React sends that string back in a custom HTTP header (e.g., &lt;code&gt;X-XSRF-TOKEN&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The server compares the cookie value with the header value. An attacker can't do this because they can't read your cookies from a different domain (thanks to the &lt;strong&gt;Same-Origin Policy&lt;/strong&gt;).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Checklist
&lt;/h2&gt;

&lt;p&gt;Do you need CSRF tokens in your React/Node app?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;YES&lt;/strong&gt; if you use &lt;strong&gt;Cookies&lt;/strong&gt; for authentication (even with &lt;code&gt;SameSite=Lax&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NO&lt;/strong&gt; if you use &lt;strong&gt;Bearer Tokens&lt;/strong&gt; stored in &lt;code&gt;localStorage&lt;/code&gt; (but be careful of XSS!).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NO&lt;/strong&gt; if your API is strictly consumed by non-browser clients (Mobile apps, IoT).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RECOMMENDED&lt;/strong&gt; if you want "Defense in Depth" to protect users on older browsers.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>discuss</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Silent Leak: Why Sensitive Data Masking is Your Most Critical Log Strategy</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Mon, 29 Dec 2025 15:07:25 +0000</pubDate>
      <link>https://dev.to/rishi-hustler/the-silent-leak-why-sensitive-data-masking-is-your-most-critical-log-strategy-36gb</link>
      <guid>https://dev.to/rishi-hustler/the-silent-leak-why-sensitive-data-masking-is-your-most-critical-log-strategy-36gb</guid>
      <description>&lt;h2&gt;
  
  
  The Silent Leak: Why Sensitive Data Masking is Your Most Critical Log Strategy
&lt;/h2&gt;

&lt;p&gt;Imagine your security team receives an alert: a high-priority production bug is causing system crashes. Your lead developer dives into the logs to find the root cause. They find the error, but they also find something else—thousands of rows containing customer email addresses, plain-text phone numbers, and home addresses.&lt;/p&gt;

&lt;p&gt;Suddenly, your debugging session has turned into a &lt;strong&gt;data breach report.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the era of GDPR, CCPA, and skyrocketing cyber-attacks, logs are no longer just "developer notes." They are high-risk assets. Here is how to ensure your PII (Personally Identifiable Information) stays where it belongs: encrypted in your database, and far away from your monitoring tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Danger of "Log Everything"
&lt;/h2&gt;

&lt;p&gt;For years, the mantra in software engineering was "log everything, sort it out later." While great for troubleshooting, this approach creates several critical vulnerabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Shadow Database:&lt;/strong&gt; Your logs become a secondary, unencrypted repository of user data that often bypasses the strict access controls of your primary database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance Nightmares:&lt;/strong&gt; Under regulations like GDPR, "the right to be forgotten" becomes impossible if a user's data is scattered across millions of log lines in a third-party tool like Datadog or Splunk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal Insider Threats:&lt;/strong&gt; Developers and QA engineers who don't need access to PII often have full access to log management platforms.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Strategies for Bulletproof Data Masking
&lt;/h2&gt;

&lt;p&gt;Protecting your logs requires a multi-layered defense. You shouldn't rely on just one method; you should catch data at every possible exit point.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Interception at the Application Level
&lt;/h3&gt;

&lt;p&gt;The most effective way to mask data is to never let it leave the application. Most modern logging frameworks (like Log4j for Java, Serilog for .NET, or Winston for Node.js) allow for &lt;strong&gt;custom layout patterns&lt;/strong&gt; or &lt;strong&gt;interceptors&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; You define a "masking provider" that scans every log message for patterns matching emails or phone numbers and replaces them with &lt;code&gt;[MASKED]&lt;/code&gt; or a SHA-256 hash before the string is written to the stream.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Regex-Based Pattern Matching
&lt;/h3&gt;

&lt;p&gt;Regular Expressions (Regex) are your best friend for identifying structured data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Emails:&lt;/strong&gt; &lt;code&gt;[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phone Numbers:&lt;/strong&gt; &lt;code&gt;(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; Don't just delete the data. Replace it with a consistent placeholder like &lt;code&gt;user-id-4058&lt;/code&gt; so you can still track a specific user’s journey through the logs without knowing who they actually are.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Edge Gateway Scrubbing
&lt;/h3&gt;

&lt;p&gt;If you use a log aggregator (like Fluentd, Logstash, or Vector), you can set up a "scrubbing station" at the edge. This acts as a final filter before the data hits your long-term storage or third-party monitoring service. Even if a developer forgets to mask a new log line, the gateway catches it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Masking vs. Anonymization vs. Pseudonymization
&lt;/h2&gt;

&lt;p&gt;When building your strategy, it's important to know the difference in how you handle the data:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Masking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Replacing characters (e.g., &lt;code&gt;555-***-**12&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;UI displays and quick logs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Redaction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Completely removing the data (&lt;code&gt;[REDACTED]&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;High-security environments.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pseudonymization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Replacing PII with a unique key/token&lt;/td&gt;
&lt;td&gt;Debugging user-specific issues without seeing PII.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Best Practices for a "PII-Free" Culture
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Automated Scanning:&lt;/strong&gt; Use tools that scan your logs for "leaks" and alert you if a pattern resembling a Credit Card or Social Security number appears.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Reviews:&lt;/strong&gt; Make "Log Review" a standard part of your PR process. Ask: &lt;em&gt;“Does this log statement include a raw user object?”&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sanitize Exceptions:&lt;/strong&gt; Error messages often dump the state of an object. Ensure your global error handlers are configured to strip sensitive properties before logging the stack trace.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Sensitive data masking isn't just a "nice-to-have" feature; it’s a fundamental pillar of modern security architecture. By implementing automated masking early in your data pipeline, you protect your customers’ privacy, ensure regulatory compliance, and allow your developers to debug with peace of mind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep your insights sharp, but keep your data hidden.&lt;/strong&gt;&lt;/p&gt;

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