<?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>Forem: Bruno Pinto</title>
    <description>The latest articles on Forem by Bruno Pinto (@brunoabpinto).</description>
    <link>https://forem.com/brunoabpinto</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%2F3726829%2Fcbabdd4e-f48c-44ee-bfc6-16abe820353c.jpg</url>
      <title>Forem: Bruno Pinto</title>
      <link>https://forem.com/brunoabpinto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/brunoabpinto"/>
    <language>en</language>
    <item>
      <title>Four Spaces Before &lt;?php</title>
      <dc:creator>Bruno Pinto</dc:creator>
      <pubDate>Tue, 10 Feb 2026 13:25:11 +0000</pubDate>
      <link>https://forem.com/brunoabpinto/four-spaces-before-php-2jai</link>
      <guid>https://forem.com/brunoabpinto/four-spaces-before-php-2jai</guid>
      <description>&lt;p&gt;I was working on a Livewire component when every interaction started throwing 419 errors. CSRF token mismatch, on every click. The kind of thing that makes you question your setup immediately.&lt;/p&gt;

&lt;p&gt;At first I assumed it was a Livewire issue. But then I noticed something stranger — every page refresh generated a new session ID. Sessions worked fine with &lt;code&gt;php artisan serve&lt;/code&gt;, but the moment I switched to Herd, no cookies stuck. Each request was a clean slate.&lt;/p&gt;

&lt;p&gt;The 419 errors were just a symptom. Laravel couldn't maintain sessions because the browser never received a cookie.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chasing the usual suspects
&lt;/h2&gt;

&lt;p&gt;I started with the &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SESSION_DRIVER=redis
SESSION_LIFETIME=120
SESSION_DOMAIN=null
SESSION_SECURE_COOKIE=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redis was running, PHP could connect to it. I created a test route to confirm sessions worked at the PHP level — they did. Data was stored, but the browser never got the &lt;code&gt;Set-Cookie&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;I checked DevTools. No &lt;code&gt;laravel_session&lt;/code&gt; cookie. No &lt;code&gt;Set-Cookie&lt;/code&gt; header at all.&lt;/p&gt;

&lt;p&gt;I went through the usual list: cookie domain, HTTPS settings, session path, Redis connection. All fine. Switched to the file driver. Same result. Tried setting a cookie manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/cookie-test'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Test'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'test_cookie'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'test_value'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&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;Still no &lt;code&gt;Set-Cookie&lt;/code&gt; header. At this point it clearly wasn't a Laravel config problem. Something was preventing PHP from sending cookies entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual problem
&lt;/h2&gt;

&lt;p&gt;The breakthrough came from a raw &lt;code&gt;header()&lt;/code&gt; call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/header-test'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'X-Custom-Test: working'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PHP responded with: &lt;em&gt;"Cannot modify header information — headers already sent"&lt;/em&gt;, and pointed to &lt;code&gt;routes/web.php:1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Line 1 should just be &lt;code&gt;&amp;lt;?php&lt;/code&gt;. I opened the file and there it was — the tag was indented. Four spaces sitting right there, plain as day. I just hadn't noticed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it only showed up in Herd
&lt;/h2&gt;

&lt;p&gt;The bug existed all along. &lt;code&gt;php artisan serve&lt;/code&gt; has output buffering enabled by default, so those spaces never reached the browser before the headers. The problem was silently masked.&lt;/p&gt;

&lt;p&gt;Herd uses nginx + PHP-FPM with &lt;code&gt;output_buffering = 0&lt;/code&gt;. Output goes out immediately. Those four spaces hit the browser before Laravel could send any headers — which meant no cookies, which meant no sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Delete four spaces. That's it.&lt;/p&gt;

&lt;p&gt;I made sure &lt;code&gt;routes/web.php&lt;/code&gt; started with &lt;code&gt;&amp;lt;?php&lt;/code&gt; on the very first character of the very first line. Saved. Everything worked.&lt;/p&gt;

