<?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: Ícaro Molinari</title>
    <description>The latest articles on DEV Community by Ícaro Molinari (@icaromol).</description>
    <link>https://dev.to/icaromol</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4068138%2Fbbe6b3f4-cbe5-41a6-ad5b-7e87390aab26.jpg</url>
      <title>DEV Community: Ícaro Molinari</title>
      <link>https://dev.to/icaromol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/icaromol"/>
    <language>en</language>
    <item>
      <title>I Turned a Dusty 2014 Lenovo Into a Two-Brained Dev + Hacker Machine (and So Can You)</title>
      <dc:creator>Ícaro Molinari</dc:creator>
      <pubDate>Thu, 20 Aug 2026 12:45:00 +0000</pubDate>
      <link>https://dev.to/icaromol/i-turned-a-dusty-2014-lenovo-into-a-two-brained-dev-hacker-machine-and-so-can-you-3jep</link>
      <guid>https://dev.to/icaromol/i-turned-a-dusty-2014-lenovo-into-a-two-brained-dev-hacker-machine-and-so-can-you-3jep</guid>
      <description>&lt;p&gt;It was dying in a drawer and I turned it into this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ONE LAPTOP
  │
  ├── 🐧 Fedora → coding, Docker, daily driver
  └── 🛡️ Kali   → pentest, security labs

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

&lt;/div&gt;



&lt;p&gt;Here's the trip: what I did, what broke, what I'd do differently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe2iiklznnm80esvnib4b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe2iiklznnm80esvnib4b.png" alt="Split-screen illustration: a blue Fedora coding setup on the left facing a red Kali Linux hacking setup on the right, the two computers merging in the middle into one login screen showing the Fedora and Kali logos" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why bother?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Full hardware access (no VM slowdown)&lt;/li&gt;
&lt;li&gt;Free — no new hardware needed&lt;/li&gt;
&lt;li&gt;Old laptops deserve a second life&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The plan
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SSD  → Kali (small) + Fedora (big, main driver)
HDD  → just files (/dados)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1 → Install Kali, partition it manually
&lt;/h2&gt;

&lt;p&gt;Guided partitioning eats the whole disk. Don't use it. Go manual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SSD
 ├── EFI   → 512 MB  → /boot/efi
 └── ext4  → rest     → /

HDD
 └── ext4  → all      → /dados
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Rules that saved me:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick disks by &lt;strong&gt;model&lt;/strong&gt;, never by name (&lt;code&gt;sda&lt;/code&gt; can change)&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;"Use as:"&lt;/strong&gt; on every partition before moving on&lt;/li&gt;
&lt;li&gt;Read the final "write to disk?" screen. Every word.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2 → Black screen on first boot
&lt;/h2&gt;

&lt;p&gt;Scary. Almost always one simple fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Boot Mode: Legacy Support ❌
      ↓
Boot Mode: UEFI Only      ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still black? Add &lt;code&gt;nomodeset&lt;/code&gt; to the boot line and try again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 → Check before you touch anything
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsblk &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;fdisk &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-hT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My Kali partition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Claimed: 447 GB
Used:    18 GB  (5%)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Huge safe gap → easy to shrink, zero risk to files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 → Install Fedora next to Kali (no wipe)
&lt;/h2&gt;

&lt;p&gt;In the installer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Use entire disk"              ❌ wipes everything
"Share disk with other OS"     ✅ this one
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It offers &lt;strong&gt;"Reclaim space"&lt;/strong&gt; — shrinks Kali live, no extra tools needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEFORE                  AFTER
Kali: 480 GB      →     Kali:   100 GB
                         Fedora: 380 GB (encrypted, new)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm screen, hit install, done in ~10 min.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 → "bad shim signature" — Kali won't boot anymore
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fedora's bootloader → trusted ✅
Kali's kernel       → not trusted ❌
      ↓
Secure Boot blocks it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; turn off Secure Boot in BIOS (Security tab). Fedora doesn't care. Kali boots again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6 → Clean up the GRUB mess
&lt;/h2&gt;

