<?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: Tetsuharu Fujiki</title>
    <description>The latest articles on DEV Community by Tetsuharu Fujiki (@lafine_systemsdesign).</description>
    <link>https://dev.to/lafine_systemsdesign</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%2F4098713%2F3732d37d-b6ac-4cb4-9fee-4119257a2bdb.jpg</url>
      <title>DEV Community: Tetsuharu Fujiki</title>
      <link>https://dev.to/lafine_systemsdesign</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lafine_systemsdesign"/>
    <language>en</language>
    <item>
      <title>You're probably overestimating public Wi-Fi 'client isolation'</title>
      <dc:creator>Tetsuharu Fujiki</dc:creator>
      <pubDate>Fri, 28 Aug 2026 14:07:55 +0000</pubDate>
      <link>https://dev.to/lafine_systemsdesign/youre-probably-overestimating-public-wi-fi-client-isolation-2ao0</link>
      <guid>https://dev.to/lafine_systemsdesign/youre-probably-overestimating-public-wi-fi-client-isolation-2ao0</guid>
      <description>&lt;p&gt;&lt;em&gt;A Japanese version of this is &lt;a href="https://zenn.dev/lafine/articles/d93cebc90a061f" rel="noopener noreferrer"&gt;on Zenn&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I was working from a café the other day and idly wondered: &lt;em&gt;on this Wi-Fi, what does my Mac actually look like to the person at the next table?&lt;/em&gt; So I went and looked into it.&lt;/p&gt;

&lt;p&gt;"Public Wi-Fi is fine as long as client isolation (AP isolation) is on, because then you can't talk to other devices" — that's the explanation you hear a lot, and I believed it for years too. Turns out the premise is shakier than I thought, so here's what I found.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client isolation isn't necessarily on in the first place
&lt;/h2&gt;

&lt;p&gt;Baseline fact: client isolation is a feature where the AP filters unicast forwarding between clients on the same SSID. It's not a legal requirement and it's not mandatory in any standard. On a cheap router or a small shop's setup, it's routinely just left off. And you generally can't tell from the outside whether it's on.&lt;/p&gt;

&lt;h2&gt;
  
  
  OK, but if it &lt;em&gt;is&lt;/em&gt; on, am I safe? Also apparently not
&lt;/h2&gt;

&lt;p&gt;This is the part that made me go "huh." The SANS Institute wrote up a technique called &lt;strong&gt;AirSnitch&lt;/strong&gt; that shows client isolation can be bypassed even when it's enabled (&lt;a href="https://www.sans.org/blog/airsnitch-wi-fi-client-isolation-what-security-teams-actually-need-know" rel="noopener noreferrer"&gt;SANS&lt;/a&gt;, &lt;a href="https://www.securityweek.com/new-airsnitch-attack-shows-wi-fi-client-isolation-could-be-a-false-sense-of-security/" rel="noopener noreferrer"&gt;SecurityWeek&lt;/a&gt;). Roughly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Abusing the GTK.&lt;/strong&gt; Isolation stops unicast client-to-client forwarding, but broadcast traffic that the network needs operationally — ARP, DHCP, mDNS — keeps getting forwarded. If you stuff a unicast payload inside a broadcast frame encrypted with the shared GTK, it goes through this gap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L3 bounce via the gateway.&lt;/strong&gt; On a network without DHCP snooping or Dynamic ARP Inspection, the source IP isn't validated. Spoof the victim's IP, send to the gateway, and routing sends the traffic back down to the victim.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rewriting the MAC table.&lt;/strong&gt; An AP has a forwarding table like a switch does. Spoof a MAC and you can overwrite the entry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this breaks the encryption itself — it's that &lt;strong&gt;the isolation implementation is architecturally weak&lt;/strong&gt;. The SANS piece says it flatly: "AP isolation alone is insufficient segmentation." The unsettling bit is that you don't need enterprise-grade knowledge for any of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  macOS is doing a fair amount of talking anyway
&lt;/h2&gt;

&lt;p&gt;Bypass or no bypass, your Mac announces plenty to everyone on the network just going about its normal business.&lt;/p&gt;

