<?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: Kacper</title>
    <description>The latest articles on DEV Community by Kacper (@kacper_35e1f61a8f41c3886b).</description>
    <link>https://dev.to/kacper_35e1f61a8f41c3886b</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4088488%2F0d03c7c3-63bd-4ed6-9216-70b926857eca.jpg</url>
      <title>DEV Community: Kacper</title>
      <link>https://dev.to/kacper_35e1f61a8f41c3886b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kacper_35e1f61a8f41c3886b"/>
    <language>en</language>
    <item>
      <title>I turned a 30-second security check into an app you can connect to Claude or ChatGPT</title>
      <dc:creator>Kacper</dc:creator>
      <pubDate>Mon, 24 Aug 2026 08:43:33 +0000</pubDate>
      <link>https://dev.to/kacper_35e1f61a8f41c3886b/i-turned-a-30-second-security-check-into-an-app-you-can-connect-to-claude-or-chatgpt-3c4f</link>
      <guid>https://dev.to/kacper_35e1f61a8f41c3886b/i-turned-a-30-second-security-check-into-an-app-you-can-connect-to-claude-or-chatgpt-3c4f</guid>
      <description>&lt;p&gt;Last week I checked the email security of eight automation agencies and seven of them could be spoofed. The check itself is two DNS lookups and takes about thirty seconds, which raises an obvious question: if it's that cheap, why does almost nobody run it?&lt;/p&gt;

&lt;p&gt;Because it's thirty seconds you have to remember to spend, on a thing that produces no visible symptom when it's broken. Nobody wakes up thinking "I should verify my SPF record today."&lt;/p&gt;

&lt;p&gt;So I moved the check to where the questions already get asked. It's now an MCP server you can connect to Claude or ChatGPT, and then just ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Connect it, then type something like &lt;em&gt;"can people spoof email from stripe.com?"&lt;/em&gt; and the assistant runs the actual DNS lookups and comes back with a graded report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Email security report: example.com&lt;/span&gt;
&lt;span class="gs"&gt;**Grade: D — effectively spoofable**&lt;/span&gt;

| Check | Result |
|---|---|
| MX | 10 mx01.example-host.com. |
| SPF | v=spf1 include:_spf.google.com ~all |
| DMARC | v=DMARC1; p=none |
| DKIM | selectors: google |

&lt;span class="gu"&gt;### Problems (1), most severe first&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**[MEDIUM]**&lt;/span&gt; DMARC is p=none — monitoring mode. Receivers check
  alignment and then do nothing on failure; a forged invoice from this
  domain lands like real mail.
&lt;span class="p"&gt;  -&lt;/span&gt; Fix: after ~2 clean weeks of reports, move to p=quarantine.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a second tool that compares up to five domains side by side, which is uncomfortable in a useful way if you run it on yourself and your competitors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting it
&lt;/h2&gt;

&lt;p&gt;It's authless — it reads public DNS and stores nothing, so there's no signup, no key, no OAuth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude:&lt;/strong&gt; Settings → Connectors → Add custom connector, and paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://deliverability-doctor.deliverability-doctor.workers.dev/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ChatGPT:&lt;/strong&gt; same URL as a custom MCP connector.&lt;/p&gt;

&lt;p&gt;Then ask it about any domain in plain language.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three findings it's actually looking for
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No SPF at all.&lt;/strong&gt; Anyone can send as you, today. One of the eight agencies I scanned was in this state on a Google-hosted domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More than one SPF record.&lt;/strong&gt; This is the one that surprises people. Per RFC 7208, a receiver that finds two &lt;code&gt;v=spf1&lt;/code&gt; records is required to return permerror — and most treat permerror as &lt;em&gt;no SPF at all&lt;/em&gt;. So the company that carefully added a second record for their new mailing tool didn't add protection, they deleted it. It happens constantly and it's invisible unless you look.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;p=none&lt;/code&gt; DMARC.&lt;/strong&gt; The sneaky one, because it looks handled. It's monitoring mode: receivers check alignment, then do nothing on failure. Six of my eight had it. A &lt;code&gt;p=none&lt;/code&gt; with no &lt;code&gt;rua=&lt;/code&gt; address is the worst version — not enforcing, and not collecting the reports that would tell you spoofing is happening.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building it, briefly
&lt;/h2&gt;

