It's almost always a false positive, not real malware. Antivirus flags unsigned PyInstaller one-file executables because the bootloader unpacks your app to a temporary folder and runs it from there — the same pattern some malware uses — so it's the *packaging*, not your code. Fixes, in increasing order of effort and effect: build `--onedir` instead of --onefile (no self-extraction, far fewer flags), add version metadata, code-sign the .exe (the real, permanent fix), submit the false positive to your AV vendor, and if it's your own build you can restore it from quarantine. Don't try to "evade" antivirus — the goal is legitimate, signed, reproducible software.
You build a Python app into an .exe with PyInstaller, hand it to a user (or download your own), and Windows Defender quarantines it as a threat — often Trojan:Win32/Wacatac or a generic Program:Win32/Wacapew. It's one of the most common and most frustrating parts of shipping Python on Windows. The good news: it's a well-known false positive, not a problem with your code, and there are real fixes. I built the same app three ways to show exactly what changes — one-file vs one-folder, and with embedded version metadata — and walk through every fix from free to permanent.
Why antivirus flags a perfectly clean PyInstaller build
A PyInstaller one-file .exe isn't just your script. It's a small bootloader plus a compressed archive of everything your program needs — the Python interpreter, the standard library, and your code. When the user runs it, the bootloader extracts that whole archive to a temporary folder (a _MEI###### directory in %TEMP%) and executes from there.
That "unpack myself to a temp folder and run" behavior is exactly what a lot of real malware does, so heuristic and machine-learning scanners treat it as suspicious. On top of that, the PyInstaller bootloader is identical across every app built with it — including any malware someone has ever packaged with PyInstaller — so scanners have learned to distrust that shared signature. Add an unsigned binary that's brand new (no reputation yet) and you get a false positive that has nothing to do with what your code does.
This affects everyone who ships PyInstaller apps — it's one of the longest-running open issues in the project. A flag means "this looks like the kind of thing that's sometimes bad," not "we found malware in your program."
First: SmartScreen is not the same as a virus flag
Two different things get lumped together, and they have different fixes:
- "Windows protected your PC" (SmartScreen) is a *reputation* prompt — it appears for any new, unsigned, downloaded
.exeuntil it's been downloaded enough to earn trust. It's not calling your file a virus. You click *More info -> Run anyway*, or remove the internet tag (right-click -> Properties -> Unblock). - Defender flags / quarantines the file is *malware detection* — a heuristic or ML verdict. This is the "flagged as a virus" case, and it needs the packaging fixes below (or code signing).
Code signing helps *both* — it establishes a real publisher identity — which is why it's the permanent fix. Everything before it just lowers the odds.
Fix 1: build one-folder instead of one-file (tested)
The single most effective free fix is to drop --onefile and build --onedir. A one-folder build doesn't self-extract — the launcher .exe just loads the files sitting next to it — so it avoids the exact behavior scanners flag. I built the same app both ways to show the difference.
$ file myapp.exemyapp.exe: PE32+ executable (console) x86-64, for MS Windows, 6 sections$ ls -l myapp.exe-rwxr-xr-x 5997536 myapp.exe # 5.72 MB, everything bundled inside
myapp/myapp.exe # the launcher — no embedded archive to unpack_internal/python312.dll # the interpreter, in the openbase_library.zip # the standard libraryVCRUNTIME140.dlllibcrypto-3.dll_hashlib.pyd _bz2.pyd _lzma.pyd _socket.pyd _decimal.pydselect.pyd unicodedata.pyd
Same program, same size (~5.6 MB), but the one-folder launcher never writes and executes a payload from %TEMP%, so it trips far fewer scanners. The trade-off is you distribute a folder (usually zipped) instead of a single file — fine for an installer or a download, less tidy for "email someone one .exe."
Our online builder has a one-file vs one-folder toggle — the one-folder option ships as a .zip specifically because it draws fewer antivirus false positives.
Fix 2: add real version metadata (tested)
An .exe with no product name, company, or version looks more like throwaway malware than legitimate software, and some heuristics weigh that. PyInstaller can embed a Windows version resource (--version-file) so the file has real Properties -> Details. I built the app with metadata and checked that it actually lands in the binary:
with-metadata build:MyApp embedded=TrueAcme Ltd embedded=True1.0.0 embedded=TrueMyApp CLI tool embedded=Trueplain build (no --version-file):MyApp embedded=FalseAcme Ltd embedded=False
Now the file shows a product name, company and version in Windows' Properties dialog. This makes it look like real software and can reduce some false positives — but on its own it does not clear SmartScreen or a determined AV verdict. Treat it as a cheap, always-do-it step, not the fix.
Fix 3: code-sign the .exe (the real, permanent fix)
Signing your executable with a code-signing certificate attaches a verified publisher identity to it. This is the only thing that reliably clears antivirus false positives and starts building SmartScreen reputation. You get a certificate from a CA (or use Microsoft's Trusted Signing, formerly Azure Code Signing, which is low-cost), then sign with signtool on Windows or osslsigncode on Linux/CI.
signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 ^/a myapp.exe
One change to know: an EV certificate no longer grants instant SmartScreen trust the way it used to. Reputation now builds with download volume over time for both OV and EV certs — signing removes the malware flag and starts the clock, but a brand-new signed app can still show a SmartScreen prompt until it's established.
Fix 4: build in a clean environment and submit the false positive
Two more steps that matter, especially before you sign:
- Build in a clean, reproducible environment — GitHub Actions on a fresh Windows runner, not your day-to-day machine. This guarantees no local infection or stray file gets bundled, and gives you a build log you can point to. The command-and-workflow generator on our Python-to-EXE tool produces a ready-to-commit Actions workflow that builds on GitHub's own Windows runner.
- Submit the false positive to the vendor. If Defender flags a genuinely clean build, report it at Microsoft's submission portal (
microsoft.com/wdsi/filesubmission); most other vendors have an equivalent. A confirmed false positive gets the detection removed in a future definition update, which helps every user of your app.
It's your own build and it's already quarantined
If Defender quarantined an .exe you built yourself and you trust it, you can restore it: open Windows Security -> Virus & threat protection -> Protection history, find the item, and choose Restore. You can also add a folder exclusion for your build output directory while developing. Only do this for your own builds — never restore or exclude a file you didn't create and can't verify.
Don't try to hide from antivirus
It's tempting to reach for tricks that make the flag "go away" — packing the exe, stripping the bootloader signature, or obfuscating specifically to dodge detection. Don't. Those techniques are exactly what malware uses to evade scanners, so they tend to *increase* detections, they can get your publisher identity flagged, and they cross the line from "ship legitimate software" to "evade security tools." The durable path is the boring one: one-folder or signed builds, real metadata, reproducible CI, and vendor submission. That's how you make trustworthy software that scanners stop flagging — not how you sneak past them.
Obfuscating your Python source (to protect your code from copying) is fine and unrelated — it changes your bytecode, not the bootloader. Just don't obfuscate *in order to* evade antivirus; do it to protect intellectual property, and sign the result.
Build it — with the antivirus-friendly options
You can produce all of the above without a local toolchain. Our free Python-to-EXE builder builds a real PyInstaller .exe in the browser with a one-folder option (the lower-false-positive build), embedded version metadata, and a matching GitHub Actions workflow for reproducible signed releases — the exact fixes from this article, ready to use.
Build a lower-false-positive .exe online
Our free Python-to-EXE builder offers the one-folder build, embedded version metadata, and a GitHub Actions workflow — the antivirus-friendly options from this guide.
Open the Python-to-EXE builderFree tools mentioned here
Related guides
Frequently asked questions
Why is my PyInstaller .exe detected as a virus?
It's almost always a false positive. A PyInstaller one-file .exe contains a bootloader that unpacks the bundled Python interpreter and your code to a temporary folder and runs it — the same self-extracting behavior some malware uses — and the bootloader is identical across all PyInstaller apps, so heuristic and ML scanners distrust it. An unsigned, brand-new binary with no reputation makes it worse. It's the packaging, not your code.
How do I stop Windows Defender flagging my PyInstaller executable?
In order of effect: build --onedir instead of --onefile (no self-extraction, far fewer flags), add version metadata with --version-file, and code-sign the .exe with a certificate (the permanent fix). Also build in a clean GitHub Actions environment and submit any genuine false positive to Microsoft so the detection is removed. For your own already-quarantined build, restore it from Protection history.
Does --onedir reduce antivirus false positives compared to --onefile?
Yes. A one-file build self-extracts its bundled interpreter and code to a temp folder at runtime, which is the pattern scanners flag. A one-folder build ships the launcher next to its files (an _internal folder with python3xx.dll, the stdlib and extension modules), so it never writes and runs a payload from %TEMP% and trips far fewer scanners. The trade-off is distributing a folder (usually zipped) instead of one file.
Will code signing fix the false positive?
Code signing is the most reliable fix — it attaches a verified publisher identity, which clears the malware flag and starts building SmartScreen reputation. One caveat: EV certificates no longer grant instant SmartScreen trust; reputation now builds with download volume over time for both OV and EV, so a freshly signed app may still show a SmartScreen prompt until it's established. Microsoft Trusted Signing is a low-cost certificate option.
Is it safe to just add my .exe to the antivirus exclusions?
Only for a build you created yourself and trust. Restoring your own build from quarantine or excluding your build folder during development is fine. Never exclude or restore an executable you didn't build and can't verify — and don't ship an app that asks *users* to disable their antivirus, which trains them into unsafe habits. Sign the build instead so exclusions aren't needed.