<?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: UPinar</title>
    <description>The latest articles on DEV Community by UPinar (@upinar).</description>
    <link>https://dev.to/upinar</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%2F3095959%2F2ee8622c-8f07-4ebd-9a82-4d8e16515037.png</url>
      <title>DEV Community: UPinar</title>
      <link>https://dev.to/upinar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/upinar"/>
    <language>en</language>
    <item>
      <title>I Scanned the Internet's Top 500 Websites for Security — Only 1% Got an A</title>
      <dc:creator>UPinar</dc:creator>
      <pubDate>Sun, 29 Mar 2026 08:15:38 +0000</pubDate>
      <link>https://dev.to/upinar/i-scanned-the-internets-top-500-websites-for-security-only-1-got-an-a-4o86</link>
      <guid>https://dev.to/upinar/i-scanned-the-internets-top-500-websites-for-security-only-1-got-an-a-4o86</guid>
      <description>&lt;p&gt;I built &lt;a href="https://contrastcyber.com" rel="noopener noreferrer"&gt;ContrastScan&lt;/a&gt; — an open-source security scanner written in C that grades websites A-F across 11 modules: SSL/TLS, HTTP headers, DNS email authentication, CORS, cookies, CSP, and more. Max score: 100 points.&lt;/p&gt;

&lt;p&gt;I took the &lt;a href="https://tranco-list.eu/" rel="noopener noreferrer"&gt;Tranco&lt;/a&gt; top 500 most visited domains, filtered out infrastructure-only entries (CDN nodes, DNS servers, API backends with no web frontend), and scanned the remaining 304 websites that had actual web frontends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The average score was 61 out of 100. A D+.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Grade&lt;/th&gt;
&lt;th&gt;Sites&lt;/th&gt;
&lt;th&gt;%&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;A&lt;/strong&gt; (90-100)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;B&lt;/strong&gt; (70-89)&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;C&lt;/strong&gt; (55-69)&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;td&gt;33%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;D&lt;/strong&gt; (40-54)&lt;/td&gt;
&lt;td&gt;126&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;41%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;F&lt;/strong&gt; (0-39)&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;6%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;3 out of 304 scored an A. The most common grade is &lt;strong&gt;D&lt;/strong&gt; — 41% of the internet's biggest sites live there.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who's Winning
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Site&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Grade&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;discord.com&lt;/td&gt;
&lt;td&gt;92&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;media.net&lt;/td&gt;
&lt;td&gt;92&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;taboola.com&lt;/td&gt;
&lt;td&gt;91&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stripe.com&lt;/td&gt;
&lt;td&gt;88&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;indeed.com&lt;/td&gt;
&lt;td&gt;88&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;openai.com&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;paypal.com&lt;/td&gt;
&lt;td&gt;85&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;salesforce.com&lt;/td&gt;
&lt;td&gt;84&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;github.com&lt;/td&gt;
&lt;td&gt;82&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;slack.com&lt;/td&gt;
&lt;td&gt;81&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Discord leads — TLS 1.3, all security headers, full SPF/DKIM/DMARC, tight CSP. Stripe and PayPal are right behind, which you'd expect from companies that handle payments.&lt;/p&gt;

&lt;p&gt;OpenAI at 87 is a pleasant surprise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who's Not
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Site&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Grade&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;microsoft.com&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;F&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;wikipedia.org&lt;/td&gt;
&lt;td&gt;41&lt;/td&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;adobe.com&lt;/td&gt;
&lt;td&gt;43&lt;/td&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;netflix.com&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;twitter.com&lt;/td&gt;
&lt;td&gt;51&lt;/td&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;reddit.com&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zoom.us&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dropbox.com&lt;/td&gt;
&lt;td&gt;53&lt;/td&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;spotify.com&lt;/td&gt;
&lt;td&gt;54&lt;/td&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Microsoft.com scores an F.&lt;/strong&gt; The company that sells Azure Security Center, Microsoft Defender, and enterprise security consulting — their own homepage fails a basic security scan.&lt;/p&gt;

