My Open Source Security Scanner Got Flagged as a Trojan by Windows Defender A developer's open-source security scanner for MCP servers, MCPSense, was flagged as a trojan by Windows Defender within its first week of release, with only 1 out of 71 antivirus engines on VirusTotal—Microsoft's—detecting it as malware. The Go-compiled binary was silently quarantined and deleted from users' machines due to a well-documented false positive pattern where Defender's machine learning model misidentifies Go binaries' static linking and runtime characteristics as malware. To fix the immediate user experience, the developer added installation via npm, bypassing the Mark of the Web flag that triggers the heuristic detection. I shipped a security scanner for MCP servers. Within the first week, Windows Defender decided it was malware and silently deleted it from users' machines. It wasn't malware. 1 out of 71 antivirus engines on VirusTotal flagged it. Just Microsoft. This post is about what happened, why it happens to Go binaries specifically, and what I did to fix it so you don't have to learn these lessons the hard way. MCPSense is a Go CLI tool that scans MCP Model Context Protocol server configurations for security vulnerabilities. MCP is the protocol Claude, ChatGPT, Cursor, and VS Code use to connect AI agents to external tools. The configs for these tools often contain things like shell commands, API keys, and package references that can be exploited. I built MCPSense to catch command injection, credential leaks, prompt injection, path traversal, and about 23 other vulnerability classes. 27 checks total. Written in Go, compiled with GoReleaser, distributed via GitHub Releases. The first week went well. 40+ unique clones. A few Reddit posts got traction. People were actually trying it. I ran my own install script on a fresh Windows laptop. The script downloaded the pre-built binary from GitHub Releases, placed it in the right directory, and said: Installed successfully. Except the binary wasn't there. Windows Defender had flagged it as Trojan:Win32/Bearfoos.B ml , quarantined it, and deleted it. All silently. My install script checked if the download succeeded but not if the file still existed three seconds later. So it happily reported success while Defender was busy removing everything. That's when it hit me. Some of those 40 early users were on Windows. Some of them hit this exact wall. And none of them filed an issue or left a comment. They just saw "Trojan detected" on a security tool and bounced. Can't really blame them. This isn't a MCPSense problem. It's a Go-on-Windows problem. There's a well-documented issue https://github.com/microsoft/go/issues/1255 on the Go GitHub where developers have been reporting this for years. Here's what's going on. Defender uses a machine learning model alongside its signature-based detection. The ML model looks at binary characteristics like file structure, import tables, entropy patterns, and compilation artifacts. Go binaries have a distinctive signature because of how the Go compiler works. It statically links everything into a single large binary, includes the Go runtime, and has a unique import/export structure. Turns out this pattern overlaps with what some malware packers produce. The ML model sees an unsigned executable with these characteristics, downloaded from the internet which gives it the "Mark of the Web" flag , and fires a heuristic detection. The key detail: locally compiled binaries don't trigger this. If you run go install on your own machine, Defender doesn't care. The binary is identical in content but lacks the Mark of the Web because it wasn't downloaded. That's the entire difference. Same bytes, different metadata, completely different Defender response. Hugo, Terraform, Syncthing, and dozens of other Go projects have dealt with this. It's not new. I just didn't know about it until my users were already affected. I uploaded mcpsense.exe to VirusTotal. Here's what came back: 1 out of 71 security engines flagged it. Just Microsoft. Kaspersky, Norton, Bitdefender, ESET, Malwarebytes, CrowdStrike, and 64 others all said clean. When 70 out of 71 independent security engines agree your binary is clean, and the one outlier is known to have this exact false positive pattern with Go binaries, you can be pretty confident it's not actually malware. I didn't just submit a false positive report and wait. That fixes the detection eventually but doesn't fix the user experience right now. So I attacked it from multiple angles. This was the biggest change. MCPSense is now installable via: npm install -g mcpsense On Linux and macOS, the npm package downloads the pre-built Go binary. Fast, no Go required. On Windows, it detects the platform and runs go install from source instead of downloading a binary. The resulting executable is compiled locally, so Defender doesn't flag it. The user never sees a Trojan warning. Why npm? Because every developer working with MCP servers already has Node.js. They're running npx commands in their MCP configs. Node is the common denominator. The old install.ps1 downloaded a binary and that was it. If Defender ate the binary, the script said "success" and closed the terminal. The new version tries three install methods in cascade: npm install -g mcpsense if npm is available go install if Go is available After the binary download, it waits 3 seconds and checks if the file still exists. If Defender deleted it, the script tells the user exactly what happened and shows manual instructions. And critically, it never closes the terminal window without a "Press Enter to close" prompt. Users can actually read the error messages now. Microsoft has a submission portal https://www.microsoft.com/en-us/wdsi/filesubmission where developers can report false positives. I submitted the binary with the VirusTotal evidence and source code link. They typically respond within a few business days and remove the detection from future definition updates. SignPath Foundation https://signpath.org provides free code signing certificates for open source projects. Once approved, GoReleaser will produce signed Windows binaries that Defender trusts. This is the permanent fix, but it takes a few weeks to process. If you're building CLI tools in Go or Rust and shipping to Windows users, here's what I wish I'd known before launch. Test on a clean Windows machine. Not your dev machine where you've already whitelisted things. A fresh install with default Defender settings. Do this before your first release, not after 40 people have already tried your tool. Never ship binary downloads as your only Windows install path. Have a source-compilation fallback. Whether that's wrapping it in npm, providing a go install command, or something else, you need a path that doesn't involve downloading a pre-built .exe. Your install script needs to verify the binary exists after installation. Not just "did the download succeed" but "is the file still there 3 seconds later." Defender is fast but not instant. Never let an install script close the terminal on failure. PowerShell scripts invoked via irm ... | iex will close the window when they exit. If your script fails and exits, the user sees nothing. Always end with Read-Host "Press Enter to close" . Apply for code signing early. SignPath Foundation is free for open source. The application takes time. Start the process when you start the project, not after you've already launched. Submit false positives proactively. Don't wait for users to complain. Upload your binary to VirusTotal with every release. If any engine flags it, submit to that vendor's false positive portal immediately. A security scanner getting flagged as malware by a security product is absurd in the best possible way. But the underlying problem is serious. Go is one of the most popular languages for CLI tools, and Defender is on every Windows machine. This friction affects the entire Go ecosystem's ability to reach Windows users. The Go team hasn't been able to fix this at the compiler level because it's a heuristic detection, not a signature match. There's no specific byte sequence to change. The only real fixes are code signing which costs money or requires applying to a foundation or not shipping pre-built binaries at all. Until one of those options is in place, source compilation is your safest Windows distribution path. If you're using MCP servers with Cursor, Claude Desktop, or VS Code, scan your config: npm install -g mcpsense mcpsense scan ./mcp.json 27 checks across security, spec compliance, and tool quality. Open source, MIT licensed.