&lt;p&gt;Livewire relies on the session to verify CSRF tokens on every request. Without a &lt;code&gt;Set-Cookie&lt;/code&gt; header, the browser never stores a session — and without a session, every Livewire interaction fails with a 419.&lt;/p&gt;

&lt;p&gt;Four spaces before &lt;code&gt;&amp;lt;?php&lt;/code&gt; were enough to start the response body, and once the body starts, PHP can't send headers anymore.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Vector: Vue in Blade, the easy way</title>
      <dc:creator>Bruno Pinto</dc:creator>
      <pubDate>Tue, 03 Feb 2026 19:13:10 +0000</pubDate>
      <link>https://forem.com/brunoabpinto/vector-the-easiest-way-to-plug-vue-in-blade-jl6</link>
      <guid>https://forem.com/brunoabpinto/vector-the-easiest-way-to-plug-vue-in-blade-jl6</guid>
      <description>&lt;p&gt;You know that feeling when you're building a Laravel app and you just need a tiny bit of reactivity? A counter. A toggle. Something that feels overkill for a full Vue component but too annoying for vanilla JavaScript?&lt;/p&gt;

&lt;p&gt;I kept reaching for Alpine.js, which is great, but I wanted Vue's Composition API. The &lt;code&gt;ref()&lt;/code&gt;, the &lt;code&gt;computed()&lt;/code&gt;, the familiar syntax I already know. So I bu4ilt Vector.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Even Is This?
&lt;/h2&gt;

&lt;p&gt;Vector is a Laravel package that lets you write Vue directly in your Blade templates with zero ceremony:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&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;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"i++"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click Me&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        Count: @{{ i }}
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"i &amp;gt; 5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Success!&lt;span class="nt"&gt;&amp;lt;/div&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;That's the whole thing. No build step for your components. No separate &lt;code&gt;.vue&lt;/code&gt; files. No special directives wrapping your code. Just a &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt; tag and you're done.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt; tag gets transformed at compile time. Vector treats the &lt;strong&gt;element immediately after&lt;/strong&gt; the script tag as your Vue template. Everything inside that element becomes reactive, and anything outside it remains regular Blade.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Blade's precompiler finds your &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt; blocks&lt;/li&gt;
&lt;li&gt;Extracts your variable declarations&lt;/li&gt;
&lt;li&gt;Mounts Vue on the next sibling element&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key part is the variable extraction. It parses &lt;code&gt;const&lt;/code&gt;, &lt;code&gt;let&lt;/code&gt;, and &lt;code&gt;var&lt;/code&gt; declarations and auto-returns them to the template. You write normal code, it figures out the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Escaping Blade Syntax
&lt;/h3&gt;

&lt;p&gt;Since Blade also uses &lt;code&gt;{{ }}&lt;/code&gt; for output, you need to prefix Vue's mustache syntax with &lt;code&gt;@&lt;/code&gt; to prevent Blade from processing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="nc"&gt;This&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;Blade&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;$phpVariable&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="nc"&gt;This&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="nf"&gt;Vue&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;vueVariable&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, use Vue directives like &lt;code&gt;v-text&lt;/code&gt; which don't conflict with Blade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;v-text=&lt;/span&gt;&lt;span class="s"&gt;"count"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require brunoabpinto/vector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add Vector to your Vite entry points in &lt;code&gt;vite.config.js&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="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;laravel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resources/css/app.css&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="s2"&gt;resources/js/app.js&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="s2"&gt;resources/js/vendor/vector.js&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="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;alias&lt;/span&gt;&lt;span class="p"&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;vue&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;vue/dist/vue.esm-bundler.js&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;@vectorJs&lt;/code&gt; before your closing &lt;code&gt;&amp;lt;/body&amp;gt;&lt;/code&gt; tag in your layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    {{ $slot }}

    @vectorJs
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Vector auto-publishes its runtime, and &lt;code&gt;@vectorJs&lt;/code&gt; loads it where you need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trade-offs
&lt;/h2&gt;