&lt;p&gt;Wikipedia — the 7th most visited site on earth — gets a D.&lt;/p&gt;

&lt;p&gt;Netflix, Twitter, Reddit, Zoom, Dropbox, Spotify — all D.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Full Leaderboard
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;discord.com      ██████████████████████████████████████████████ 92 A
stripe.com       ████████████████████████████████████████████   88 B
paypal.com       ██████████████████████████████████████████     85 B
salesforce.com   ████████████████████████████████████████████   84 B
github.com       █████████████████████████████████████████      82 B
slack.com        ████████████████████████████████████████       81 B
oracle.com       ████████████████████████████████████████       80 B
booking.com      █████████████████████████████████              67 C
youtube.com      █████████████████████████████████              67 C
facebook.com     █████████████████████████████████              66 C
whatsapp.com     ███████████████████████████████                62 C
instagram.com    ██████████████████████████████                 60 C
linkedin.com     ██████████████████████████████                 60 C
apple.com        █████████████████████████████                  59 D
amazon.com       ████████████████████████████                   56 D
telegram.org     ███████████████████████████                    55 D
ibm.com          ███████████████████████████                    54 D
spotify.com      ███████████████████████████                    54 D
dropbox.com      ██████████████████████████                     53 D
reddit.com       ██████████████████████████                     52 D
zoom.us          ██████████████████████████                     52 D
twitter.com      █████████████████████████                      51 D
netflix.com      █████████████████████████                      50 D
adobe.com        █████████████████████                          43 D
wikipedia.org    ████████████████████                           41 D
microsoft.com    ███████████████████                            38 F
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Where Sites Lose the Most Points
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Missing Security Headers
&lt;/h3&gt;

&lt;p&gt;The biggest problem across the board. Out of 304 sites:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Header&lt;/th&gt;
&lt;th&gt;Missing&lt;/th&gt;
&lt;th&gt;%&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Permissions-Policy&lt;/td&gt;
&lt;td&gt;252&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;83%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Referrer-Policy&lt;/td&gt;
&lt;td&gt;231&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;76%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Security-Policy&lt;/td&gt;
&lt;td&gt;185&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;61%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Content-Type-Options&lt;/td&gt;
&lt;td&gt;151&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Frame-Options&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;td&gt;49%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strict-Transport-Security&lt;/td&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;34%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;83% don't set Permissions-Policy.&lt;/strong&gt; Without it, any third-party script on your page (analytics, ads, chat widgets) can access your visitors' camera, microphone, and geolocation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;61% have no CSP&lt;/strong&gt; — the single most effective defense against XSS.&lt;/p&gt;

&lt;p&gt;HSTS has been a best practice since 2012. 34% of top sites still don't use it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Module Breakdown
&lt;/h3&gt;

&lt;p&gt;How each security module scored on average:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Avg Score&lt;/th&gt;
&lt;th&gt;Max&lt;/th&gt;
&lt;th&gt;%&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CORS&lt;/td&gt;
&lt;td&gt;4.8&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML Analysis&lt;/td&gt;
&lt;td&gt;4.2&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;85%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS (Email Auth)&lt;/td&gt;
&lt;td&gt;11.9&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;80%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cookies&lt;/td&gt;
&lt;td&gt;3.8&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;77%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Info Disclosure&lt;/td&gt;
&lt;td&gt;3.6&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;72%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL/TLS&lt;/td&gt;
&lt;td&gt;10.1&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;51%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Headers&lt;/td&gt;
&lt;td&gt;9.9&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;40%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSP Analysis&lt;/td&gt;
&lt;td&gt;0.4&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;21%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Headers and CSP are where the internet bleeds points. CORS and HTML are generally fine — most sites don't expose dangerous CORS configurations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Email Authentication
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Record&lt;/th&gt;
&lt;th&gt;Present&lt;/th&gt;
&lt;th&gt;%&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DMARC&lt;/td&gt;
&lt;td&gt;268&lt;/td&gt;
&lt;td&gt;88%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SPF&lt;/td&gt;
&lt;td&gt;267&lt;/td&gt;
&lt;td&gt;88%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DKIM&lt;/td&gt;
&lt;td&gt;191&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;63%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;SPF and DMARC adoption is strong. But &lt;strong&gt;37% of top sites don't have DKIM&lt;/strong&gt; — which means their emails can be spoofed without cryptographic detection.&lt;/p&gt;




