<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thi Nguyen (T)</title>
    <description>The latest articles on DEV Community by Thi Nguyen (T) (@anhthii).</description>
    <link>https://dev.to/anhthii</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F800657%2F40146602-2474-4f0f-a742-19e340bea168.jpg</url>
      <title>DEV Community: Thi Nguyen (T)</title>
      <link>https://dev.to/anhthii</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anhthii"/>
    <language>en</language>
    <item>
      <title>Hackers Love Lazy Developers — 19 Security Mistakes You’re Making Right Now</title>
      <dc:creator>Thi Nguyen (T)</dc:creator>
      <pubDate>Tue, 21 Apr 2026 03:42:00 +0000</pubDate>
      <link>https://dev.to/anhthii/hackers-love-lazy-developers-19-security-mistakes-youre-making-right-now-17aj</link>
      <guid>https://dev.to/anhthii/hackers-love-lazy-developers-19-security-mistakes-youre-making-right-now-17aj</guid>
      <description>&lt;h1&gt;
  
  
  Security Handbook for Developers
&lt;/h1&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Hackers don't break in — they walk through the door you left open."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part I — Developer Identity &amp;amp; Workstation
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Threats that start at the endpoint: your laptop, your keys, your credentials. If an attacker owns the developer, the rest of the defenses barely matter.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. SSH Keys: Hackers' Easiest Target &amp;amp; Prime Hotspots
&lt;/h3&gt;

&lt;p&gt;Let's be honest—every developer, at least once, has raced through ssh-keygen in a caffeine-fueled haze, hammered Enter three times to skip the passphrase, and thought, "I'll add it later… maybe." But guess what? That heroic shortcut is like leaving your car unlocked with the keys in the ignition and a "Please Steal Me" bumper sticker.&lt;/p&gt;

&lt;p&gt;If some sneaky hacker nabs your unencrypted private SSH key, they don't need to knock—they walk right in. They can masquerade as you on your servers or GitHub, push malicious code, raid private repos, and throw a root-level rave in your infrastructure.&lt;/p&gt;

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

&lt;p&gt;There have even been exploits—like the SSH-key-scan honeypot attack—that prey on keys without passphrases.&lt;/p&gt;

&lt;p&gt;Don't be that person who leaves the passphrase blank. Instead, channel your inner secret-agent and pick a passphrase like &lt;code&gt;C0ffee#Mug@3xtraShot&lt;/code&gt; (words + numbers + special chars). Your future self (and your servers) will thank you! And remember: rotate those keys every month, because even the best locks need fresh keys now and then.&lt;/p&gt;

&lt;p&gt;If you provide an empty passphrase when generating an SSH key, the private key will not be encrypted. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anyone who gains access to your private key file (e.g., via a compromised machine, malware, or accidental exposure) can use it without any restriction to authenticate as you.&lt;/li&gt;
&lt;li&gt;There will be no additional layer of security beyond file system permissions.&lt;/li&gt;
&lt;li&gt;Attackers can use stolen private keys immediately, making them a prime target in exploits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By setting a strong passphrase, your private key is encrypted with that passphrase, meaning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Even if someone steals your private key file, they cannot use it without knowing the passphrase.&lt;/li&gt;
&lt;li&gt;It adds an extra layer of security, making it much harder for attackers to exploit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Maximum Security: Store Your SSH Key on a YubiKey (FIDO2)
&lt;/h4&gt;

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

&lt;p&gt;Even a passphrase-protected SSH key still lives on disk — and anything on disk can be copied. If your laptop gets popped by malware, info-stealer, or a malicious &lt;code&gt;postinstall&lt;/code&gt; script, the attacker walks away with &lt;code&gt;~/.ssh/id_ed25519&lt;/code&gt; and just needs to crack (or keylog) the passphrase.&lt;/p&gt;

&lt;p&gt;The fix: &lt;strong&gt;don't store the private key on disk at all.&lt;/strong&gt; Generate a FIDO2/resident SSH key directly on a hardware token like a YubiKey. The private key material never leaves the device, and every &lt;code&gt;git push&lt;/code&gt; requires a physical touch on the key. No touch = no auth. Steal the laptop, still can't push.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this is the gold standard for pushing to GitHub:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private key is non-exportable — malware literally cannot exfiltrate it&lt;/li&gt;
&lt;li&gt;Physical presence check (touch-to-authenticate) stops remote abuse even if the machine is fully compromised&lt;/li&gt;
&lt;li&gt;Works with OpenSSH 8.2+ natively — no extra agents, no GPG dance&lt;/li&gt;
&lt;li&gt;Same key can sign commits (&lt;code&gt;gpg.format ssh&lt;/code&gt;) so auth &lt;em&gt;and&lt;/em&gt; commit signing are hardware-backed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Generate a resident SSH key on the YubiKey:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519-sk &lt;span class="nt"&gt;-O&lt;/span&gt; resident &lt;span class="nt"&gt;-O&lt;/span&gt; &lt;span class="nv"&gt;application&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ssh:github &lt;span class="nt"&gt;-O&lt;/span&gt; verify-required &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"github-yubikey"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-t ed25519-sk&lt;/code&gt; → hardware-backed Ed25519 key&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-O resident&lt;/code&gt; → key can be pulled back onto any machine with &lt;code&gt;ssh-keygen -K&lt;/code&gt; (no backup file needed)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-O verify-required&lt;/code&gt; → requires PIN &lt;em&gt;and&lt;/em&gt; touch on every use (defense in depth)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pin the key for GitHub pushes only:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; core.sshCommand &lt;span class="s1"&gt;'ssh -i ~/.ssh/id_ed25519_sk -o IdentitiesOnly=yes'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;IdentitiesOnly=yes&lt;/code&gt; flag prevents SSH from leaking other identities to the server. Add the public key (&lt;code&gt;id_ed25519_sk.pub&lt;/code&gt;) to GitHub → Settings → SSH keys, and every push now demands a physical touch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recovery:&lt;/strong&gt; Buy &lt;strong&gt;two&lt;/strong&gt; YubiKeys and enroll both up front. If you lose one, you're not locked out of your own repos at 2 AM on a Friday.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Don't Let Hackers Impersonate You, Lock Down Commits with GPG
&lt;/h3&gt;

&lt;p&gt;Why would a hacker forge your commits? How do they pull it off?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sneak in malicious code&lt;/strong&gt;: By masquerading as a trusted contributor, they slip dangerous payloads into your codebase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Corrupt your audit trail&lt;/strong&gt;: Fake author metadata clouds the "blame" history, making investigations a nightmare.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exploit CI/CD&lt;/strong&gt;: A forged commit can trigger automated pipelines, provisioning backdoors or leaking secrets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How they hack through forged commits — spoofing Git metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;--author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"You "&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Awesome new feature"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Signed commits add an extra layer of security by proving the authenticity of code contributions. This prevents commit forgery and ensures that only verified developers contribute to the codebase.&lt;/p&gt;