&lt;p&gt;Let's be real about what this is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick interactive elements&lt;/li&gt;
&lt;li&gt;Prototyping&lt;/li&gt;
&lt;li&gt;When you want Vue's API without Vue's ceremony&lt;/li&gt;
&lt;li&gt;Laravel apps that are mostly server-rendered with islands of reactivity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Not great for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complex component hierarchies&lt;/li&gt;
&lt;li&gt;When you need proper SFC features (scoped styles, etc.)&lt;/li&gt;
&lt;li&gt;Large-scale SPAs (just use Inertia at that point)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;The package is available on &lt;a href="https://github.com/brunoabpinto/vector" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Star it, fork it, tell me it's an abomination. Whatever feels right.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require brunoabpinto/vector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>laravel</category>
      <category>vue</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>I Turned Images Into 10,000 Tiny HTML Elements Because Why Not</title>
      <dc:creator>Bruno Pinto</dc:creator>
      <pubDate>Thu, 29 Jan 2026 12:41:30 +0000</pubDate>
      <link>https://forem.com/brunoabpinto/i-turned-images-into-10000-tiny-html-elements-because-why-not-7md</link>
      <guid>https://forem.com/brunoabpinto/i-turned-images-into-10000-tiny-html-elements-because-why-not-7md</guid>
      <description>&lt;p&gt;&lt;em&gt;Sometimes the best projects are the ones that solve problems nobody has.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Last weekend, I found myself staring at my screen, thinking about images. Not in a productive way. Not "how can I optimize image loading" or "what's the best format for web." No, I was thinking something far more unhinged:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if every pixel was just a tiny HTML element?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And thus, IMGML was born.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Premise
&lt;/h2&gt;

&lt;p&gt;Here's the concept: take an image, read it pixel by pixel, and generate an HTML file where each pixel is represented by a 1x1 &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt; element with a background color matching the original pixel.&lt;/p&gt;

&lt;p&gt;That's it. That's the whole thing.&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags. No &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;. No SVG. Just thousands upon thousands of microscopic horizontal rules, arranged in a grid, pretending to be an image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does It Work?
&lt;/h2&gt;

&lt;p&gt;Technically? Yes.&lt;/p&gt;

&lt;p&gt;Practically? That's a strong word.&lt;/p&gt;

&lt;p&gt;Upload a 100x100 pixel image and you get 10,000 HTML elements. A 200x200 image? 40,000 elements. Your browser will render it. Your browser might also ask you why you've done this.&lt;/p&gt;

&lt;p&gt;But here's the thing — it &lt;em&gt;does&lt;/em&gt; look like the image. Open the HTML file and there it is, your photo, reconstructed entirely from styled &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt; tags. It's beautiful in the way that a Rube Goldberg machine is beautiful. Unnecessarily complex, deeply impractical, and yet somehow satisfying.&lt;/p&gt;

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

&lt;p&gt;I get asked this a lot. "Why would you do this?" "What's the use case?" "Are you okay?"&lt;/p&gt;

&lt;p&gt;The answers are: because I could, there isn't one, and debatable.&lt;/p&gt;

&lt;p&gt;This is a "what if" project. It exists in that space between curiosity and questionable judgment. The space where you wonder "can I do this?" before asking "should I do this?"&lt;/p&gt;

&lt;p&gt;Some might call it a waste of time. I call it a learning experience wrapped in absurdity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tech
&lt;/h2&gt;

&lt;p&gt;For those curious, it's built with Laravel 12 and Livewire. Upload an image, the backend processes it pixel by pixel, and you download your freshly minted HTML monstrosity.&lt;/p&gt;

&lt;p&gt;Here's what the output looks like — just a wall of &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt; tags, each with an inline background color:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;r&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:#cad5d9"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:#c5ced3"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:#cdd6db"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:#dde4ea"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:#e4ebf1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:#e1e6ec"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:#dadfe5"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:#d7dadf"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/r&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Optimization Rabbit Hole
&lt;/h2&gt;