&lt;h2&gt;
  
  
  Vulnerability Count
&lt;/h2&gt;

&lt;p&gt;Each scan produces findings with severity ratings:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;th&gt;Per site&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Critical&lt;/td&gt;
&lt;td&gt;139&lt;/td&gt;
&lt;td&gt;0.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;482&lt;/td&gt;
&lt;td&gt;1.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;846&lt;/td&gt;
&lt;td&gt;2.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;988&lt;/td&gt;
&lt;td&gt;3.2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;46% of the top sites have at least one critical finding.&lt;/strong&gt; Most common: missing or broken TLS.&lt;/p&gt;

&lt;p&gt;The average site has &lt;strong&gt;8 security findings&lt;/strong&gt;. Even Discord (our #1) has a few low-severity items.&lt;/p&gt;




&lt;h2&gt;
  
  
  Five Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. You can beat 83% of the internet in 5 minutes.&lt;/strong&gt;&lt;br&gt;
Add these 6 headers to your nginx/Apache config and you're ahead of almost everyone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. CSP is hard — but worth it.&lt;/strong&gt;&lt;br&gt;
61% of top sites skip it. It's complex to implement without breaking things. Start with &lt;code&gt;default-src 'self'&lt;/code&gt; in report-only mode, watch the violations, and tighten gradually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. DKIM is the gap in email security.&lt;/strong&gt;&lt;br&gt;
SPF and DMARC are at ~88%. DKIM is at 63%. If you run email, configure all three.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Big brand ≠ good security.&lt;/strong&gt;&lt;br&gt;
Microsoft scores lower than a random ad network. Security configuration is an afterthought even at companies that literally sell security products.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. The bar is embarrassingly low.&lt;/strong&gt;&lt;br&gt;
Score above 70 and you're in the top 20% of the internet. That's an afternoon of work — nginx config changes, a Let's Encrypt cert, and three DNS records.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scan Your Site
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free scan:&lt;/strong&gt; &lt;a href="https://contrastcyber.com" rel="noopener noreferrer"&gt;contrastcyber.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;GET https://contrastcyber.com/api/scan?domain=yoursite.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://github.com/UPinar/contrastscan" rel="noopener noreferrer"&gt;github.com/UPinar/contrastscan&lt;/a&gt; — C + Python, MIT license&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security API:&lt;/strong&gt; &lt;a href="https://api.contrastcyber.com" rel="noopener noreferrer"&gt;api.contrastcyber.com&lt;/a&gt; — CVE lookup, domain intel, code security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Written in C — a full 11-module scan completes in under 1 second.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Data: March 29, 2026. Scanner: ContrastScan v1.0. Source: Tranco top 500. 196 entries were infrastructure-only domains (CDN nodes, DNS servers, API backends) with no web frontend — excluded from analysis.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Some large enterprises intentionally omit certain headers due to CDN constraints or scale-specific trade-offs. A lower score doesn't always mean the site is insecure — but it does mean observable security signals are weaker.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>I hardened my Hetzner VPS from scratch — here's everything I did (and the tools I built along the way)</title>
      <dc:creator>UPinar</dc:creator>
      <pubDate>Sat, 28 Mar 2026 00:16:46 +0000</pubDate>
      <link>https://dev.to/upinar/i-hardened-my-hetzner-vps-from-scratch-heres-everything-i-did-and-the-tools-i-built-along-the-41k4</link>
      <guid>https://dev.to/upinar/i-hardened-my-hetzner-vps-from-scratch-heres-everything-i-did-and-the-tools-i-built-along-the-41k4</guid>
      <description>&lt;p&gt;I run a production server on Hetzner (Ubuntu 24.04) and get hit with thousands of attack attempts daily. After 3 months of hardening, I've blocked &lt;strong&gt;8,000+ IPs from 132 countries&lt;/strong&gt; with zero successful intrusions.&lt;/p&gt;

&lt;p&gt;Here's every step I applied, what actually worked, and the open-source tools I built to make it easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. SSH (biggest single impact)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/ssh/sshd_config&lt;/span&gt;
Port 2222
PasswordAuthentication no
PubkeyAuthentication &lt;span class="nb"&gt;yes
&lt;/span&gt;MaxAuthTries 3
LoginGraceTime 30
AllowUsers myuser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Moving SSH port sounds like security through obscurity, but it &lt;strong&gt;dropped 90% of automated scans overnight&lt;/strong&gt;. Real attackers scan all ports anyway — this just filters out the lazy bots.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Firewall + IP blacklisting
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create ipset blacklist&lt;/span&gt;
ipset create blacklist_set &lt;span class="nb"&gt;hash&lt;/span&gt;:ip hashsize 65536 maxelem 131072

&lt;span class="c"&gt;# Add to iptables&lt;/span&gt;
iptables &lt;span class="nt"&gt;-I&lt;/span&gt; INPUT &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;--match-set&lt;/span&gt; blacklist_set src &lt;span class="nt"&gt;-j&lt;/span&gt; DROP

&lt;span class="c"&gt;# Atomic swap for zero-downtime updates&lt;/span&gt;
ipset create blacklist_tmp &lt;span class="nb"&gt;hash&lt;/span&gt;:ip hashsize 65536 maxelem 131072
&lt;span class="c"&gt;# ... populate blacklist_tmp ...&lt;/span&gt;
ipset swap blacklist_tmp blacklist_set
ipset destroy blacklist_tmp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;~8,000 IPs&lt;/strong&gt; blocked and growing. ipset gives you O(1) lookup regardless of list size — regular iptables chains would crawl at this scale.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. fail2ban (custom jails)
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/fail2ban/jail.local
&lt;/span&gt;&lt;span class="nn"&gt;[sshd]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;maxretry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1&lt;/span&gt;
&lt;span class="py"&gt;bantime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;-1&lt;/span&gt;
&lt;span class="py"&gt;action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(action_)s&lt;/span&gt;
         &lt;span class="err"&gt;ipset-blacklist&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;maxretry=1&lt;/code&gt; — sounds aggressive, zero false positives in 3 months with key-only auth&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bantime = -1&lt;/code&gt; — permanent ban&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;7 jails:&lt;/strong&gt; SSH + 5 nginx patterns + Suricata integration&lt;/li&gt;
&lt;li&gt;Bans feed into ipset automatically&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  4. Suricata IDS
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Suricata + fail2ban integration&lt;/span&gt;
&lt;span class="c1"&gt;# /etc/fail2ban/filter.d/suricata.conf&lt;/span&gt;
&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Definition&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="s"&gt;failregex = \[.*\] .* \[Priority&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;12&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;&lt;span class="s"&gt;\] .* &amp;lt;HOST&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Running in IDS mode with &lt;strong&gt;~32K rules&lt;/strong&gt;. The integration chain: &lt;strong&gt;Suricata detects → fail2ban bans → ipset blocks.&lt;/strong&gt; Each layer feeds the next.&lt;/p&gt;


&lt;h2&gt;
  
  
  5. nginx hardening
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# block-exploits.conf — 37+ patterns, silent drop&lt;/span&gt;
&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.env|wp-login|phpMyAdmin|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.git|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.sql|/admin)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;444&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Security headers&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class="s"&gt;"max-age=63072000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;includeSubDomains&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;preload"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Content-Security-Policy&lt;/span&gt; &lt;span class="s"&gt;"default-src&lt;/span&gt; &lt;span class="s"&gt;'self'"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Frame-Options&lt;/span&gt; &lt;span class="s"&gt;"DENY"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Content-Type-Options&lt;/span&gt; &lt;span class="s"&gt;"nosniff"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Referrer-Policy&lt;/span&gt; &lt;span class="s"&gt;"strict-origin-when-cross-origin"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Permissions-Policy&lt;/span&gt; &lt;span class="s"&gt;"camera=(),&lt;/span&gt; &lt;span class="s"&gt;microphone=(),&lt;/span&gt; &lt;span class="s"&gt;geolocation=()"&lt;/span&gt; &lt;span class="s"&gt;always&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;Status 444&lt;/strong&gt; = nginx closes the connection silently. No response body, no headers, no information leakage. Bots get nothing.&lt;/p&gt;