&lt;p&gt;Bonjour (mDNS, UDP 5353) advertises file sharing, screen sharing, AirDrop candidacy, printers, and so on — &lt;strong&gt;in cleartext&lt;/strong&gt;. Anyone on the same Wi-Fi can see your device name and service info.&lt;/p&gt;

&lt;p&gt;You can check what's actually being broadcast from a terminal:&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;# Enumerate Bonjour services on the local network&lt;/span&gt;
dns-sd &lt;span class="nt"&gt;-B&lt;/span&gt; _services._dns-sd._udp local.

&lt;span class="c"&gt;# See which ports your own Mac is listening on&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;lsof &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;LISTEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try it once in a café and it's surprisingly talkative (not that "fun" is the right reaction).&lt;/p&gt;

&lt;p&gt;AirDrop has its own history here — TU Darmstadt's SEEMOO lab flagged it at USENIX Security 2019. The authentication handshake exchanges hashes of your phone number and email, and those hashes turn out to be fairly easy to brute-force back. The team proposed a privacy-preserving version called &lt;a href="https://privatedrop.github.io/" rel="noopener noreferrer"&gt;PrivateDrop&lt;/a&gt; in 2021, but for backward-compatibility reasons it &lt;a href="https://www.crossing.tu-darmstadt.de/news_events/crossing_details_294784.en.jsp" rel="noopener noreferrer"&gt;reportedly isn't fully resolved&lt;/a&gt; as of writing.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9k37j25lnvewgahhu0u8.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9k37j25lnvewgahhu0u8.png" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So what do you actually do
&lt;/h2&gt;

&lt;p&gt;After all this, it seems like there are really only two moves.&lt;/p&gt;

&lt;p&gt;One is just &lt;strong&gt;reduce your exposure&lt;/strong&gt;: turn off sharing features you're not using, and look at your firewall state yourself under &lt;code&gt;System Settings &amp;gt; Network &amp;gt; Firewall&lt;/code&gt; (the default varies by OS version and configuration profile, so I won't assert what it is — check yours).&lt;/p&gt;

&lt;p&gt;The other is to stop assuming &lt;strong&gt;you'll flip the switches yourself every time the network changes&lt;/strong&gt;. Honestly, nobody re-reviews their settings every time they walk into a café. I don't. So a setup that automatically distinguishes trusted networks (home, office) from everything else, and quietly narrows your exposure on unknown ones, is what actually works in practice.&lt;/p&gt;

&lt;p&gt;I happen to have built a macOS app that automates that second part — &lt;a href="https://lafine.net/" rel="noopener noreferrer"&gt;RoamSwitch&lt;/a&gt;. The moment you connect to a network that isn't on your registered list, it stealths the firewall and stops sharing and AirDrop. No magic — it just does the "reduce your exposure" part for you, instead of you.&lt;/p&gt;

&lt;p&gt;Start by poking at your own setup with &lt;code&gt;dns-sd&lt;/code&gt; and &lt;code&gt;lsof&lt;/code&gt;. It's a good way in.&lt;/p&gt;

</description>
      <category>security</category>
      <category>networking</category>
      <category>wifi</category>
      <category>privacy</category>
    </item>
    <item>
      <title>The app was the easy part. Getting anyone to trust a security tool from a solo dev wasn't.</title>
      <dc:creator>Tetsuharu Fujiki</dc:creator>
      <pubDate>Fri, 28 Aug 2026 10:36:18 +0000</pubDate>
      <link>https://dev.to/lafine_systemsdesign/the-app-was-the-easy-part-getting-anyone-to-trust-a-security-tool-from-a-solo-dev-wasnt-47h4</link>
      <guid>https://dev.to/lafine_systemsdesign/the-app-was-the-easy-part-getting-anyone-to-trust-a-security-tool-from-a-solo-dev-wasnt-47h4</guid>
      <description>&lt;p&gt;&lt;em&gt;A Japanese version of this is &lt;a href="https://note.com/lafine/n/nddd44611aacd" rel="noopener noreferrer"&gt;on Note&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I build a Mac app that automatically tightens your network security when you're on a Wi-Fi you don't trust — coffee shop, airport, conference. The moment you join a network you haven't marked as trusted, it closes the firewall, stops the sharing services, and blocks any dev-server port you left listening on &lt;code&gt;0.0.0.0&lt;/code&gt;. Back on your trusted home or office network, it undoes all of it.&lt;/p&gt;