&lt;p&gt;Once I committed to this absurd idea, I became obsessed with making each pixel as small as possible. Here's how that went:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt 1: RGB&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:rgb(255, 255, 255)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Works, but verbose. All those characters add up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt 2: Hex&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:#c5ced3"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shorter. Hex codes are more compact than RGB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt 3: Drop the self-closing slash&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:#c5ced3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's optional in HTML5. Every byte counts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt 4: Drop the quotes&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;background:#c5ced3&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also valid HTML. We're getting minimal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt 5: The bgcolor attribute&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;bgcolor=&lt;/span&gt;&lt;span class="s"&gt;"#c5ced3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deprecated, and for some reason only works on &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;. Dead end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt 6: The color attribute&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;#c5ced3&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works. It's deprecated, it's not recommended, and it's perfect for this project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt 7: Drop the hashtag&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;c5ced3&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turns out the &lt;code&gt;#&lt;/code&gt; is optional on hex colors. One more character gone.&lt;/p&gt;

&lt;p&gt;This is the shortest I could make each pixel. If you know a way to make it smaller, I'm genuinely curious.&lt;/p&gt;

&lt;p&gt;The code is straightforward. PHP's image functions handle the pixel reading:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Resize to keep things manageable&lt;/span&gt;
&lt;span class="nv"&gt;$image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;resizeImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagecreatefromjpeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$image&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagesx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$resource&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagesy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$resource&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$pixels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="c1"&gt;// Loop through every pixel&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="o"&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;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Get color index at this coordinate&lt;/span&gt;
        &lt;span class="nv"&gt;$color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagecolorat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Convert to RGB array&lt;/span&gt;
        &lt;span class="nv"&gt;$rgb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagecolorsforindex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Format as hex (no hashtag needed)&lt;/span&gt;
        &lt;span class="nv"&gt;$hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'%02x%02x%02x'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rgb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$rgb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$rgb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$pixels&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$hex&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;Loop through each row, each column, grab the color, convert to hex, done. Livewire handles the upload/download flow. Nothing revolutionary — just reasonable tools applied to an unreasonable idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Actually Learned
&lt;/h2&gt;

&lt;p&gt;Despite the silliness, building IMGML reminded me of a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Constraints breed creativity.&lt;/strong&gt; Limiting myself to just HTML elements forced me to think differently about rendering.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance matters everywhere.&lt;/strong&gt; Processing images pixel by pixel taught me to respect the work that actual image libraries do.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Side projects don't need purpose.&lt;/strong&gt; Not everything has to ship, scale, or solve a real problem. Sometimes you just build something weird and smile.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Should You Use This?
&lt;/h2&gt;

&lt;p&gt;Absolutely not.&lt;/p&gt;