&lt;h2&gt;
  
  
  6. File integrity + Kernel hardening
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# AIDE — monitors ~210K files&lt;/span&gt;
aide &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; /var/lib/aide/aide.db.new /var/lib/aide/aide.db
&lt;span class="c"&gt;# Daily cron checks for unauthorized changes&lt;/span&gt;

&lt;span class="c"&gt;# /etc/sysctl.d/99-hardening.conf&lt;/span&gt;
net.ipv4.tcp_syncookies &lt;span class="o"&gt;=&lt;/span&gt; 1
net.ipv4.conf.all.accept_redirects &lt;span class="o"&gt;=&lt;/span&gt; 0
net.ipv4.conf.all.rp_filter &lt;span class="o"&gt;=&lt;/span&gt; 1
net.ipv4.icmp_echo_ignore_broadcasts &lt;span class="o"&gt;=&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Aligned with &lt;strong&gt;CIS benchmarks&lt;/strong&gt;. SYN cookies alone prevent most SYN flood attempts.&lt;/p&gt;


&lt;h2&gt;
  
  
  7. Real-time monitoring
&lt;/h2&gt;

&lt;p&gt;Telegram bot sends instant alerts for every ban:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fail2ban [sshd]
IP: 45.133.xx.xx
Action: Ban
Time: 2026-03-27 14:32:01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Plus a custom status script — uptime, disk, fail2ban stats, SSL expiry, recent attacks — all in one command.&lt;/p&gt;