&lt;p&gt;The engineering wasn't hard. Poke &lt;code&gt;pf&lt;/code&gt;, listen for network-change events from the OS, stop the sharing daemons with &lt;code&gt;launchctl&lt;/code&gt;. I had something working pretty quickly.&lt;/p&gt;

&lt;p&gt;The hard part started when I decided to ship it as a product. And it started &lt;em&gt;before&lt;/em&gt; "will it sell" — I got stuck one step earlier, at &lt;strong&gt;"will anyone actually install this?"&lt;/strong&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feowqpntv65clbkl9ofwn.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feowqpntv65clbkl9ofwn.png" alt=" " width="800" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  For a security tool, trust is the bottleneck
&lt;/h2&gt;

&lt;p&gt;When I write out what I'm actually asking people to do, it's this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An unknown individual built a piece of software that includes a root-privileged background process, pitches it as something that will &lt;em&gt;cut off your network traffic&lt;/em&gt;, and ships it as a direct download.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Spelled out, even I don't want to install it. And the people with healthy suspicion — the engineers and privacy-minded folks who need this most — are exactly the ones who stop right here.&lt;/p&gt;

&lt;p&gt;A product from a big company gets to borrow that company's brand to cover this. A solo dev has none of it. So I ended up having to build every piece of "here's why you can trust this" myself. Here are the walls I hit, what I did about each, and — honestly — what I still haven't solved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wall 1: you can't see inside
&lt;/h3&gt;

&lt;p&gt;What I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Published an architecture &amp;amp; security whitepaper.&lt;/strong&gt; The complete list of operations the privileged helper can perform, how it touches &lt;code&gt;pf&lt;/code&gt;, every outbound network path, the crypto, the threat model and the explicit non-goals. Not "trust me" — written at a level you can check against the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open-sourced the MCP server and the detection logic&lt;/strong&gt; (MIT). So you can read, in code, exactly what it hands to an AI client and that it sends nothing out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrote a verify script.&lt;/strong&gt; A short read-only shell script that checks the signature, notarization, entitlements, and current state against an installed copy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The funny part: after open-sourcing it I got nervous — &lt;em&gt;people are going to go looking for bugs now&lt;/em&gt; — so I fuzzed my own JSON-RPC parser before anyone else could. And immediately hit a crash &lt;strong&gt;inside Apple's JSON parser&lt;/strong&gt; (a stack overflow on deeply-nested JSON objects; &lt;code&gt;try?&lt;/code&gt; doesn't catch it — the process just dies). If I hadn't published the code, I probably never would have looked. Fixed in the next release.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wall 2: distribution economics and the Apple tax
&lt;/h3&gt;

&lt;p&gt;I can't ship on the Mac App Store — the privileged-helper design won't pass review. So it's direct distribution: Developer ID signing, submit to Apple's notary service on every build, staple. That's a $99/year Developer Program membership, and a notarization round-trip on every release.&lt;/p&gt;

&lt;p&gt;What I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collapsed sign → notarize → package → update the appcast → deploy into one script. A manual checklist always drops a step somewhere.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SMAppService.daemon&lt;/code&gt; (registering the helper) &lt;strong&gt;won't register unless the app is in &lt;code&gt;/Applications&lt;/code&gt;.&lt;/strong&gt; The first-run "approve this in System Settings" friction is still not fully solved.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wall 3: the support surface of an app that &lt;em&gt;does&lt;/em&gt; things
&lt;/h3&gt;

&lt;p&gt;This app blocks ports and cuts off traffic on its own when conditions are met. Useful — but the flip side is a structural stream of "hey, X stopped working" tickets. Your dev server isn't reachable from your phone anymore, that kind of thing.&lt;/p&gt;