&lt;p&gt;Two distros + old kernels + recovery modes = &lt;strong&gt;8 menu entries&lt;/strong&gt;. Fix it in 2 moves:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Drop old kernels:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fedora&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf remove &lt;span class="nt"&gt;--oldinstallonly&lt;/span&gt; &lt;span class="nt"&gt;--setopt&lt;/span&gt; &lt;span class="nv"&gt;installonly_limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Kali (check exact name first!)&lt;/span&gt;
dpkg &lt;span class="nt"&gt;--list&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;linux-image
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt purge &lt;span class="nt"&gt;-y&lt;/span&gt; linux-image-OLD-VERSION+kali-amd64
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt autoremove &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;update-grub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Kill recovery-mode duplicates:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'GRUB_DISABLE_RECOVERY="true"'&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/default/grub
&lt;span class="nb"&gt;sudo &lt;/span&gt;update-grub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;8 entries → 4 entries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7 → Make it pretty + make it yours
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvinceliuice%2Fgrub2-themes%2Fmaster%2Fpreview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvinceliuice%2Fgrub2-themes%2Fmaster%2Fpreview.png" alt="Four GRUB boot menu theme previews stacked vertically - Tela, Stylish, Vimix, and WhiteSur - each showing a dark boot menu listing Arch Linux, Manjaro, Ubuntu, and Windows entries with a different colored background design" width="800" height="1951"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GRUB_TIMEOUT=-1&lt;/code&gt; → menu waits, no countdown race&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/vinceliuice/grub2-themes" rel="noopener noreferrer"&gt;grub2-themes&lt;/a&gt; → real GRUB theme in 2 commands&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hostnamectl set-hostname kali&lt;/code&gt; → fixes your terminal prompt&lt;/li&gt;
&lt;li&gt;Second keyboard layout, one toggle:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'XKBLAYOUT="br,us"'&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/default/keyboard
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'XKBOPTIONS="grp:alt_shift_toggle"'&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/default/keyboard
&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg-reconfigure &lt;span class="nt"&gt;-f&lt;/span&gt; noninteractive keyboard-configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What I'd do differently
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Check &lt;strong&gt;Secure Boot&lt;/strong&gt; before starting, not after a scary error&lt;/li&gt;
&lt;li&gt;Always &lt;code&gt;lsblk -f&lt;/code&gt; first. I got this one right — kept it that way&lt;/li&gt;
&lt;li&gt;Pick disks by &lt;strong&gt;model&lt;/strong&gt;, never by name&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Measure before you shrink&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Read every confirm screen. Every time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Got an old laptop doing nothing? This is a weekend project, not a wizard-level one. Go dig it out.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>fedora</category>
      <category>cybersecurity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Open Redirect: When a Real google.com Link Turns Malicious</title>
      <dc:creator>Ícaro Molinari</dc:creator>
      <pubDate>Tue, 18 Aug 2026 04:41:59 +0000</pubDate>
      <link>https://dev.to/icaromol/open-redirect-when-a-real-googlecom-link-turns-malicious-6mh</link>
      <guid>https://dev.to/icaromol/open-redirect-when-a-real-googlecom-link-turns-malicious-6mh</guid>
      <description>&lt;p&gt;In December 2025, Check Point's researchers flagged something odd: thousands of phishing emails landing in inboxes with a real, valid &lt;code&gt;google.com&lt;/code&gt; link inside them.&lt;/p&gt;

&lt;p&gt;Not a lookalike domain. Not a typo-squat. The actual &lt;code&gt;google.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nearly 3,200 companies got hit. Over 9,300 emails, all disguised as Google voicemail or file-share notifications, all carrying a link that genuinely pointed at Google's own servers. Clicking it sent victims through a CAPTCHA (for "legitimacy") and then on to a fake Microsoft login page built to steal credentials. (&lt;a href="https://www.scworld.com/brief/official-google-domain-exploited-in-sweeping-phishing-campaign" rel="noopener noreferrer"&gt;SC Media&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Nobody hacked Google. Nobody forged the domain. The attackers just found a corner of Google's own infrastructure that would forward a visitor anywhere they asked, and used it as a launchpad.&lt;/p&gt;

&lt;p&gt;That corner has a name: &lt;strong&gt;Open Redirect&lt;/strong&gt;. And it's a lot more common, and a lot older, than a single 2025 headline suggests.&lt;/p&gt;

&lt;h2&gt;
  
  
  This Bug Has Been Everywhere
&lt;/h2&gt;