&lt;h2&gt;
  
  
  Results after 3 months
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;IPs blocked&lt;/td&gt;
&lt;td&gt;8,000+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Countries&lt;/td&gt;
&lt;td&gt;132&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Successful intrusions&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;False positives (SSH)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avg server load&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  The tool I built to verify all this
&lt;/h2&gt;

&lt;p&gt;After setting everything up, I wanted a quick way to check if my headers, SSL, and DNS were actually correct.&lt;/p&gt;

&lt;p&gt;Every existing tool was either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enterprise SaaS with a sales call&lt;/li&gt;
&lt;li&gt;A CLI that dumps 200 lines of raw output&lt;/li&gt;
&lt;li&gt;Free but limited to SSL-only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built &lt;strong&gt;&lt;a href="https://contrastcyber.com" rel="noopener noreferrer"&gt;ContrastScan&lt;/a&gt;&lt;/strong&gt; — a free, open-source security scanner. Paste a domain, get an &lt;strong&gt;A-F grade&lt;/strong&gt; covering 11 checks in under 3 seconds.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://contrastcyber.com/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcontrastcyber.com%2Fstatic%2Fog-image.png" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://contrastcyber.com/" rel="noopener noreferrer" class="c-link"&gt;
            ContrastScan — Free Security Scanner
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Scan any domain in seconds. Get an A-F security grade covering 11 security checks. Free, no signup required.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcontrastcyber.com%2Fstatic%2Ffavicon.svg"&gt;
          contrastcyber.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;The core scanner is &lt;strong&gt;2,300 lines of C&lt;/strong&gt; — raw TCP handshakes for SSL, direct DNS queries via libresolv, HTTP header parsing with libcurl. No frameworks, no runtime bloat.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it checks
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Points&lt;/th&gt;
&lt;th&gt;What It Checks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Security Headers&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;CSP, HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL/TLS&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;Protocol version, cipher strength, cert validity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS Security&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;SPF, DKIM, DMARC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTPS Redirect&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;HTTP → HTTPS redirect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Info Disclosure&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Server/X-Powered-By exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cookie Security&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Secure, HttpOnly, SameSite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNSSEC&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;DNS response signatures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP Methods&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;TRACE, DELETE, PUT detection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CORS&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Cross-origin misconfig&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML Analysis&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Mixed content, inline scripts, SRI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSP Analysis&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;unsafe-inline, unsafe-eval, wildcards&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It also runs &lt;strong&gt;passive recon&lt;/strong&gt; in the background: WHOIS, tech stack detection, WAF fingerprinting, subdomain enumeration, and &lt;strong&gt;subdomain takeover detection&lt;/strong&gt; (checks for dangling CNAMEs across 30 services like GitHub Pages, Heroku, AWS S3, Netlify).&lt;/p&gt;