&lt;p&gt;Two things I'd do again.&lt;/p&gt;

&lt;p&gt;I used DNS-over-HTTPS rather than Node's &lt;code&gt;dns&lt;/code&gt; module. That decision looked like fussiness at the time; it meant the same analyzer file ran unchanged locally and then on Cloudflare Workers when I deployed, because Workers has no &lt;code&gt;dns&lt;/code&gt; module. Choosing the more portable primitive early cost nothing and saved a rewrite.&lt;/p&gt;

&lt;p&gt;And I tested the analyzer against domains whose answers I already knew before wiring up any protocol. That caught two real bugs. &lt;code&gt;gmail.com&lt;/code&gt; was being flagged for a missing &lt;code&gt;all&lt;/code&gt; mechanism — but its SPF ends in &lt;code&gt;redirect=&lt;/code&gt;, which validly replaces &lt;code&gt;all&lt;/code&gt;, so the tool was wrong and Google was right. And a domain that doesn't exist was being graded &lt;strong&gt;F — spoofable today&lt;/strong&gt;, which is nonsense: NXDOMAIN means there's no domain to spoof. Both were fixed before the server ran once. Neither would have been caught by testing against domains I hadn't already characterised.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;DKIM detection probes seven common selectors, so a custom selector reads as "not found" — that's why it never counts against the grade. The tool sees DNS only: it can't tell you whether your mail actually lands in inboxes, only whether receivers have been told who's allowed to send. And a grade of A means the authentication records are right, not that your sending reputation is good.&lt;/p&gt;

&lt;p&gt;If you'd rather not connect anything, the free version is still 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;nslookup &lt;span class="nt"&gt;-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;TXT yourdomain.com
nslookup &lt;span class="nt"&gt;-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;TXT _dmarc.yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run those before you connect anything of mine, or anyone else's.&lt;/p&gt;

&lt;p&gt;And if the check finds problems you would rather hand to someone: I do a one-page written version - your domain, exactly what is wrong, the exact records to paste, within 24h - for $39: &lt;a href="https://niekonieczny.gumroad.com/l/spoofcheck" rel="noopener noreferrer"&gt;https://niekonieczny.gumroad.com/l/spoofcheck&lt;/a&gt;. The free tool above is the same diagnosis; the $39 is for having it explained and turned into a to-do list.&lt;/p&gt;

&lt;p&gt;— Kacper Konieczny, Łódź&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>claude</category>
      <category>mcp</category>
      <category>security</category>
    </item>
    <item>
      <title>I checked the email security of 8 automation agencies. 7 were spoofable.</title>
      <dc:creator>Kacper</dc:creator>
      <pubDate>Sat, 22 Aug 2026 22:03:16 +0000</pubDate>
      <link>https://dev.to/kacper_35e1f61a8f41c3886b/i-checked-the-email-security-of-8-automation-agencies-7-were-spoofable-33l0</link>
      <guid>https://dev.to/kacper_35e1f61a8f41c3886b/i-checked-the-email-security-of-8-automation-agencies-7-were-spoofable-33l0</guid>
      <description>&lt;p&gt;I was cold-emailing automation agencies last week, looking for subcontract work. Before I contact any company I run one check on their domain — SPF and DMARC, straight from public DNS, about thirty seconds each. It started as a way to find something genuine to open with. It turned into an uncomfortable little dataset.&lt;/p&gt;

&lt;p&gt;Eight agencies. US, Canada, Australia, UK. All of them sell automation, integration or AI services — companies whose entire pitch is that they will wire your systems up properly.&lt;/p&gt;