&lt;p&gt;Microsoft's own security team wrote about this exact pattern back in 2021, after tracking a single campaign that used &lt;strong&gt;over 350 unique phishing domains&lt;/strong&gt;, all funneled through open redirect links on trusted platforms. Their reasoning for why it works so well: people are trained to check the domain in a link, and an open redirect lets the visible domain be completely legitimate. (&lt;a href="https://www.microsoft.com/en-us/security/blog/2021/08/26/widespread-credential-phishing-campaign-abuses-open-redirector-links/" rel="noopener noreferrer"&gt;Microsoft Security Blog&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;It's not just email providers, either. Cofense's threat intel team tracked phishing campaigns abusing &lt;code&gt;.gov&lt;/code&gt; websites across dozens of countries, and found that &lt;strong&gt;almost 60% of the abused government domains shared the exact same vulnerable code path&lt;/strong&gt;, traced back to a single Liferay CMS bug, CVE-2024-25608. (&lt;a href="https://cofense.com/blog/threat-actors-exploit-government-website-vulnerabilities-for-phishing-campaigns" rel="noopener noreferrer"&gt;Cofense&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;One bug class. One shared root cause. Reused across governments, cloud platforms, and email systems, for years.&lt;/p&gt;

&lt;p&gt;So let's actually look at what it is, and why it keeps showing up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F39lw29tqlshuocqmlj6s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F39lw29tqlshuocqmlj6s.jpg" alt=" " width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bug, In Its Simplest Form
&lt;/h2&gt;

&lt;p&gt;Open Redirect happens when your app takes a destination from the user and sends them there without checking it first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/login?redirect=/dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Somewhere on the backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;redirect&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change the parameter, and the server obeys just as happily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/login?redirect=https://attacker.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;302&lt;/span&gt; &lt;span class="ne"&gt;Found&lt;/span&gt;
&lt;span class="na"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://attacker.example&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't a hypothetical. In 2024, a bug bounty researcher found this exact pattern on &lt;strong&gt;Tumblr's own logout endpoint&lt;/strong&gt;, where a &lt;code&gt;redirect_to&lt;/code&gt; parameter sent users wherever the URL said, no validation attached. (&lt;a href="https://medium.com/@halfcircassian/bug-bounty-in-2025-part-3-investigating-4-open-redirect-reports-at-hackerone-so-you-dont-have-499948a0e6b1" rel="noopener noreferrer"&gt;writeup&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;It also showed up in &lt;strong&gt;Expedia's&lt;/strong&gt; login and logout flow, reported through HackerOne in 2023. (&lt;a href="https://hackerone.com/reports/1788006" rel="noopener noreferrer"&gt;report&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;It even shipped inside &lt;strong&gt;Ruby on Rails itself&lt;/strong&gt;. CVE-2023-22797 was an open redirect baked into Action Pack's &lt;code&gt;redirect_to&lt;/code&gt; helper, meaning any Rails app using it by default inherited the bug. (&lt;a href="https://hackerone.com/reports/1865991" rel="noopener noreferrer"&gt;HackerOne&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;If a framework used by hundreds of thousands of production apps can ship this by accident, "we'd never make that mistake" isn't a real defense.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Method Doesn't Matter
&lt;/h2&gt;

&lt;p&gt;A quick myth to clear up: this isn't a GET-only problem.&lt;/p&gt;

&lt;p&gt;The destination can arrive in a POST body, a PUT payload, a JSON field, anywhere the server reads user-supplied data from. The only question that matters:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Does anything the user controls decide where the redirect goes?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If yes, and nothing validates it, you have the bug. The HTTP verb is just the delivery truck.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Wait, Isn't This Just MITM?"
&lt;/h2&gt;

&lt;p&gt;No, and this mix-up trips people up a lot.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open Redirect&lt;/strong&gt;: the &lt;em&gt;server itself&lt;/em&gt; honestly generates a malicious &lt;code&gt;Location&lt;/code&gt; header, because it trusted a parameter it shouldn't have. HTTPS does nothing to stop this, the channel was never the problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MITM (man-in-the-middle)&lt;/strong&gt;: someone sits &lt;em&gt;between&lt;/em&gt; the browser and server, altering traffic in transit. This requires actual network positioning, not just a crafted URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've ever tested this in Burp Suite by editing a &lt;code&gt;redirect&lt;/code&gt; parameter, you weren't simulating MITM. You already controlled the browser and configured the proxy yourself. That's a lab setup, not an attacker's vantage point.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Version That Never Touches Your Server
&lt;/h2&gt;

&lt;p&gt;Here's where it gets genuinely sneaky.&lt;/p&gt;