&lt;h3&gt;
  
  
  API access
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# JSON&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://contrastcyber.com/api/scan?domain=yourdomain.com"&lt;/span&gt;

&lt;span class="c"&gt;# Text report&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://contrastcyber.com/api/report?domain=yourdomain.com"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; report.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  For AI agents (MCP)
&lt;/h3&gt;

&lt;p&gt;I also built &lt;strong&gt;&lt;a href="https://api.contrastcyber.com" rel="noopener noreferrer"&gt;ContrastAPI&lt;/a&gt;&lt;/strong&gt; — 20 security tools in one API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http contrastapi https://api.contrastcyber.com/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CVE lookup, domain recon, tech fingerprinting, IP reputation, code security — no key required.&lt;/p&gt;




&lt;h2&gt;
  
  
  What surprised me
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Moving SSH port had more impact than any other single change.&lt;/strong&gt; Not "real" security, but eliminates 90% of log noise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Most attacks are dumb bots.&lt;/strong&gt; 95% hit &lt;code&gt;wp-login.php&lt;/code&gt; on a server that doesn't run WordPress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;maxretry=1 is not aggressive.&lt;/strong&gt; With key-only SSH, a single failed attempt is always suspicious.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A single grade changes behavior.&lt;/strong&gt; Raw headers → eyes glaze over. "Grade: D" → they want to fix it immediately.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scanner&lt;/td&gt;
&lt;td&gt;C (libcurl, openssl, libresolv, cJSON)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Python, FastAPI, SQLite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API&lt;/td&gt;
&lt;td&gt;Python, FastAPI, MCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Vanilla HTML/CSS/JS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infra&lt;/td&gt;
&lt;td&gt;Hetzner VPS, nginx, systemd, Let's Encrypt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;fail2ban, Suricata, ipset, AIDE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No Docker. No Kubernetes. One VPS, two systemd services.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scan your domain:&lt;/strong&gt; &lt;a href="https://contrastcyber.com" rel="noopener noreferrer"&gt;contrastcyber.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;a href="https://api.contrastcyber.com" rel="noopener noreferrer"&gt;api.contrastcyber.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://github.com/UPinar/contrastscan" rel="noopener noreferrer"&gt;github.com/UPinar/contrastscan&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No signup, no API key. Happy to answer questions about any of these steps.&lt;/p&gt;

</description>
      <category>security</category>
      <category>linux</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Built a Security Scanner in C That Grades Any Website A-F — Here's How</title>
      <dc:creator>UPinar</dc:creator>
      <pubDate>Fri, 27 Mar 2026 12:10:52 +0000</pubDate>
      <link>https://dev.to/upinar/i-built-a-security-scanner-in-c-that-grades-any-website-a-f-heres-how-dbj</link>
      <guid>https://dev.to/upinar/i-built-a-security-scanner-in-c-that-grades-any-website-a-f-heres-how-dbj</guid>
      <description>&lt;p&gt;You paste a domain. Ten seconds later you get a single grade — &lt;strong&gt;A through F&lt;/strong&gt; — covering 11 security checks.&lt;/p&gt;