&lt;p&gt;Seven of the eight can be spoofed.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agency&lt;/th&gt;
&lt;th&gt;SPF&lt;/th&gt;
&lt;th&gt;DMARC&lt;/th&gt;
&lt;th&gt;Spoofable?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;strict&lt;/td&gt;
&lt;td&gt;p=none&lt;/td&gt;
&lt;td&gt;effectively yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;soft&lt;/td&gt;
&lt;td&gt;p=none, no reporting&lt;/td&gt;
&lt;td&gt;yes, and they'd never find out&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;soft&lt;/td&gt;
&lt;td&gt;p=none&lt;/td&gt;
&lt;td&gt;effectively yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;missing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;missing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;completely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;strict&lt;/td&gt;
&lt;td&gt;p=none&lt;/td&gt;
&lt;td&gt;effectively yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;strict&lt;/td&gt;
&lt;td&gt;p=none&lt;/td&gt;
&lt;td&gt;effectively yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G&lt;/td&gt;
&lt;td&gt;ok&lt;/td&gt;
&lt;td&gt;p=none&lt;/td&gt;
&lt;td&gt;effectively yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H&lt;/td&gt;
&lt;td&gt;strict&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;p=quarantine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No names. I emailed every one of them their own result privately, for free, before writing any of this, and one of them is only in the table because they wrote back and told me to get lost, which is fair enough.&lt;/p&gt;

&lt;p&gt;Company D is the one that bothers me. A working consultancy with real clients, on a Google-hosted domain, with no SPF record at all. Anyone on the internet can send mail as them today.&lt;/p&gt;

&lt;h2&gt;
  
  
  p=none is the trap
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;p=none&lt;/code&gt; is the one worth understanding, because it looks like the responsible option and isn't. It's monitoring mode. Receiving servers check whether the mail aligns, and then — on failure — do nothing. A forged invoice from &lt;code&gt;billing@your-agency.com&lt;/code&gt; arrives with exactly the same standing as your real mail. Six of my eight had it, which means six of them have almost certainly ticked "DMARC" off a list at some point and moved on.&lt;/p&gt;

&lt;p&gt;The version with no &lt;code&gt;rua=&lt;/code&gt; is worse than useless, because now you're not enforcing &lt;em&gt;and&lt;/em&gt; not collecting the reports that would tell you it's happening.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check yours
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;nslookup -type=TXT yourdomain.com
nslookup -type=TXT _dmarc.yourdomain.com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the first one returns nothing containing &lt;code&gt;v=spf1&lt;/code&gt;, anyone can send as you, and that is a today problem rather than a roadmap problem. If you have SPF but no DMARC, you've told receivers who is allowed to send but not what to do about anyone who isn't. If you have &lt;code&gt;p=none&lt;/code&gt; with a &lt;code&gt;rua=&lt;/code&gt; address, you're in a reasonable place — read a couple of weeks of reports, confirm your real senders pass, then move to &lt;code&gt;p=quarantine&lt;/code&gt;. If you have &lt;code&gt;p=none&lt;/code&gt; with no reporting, add the reporting address first; you can't tighten safely without knowing what you'd break.&lt;/p&gt;

&lt;p&gt;One more thing worth knowing: if you have more than one &lt;code&gt;v=spf1&lt;/code&gt; record on the same domain, that isn't extra protection, it's a permanent error. Per RFC 7208 a receiver seeing two SPF records is required to return permerror, and most treat that as "no SPF at all". It happens constantly when a company adds a second sending tool and pastes in a second record rather than merging into the first.&lt;/p&gt;

&lt;p&gt;The whole fix is two DNS records and no budget. It is genuinely boring. That's why nobody does it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclosure
&lt;/h2&gt;

&lt;p&gt;I sell this — a written deliverability audit, 48 hours, $99: &lt;a href="https://niekonieczny.gumroad.com/l/vscjt" rel="noopener noreferrer"&gt;https://niekonieczny.gumroad.com/l/vscjt&lt;/a&gt;. The two commands above are the free version and for a lot of you they are the entire answer. Run them before you pay anyone, including me.&lt;/p&gt;