&lt;p&gt;A signed commit with verified badge:&lt;/p&gt;

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

&lt;p&gt;When you sign a commit, you must enter the password for the GPG key:&lt;/p&gt;

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

&lt;p&gt;Additionally, to be able to push code to Github, you must enter the passphrase for the SSH key. This creates 2 layers of protection similar to multi factor authentication.&lt;/p&gt;

&lt;p&gt;When generating GPG key, should generate with an expiration. Recommendation is 3 months.&lt;/p&gt;

&lt;p&gt;Adding GPG key in Github Account Setting:&lt;/p&gt;

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




&lt;h3&gt;
  
  
  3. Enforce Strong Password Practices &amp;amp; Secure Credential Management
&lt;/h3&gt;

&lt;p&gt;Ensuring strong password hygiene is critical to protecting developer accounts, repositories, and infrastructure from unauthorized access. Weak or reused passwords are a major attack vector, leading to account takeovers and data breaches.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  Best Practices for Strong Password Security
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use a Password Manager&lt;/strong&gt; — Developers should never store passwords in plaintext. Use a trusted password manager such as Bitwarden, 1Password, LastPass, or KeePassXC. Enable 2FA for the password manager itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Strong, Unique Passwords for Each Service&lt;/strong&gt; — Generate randomized, long passwords (at least 16-24 characters with uppercase, lowercase, numbers, and special characters).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotate Passwords for Critical Applications Regularly&lt;/strong&gt; — Critical applications include GitHub, social accounts, Google Account, crypto wallets, database credentials, cloud infrastructure, and financial accounts. Rotate every 3-6 months.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable Two-Factor Authentication (2FA) on All Apps&lt;/strong&gt; — MFA is non-negotiable. Prefer hardware security keys (YubiKey, NitroKey) over SMS or authenticator apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Passkeys Where Possible&lt;/strong&gt; — Passkeys (WebAuthn) are a more secure alternative to passwords. Prevents phishing attacks by eliminating password-based logins.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Secrets Aren't for Sharing, Not Even with Your Team
&lt;/h3&gt;

&lt;p&gt;Never share private keys, API secrets, or credentials with anyone—including coworkers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Do Not Share Credentials&lt;/strong&gt;: Use role-based access controls (RBAC) and secure secret management tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotate Credentials Regularly&lt;/strong&gt;: Implement automated credential rotation policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compromised Secrets Lead to Untraceable Security Breaches&lt;/strong&gt;: If credentials are leaked, attackers could move laterally within the system, making it harder to identify the entry point.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  5. Don't Store Secrets in .env Files – Use a Secure Secret Vault
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Why .env Files Are a Security Risk
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;.env files can be accidentally committed to Git, exposing secrets in repositories.&lt;/li&gt;
&lt;li&gt;Attackers with access to a developer's machine can extract credentials from .env files.&lt;/li&gt;
&lt;li&gt;.env files lack access controls, making it impossible to enforce least privilege access.&lt;/li&gt;
&lt;li&gt;Secrets in .env files are not automatically rotated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Use HashiCorp Vault Instead
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Secrets are encrypted on the disk level&lt;/li&gt;
&lt;li&gt;Provides dynamic secret injection without storing credentials in local files&lt;/li&gt;
&lt;li&gt;Supports RBAC for secure access management&lt;/li&gt;
&lt;li&gt;Allows automatic secret rotation
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Inject secrets dynamically&lt;/span&gt;
vault &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-wrap-env&lt;/span&gt; my_command

&lt;span class="c"&gt;# Example: Injecting Database Credentials Securely&lt;/span&gt;
vault &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--env&lt;/span&gt; DB_USERNAME &lt;span class="nt"&gt;--env&lt;/span&gt; DB_PASSWORD my_command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Secrets are never stored in local files or exposed in shell history.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Secure Firewall Policy for Developer Desktops
&lt;/h3&gt;

&lt;p&gt;A firewall is critical for developer desktops, ensuring unauthorized network traffic is properly controlled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key reasons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Block unauthorized outbound traffic&lt;/strong&gt; — Prevents malware from leaking sensitive data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Restrict inbound access&lt;/strong&gt; — Ensures only necessary services are accessible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mitigate attack risks&lt;/strong&gt; — Reduces exposure to port scanning and unauthorized access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best Practices:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Least Privilege: Allow only necessary services.&lt;/li&gt;
&lt;li&gt;Deny by Default: Block all and allow only required traffic.&lt;/li&gt;
&lt;li&gt;Logging &amp;amp; Monitoring: Enable logging for audit trails.&lt;/li&gt;
&lt;li&gt;Regular Review: Periodically check rules for outdated permissions.&lt;/li&gt;
&lt;li&gt;Use IP Whitelisting: Restrict access to trusted IPs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suggested tools: UFW, OpenSnitch.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Monitor for Compromised Developer Devices
&lt;/h3&gt;

&lt;p&gt;Even if your backend is locked down, all it takes is one developer's infected laptop to sink the ship.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;Endpoint Detection &amp;amp; Response (EDR) tools&lt;/strong&gt; like CrowdStrike, SentinelOne, or open-source Wazuh.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disable automatic token caching&lt;/strong&gt; in CLI tools like GitHub CLI, AWS CLI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limit SSH agent forwarding&lt;/strong&gt;, especially on jump boxes and bastion hosts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Restrict privileged developer laptops from using public Wi-Fi&lt;/strong&gt; or enforce VPN-only policies.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part II — Supply Chain &amp;amp; Dependencies
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Everything that enters your machine from the outside world: packages, images, downloads, attachments. The inbound trust boundary is where modern attacks land first.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  8. No Blind Installs: Treat Each Package Like a Potential Trojan
&lt;/h3&gt;

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

&lt;p&gt;The open-source package ecosystems (npm, PyPI, Go modules and beyond) are prime real-estate for supply-chain attacks. One malicious dependency can turn your entire codebase into a backdoor.&lt;/p&gt;