&lt;p&gt;Everything so far assumed the &lt;em&gt;server&lt;/em&gt; decides the redirect. But plenty of redirect logic lives entirely in JavaScript, in the browser, after the page has already loaded. When that's the case, your server logs never see the attack happen.&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;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfectly ordinary code. Probably built for some deep-linking feature. But it reads directly from the URL fragment and acts on it with zero validation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/redirect#https://attacker.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The part after &lt;code&gt;#&lt;/code&gt; never gets sent to the server at all, it's pure client-side. The victim's own browser reads it and redirects them. No server involved, no request log, nothing for a WAF to catch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This One Is Scary: HackerOne Found It on Its Own Site
&lt;/h2&gt;

&lt;p&gt;Here's the part I find genuinely funny. HackerOne, the bug bounty platform, runs one of the largest security researcher communities on earth.&lt;/p&gt;

&lt;p&gt;Report #398054, disclosed publicly on their own platform: a &lt;strong&gt;DOM-based XSS vulnerability on hackerone.com itself&lt;/strong&gt;, caused by an insecure &lt;code&gt;message&lt;/code&gt; event listener tied to a Marketo contact form. (&lt;a href="https://hackerone.com/reports/398054" rel="noopener noreferrer"&gt;HackerOne&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The presentation tool &lt;code&gt;reveal.js&lt;/code&gt; had the same class of bug (CVE-2020-8127): a &lt;code&gt;postMessage&lt;/code&gt; handler that let a caller invoke arbitrary internal methods, turned into a working XSS chain. (&lt;a href="https://jlajara.gitlab.io/Dom_XSS_PostMessage_2" rel="noopener noreferrer"&gt;writeup&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The common thread: a page listens for cross-window messages and trusts whatever arrives.&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// who sent this?&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anyone who can get the victim to open a popup or iframe can fire data into that handler. The fix is one line, and it's the one line that keeps getting skipped:&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://trusted-partner.com&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;There's a reason &lt;code&gt;location.hash&lt;/code&gt; in particular is a favorite for bug bounty hunters: it's &lt;strong&gt;never sent to the server&lt;/strong&gt;, which means it's invisible to server logs, WAFs, and most automated scanners entirely. You can only find this class of bug by actually reading the client-side JavaScript. (&lt;a href="https://dev.to/kai_learner/dom-xss-test-1m18"&gt;dev.to writeup&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  The One Question That Explains All of It
&lt;/h2&gt;