&lt;p&gt;If you want to know how I work before you'd trust me with anything: I published the two bugs my own acceptance tests caught in my own product before launch — &lt;a href="https://dev.to/kacper_35e1f61a8f41c3886b/my-own-acceptance-tests-caught-2-real-bugs-in-my-product-before-a-single-customer-saw-it-598b"&gt;https://dev.to/kacper_35e1f61a8f41c3886b/my-own-acceptance-tests-caught-2-real-bugs-in-my-product-before-a-single-customer-saw-it-598b&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;— Kacper Konieczny, Łódź&lt;/p&gt;

</description>
    </item>
    <item>
      <title>My own acceptance tests caught 2 real bugs in my product — before a single customer saw it</title>
      <dc:creator>Kacper</dc:creator>
      <pubDate>Fri, 21 Aug 2026 15:01:25 +0000</pubDate>
      <link>https://dev.to/kacper_35e1f61a8f41c3886b/my-own-acceptance-tests-caught-2-real-bugs-in-my-product-before-a-single-customer-saw-it-598b</link>
      <guid>https://dev.to/kacper_35e1f61a8f41c3886b/my-own-acceptance-tests-caught-2-real-bugs-in-my-product-before-a-single-customer-saw-it-598b</guid>
      <description>&lt;p&gt;I sell a small pack of n8n workflows built around one idea: &lt;strong&gt;automation should ship with its own acceptance tests, and sends should stay disabled until those tests pass.&lt;/strong&gt; Before listing it, I did the only honest thing you can do with a claim like that — I ran my own tests against my own product on a live n8n instance. They failed. Twice. This is the story, because both bugs are ones your workflows probably have too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 1: &lt;code&gt;require('crypto')&lt;/code&gt; doesn't exist where you think it does
&lt;/h2&gt;

&lt;p&gt;My intake workflow deduplicates submissions with a hash key. Locally-authored, looked clean, "obviously worked." On a stock n8n install it died instantly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Module 'crypto' is disallowed&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;n8n's Code node sandboxes away Node builtins by default. If your dedupe, signing, or ID logic uses &lt;code&gt;require('crypto')&lt;/code&gt;, it works on your tweaked dev instance and breaks on your client's stock one. Fix: a pure-JS hash (I used double FNV-1a — dedupe keys don't need cryptographic strength) or enabling builtin access consciously via env config — as a documented decision, not an accident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 2: your env-var read is a silent crash on stock installs
&lt;/h2&gt;

&lt;p&gt;Every "armed/disarmed" gate in the pack reads an env var: delivery stays OFF until &lt;code&gt;AF_DELIVERY_URL&lt;/code&gt; exists. Except on default installs, &lt;code&gt;N8N_BLOCK_ENV_ACCESS_IN_NODE&lt;/code&gt; makes &lt;code&gt;$env&lt;/code&gt; access THROW — so my fail-safe gate was actually a fail-crash gate. The fix is boring and important:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&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;AF_DELIVERY_URL&lt;/span&gt; &lt;span class="o"&gt;||&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;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fail-safe now means: on any stock install, the workflow imports, runs, and refuses to send — instead of erroring out and teaching the buyer your stuff is broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is a sales pitch (honestly)
&lt;/h2&gt;

&lt;p&gt;Both bugs share a shape: &lt;strong&gt;they're invisible until the workflow runs somewhere you didn't build it.&lt;/strong&gt; A demo can't catch them. A screenshot can't catch them. Only acceptance tests executed on a clean instance can — which is why every workflow I ship has its criteria written on the canvas in a sticky note, and a checklist the buyer runs before trusting anything.&lt;/p&gt;

&lt;p&gt;The tests cost me an evening and two embarrassing bugs. They also mean the thing I sell is the thing I verified — and that discipline is the actual product.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(The full acceptance-first pack is at &lt;a href="https://niekonieczny.gumroad.com/l/imbsml" rel="noopener noreferrer"&gt;https://niekonieczny.gumroad.com/l/imbsml&lt;/a&gt; — and the error handler alone at &lt;a href="https://niekonieczny.gumroad.com/l/uwxmpx" rel="noopener noreferrer"&gt;https://niekonieczny.gumroad.com/l/uwxmpx&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>n8n</category>
      <category>automation</category>
      <category>testing</category>
      <category>buildinpublic</category>
    </item>
  </channel>
</rss>