&lt;h4&gt;
  
  
  Real-World Supply-Chain Ambushes
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.bleepingcomputer.com/news/security/malicious-npm-packages-target-ethereum-developers-private-keys/" rel="noopener noreferrer"&gt;Malicious NPM Packages Target Ethereum Developers' Private Keys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thehackernews.com/2025/01/hackers-deploy-malicious-npm-packages.html" rel="noopener noreferrer"&gt;Hackers Deploy Malicious npm Packages Targeting Crypto Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thehackernews.com/2025/04/ripples-xrpljs-npm-package-backdoored.html" rel="noopener noreferrer"&gt;Ripple's xrpl.js npm Package Backdoored&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.scworld.com/brief/malicious-python-package-found-stealing-ethereum-private-keys" rel="noopener noreferrer"&gt;Malicious Python Package Stealing Ethereum Private Keys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.theregister.com/2025/02/04/golang_supply_chain_attack/" rel="noopener noreferrer"&gt;The trojanized Golang BoltDB repo went undetected for 3+ years&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Common Attack Patterns
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Typosquatting &amp;amp; Look-Alikes&lt;/strong&gt; — Packages with names almost identical to popular ones sneak past casual installs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compromised Maintainers&lt;/strong&gt; — If a trusted owner's account is hijacked, legitimate libraries can be laced with malware.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Confusion&lt;/strong&gt; — Publishing internal package names publicly tricks CI/CD pipelines into fetching malicious versions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Obfuscated Malware&lt;/strong&gt; — Minified or compiled code conceals data-stealing routines.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h4&gt;
  
  
  Pre-Installation Security Checklist
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Authenticate the Source&lt;/strong&gt; — Install only from official registries and verify the maintainer's identity. Run &lt;code&gt;npm audit&lt;/code&gt;, &lt;code&gt;pip audit&lt;/code&gt;, or use tools like Socket.dev.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pin &amp;amp; Inspect Your Dependencies&lt;/strong&gt; — Commit lockfiles. Preview dependency trees with &lt;code&gt;npm ls&lt;/code&gt;, &lt;code&gt;go mod graph&lt;/code&gt;, or &lt;code&gt;pipdeptree&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spot Typosquats&lt;/strong&gt; — Double-check package names against the registry and GitHub repo links.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  9. Don't Let Docker Be Your Trojan Horse: Lock Down Your Containers
&lt;/h3&gt;

&lt;p&gt;Containers are like magic boxes: lightweight, portable, and fast. But if you treat them like black boxes and skip security, they'll behave like Pandora's Box.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A container isn't a sandbox unless you make it one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Major Docker Security Breaches
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://arstechnica.com/information-technology/2018/02/tesla-cloud-resources-are-hacked-to-run-cryptocurrency-mining-malware/" rel="noopener noreferrer"&gt;Tesla Kubernetes Hack (2018)&lt;/a&gt; — Attackers exploited an open Kubernetes dashboard to deploy cryptominers.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://thehackernews.com/2019/04/docker-hub-data-breach.html" rel="noopener noreferrer"&gt;Docker Hub Data Breach (2019)&lt;/a&gt; — 190,000 user credentials exposed.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.bleepingcomputer.com/news/security/teamtnt-hackers-target-your-poorly-configured-docker-servers/" rel="noopener noreferrer"&gt;TeamTNT Docker API Attacks (2020–2021)&lt;/a&gt; — Exploited unauthenticated Docker daemons.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://unit42.paloaltonetworks.com/graboid-first-ever-cryptojacking-worm-found-in-images-on-docker-hub/" rel="noopener noreferrer"&gt;Graboid Docker Worm (2019)&lt;/a&gt; — First Docker worm spread through unsecured daemons.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.techradar.com/pro/security/misconfigured-docker-instances-are-being-hacked-to-mine-cryptocurrency" rel="noopener noreferrer"&gt;Dero Miner Targeting Docker (2025)&lt;/a&gt; — Cryptomining worm exploiting misconfigured Docker daemons.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Best Practices for Secure Docker Usage
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;1. Never Run Containers as Root&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Bad&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; root&lt;/span&gt;

&lt;span class="c"&gt;# Good - Use a non-root user&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;-m&lt;/span&gt; appuser
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; appuser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Use Minimal Base Images&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Small and secure base image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:3.20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Scan Images for Vulnerabilities&lt;/strong&gt; — Use &lt;a href="https://github.com/aquasecurity/trivy" rel="noopener noreferrer"&gt;Trivy&lt;/a&gt; or &lt;a href="https://github.com/goodwithtech/dockle" rel="noopener noreferrer"&gt;Dockle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Sign and Verify Docker Images&lt;/strong&gt; — Use Docker Content Trust (DCT) or &lt;a href="https://github.com/sigstore/cosign" rel="noopener noreferrer"&gt;Cosign&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Avoid Leaking Secrets in Docker Images&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Bad&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; .env /app/.env&lt;/span&gt;

&lt;span class="c"&gt;# Better&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; API_KEY&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; API_KEY=$API_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Use Docker Networks + Firewalls Wisely&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Limit to localhost&lt;/span&gt;
&lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:8080:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. Monitor and Limit Container Resources&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--memory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;256m &lt;span class="nt"&gt;--cpus&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.5 myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8. Keep Docker &amp;amp; Host Up-To-Date&lt;/strong&gt; — Consider distros like Bottlerocket or Flatcar designed for containers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Runtime Security with eBPF + Sandboxing&lt;/strong&gt; — Use &lt;a href="https://github.com/cilium/tetragon" rel="noopener noreferrer"&gt;Cilium Tetragon&lt;/a&gt; for eBPF-based monitoring. Use gVisor or Kata Containers for sandboxing.&lt;/p&gt;




&lt;h3&gt;
  
  
  10. Verify Website URLs Carefully Before Downloading Anything
&lt;/h3&gt;

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

&lt;p&gt;&lt;strong&gt;The Download Trap: When "Official" Isn't Actually Official&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You're rushing to install a new tool, you Google it, click the first result, and BAM — you just downloaded malware disguised as legitimate software. Even Homebrew has been &lt;a href="https://www.bleepingcomputer.com/news/security/fake-homebrew-google-ads-target-mac-users-with-malware/" rel="noopener noreferrer"&gt;targeted by sophisticated phishing campaigns&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  How Attackers Hook Developers
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Google Ads Hijack&lt;/strong&gt; — Malicious ads appear &lt;em&gt;above&lt;/em&gt; legitimate search results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typosquatting&lt;/strong&gt; — &lt;code&gt;https://node-js.org&lt;/code&gt; instead of &lt;code&gt;https://nodejs.org&lt;/code&gt;, &lt;code&gt;https://g1thub.com&lt;/code&gt; instead of &lt;code&gt;https://github.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SEO Poisoning&lt;/strong&gt; — Fake sites optimize for search rankings.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  The Developer's Download Defense Playbook
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Source Authentication&lt;/strong&gt; — Never trust search engines for software downloads. Bookmark trusted sources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: URL Forensics&lt;/strong&gt; — HTTPS is non-negotiable. Inspect certificates. Read URLs character by character.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Prefer Package Managers&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Secure: Use official package managers&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;node          &lt;span class="c"&gt;# macOS&lt;/span&gt;
apt &lt;span class="nb"&gt;install &lt;/span&gt;nodejs         &lt;span class="c"&gt;# Ubuntu/Debian&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; typescript  &lt;span class="c"&gt;# Node.js packages&lt;/span&gt;

