{"slug": "my-open-source-security-scanner-got-flagged-as-a-trojan-by-windows-defender", "title": "My Open Source Security Scanner Got Flagged as a Trojan by Windows Defender", "summary": "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.", "body_md": "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.\n\nIt wasn't malware. **1 out of 71 antivirus engines on VirusTotal flagged it. Just Microsoft.**\n\nThis 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.\n\nMCPSense 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.\n\nI 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.\n\nThe first week went well. 40+ unique clones. A few Reddit posts got traction. People were actually trying it.\n\nI 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:\n\n```\nInstalled successfully.\n```\n\nExcept the binary wasn't there. Windows Defender had flagged it as `Trojan:Win32/Bearfoos.B!ml`\n\n, 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.\n\nThat'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.\n\nThis 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.\n\nHere'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.\n\nTurns 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.\n\nThe key detail: **locally compiled binaries don't trigger this.** If you run `go install`\n\non 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.\n\nHugo, 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.\n\nI uploaded `mcpsense.exe`\n\nto VirusTotal. Here's what came back:\n\n**1 out of 71 security engines flagged it.** Just Microsoft. Kaspersky, Norton, Bitdefender, ESET, Malwarebytes, CrowdStrike, and 64 others all said clean.\n\nWhen 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.\n\nI 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.\n\nThis was the biggest change. MCPSense is now installable via:\n\n```\nnpm install -g mcpsense\n```\n\nOn Linux and macOS, the npm package downloads the pre-built Go binary. Fast, no Go required.\n\nOn Windows, it detects the platform and runs `go install`\n\nfrom 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.\n\nWhy npm? Because every developer working with MCP servers already has Node.js. They're running `npx`\n\ncommands in their MCP configs. Node is the common denominator.\n\nThe old `install.ps1`\n\ndownloaded a binary and that was it. If Defender ate the binary, the script said \"success\" and closed the terminal.\n\nThe new version tries three install methods in cascade:\n\n`npm install -g mcpsense`\n\n(if npm is available)`go install`\n\n(if Go is available)\nAfter 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.\n\nMicrosoft 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.\n\n[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.\n\nIf you're building CLI tools in Go or Rust and shipping to Windows users, here's what I wish I'd known before launch.\n\n**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.\n\n**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`\n\ncommand, or something else, you need a path that doesn't involve downloading a pre-built .exe.\n\n**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.\n\n**Never let an install script close the terminal on failure.** PowerShell scripts invoked via `irm ... | iex`\n\nwill 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\"`\n\n.\n\n**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.\n\n**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.\n\nA 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.\n\nThe 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.\n\nUntil one of those options is in place, source compilation is your safest Windows distribution path.\n\nIf you're using MCP servers with Cursor, Claude Desktop, or VS Code, scan your config:\n\n```\nnpm install -g mcpsense\nmcpsense scan ./mcp.json\n```\n\n27 checks across security, spec compliance, and tool quality. Open source, MIT licensed.", "url": "https://wpnews.pro/news/my-open-source-security-scanner-got-flagged-as-a-trojan-by-windows-defender", "canonical_source": "https://dev.to/tana_shahh/my-open-source-security-scanner-got-flagged-as-a-trojan-by-windows-defender-558n", "published_at": "2026-05-26 14:47:47+00:00", "updated_at": "2026-05-26 15:04:46.904044+00:00", "lang": "en", "topics": ["ai-tools", "ai-agents", "ai-safety", "ai-products", "ai-infrastructure"], "entities": ["MCPSense", "Windows Defender", "Microsoft", "Go", "GoReleaser", "GitHub", "Claude", "ChatGPT"], "alternates": {"html": "https://wpnews.pro/news/my-open-source-security-scanner-got-flagged-as-a-trojan-by-windows-defender", "markdown": "https://wpnews.pro/news/my-open-source-security-scanner-got-flagged-as-a-trojan-by-windows-defender.md", "text": "https://wpnews.pro/news/my-open-source-security-scanner-got-flagged-as-a-trojan-by-windows-defender.txt", "jsonld": "https://wpnews.pro/news/my-open-source-security-scanner-got-flagged-as-a-trojan-by-windows-defender.jsonld"}}