&lt;p&gt;No signup. No API key. Just a URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://contrastcyber.com" rel="noopener noreferrer"&gt;Try it right now → contrastcyber.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;Every security scanner I found was either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enterprise SaaS with a sales call&lt;/li&gt;
&lt;li&gt;A CLI tool that dumps 200 lines of raw output&lt;/li&gt;
&lt;li&gt;Free but limited to SSL-only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted something that gives a &lt;strong&gt;single, opinionated score&lt;/strong&gt; — like a credit score for your server's security posture. Something a developer can run in 10 seconds and immediately know where they stand.&lt;/p&gt;

&lt;p&gt;So I wrote one from scratch. In C.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Scanner: 2,300 Lines of C
&lt;/h2&gt;

&lt;p&gt;The core scanner is a single C binary. No frameworks, no runtime dependencies beyond &lt;code&gt;libcurl&lt;/code&gt;, &lt;code&gt;openssl&lt;/code&gt;, &lt;code&gt;libresolv&lt;/code&gt;, and &lt;code&gt;cJSON&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It runs 11 checks and scores them out of 100:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Points&lt;/th&gt;
&lt;th&gt;What It Checks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Security Headers&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;CSP, HSTS, X-Frame-Options, X-Content-Type, Referrer-Policy, Permissions-Policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL/TLS&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;Protocol version, cipher strength, certificate validity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS Security&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;SPF, DKIM, DMARC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTPS Redirect&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;HTTP → HTTPS automatic redirect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Info Disclosure&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Server header, X-Powered-By exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cookie Security&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Secure, HttpOnly, SameSite flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNSSEC&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;DNS response signature verification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP Methods&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Dangerous methods (TRACE, DELETE, PUT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CORS&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Cross-origin misconfiguration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML Analysis&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Mixed content, inline scripts, SRI, form security&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSP Analysis&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Deep Content Security Policy inspection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The output is a single JSON object:&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="nv"&gt;$ &lt;/span&gt;./contrastscan example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"max_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"grade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"headers"&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;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&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;"ssl"&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;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&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;"dns"&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;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&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="err"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why C?
&lt;/h3&gt;

&lt;p&gt;Speed and control. The scanner does raw TCP handshakes for SSL checks, direct DNS queries via &lt;code&gt;libresolv&lt;/code&gt;, and HTTP header parsing with libcurl. A full scan completes in under 3 seconds. No garbage collector, no startup time, no 400MB node_modules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;curl/curl.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;openssl/ssl.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;arpa/nameser.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;resolv.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cjson/cJSON.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// That's it. Five libraries. 2,300 lines. 11 modules.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Web App
&lt;/h2&gt;

&lt;p&gt;The C scanner is wrapped in a &lt;strong&gt;Python FastAPI&lt;/strong&gt; backend that handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Domain validation &amp;amp; sanitization&lt;/li&gt;
&lt;li&gt;Rate limiting (60 scans/hour per IP)&lt;/li&gt;
&lt;li&gt;SQLite scan storage&lt;/li&gt;
&lt;li&gt;HTML report rendering&lt;/li&gt;
&lt;li&gt;SVG grade badges for README files&lt;/li&gt;
&lt;li&gt;Async passive reconnaissance (WHOIS, tech stack, WAF detection, subdomains)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The frontend is pure HTML/CSS/JS — no React, no build step. When you submit a scan, you get an animated progress overlay showing each module completing in real-time, then the full result page.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Access
&lt;/h3&gt;

&lt;p&gt;Every scan is also available as JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://contrastcyber.com/api/scan?domain=example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or download a plain text report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://contrastcyber.com/api/report?domain=example.com"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; report.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Going Deeper: ContrastAPI
&lt;/h2&gt;

&lt;p&gt;After building the scanner, I wanted more. CVE intelligence. Code analysis. Domain reconnaissance at scale.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;&lt;a href="https://api.contrastcyber.com" rel="noopener noreferrer"&gt;ContrastAPI&lt;/a&gt;&lt;/strong&gt; — a full security intelligence API with 13 endpoints:&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE Intelligence
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Search CVEs by keyword&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://api.contrastcyber.com/v1/cve/search?q=apache&amp;amp;limit=5"&lt;/span&gt;

&lt;span class="c"&gt;# Get EPSS score (exploitation probability)&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://api.contrastcyber.com/v1/cve/CVE-2024-3094/epss"&lt;/span&gt;

&lt;span class="c"&gt;# Check if it's in CISA KEV (Known Exploited Vulnerabilities)&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://api.contrastcyber.com/v1/cve/CVE-2024-3094/kev"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Domain Recon
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Full domain intelligence&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://api.contrastcyber.com/v1/domain/example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns DNS records, WHOIS data, SSL certificate details, subdomains, WAF detection, and technology stack — all in one call.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Security
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check code for secrets, injection, misconfigurations&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.contrastcyber.com/v1/code/check"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"code": "password = \"admin123\"", "language": "python"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  MCP Support (for AI Agents)
&lt;/h3&gt;

&lt;p&gt;ContrastAPI is also an &lt;strong&gt;MCP server&lt;/strong&gt;. If you use Claude, Cursor, or any MCP-compatible AI tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&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;"contrastapi"&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;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://mcp.contrastcyber.com/mcp"&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your AI agent gets 19 security tools — CVE lookup, domain recon, code scanning — without writing any integration code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Numbers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;2,287&lt;/strong&gt; lines of C (scanner)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;905&lt;/strong&gt; tests across both projects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;340K+&lt;/strong&gt; CVEs indexed with EPSS scores&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1,500+&lt;/strong&gt; CISA KEV entries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;11&lt;/strong&gt; security checks, &lt;strong&gt;100-point&lt;/strong&gt; scoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&amp;lt; 3 seconds&lt;/strong&gt; per scan&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$0&lt;/strong&gt; cost to use&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scanner&lt;/td&gt;
&lt;td&gt;C (gcc, libcurl, openssl, libresolv, cJSON)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web Backend&lt;/td&gt;
&lt;td&gt;Python, FastAPI, SQLite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Platform&lt;/td&gt;
&lt;td&gt;Python, FastAPI, SQLite, MCP SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Vanilla HTML/CSS/JS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;Hetzner VPS, nginx, systemd, Let's Encrypt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;fail2ban, Suricata IDS, ipset, AIDE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No Docker. No Kubernetes. No cloud functions. One VPS, two systemd services, done.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;1. C is underrated for web tooling.&lt;/strong&gt; Everyone reaches for Python or Go. But when you need to do raw TLS handshakes and DNS queries, C gives you direct access to the system libraries that are already there. No wrappers, no abstractions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A single score changes behavior.&lt;/strong&gt; When I show someone a wall of security headers, they glaze over. When I show them "Grade: D", they immediately want to fix it. Opinionated scoring works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Ship the smallest thing that's useful.&lt;/strong&gt; The first version had 3 checks. Now it has 11. But the first version was already useful — SSL + headers + DNS covers 60% of what matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. MCP is a distribution channel.&lt;/strong&gt; Adding MCP support to ContrastAPI took a day. Now any AI agent can use it as a security toolkit. That's distribution I didn't have to build.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scan a domain:&lt;/strong&gt; &lt;a href="https://contrastcyber.com" rel="noopener noreferrer"&gt;contrastcyber.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API docs:&lt;/strong&gt; &lt;a href="https://contrastcyber.com/api" rel="noopener noreferrer"&gt;contrastcyber.com/api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full API platform:&lt;/strong&gt; &lt;a href="https://api.contrastcyber.com" rel="noopener noreferrer"&gt;api.contrastcyber.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source code:&lt;/strong&gt; &lt;a href="https://github.com/UPinar/contrastscan" rel="noopener noreferrer"&gt;github.com/UPinar/contrastscan&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No signup, no API key, no paywall. Scan something and tell me what you think.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm a solo developer building security tools. If you have feedback or feature requests, drop a comment or reach out at &lt;a href="mailto:contact@contrastcyber.com"&gt;contact@contrastcyber.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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