&lt;span class="c"&gt;# Risky: Manual downloads from random websites&lt;/span&gt;
curl https://suspicious-site.com/nodejs.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Pre-Installation Scanning&lt;/strong&gt; — Upload to VirusTotal, verify checksums, sandbox test suspicious downloads.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Attack&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Year&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Impact&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Method&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PyPI Package Attack&lt;/td&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;Thousands infected&lt;/td&gt;
&lt;td&gt;Mimicking &lt;code&gt;pytorch-nightly&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Ads Malware&lt;/td&gt;
&lt;td&gt;2023&lt;/td&gt;
&lt;td&gt;Mass infections&lt;/td&gt;
&lt;td&gt;Fake ads for VLC, Notepad++&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NPM Supply Chain&lt;/td&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;Worldwide impact&lt;/td&gt;
&lt;td&gt;Malware in &lt;code&gt;ua-parser-js&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  11. Weaponized PDFs &amp;amp; File Traps: Don't Get Baited
&lt;/h3&gt;

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

&lt;p&gt;Cybercriminals love when you open random files, especially PDFs via Telegram, email, or Discord. From Radiant to Ronin, multimillion-dollar exploits began with a single careless click.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Radiant hack (2024)&lt;/strong&gt; — $50M lost from malware in a PDF&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ronin Bridge hack (2022)&lt;/strong&gt; — $615M lost from a similar vector&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Guidelines for Handling PDFs:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Do NOT download and open PDFs directly&lt;/strong&gt; — Open them in your browser using Google Drive or other secure preview options.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be wary of unexpected attachments&lt;/strong&gt; — Verify legitimacy before opening.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never enable macros or scripts&lt;/strong&gt; — Some PDFs prompt you to enable features that execute malicious code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Report suspicious files&lt;/strong&gt; — If you receive a suspicious PDF, report it to your security team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use application sandboxing if you must open a PDF locally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Windows&lt;/strong&gt;: Windows Sandbox (built-in)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux&lt;/strong&gt;: Firejail&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS&lt;/strong&gt;: App Sandbox&lt;/li&gt;
&lt;/ul&gt;

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

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




&lt;h2&gt;
  
  
  Part III — DevSecOps &amp;amp; Shift-Left
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Security baked into the build pipeline and the code itself. Find bugs before attackers do.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  12. Secure Your CI/CD Pipelines: Attackers Love Automated Trust
&lt;/h3&gt;

&lt;p&gt;Your CI/CD pipeline has the keys to the kingdom: access to source code, secrets, cloud credentials, and deployment mechanisms.&lt;/p&gt;

&lt;h4&gt;
  
  
  Major CI/CD Security Breaches
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SolarWinds Orion (2020)&lt;/strong&gt; — Nation-state attackers inserted a backdoor, impacting 18,000+ customers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codecov (2021)&lt;/strong&gt; — Attackers tampered with the Bash uploader, stealing secrets from thousands of environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CircleCI (2023)&lt;/strong&gt; — Compromise led to theft of environment variables, secrets, and keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Travis CI (2022)&lt;/strong&gt; — Leaked secrets in build logs exposed thousands of credentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PHP Git Server (2021)&lt;/strong&gt; — CI pipeline was hijacked to insert malicious code into official PHP source.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Best Practices:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use ephemeral environments&lt;/strong&gt;: Rebuild containers and runners on every job.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Restrict secrets exposure&lt;/strong&gt;: Never expose all secrets to every job; use secret-scoping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Require commit signature verification&lt;/strong&gt; before running deploy jobs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use OpenID Connect (OIDC)&lt;/strong&gt; for temporary cloud permissions via short-lived tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit your pipeline dependencies&lt;/strong&gt;: Install only trusted tools and lock versions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline Isolation &amp;amp; Segmentation&lt;/strong&gt;: Separate pipelines by environment.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  13. Secure Coding: Write Code That Resists Attacks
&lt;/h3&gt;

&lt;p&gt;Developers must write code that is resilient to common attacks. Key practices from the OWASP Top 10:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input Validation&lt;/strong&gt;: Treat all user input as untrusted. Validate and sanitize on the server side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output Encoding&lt;/strong&gt;: Encode data output to prevent XSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parameterized Queries&lt;/strong&gt;: Prevent SQL injection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication and Session Management&lt;/strong&gt;: Implement strong auth, MFA, and secure cookies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling&lt;/strong&gt;: Avoid leaking sensitive info in error messages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least Privilege&lt;/strong&gt;: Never run applications as root.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Vulnerable to SQL injection
&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE username = &lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"'&lt;/span&gt;&lt;span class="s"&gt; AND password = &lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"'"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Secure: Parameterized query
&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE username = ? AND password = ?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  14. Security Testing: Shift Left and Catch Issues Early
&lt;/h3&gt;

&lt;p&gt;Shifting security left means integrating security early in the SDLC:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SAST (Static Application Security Testing)&lt;/strong&gt;: Analyze source code during development. Tools: SonarQube, Bandit, ESLint with security plugins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DAST (Dynamic Application Security Testing)&lt;/strong&gt;: Test running applications. Tools: OWASP ZAP, Burp Suite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Scanning&lt;/strong&gt;: Use Dependabot, Renovate, or Snyk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret Scanning&lt;/strong&gt;: Use GitGuardian or TruffleHog to prevent secrets from being committed.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part IV — Access &amp;amp; Infrastructure
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Shrink the blast radius: no standing production access, no flat networks, no permanent cloud admins.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  15. VPN Connection Required for Critical Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;VPN authentication must require Two-Factor Authentication (2FA).&lt;/li&gt;
&lt;li&gt;All employees and contractors must enable 2FA on cloud accounts, code repositories, and internal dashboards.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  16. Implement Just-In-Time (JIT) Privileges
&lt;/h3&gt;

&lt;p&gt;Developers often have standing access to sensitive infrastructure. JIT access ensures elevated permissions are granted temporarily, on-demand, with approval, and revoked automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Implement:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS IAM + SSO + Identity Center&lt;/strong&gt; — Short-duration assume-role sessions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure PIM&lt;/strong&gt; — Temporary admin roles with approval and MFA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teleport Access Requests&lt;/strong&gt; — JIT SSH/Kubernetes/database access via Slack or web UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;StrongDM or Boundary (HashiCorp)&lt;/strong&gt; — Identity-based JIT session brokering&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  17. Cloud Security: Shared Responsibility Model
&lt;/h3&gt;