&lt;p&gt;What I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every block ships with a "lift it" button and a reason. After applying, it reads the rules back with &lt;code&gt;pfctl&lt;/code&gt; and, if that failed, the modal says so honestly: "traffic is not stopped yet — turn off Wi-Fi now."&lt;/li&gt;
&lt;li&gt;The automatic guards default toward opt-in early on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Still, as one person, support is basically a 24/7 on-call rotation. That one's a scale problem, not something I can design away.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wall 4: you can't say "we protect you"
&lt;/h3&gt;

&lt;p&gt;If your security-product copy says "we'll keep you safe," that's a problem both legally and ethically. When ransomware gets through, it becomes "but you &lt;em&gt;said&lt;/em&gt; you'd protect me."&lt;/p&gt;

&lt;p&gt;What I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The whitepaper and the site both state plainly: one layer of defense-in-depth, not a guarantee.&lt;/li&gt;
&lt;li&gt;"Completely prevents X" is off the table as copy. I actually caught the landing page claiming everything "stays inside a secure sandbox" — the app deliberately doesn't use the App Sandbox, so that was just false. Fixed it, in all ten languages.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wall 5: pricing a fear product
&lt;/h3&gt;

&lt;p&gt;I didn't want to do the "scare them, charge a premium" thing. But price it too low and it's "isn't free security software kind of suspicious?"&lt;/p&gt;

&lt;p&gt;What I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One-time $19.99, no subscription. Aimed at the buy-once crowd who are tired of subscriptions. "A coffee and a snack, once, and it's handled from now on."&lt;/li&gt;
&lt;li&gt;A free tier so people can install it and watch what it does first. The paid value is framed as "it acts for you, no clicks" rather than "it warns you."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wall 6: Zero Telemetry means &lt;em&gt;I&lt;/em&gt; go blind
&lt;/h3&gt;

&lt;p&gt;I decided the app sends nothing externally. That's core to the trust story, non-negotiable. But the cost: &lt;strong&gt;no funnel analytics.&lt;/strong&gt; Where people drop off, which features get used, A/B tests — none of it.&lt;/p&gt;

&lt;p&gt;What I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accepted it. Download counts, checkout, referrers, GitHub stars, article response — run the business on that coarse data.&lt;/li&gt;
&lt;li&gt;Wrote down, explicitly, that "add telemetry" is a lever I'm choosing not to pull.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wall 7: "what if the developer disappears?"
&lt;/h3&gt;

&lt;p&gt;This is the purchase objection specific to security software. The thing that sits resident and defends you might, one day, stop being maintained.&lt;/p&gt;

&lt;p&gt;What I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;License activation is &lt;strong&gt;fully offline.&lt;/strong&gt; Ed25519 signature + a device hash, so if the activation server ever goes away, activated Macs keep working.&lt;/li&gt;
&lt;li&gt;Working toward an end-of-life policy (final build stays available, signed, indefinitely). Open-sourcing the key components is part of the same insurance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I still haven't solved
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A third-party security review.&lt;/strong&gt; I test it myself and show my work, but an independent set of eyes hasn't looked yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Just being found at all.&lt;/strong&gt; Unknown, near-zero ad budget. You can build something good and still not get discovered. Separate post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The coarse metrics&lt;/strong&gt; are here to stay by design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Being one person.&lt;/strong&gt; Response time, sick days, bus factor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Still
&lt;/h2&gt;

&lt;p&gt;"Won't publishing the code just get you exploited?" — I get the worry, I had it too. But having actually done it: nothing that isn't already in the shipped binary got exposed, and &lt;strong&gt;because I expected people to read it, I actually tested the thing properly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Shipping a security product as an individual is, I think, a job where "building the features" is the smaller half and "assembling the trust" is the bigger one. That's what the barrier really is — and also, it turns out, something a solo dev &lt;em&gt;can&lt;/em&gt; do.&lt;/p&gt;




&lt;p&gt;The app is &lt;a href="https://lafine.net/" rel="noopener noreferrer"&gt;RoamSwitch&lt;/a&gt;. The full design is in the &lt;a href="https://lafine.net/security.html" rel="noopener noreferrer"&gt;security whitepaper&lt;/a&gt;; the open-source MCP server is &lt;a href="https://github.com/lafine1211/roamswitch-mcp" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>indiehackers</category>
      <category>startup</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