&lt;p&gt;Every example above, the Tumblr redirect, the Rails CVE, the HackerOne postMessage bug, the Google Cloud phishing campaign, comes back to one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where did the data come from, and where did it end up?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Security people call the origin a &lt;strong&gt;source&lt;/strong&gt; and the destination a &lt;strong&gt;sink&lt;/strong&gt;. Common sources:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Where it shows up&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;location.hash&lt;/code&gt; / &lt;code&gt;location.search&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;URL fragment and query string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;event.data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cross-window messages (&lt;code&gt;postMessage&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;document.cookie&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only non-&lt;code&gt;HttpOnly&lt;/code&gt; cookies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;input.value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Form fields&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API responses&lt;/td&gt;
&lt;td&gt;Anything a user or third party can influence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Common sinks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sink&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;window.location = data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open Redirect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;element.innerHTML = data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;DOM XSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;eval(data)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Arbitrary code execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;document.write(data)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unsanitized DOM injection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Neither a source nor a sink is a bug on its own.&lt;/strong&gt; The vulnerability lives in the unguarded path between them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnpyfckkfdlujqksr7cyy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnpyfckkfdlujqksr7cyy.jpg" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Five-Question Checklist
&lt;/h2&gt;

&lt;p&gt;Next time you're staring at a piece of code and trying to decide if it's a problem:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where did the data come from?&lt;/li&gt;
&lt;li&gt;Can an attacker influence it?&lt;/li&gt;
&lt;li&gt;Where does it end up?&lt;/li&gt;
&lt;li&gt;Is there validation between the two?&lt;/li&gt;
&lt;li&gt;What actually happens if it's abused?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's the entire audit. No memorized vulnerability list required.&lt;/p&gt;

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

&lt;p&gt;Open Redirect and DOM XSS both survive because they exploit a very human habit: we check the domain, and we trust it once it looks right.&lt;/p&gt;

&lt;p&gt;An attacker doesn't need to break into &lt;code&gt;google.com&lt;/code&gt;, &lt;code&gt;hackerone.com&lt;/code&gt;, or a government &lt;code&gt;.gov&lt;/code&gt; site. They just need one endpoint that forwards a visitor without asking questions, and 350 phishing domains, or 9,300 emails, later, it's still working.&lt;/p&gt;

&lt;p&gt;Go check your own &lt;code&gt;postMessage&lt;/code&gt; listeners and redirect logic today. It costs one afternoon. The alternative costs a lot more.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Ícaro Molinari</dc:creator>
      <pubDate>Mon, 10 Aug 2026 20:27:40 +0000</pubDate>
      <link>https://dev.to/icaromol/-1gb3</link>
      <guid>https://dev.to/icaromol/-1gb3</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/icaromol/the-best-hot-dog-css-interactive-art-for-the-comfort-food-edition-challenge-4ela" class="crayons-story__hidden-navigation-link"&gt;The Best Hot Dog! CSS Interactive Art for the Comfort Food Edition Challenge&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/icaromol/the-best-hot-dog-css-interactive-art-for-the-comfort-food-edition-challenge-4ela" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Frontend Challenge CSS Art Submission 🍲🥧&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/icaromol" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4068138%2Fbbe6b3f4-cbe5-41a6-ad5b-7e87390aab26.jpg" alt="icaromol profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/icaromol" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Ícaro Molinari
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Ícaro Molinari
                
              
              &lt;div id="story-author-preview-content-4362637" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/icaromol" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4068138%2Fbbe6b3f4-cbe5-41a6-ad5b-7e87390aab26.jpg" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Ícaro Molinari&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/icaromol/the-best-hot-dog-css-interactive-art-for-the-comfort-food-edition-challenge-4ela" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 10&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/icaromol/the-best-hot-dog-css-interactive-art-for-the-comfort-food-edition-challenge-4ela" id="article-link-4362637"&gt;
          The Best Hot Dog! CSS Interactive Art for the Comfort Food Edition Challenge
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/frontendchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;frontendchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/css"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;css&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/icaromol/the-best-hot-dog-css-interactive-art-for-the-comfort-food-edition-challenge-4ela" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/icaromol/the-best-hot-dog-css-interactive-art-for-the-comfort-food-edition-challenge-4ela#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>The Best Hot Dog! CSS Interactive Art for the Comfort Food Edition Challenge</title>
      <dc:creator>Ícaro Molinari</dc:creator>
      <pubDate>Mon, 10 Aug 2026 17:37:02 +0000</pubDate>
      <link>https://dev.to/icaromol/the-best-hot-dog-css-interactive-art-for-the-comfort-food-edition-challenge-4ela</link>
      <guid>https://dev.to/icaromol/the-best-hot-dog-css-interactive-art-for-the-comfort-food-edition-challenge-4ela</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/frontend-2026-07-29"&gt;Frontend Challenge - Comfort Food Edition, CSS Art&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspiration
&lt;/h2&gt;

&lt;p&gt;The Brazilian hot dog (&lt;em&gt;cachorro-quente&lt;/em&gt;) isn't just bread, sausage, ketchup and mustard... It's a &lt;strong&gt;whole toppings culture&lt;/strong&gt;: quail egg, crispy potato sticks (&lt;em&gt;batata-palha&lt;/em&gt;), corn, mashed potatoes, and the eternally controversial &lt;em&gt;raisins&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;My personal connection to this one is a little silly: my wife nicknamed our dog "hot dog" because she's so warm she basically doubles as a space heater in bed. &lt;/p&gt;

&lt;p&gt;That nickname is what actually clicked something for me (we both already love hot dogs), and I realized the version I grew up with, the loaded, toppings-everywhere Brazilian one, is basically unknown outside Brazil. So this became my excuse to finally show it to the rest of the world.&lt;/p&gt;

&lt;p&gt;I set the scene on Copacabana beach in Rio: sky, Sugarloaf and Christ the Redeemer in the background, sailboats drifting by, and a &lt;em&gt;vira-lata caramelo&lt;/em&gt; &lt;em&gt;(the "caramel mutt," one of Brazil's most-loved street dogs)&lt;/em&gt; sitting next to the stand, a little tribute to the real one who started this. &lt;/p&gt;

&lt;p&gt;Clicking through the toppings became the whole interaction: each one gets a little pixel-art icon and a real fact about where in Brazil it shows up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://the-best-brazilian-hot-dog-css.vercel.app/" rel="noopener noreferrer"&gt;https://the-best-brazilian-hot-dog-css.vercel.app/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Video walkthrough:&lt;/strong&gt;   &lt;iframe src="https://www.youtube.com/embed/vMl0N9eqd4E"&gt;
  &lt;/iframe&gt;
&lt;br&gt;
&lt;em&gt;(if the embed doesn't render: &lt;a href="https://youtu.be/vMl0N9eqd4E" rel="noopener noreferrer"&gt;https://youtu.be/vMl0N9eqd4E&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Source code:&lt;/strong&gt; &lt;a href="https://github.com/icaromol/the-best-brazilian-hot-dog-css" rel="noopener noreferrer"&gt;https://github.com/icaromol/the-best-brazilian-hot-dog-css&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwq4pql64itbm7d1i6dsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwq4pql64itbm7d1i6dsp.png" alt="The Corn ingredient info card open over the Copacabana scene, showing the loaded hot dog, the beach and sailboats, and Christ the Redeemer in the background" width="799" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;Every shape in the scene — the mountains, the boats, the food, the dog — is CSS: gradients, &lt;code&gt;clip-path&lt;/code&gt;, and pixel art drawn with &lt;code&gt;box-shadow&lt;/code&gt; (each sprite is a big list of &lt;code&gt;x y color&lt;/code&gt; shadows, basically a matrix). &lt;/p&gt;

&lt;p&gt;No raster images, no SVG. There's a thin layer of vanilla JavaScript (~300 lines total, no framework) for the click interactions — opening ingredient cards, the START gate, a responsive "dual-screen" layout on portrait viewports — but it's purely interaction, kept intentionally small so it stays a "sprinkle," never the thing producing the visuals.&lt;/p&gt;

&lt;p&gt;None of that pixel art was hand-typed as &lt;code&gt;box-shadow&lt;/code&gt; values, though — for this challenge I ended up building an entire second tool to make that possible: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/icaromol/free-css-sprite-generator" rel="noopener noreferrer"&gt;free-css-sprite-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A local pixel-art editor with a brush/eraser, a locked color palette, and a live CSS preview, plus a CLI path for turning a reference image into pixel art automatically. Every sprite (the boats, the clouds, the dog's four walk/stand frames, the hot dog, all ten ingredient icons) was painted or imported there, saved as a pixel grid, then compiled into CSS with one generated &lt;code&gt;box-shadow&lt;/code&gt; entry per pixel.&lt;/p&gt;

&lt;p&gt;That's the actual source of the &lt;strong&gt;~121,000 lines of pixel-art&lt;/strong&gt; code in this repo. I'm glad I never wrote a shadow coordinate by hand.&lt;/p&gt;

&lt;p&gt;Quick note since this is a CSS Art challenge: I wrote the styles in &lt;strong&gt;SCSS&lt;/strong&gt;, but think of SCSS as a writing tool, not a runtime one — nothing SCSS-specific ever reaches the browser. Before anything ships, a compiler (&lt;code&gt;sass&lt;/code&gt;) turns all my &lt;code&gt;.scss&lt;/code&gt; files into one plain &lt;code&gt;css/style.css&lt;/code&gt; file, and that's the only thing the browser ever loads and renders. &lt;/p&gt;

&lt;p&gt;I only used SCSS to keep those &lt;strong&gt;~121,000 lines of pixel-art&lt;/strong&gt; code split into &lt;strong&gt;56 organized files&lt;/strong&gt; instead of one giant unreadable stylesheet — no clever logic, no loops, barely any variables. So when it's judged, what's actually running is 100% plain CSS.&lt;/p&gt;

&lt;p&gt;The trickiest part was the responsive "dual-screen" mode: below a portrait ~900px breakpoint, popups dock into a dedicated panel above the scene instead of overlaying it, so nothing on a phone gets covered by its own popup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fphrggwnsyq2rk0btxya1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fphrggwnsyq2rk0btxya1.png" alt="The scene in dual-screen mode on a portrait viewport: a " width="738" height="984"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Proudest of: &lt;strong&gt;the whole scene renders with zero images and zero SVG&lt;/strong&gt;, and it still holds up scaled from a phone to a wide desktop.&lt;/p&gt;

&lt;p&gt;What's next: probably more regional toppings, and maybe sound — though that'll be the tricky part to pull off using only CSS 😄&lt;/p&gt;

&lt;p&gt;License: &lt;a href="https://github.com/icaromol/the-best-brazilian-hot-dog-css/blob/main/LICENSE" rel="noopener noreferrer"&gt;MIT&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Huge thanks to the DEV community and to dev.to for such an inspiring challenge — building this in just one weekend and having it come together made me genuinely happy. &lt;/p&gt;

&lt;p&gt;I've also been having a blast scrolling through everyone else's submissions.&lt;/p&gt;

</description>
      <category>frontendchallenge</category>
      <category>devchallenge</category>
      <category>css</category>
    </item>
  </channel>
</rss>