&lt;p&gt;Key practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IAM&lt;/strong&gt;: Assign minimal permissions. Use groups and roles. Enable MFA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network Security&lt;/strong&gt;: Use VPCs, security groups, and network ACLs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption&lt;/strong&gt;: Encrypt data at rest and in transit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging and Monitoring&lt;/strong&gt;: Enable cloud provider logs and set up alerts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IaC Security&lt;/strong&gt;: Scan Terraform/CloudFormation templates with Checkov or tfsec.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Bad:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;access&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-bucket/*"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Good:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Restrict&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;specific&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;IAM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;role&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::123456789012:role/my-role"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-bucket/*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part V — Detect &amp;amp; Respond
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Assume breach. The question isn't if something slips through — it's how fast you see it and how cleanly you contain it.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  18. Security Logging &amp;amp; Alerting: Detecting Threats Before They Strike
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"You can't defend what you can't see."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Centralizing developer logs using SIEM tools is essential. A well-configured SIEM can help you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detect lateral movement across developer machines&lt;/li&gt;
&lt;li&gt;Correlate developer activity with alerts from cloud systems&lt;/li&gt;
&lt;li&gt;Set up anomaly detection alerts for suspicious behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tools:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://documentation.wazuh.com/current/index.html" rel="noopener noreferrer"&gt;Wazuh&lt;/a&gt; — Open-source SIEM + XDR&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://falco.org/" rel="noopener noreferrer"&gt;Falco (CNCF)&lt;/a&gt; — Cloud-native runtime threat detection&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://osquery.io/" rel="noopener noreferrer"&gt;Osquery&lt;/a&gt; — Query endpoints like a database&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://attack.mitre.org/" rel="noopener noreferrer"&gt;MITRE ATT&amp;amp;CK Framework&lt;/a&gt; — Map attacker behavior to detection patterns&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  19. Incident Response: Be Prepared for the Worst
&lt;/h3&gt;

&lt;p&gt;Following the NIST model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Detection and Reporting&lt;/strong&gt;: Recognize breaches through unusual behavior and monitoring alerts. Report immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Containment&lt;/strong&gt;: Isolate affected systems. Revoke compromised credentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eradication&lt;/strong&gt;: Patch vulnerabilities. Remove malware.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recovery&lt;/strong&gt;: Restore from clean backups. Monitor for recurrence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-Incident Analysis&lt;/strong&gt;: Conduct retrospectives to improve defenses.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Frameworks:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://csrc.nist.gov/publications/detail/sp/800-61/rev-2/final" rel="noopener noreferrer"&gt;NIST SP 800-61r2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sans.org/white-papers/1741/" rel="noopener noreferrer"&gt;SANS Incident Handler's Handbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://attack.mitre.org/" rel="noopener noreferrer"&gt;MITRE ATT&amp;amp;CK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Open Source Toolkits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/google/grr" rel="noopener noreferrer"&gt;GRR Rapid Response&lt;/a&gt; — Remote forensics&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://thehive-project.org/" rel="noopener noreferrer"&gt;TheHive + Cortex&lt;/a&gt; — Collaborative incident handling&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zeek.org/" rel="noopener noreferrer"&gt;Zeek&lt;/a&gt; — Network traffic analysis&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://github.com/fystack/developer-security-handbook" rel="noopener noreferrer"&gt;fystack/developer-security-handbook&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Secure crypto infrastructure: SLSA L3 Provenance for Docker Images - How We Made Our Builds Verifiable</title>
      <dc:creator>Thi Nguyen (T)</dc:creator>
      <pubDate>Wed, 15 Apr 2026 05:54:01 +0000</pubDate>
      <link>https://dev.to/anhthii/secure-crypto-infrastructure-slsa-l3-provenance-for-docker-images-how-we-made-our-builds-55hn</link>
      <guid>https://dev.to/anhthii/secure-crypto-infrastructure-slsa-l3-provenance-for-docker-images-how-we-made-our-builds-55hn</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In March 2026, the &lt;code&gt;axios&lt;/code&gt; package was compromised through a hijacked npm maintainer account. A malicious version was published containing a credential-stealing backdoor that exfiltrated cloud keys before self-destructing. This incident exemplified a persistent problem: downstream users must trust artifacts blindly without cryptographic verification of build provenance.&lt;/p&gt;

&lt;p&gt;At Fystack, a crypto custody infrastructure provider, supply chain integrity is critical—"a tampered image in our environment doesn't mean a bug, it means compromised keys and drained wallets." The company addressed this challenge through SLSA L3 provenance implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsh6ujjfbg3gu62x01ns0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsh6ujjfbg3gu62x01ns0.png" alt="How Checksum is using in Supply Chain" width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Verification Gap Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;When pulling a Docker image, users receive a SHA-256 digest proving content integrity. However, this reveals nothing about production methods. Signatures verify identity but not whether the build environment was compromised or if code matched the source commit.&lt;/p&gt;

&lt;p&gt;The gap exists between "signed" and "provable." A malicious actor accessing CI runners can build and sign anything with legitimate credentials. Dependency poisoning during builds produces validly-signed images containing malicious code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fghost.fystack.io%2Fcontent%2Fimages%2F2026%2F04%2Fsupplychain-deps-atk.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fghost.fystack.io%2Fcontent%2Fimages%2F2026%2F04%2Fsupplychain-deps-atk.svg" alt="Supply Chain threads" width="784" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This gap requires a third guarantee: &lt;strong&gt;provenance&lt;/strong&gt;—a cryptographically signed record of the exact source commit, build environment, workflow, and parameters, generated by a process isolated from the build itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What SLSA Actually Means (Beyond the Acronym)
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Supply-chain Levels for Software Artifacts&lt;/em&gt; was developed by Google and is governed by the OpenSSF. The framework defines graduated security guarantees for build pipelines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;L1&lt;/strong&gt;: Untrusted provenance document; useful for auditing but easily forgeable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L2&lt;/strong&gt;: Cryptographically signed provenance by CI platform; prevents post-build tampering but the same job generating the build creates the proof&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L3&lt;/strong&gt;: Provenance generated in a completely isolated process with separate identity and credentials; the build job cannot influence it&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In practical terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No SLSA/L1&lt;/strong&gt;: "Trust me, I built this"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLSA L2&lt;/strong&gt;: "Our CI built this, but if compromised, proof can be faked"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLSA L3&lt;/strong&gt;: "This image was built by our CI in a locked-down environment, and we can prove it, even if the build job is fully compromised"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SLSA L3 is now baseline for serious infrastructure providers. Google ships official container images at SLSA L3; GitHub builds Artifact Attestations on SLSA L3; Bitnami's Secure Images are SLSA L3 with publicly published verification keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Critical Difference: BuildKit vs. SLSA Generator
&lt;/h2&gt;

&lt;p&gt;Most implementations conflate these approaches. Docker's &lt;code&gt;build-push-action&lt;/code&gt; with &lt;code&gt;provenance: true&lt;/code&gt; provides L2 guarantees, not L3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BuildKit Provenance&lt;/strong&gt; (&lt;code&gt;provenance: true&lt;/code&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generated in the same job as the build&lt;/li&gt;
&lt;li&gt;Forgeable if the build is compromised&lt;/li&gt;
&lt;li&gt;SLSA L1–L2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SLSA L3 Provenance&lt;/strong&gt; (via &lt;code&gt;slsa-github-generator&lt;/code&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generated in a separate isolated job&lt;/li&gt;
&lt;li&gt;Receives only the image digest&lt;/li&gt;
&lt;li&gt;Not forgeable even if the build is compromised&lt;/li&gt;
&lt;li&gt;Signed by the SLSA generator's identity&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  How Fystack Applied SLSA
&lt;/h2&gt;

&lt;p&gt;Fystack's implementation uses three sequential jobs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Job 1: Build &amp;amp; Push&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
BuildKit compiles and pushes the image; native provenance is disabled, keeping only the immutable image digest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Job 2: SLSA L3 Provenance&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Uses &lt;code&gt;slsa-framework/slsa-github-generator&lt;/code&gt; in an isolated job. It receives only the final image digest, independently verifies the source repository, commit, and workflow via GitHub APIs, and generates non-forgeable SLSA Level 3 attestation. Even if Job 1 is compromised, this provenance cannot be faked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Job 3: Signing &amp;amp; Attestation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signs the image using cosign with keyless signing (GitHub OIDC + Fulcio); no private keys touch the repository or runner&lt;/li&gt;
&lt;li&gt;Generates full SPDX SBOM with Syft and attests it to the image&lt;/li&gt;
&lt;li&gt;Stores signatures and attestations using OCI 1.1 referrers mode to avoid tag pollution&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The final image carries five artifacts on the same digest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image layers&lt;/li&gt;
&lt;li&gt;BuildKit SBOM (for Docker Scout)&lt;/li&gt;
&lt;li&gt;Cosign signature&lt;/li&gt;
&lt;li&gt;SLSA L3 provenance&lt;/li&gt;
&lt;li&gt;Sigstore-attested SPDX SBOM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fystack open sourced this pipeline as a reusable GitHub Actions workflow at &lt;a href="https://github.com/fystack/slsa-workflows" rel="noopener noreferrer"&gt;fystack/slsa-workflows&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  What Verification Looks Like
&lt;/h2&gt;

&lt;p&gt;Downstream consumers verify independently with two commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Verify the cosign signature&lt;/span&gt;
cosign verify &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--certificate-identity-regexp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'https://github.com/fystack/slsa-workflows/.github/workflows/docker-build-slsa.yml@.*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--certificate-oidc-issuer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'https://token.actions.githubusercontent.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  fystacklabs/apex:v1.0.54

&lt;span class="c"&gt;# 2. Verify SLSA L3 provenance&lt;/span&gt;
slsa-verifier verify-image &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--source-uri&lt;/span&gt; github.com/yourorg/your-repo &lt;span class="se"&gt;\&lt;/span&gt;
  fystacklabs/apex@sha256:...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the build was tampered with, provenance checks fail even if the signature remains valid.&lt;/p&gt;

&lt;p&gt;All signatures and attestations are recorded in Rekor, Sigstore's public transparency log, creating an immutable, independently auditable record.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What This Still Doesn't Solve
&lt;/h2&gt;

&lt;p&gt;SLSA L3 is powerful but not comprehensive. Dependency attacks remain real threats. Malicious packages can be legitimate at build time while the image passes all verification. SBOMs provide visibility, not prevention.&lt;/p&gt;

&lt;p&gt;Base image risks are inherited. Backdoors like XZ Utils hid in official Debian images for over a year. Provenance records the base used but cannot detect compromise. Pinning by digest helps but doesn't eliminate risk.&lt;/p&gt;

&lt;p&gt;Malicious maintainers bypass everything. If trusted committers merge backdoored code, SLSA L3 still passes. It proves the pipeline ran correctly, not that code was safe. Code review and branch protection remain essential.&lt;/p&gt;

&lt;p&gt;Language registries such as npm and PyPI still lag behind container registry tooling.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The Standard Is Moving
&lt;/h2&gt;

&lt;p&gt;Three years ago, SLSA L3 was considered advanced security theater. Today it's becoming baseline expectation for serious projects.&lt;/p&gt;

&lt;p&gt;The question has shifted from "Should we adopt SLSA L3?" to "Why haven't we done it yet?"&lt;/p&gt;

&lt;p&gt;Tools are free, mature, and maintained by Google and the OpenSSF. The effort is real but measured in hours, not weeks.&lt;/p&gt;

&lt;p&gt;"Your users run your code in production. They deserve more than 'trust me.' They deserve cryptographic proof."&lt;/p&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://slsa.dev/spec/v1.0/levels" rel="noopener noreferrer"&gt;SLSA v1.0 Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/enterprise-software/devsecops/enhance-build-security-and-reach-slsa-level-3-with-github-artifact-attestations/" rel="noopener noreferrer"&gt;GitHub SLSA L3 with Artifact Attestations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/slsa-framework/slsa-github-generator" rel="noopener noreferrer"&gt;slsa-github-generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/fystack/slsa-workflows" rel="noopener noreferrer"&gt;Fystack reusable workflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>docker</category>
      <category>devops</category>
      <category>cicd</category>
    </item>
    <item>
      <title>How to build a Crypto Payment Gateway with Fystack Programmable Wallet Infrastructure (Part 1)</title>
      <dc:creator>Thi Nguyen (T)</dc:creator>
      <pubDate>Wed, 15 Apr 2026 05:41:40 +0000</pubDate>
      <link>https://dev.to/anhthii/how-to-build-a-crypto-payment-gateway-with-fystack-programmable-wallet-infrastructure-part-1-1lga</link>
      <guid>https://dev.to/anhthii/how-to-build-a-crypto-payment-gateway-with-fystack-programmable-wallet-infrastructure-part-1-1lga</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Fystack enables developers to create production-ready cryptocurrency payment gateways without managing private keys or blockchain infrastructure. The platform handles wallet creation, deposit address generation across multiple chains, automatic fund consolidation, and transaction monitoring through a unified SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;The payment flow consists of six steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Applications create wallets per user via the Fystack SDK&lt;/li&gt;
&lt;li&gt;Fystack generates deposit addresses across Ethereum, Solana, Tron, and Bitcoin&lt;/li&gt;
&lt;li&gt;Users deposit funds to their assigned addresses&lt;/li&gt;
&lt;li&gt;Sweep tasks automatically consolidate funds into a central hot wallet when thresholds are met&lt;/li&gt;
&lt;li&gt;Consolidated funds reach the hot wallet for settlement&lt;/li&gt;
&lt;li&gt;Withdrawals and payouts distribute funds to merchants or external addresses&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fghost.fystack.io%2Fcontent%2Fimages%2F2026%2F04%2Ffystack_payment_flow--1-.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fghost.fystack.io%2Fcontent%2Fimages%2F2026%2F04%2Ffystack_payment_flow--1-.svg" alt="Build a crypto payment gateway with Fystack wallet infrastructure" width="100" height="120.58823529411765"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The system uses &lt;strong&gt;Hyper wallets&lt;/strong&gt; (HD-derived for high-volume user wallets) and &lt;strong&gt;MPC wallets&lt;/strong&gt; (threshold signatures for treasury storage), eliminating direct private key exposure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 22 or later&lt;/li&gt;
&lt;li&gt;Fystack account with API credentials&lt;/li&gt;
&lt;li&gt;Workspace ID from the Fystack dashboard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmckbddhmms2izbu5tulz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmckbddhmms2izbu5tulz.png" alt="Copy workspaceID from API Key section" width="800" height="357"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Copy workspaceID from API Key section&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup Steps
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Install and Configure SDK
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @fystack/sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file with credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;FYSTACK_API_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your-api-key&lt;/span&gt;
&lt;span class="py"&gt;FYSTACK_API_SECRET&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your-api-secret&lt;/span&gt;
&lt;span class="py"&gt;FYSTACK_WORKSPACE_ID&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your-workspace-uuid&lt;/span&gt;
&lt;span class="py"&gt;HOT_WALLET_ID&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your-hot-wallet-uuid&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize the SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;FystackSDK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;WalletType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;WalletPurpose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;AddressType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@fystack/sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FystackSDK&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FYSTACK_API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FYSTACK_API_SECRET&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Production&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;workspaceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FYSTACK_WORKSPACE_ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Create a Hot Wallet
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hotWallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createWallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Treasury Hot Wallet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;walletType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WalletType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MPC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;walletPurpose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WalletPurpose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;General&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// Wait for creation to complete&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hot wallet ID:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hotWallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wallet_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnqubtch7g8ulnlezic0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnqubtch7g8ulnlezic0.png" alt="Create a wallet through Fystack portal" width="800" height="532"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Create a wallet through Fystack portal&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;MPC wallet creation is asynchronous; the distributed key generation protocol requires 10-30 seconds across multiple nodes.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: Create a Sweep Task
&lt;/h3&gt;

&lt;p&gt;Visit the Fystack portal → Automation → Add sweep task. Configure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Task name&lt;/li&gt;
&lt;li&gt;Destination wallet (the MPC hot wallet)&lt;/li&gt;
&lt;li&gt;Minimum trigger value in USD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkorky2wz9lf1pynxtsmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkorky2wz9lf1pynxtsmz.png" alt="Create a sweep task" width="800" height="331"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Create a sweep task&lt;/em&gt;&lt;/p&gt;

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

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

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

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

&lt;p&gt;The sweep task ID appears as the last segment of the URL.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 4: Create Per-User Wallets
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createUserWallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createWallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`user_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;walletType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WalletType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hyper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;walletPurpose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WalletPurpose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OneTimeUse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sweepTaskID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;6bdc8e47-dc1a-4416-9158-b99cdc23205a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;OneTimeUse wallets&lt;/strong&gt; attempt to empty completely during sweeps rather than preserving dust amounts for future gas fees, preventing stranded balances across thousands of deposit wallets.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 5: Get Multi-Chain Deposit Addresses
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDepositAddresses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;walletId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;evm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDepositAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;walletId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AddressType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Evm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDepositAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;walletId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AddressType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Solana&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qr_code&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Supported chains by address type:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Chains&lt;/th&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;evm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ethereum, Polygon, Arbitrum, Optimism, Base&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sol&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Solana&lt;/td&gt;
&lt;td&gt;Base58 public key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tron&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tron&lt;/td&gt;
&lt;td&gt;&lt;code&gt;T...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;btc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bitcoin&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bc1q...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Display endpoint example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/payment/:userId/address&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getOrCreateWallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addressType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;solana&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;AddressType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Solana&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AddressType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Evm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deposit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDepositAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wallet_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;addressType&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;qrCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;qr_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Listen for Deposits with Webhooks
&lt;/h3&gt;

&lt;p&gt;Fystack sends webhook events for transaction state changes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Trigger&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deposit.pending&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;On-chain detection, unconfirmed&lt;/td&gt;
&lt;td&gt;Show pending UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deposit.confirmed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Blockchain confirmation&lt;/td&gt;
&lt;td&gt;Credit account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;withdrawal.pending&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Withdrawal request created&lt;/td&gt;
&lt;td&gt;Update records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;withdrawal.confirmed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Transaction confirmed&lt;/td&gt;
&lt;td&gt;Mark complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;withdrawal.failed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Transaction failed&lt;/td&gt;
&lt;td&gt;Alert team&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Verify webhook signatures&lt;/strong&gt; using Ed25519:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;public_key&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getWebhookPublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FYSTACK_WORKSPACE_ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/webhook/fystack&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-webhook-signature&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-webhook-event&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canonical&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sortKeysDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canonical&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;public_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;der&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spki&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid signature&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deposit.confirmed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;handleDepositConfirmed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;withdrawal.confirmed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;handleWithdrawalConfirmed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;withdrawal.failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;handleWithdrawalFailed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;received&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sortKeysDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sortKeysDeep&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sortKeysDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This part covers wallet infrastructure, deposit address generation, automatic consolidation via sweep tasks, and webhook-based deposit detection. Part 2 will explore withdrawals, treasury management, and production architecture patterns.&lt;/p&gt;

&lt;p&gt;For questions about custody setup, visit the &lt;a href="https://app.youform.com/forms/qyanutyi" rel="noopener noreferrer"&gt;inquiry form&lt;/a&gt; or join the &lt;a href="https://t.me/+9AtC0z8sS79iZjFl" rel="noopener noreferrer"&gt;Telegram community&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>tutorial</category>
      <category>typescript</category>
    </item>
    <item>
      <title>When CPUs Hit 100%: Hard-Earned Lessons from a Multichain Indexer Outage, with Bloom Filters as the Rescue.</title>
      <dc:creator>Thi Nguyen (T)</dc:creator>
      <pubDate>Tue, 30 Sep 2025 15:30:53 +0000</pubDate>
      <link>https://dev.to/anhthii/when-cpus-hit-100-hard-earned-lessons-from-a-multichain-indexer-outage-with-bloom-filters-as-the-46af</link>
      <guid>https://dev.to/anhthii/when-cpus-hit-100-hard-earned-lessons-from-a-multichain-indexer-outage-with-bloom-filters-as-the-46af</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3s2ooqgaebewbfm72j8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3s2ooqgaebewbfm72j8a.png" alt=" " width="800" height="592"&gt;&lt;/a&gt;# When CPUs Hit 100%: Hard-Earned Lessons from a Multichain Indexer Outage | Fystack Blog&lt;br&gt;
At &lt;strong&gt;Fystack&lt;/strong&gt;, where we build blockchain wallet infrastructure, our transaction indexer needs to process &lt;strong&gt;over 100 million transactions per day&lt;/strong&gt; across multiple blockchains, including Ethereum, BNB, Polygon, Tron, and Solana.&lt;/p&gt;

&lt;p&gt;Our initial indexing logic was straightforward:&lt;br&gt;&lt;br&gt;
We maintain a &lt;strong&gt;database of wallet addresses&lt;/strong&gt; generated for our users. For each block on the blockchain, we parse the raw transaction data and &lt;strong&gt;check if the destination address exists in our database&lt;/strong&gt;. If it does, we process the transaction; otherwise, we ignore it.&lt;/p&gt;

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

&lt;p&gt;Indexing flow of Fytack indexer&lt;/p&gt;

&lt;p&gt;Handling EVM chains alone was manageable, but everything changed when we integrated &lt;strong&gt;Solana,&lt;/strong&gt; one of the most active chains, with huge transaction volumes driven by meme coin crazes and projects like &lt;a href="https://bump.fun/?ref=ghost.fystack.io" rel="noopener noreferrer"&gt;Bump.fun&lt;/a&gt;, averaging around &lt;strong&gt;42 million transactions per day&lt;/strong&gt; (~3,000 TPS).&lt;/p&gt;

&lt;p&gt;Our servers, particularly the CPU, were constantly under stress, with utilization hovering between &lt;strong&gt;80–90%&lt;/strong&gt;. On peak days, CPU usage reached &lt;strong&gt;100%&lt;/strong&gt;, causing the server to become unresponsive and our customers repeatedly encounter &lt;strong&gt;504 Gateway Timeout&lt;/strong&gt; errors and started complaining.&lt;/p&gt;

&lt;p&gt;The team had to temporarily suspend Solana processing and restart the server just to restore normal operations.&lt;/p&gt;

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

&lt;p&gt;CPU is under high stress&lt;/p&gt;

&lt;p&gt;We knew it was time to optimize.&lt;br&gt;&lt;br&gt;
Our team quickly identified that Consul where we persist user wallet addresses, was becoming a bottleneck. Storing and querying every address there doesn’t scale well when transaction volume is high.&lt;/p&gt;

&lt;p&gt;To handle this efficiently, we adopted a &lt;strong&gt;Bloom filter&lt;/strong&gt;, a well-known probabilistic data structure also used by the Ethereum blockchain for log filtering. A Bloom filter answers a simple question: &lt;em&gt;Could this item be in the set?&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If it says &lt;strong&gt;no&lt;/strong&gt;, the item is definitely absent and can be skipped.&lt;/li&gt;
&lt;li&gt;  If it says &lt;strong&gt;yes&lt;/strong&gt;, the item might be present, and we perform a full check against our source of truth.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because most transactions are unrelated to our platform, this lets us skip the vast majority of checks. Properly tuned, a Bloom filter can store millions of wallet addresses while consuming only a few MBs of memory.&lt;/p&gt;
&lt;h3&gt;
  
  
  Bloom Filter Process
&lt;/h3&gt;

&lt;p&gt;To ensure efficiency and scalability, we utilize the &lt;a href="https://redis.io/docs/latest/develop/data-types/probabilistic/bloom-filter/?ref=ghost.fystack.io" rel="noopener noreferrer"&gt;Redis Bloom filter module&lt;/a&gt;. When a transaction arrives, we check if the destination address exists in the Bloom filter. If it does not, we skip the transaction; if it does, we proceed to verify it in persistent storage.&lt;/p&gt;

&lt;p&gt;The team successfully refactored the system, added new logic, tested, and deployed the solution in under 2 days, allowing operations on Solana to resume as usual.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func (s *publicKeyStore) Exist(addressType enum.AddressType, publicKey string) bool {
    // First check the bloom filter.
    // If the bloom filter returns false, the key definitely doesn't exist.
    if !s.bloomFilter.Contains(publicKey, addressType) {
        return false
    }

    // Since bloom filters may have false positives, check the underlying KV store.
    v, err := s.kvstore.GetWithOptions(composeKey(addressType, publicKey), &amp;amp;infra.DefaultCacheOptions)
    if v == "" || err != nil {
        return false
    }

    return true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make it works seamlessly, we periodically synchronize addresses from our PostgreSQL database to a Redis Bloom filter through a simple and efficient process.&lt;/p&gt;

&lt;p&gt;Recent optimizations have significantly enhanced our indexer’s performance and resilience. It now maintains CPU utilization between 40-60%, even under high load, rarely reaching 100%.&lt;/p&gt;

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

&lt;p&gt;Fystack indexer with Bloom filter&lt;/p&gt;

&lt;p&gt;We’ve open-sourced our multichain indexer, supporting Ethereum, EVM chains, and Tron. Check it out at &lt;a href="https://github.com/fystack/multichain-indexer?ref=ghost.fystack.io" rel="noopener noreferrer"&gt;github.com/fystack/multichain-indexer.&lt;/a&gt; Bitcoin and Solana support are planned for future development.&lt;/p&gt;

&lt;p&gt;At &lt;a href="http://fystack.io/?ref=ghost.fystack.io" rel="noopener noreferrer"&gt;Fystack&lt;/a&gt;, we are building open source scallable wallet infrastructure that users can self host and doens't need to rely on expensive custodians.&lt;/p&gt;

&lt;p&gt;Check out our Github : &lt;a href="https://github.com/fystack/?ref=dev.to"&gt;https://github.com/fystack/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>performance</category>
      <category>architecture</category>
      <category>blockchain</category>
      <category>systemdesign</category>
    </item>
  </channel>
</rss>