&lt;p&gt;Well, maybe. If you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confuse a web developer&lt;/li&gt;
&lt;li&gt;Create the world's least efficient image format&lt;/li&gt;
&lt;li&gt;Prove a point about HTML being turing complete (it's not, but this feels adjacent)&lt;/li&gt;
&lt;li&gt;Kill time on a Saturday&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then yes, IMGML is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;The project is open source. Clone it, run it, upload an image, and watch your browser question its life choices as it renders your photo one &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt; at a time.&lt;/p&gt;

&lt;p&gt;Will it change the world? No.&lt;/p&gt;

&lt;p&gt;Will it make you briefly happy in a "wow, that's dumb" kind of way? Almost certainly.&lt;/p&gt;

&lt;p&gt;And sometimes, that's enough.&lt;/p&gt;

&lt;p&gt;Here's &lt;a href="https://placeholderblog.netlify.app/assets/blog/imgml.html" rel="noopener noreferrer"&gt;my GitHub avatar in IMGML format&lt;/a&gt; if you want to see it in action.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"c5ced3"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;small&gt;&lt;em&gt;Does not work on Firefox. This example uses the following structure:&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;


&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background:#07040b"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;




&lt;p&gt;&lt;em&gt;IMGML is available on &lt;a href="https://github.com/brunoabpinto/IMGML" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Star it if you appreciate the absurdity.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>html</category>
      <category>livewire</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Solving Livewire's 419 After Session Expiration</title>
      <dc:creator>Bruno Pinto</dc:creator>
      <pubDate>Thu, 22 Jan 2026 19:53:39 +0000</pubDate>
      <link>https://forem.com/brunoabpinto/solving-livewires-419-after-session-expiration-4395</link>
      <guid>https://forem.com/brunoabpinto/solving-livewires-419-after-session-expiration-4395</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;If you've worked with Livewire in Laravel applications, you've probably encountered this frustrating scenario: a user is actively working in your application, filling out a long form or interacting with components, when suddenly—&lt;strong&gt;BAM!&lt;/strong&gt; A 419 error appears, and all their work is lost. The dreaded "CSRF token mismatch" strikes again.&lt;/p&gt;

&lt;p&gt;This happens because Laravel's session expires (typically after 120 minutes by default), invalidating the CSRF token. When the user tries to interact with a Livewire component after this expiration, Laravel rejects the request for security reasons. The user is forced to refresh the page manually and start over.&lt;/p&gt;

&lt;p&gt;Not a great user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Happens
&lt;/h2&gt;

&lt;p&gt;Laravel's CSRF protection is essential for security—it prevents cross-site request forgery attacks by ensuring requests come from your application. Each session gets a unique CSRF token that's validated on every state-changing request.&lt;/p&gt;

&lt;p&gt;When a session expires:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The CSRF token in the user's browser becomes stale&lt;/li&gt;
&lt;li&gt;The server generates a new token for the new session&lt;/li&gt;
&lt;li&gt;Any Livewire action sends the old, invalid token&lt;/li&gt;
&lt;li&gt;Laravel returns a 419 status code&lt;/li&gt;
&lt;li&gt;User frustration ensues&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While Livewire does handle this with a &lt;code&gt;page-expired&lt;/code&gt; event, it typically just shows an error or reloads the page—still losing user data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Automatic CSRF Token Refresh
&lt;/h2&gt;

&lt;p&gt;I built a simple Laravel package that silently refreshes the CSRF token in the background before the session expires, preventing the 419 error entirely. The user never knows it's happening—they just keep working without interruption.&lt;/p&gt;

&lt;p&gt;The package:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically calculates the refresh interval based on your session lifetime&lt;/li&gt;
&lt;li&gt;Fetches a fresh CSRF token via AJAX&lt;/li&gt;
&lt;li&gt;Updates the meta tag in the DOM&lt;/li&gt;
&lt;li&gt;Works seamlessly with Livewire and all Laravel applications&lt;/li&gt;
&lt;li&gt;Requires zero configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Install via Composer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require brunoabpinto/csrf-refresh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Publishes the JavaScript file to &lt;code&gt;public/vendor/csrf-refresh/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Registers the refresh route&lt;/li&gt;
&lt;li&gt;Registers the &lt;code&gt;@csrfRefresh&lt;/code&gt; Blade directive&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Just add one line to your layout file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta name="csrf-token" content="{{ csrf_token() }}"&amp;gt;
    &amp;lt;title&amp;gt;My App&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    {{ $slot }}

    @csrfRefresh
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! Your CSRF tokens will now refresh automatically before the session expires.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The package does four things:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Calculates the Refresh Interval&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Based on your &lt;code&gt;config/session.php&lt;/code&gt; lifetime setting, the package calculates when to refresh the token—50 seconds before expiration by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'session.lifetime'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// in milliseconds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. &lt;strong&gt;Registers a Refresh Endpoint&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A simple route that returns a fresh CSRF token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/csrf-token/refresh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;csrf_token&lt;/span&gt;&lt;span class="p"&gt;()]);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'web'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'csrf.refresh'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. &lt;strong&gt;Injects Minified JavaScript&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;@csrfRefresh&lt;/code&gt; directive injects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The calculated interval as a global variable&lt;/li&gt;
&lt;li&gt;A minified script that runs in the background&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Silently Updates the Token&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The JavaScript periodically fetches a new token and updates the meta tag:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;refreshCsrfToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/csrf-token/refresh&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="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-Requested-With&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="s2"&gt;XMLHttpRequest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;metaTag&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="s1"&gt;meta[name="csrf-token"]&lt;/span&gt;&lt;span class="dl"&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;metaTag&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;metaTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;token&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;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to refresh CSRF token:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refreshCsrfToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refreshInterval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why I Built This as a Package
&lt;/h2&gt;

&lt;p&gt;Initially, I was copying and pasting this solution across multiple projects. Every time I started a new Laravel/Livewire application, I'd recreate the same JavaScript, the same route, the same logic.&lt;/p&gt;

&lt;p&gt;By packaging it, I can now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Install once&lt;/strong&gt;: &lt;code&gt;composer require brunoabpinto/csrf-refresh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add one directive&lt;/strong&gt;: &lt;code&gt;@csrfRefresh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forget about it&lt;/strong&gt;: It just works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's saved me countless hours and eliminated a frustrating user experience issue across all my projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No more 419 errors&lt;/strong&gt; after session expiration&lt;br&gt;
&lt;strong&gt;Zero configuration&lt;/strong&gt; needed&lt;br&gt;
&lt;strong&gt;Automatic refresh&lt;/strong&gt; before expiration&lt;br&gt;
&lt;strong&gt;Works with Livewire, Inertia, and traditional Laravel apps&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Minimal overhead&lt;/strong&gt; (one AJAX request per hour)&lt;br&gt;
&lt;strong&gt;Reusable across projects&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you're building Livewire applications (or any long-running Laravel sessions), silent CSRF token refresh is a must-have for good UX. Instead of forcing users to refresh and lose their work, let this package handle it automatically in the background.&lt;/p&gt;

&lt;p&gt;Check it out on &lt;a href="https://github.com/brunoabpinto/csrf-refresh" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; or install it now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require brunoabpinto/csrf-refresh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>programming</category>
      <category>laravel</category>
      <category>livewire</category>
    </item>
    <item>
      <title>How a Livewire Vulnerability Led to Crypto Mining on Our Servers</title>
      <dc:creator>Bruno Pinto</dc:creator>
      <pubDate>Thu, 22 Jan 2026 18:17:53 +0000</pubDate>
      <link>https://forem.com/brunoabpinto/how-a-livewire-vulnerability-led-to-crypto-mining-on-our-servers-5gh8</link>
      <guid>https://forem.com/brunoabpinto/how-a-livewire-vulnerability-led-to-crypto-mining-on-our-servers-5gh8</guid>
      <description>&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.amazonaws.com%2Fuploads%2Farticles%2Fb4bf6aqywqnvwsn470io.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.amazonaws.com%2Fuploads%2Farticles%2Fb4bf6aqywqnvwsn470io.jpg" alt=" " width="640" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last week, we experienced a security incident that started as a performance issue and turned into a crypto mining investigation. Here's what happened and what you need to know if you're running Livewire in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Initial Signs
&lt;/h2&gt;

&lt;p&gt;Pages were loading slowly, and Livewire components were lagging. Our initial investigation pointed to pending PHP-FPM processes consuming server resources, coinciding with a recent deployment. We killed the processes, and everything seemed back to normal.&lt;/p&gt;

&lt;p&gt;Or so we thought.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Problem Emerges
&lt;/h2&gt;

&lt;p&gt;Within hours, the server was slow again. CPU usage spiked to nearly 100% between 1:00 PM and 1:30 PM. This time, deeper investigation revealed something more sinister—a suspicious process running on the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apps 376184 547 13.9 4658672 4581484 ? Sl 12:46 268:46 &lt;span class="se"&gt;\_&lt;/span&gt; /var/www/apps/website/releases/1768928757/storage/stmept &lt;span class="nt"&gt;--url&lt;/span&gt; pool.supportxmr.com:3333 &lt;span class="nt"&gt;--user&lt;/span&gt; 8556M2fMqE8Dg1U3pERP9rJ64jaa6MMha5SY5ovWQ7XiYjxdKquPQ7Z4afpEeXUtfJVBLGvLncGxtKMugv61S9nFGMHNAFK &lt;span class="nt"&gt;--pass&lt;/span&gt; next &lt;span class="nt"&gt;--donate-level&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The site had been compromised. Malicious files had been injected for Monero cryptocurrency mining.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Malware Arsenal
&lt;/h2&gt;

&lt;p&gt;We discovered multiple malicious files scattered across the application:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In the storage directory:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gd.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;guard.sh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stmept&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wp-admin.php&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In the public directory:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;339a36afe37df27417e6c26b684845d4.lock&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Multiple suspicious PHP files: &lt;code&gt;4hpce7mz.php&lt;/code&gt;, &lt;code&gt;9hb1pmgk.php&lt;/code&gt;, &lt;code&gt;klhrqd7x.php&lt;/code&gt;, &lt;code&gt;wp-admin.php&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most persistent was the &lt;code&gt;stmept&lt;/code&gt; binary—it would reappear within a minute of deletion, even after fresh deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Week Before
&lt;/h2&gt;

&lt;p&gt;In retrospect, the warning signs were there. A week earlier, other of our content websites had experienced a hack with remote execution file injection. We cleaned it up, and the files didn't return. We only noticed it because attackers had wiped the &lt;code&gt;index.php&lt;/code&gt;, leaving the site blank. At the time, we couldn't identify the entry point.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Investigation
&lt;/h2&gt;

&lt;p&gt;Working with our hosting provider, we tried everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modified request validators in the code&lt;/li&gt;
&lt;li&gt;Reviewed all installed packages&lt;/li&gt;
&lt;li&gt;Used AI agents to search for backdoors&lt;/li&gt;
&lt;li&gt;Killed processes and deployed fresh releases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing worked. The malware kept coming back.&lt;/p&gt;

&lt;p&gt;Then, a Google search led us to &lt;a href="https://ruslanmed.medium.com/a-weekend-debugging-session-that-turned-into-a-cybercrime-investigation-cfb470ae027c" rel="noopener noreferrer"&gt;this article&lt;/a&gt;, which described an identical scenario.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Root Cause: CVE-2025-54068
&lt;/h2&gt;

&lt;p&gt;The culprit was &lt;strong&gt;CVE-2025-54068&lt;/strong&gt;, a remote code execution vulnerability disclosed in April 2025 affecting Livewire versions prior to 4.0. This vulnerability allows attackers to run arbitrary commands on your server simply by sending malformed requests.&lt;/p&gt;

&lt;p&gt;We were running Livewire 3.5 across multiple projects.&lt;/p&gt;

&lt;p&gt;All were vulnerable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;We updated all projects to Livewire 4.0 via &lt;code&gt;composer update&lt;/code&gt;. Since the update, the malware has not returned, and server performance has been stable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Update immediately&lt;/strong&gt;: If you're running any version of Livewire older than 4.0, update now. This is a critical remote code execution vulnerability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor for unusual processes&lt;/strong&gt;: Regular server monitoring could have caught the crypto mining earlier.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don't dismiss related incidents&lt;/strong&gt;: The previous week's hack was a warning sign we didn't fully investigate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance issues can be security issues&lt;/strong&gt;: What started as a "slow website" complaint was actually an active breach.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Action Items
&lt;/h2&gt;

&lt;p&gt;If you're running Livewire in production:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check your Livewire version: &lt;code&gt;composer show livewire/livewire&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you're on any version before 4.0, update immediately&lt;/li&gt;
&lt;li&gt;Check for suspicious files in your storage and public directories&lt;/li&gt;
&lt;li&gt;Review server processes for unusual CPU consumption&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Originally published on my &lt;a href="https://placeholderblog.netlify.app/livewire-vulnerability/" rel="noopener noreferrer"&gt;blog&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you found this helpful, please share it with other Livewire users. This vulnerability is serious and widespread awareness is crucial.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>livewire</category>
      <category>security</category>
    </item>
  </channel>
</rss>
