A Minimum Security Checklist for Windows Application Development
Bottom line
The first things you do not want to skip in Windows application security are: don’t request administrator privileges you don’t need, sign your binaries, don’t keep secrets in plain text, and don’t disable certificate validation.
Closing the basic gaps is more practical than reaching for advanced defenses first.
The checklist at a glance
| Item | Minimum to do | Typical anti-pattern |
|---|---|---|
| Execution privilege | Default to asInvoker; isolate only the parts that need elevation | Marking the whole app as requireAdministrator |
| Trust of distributed binaries | Code-sign EXE/DLL/MSI/MSIX with a timestamp | Shipping unsigned |
| Updates | Use HTTPS and verify signatures to detect tampering | Downloading over HTTP and overwriting as-is |
| Secrets | Protect with DPAPI, Credential Locker, etc. | API keys or connection strings stored in plain text |
| Communication | Use HTTPS and don’t disable certificate validation | Always skipping with return true |
| External input | Validate input from SQL, files, IPC, etc. | “It’s just an internal tool” so no checks |
| DLL loading | Use absolute paths and a safe search order | LoadLibrary("foo.dll") relying on the current directory |
| Logs | Mask tokens, passwords, personal data | Dumping exception details or connection strings as-is |
1. Privileges: default to asInvoker
If the entire app runs as administrator, every bug, swapped DLL, or misread config file gets that strong privilege for free.
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
- Use
asInvokerfor normal UI applications - Move work that truly requires administrator privileges into a separate process or service
- Elevate only at the moment it is actually needed
2. Sign what you ship
On Windows, the binaries you distribute are themselves an attack surface. At minimum:
- Sign EXE/DLL/MSI/MSIX
- Sign helper binaries used for updates, not just the installer
- Add a timestamp so signatures still verify after the certificate expires
- Track certificate expiration and the renewal procedure as part of your release process
3. Secure the update path
- Fetch update files over HTTPS
- Verify the signature or hash of the downloaded update
- Don’t let the update URL be swapped freely from code or config
- Sign the updater itself
- Decide on a rollback or recovery procedure for failed updates
HTTPS protects the transport, but on its own it does not prove that the file is really something you published.
4. Don’t keep secrets in plain text
Things to avoid at all costs:
- API keys hardcoded in source
- Plain-text passwords in
appsettings.json - Connection strings checked into the repository
- A design where the decryption key sits next to the ciphertext
Practical options:
- If Windows or integrated authentication is available, don’t make the app hold a password at all
- For local storage, use DPAPI /
ProtectedData(typicallyCurrentUser) - If secrets can be managed on the cloud side, don’t embed them in the client
byte[] plaintext = Encoding.UTF8.GetBytes(secretText);
byte[] ciphertext = ProtectedData.Protect(
plaintext, null, DataProtectionScope.CurrentUser);
5. Communication: don’t kill certificate validation
Particularly dangerous code:
// Never leave this in production
ServicePointManager.ServerCertificateValidationCallback += (_, _, _, _) => true;
- Use HTTPS for production traffic
- Don’t permanently bypass certificate validation
- Make sure development workarounds are stripped out by build conditions or configuration
- On .NET, also keep revocation checks in mind
6. Validate external input
A Windows app actually has a lot of input entry points:
- File paths; CSV, Excel, JSON, XML; command-line arguments
- Named pipes, sockets, COM, RPC; database queries; registry values
- Clipboard, URLs and deep links, data from external devices
The bare minimum:
- Always parameterize SQL (no string concatenation)
- Normalize file paths before using them
- Apply size limits and format checks when reading external files
// Good
cmd.CommandText = "SELECT * FROM Users WHERE Name = @name";
cmd.Parameters.Add("@name", SqlDbType.NVarChar, 256).Value = userName;
7. Be explicit about where DLLs are loaded from
// Early in process startup
SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
- Where possible, load DLLs by absolute path
- Don’t rely on the current directory or PATH
- Register only the additional directories you actually need with
AddDllDirectory
8. Don’t leak secrets through logs and exceptions
- Don’t log passwords, bearer tokens, or API keys
- Don’t log full connection strings
- Separate user-facing exception messages from internal logs
- Keep error dialogs to something like “failed to connect to the server” and put the details in internal logs
Pre-release checklist (excerpt)
Privileges and execution
- The app runs under asInvoker for normal use
- Work that requires administrator privileges is split into a separate EXE or service
Distribution and signing
- EXE/DLL/MSI/MSIX/updater are all signed
- Signatures include a timestamp
Secrets
- No passwords or API keys are hardcoded in source
- No secrets sit in plain-text config files
Communication
- Production traffic uses HTTPS
- No
=> truecallbacks shipped with the product
Input
- SQL is parameterized
- Command-line, file, and IPC input have size limits and format checks
DLL loading
- DLL load locations are made explicit
- Nothing relies on the current directory
Logs
- Tokens, passwords, and personal data are not written to logs
- Internal logs and user-facing messages are separated
Common anti-patterns
- “It’s just an internal tool, so it’s fine” — corrupted files, mistakes, shared folders, and stale DLLs all happen in normal operations
- “It’s HTTPS, so it’s safe” — disabling certificate validation drains most of that value
- “It’s encrypted, so it’s safe” — without thinking through where the key lives and the privilege boundaries, encryption alone is not enough
- “More logging means we can investigate anything” — if logs leak secrets, the logs themselves become the incident
- “Just run it as admin and it works” — easy in the short term, painful at the privilege boundary in the long run
Priority order
- Revisit administrator privileges (stop using
requireAdministratorby default) - Code signing and timestamps
- Move secrets out of source code and plain-text config
- HTTPS plus correct certificate validation
- Review SQL, file, and IPC input handling
- Lock down DLL loading
- Mask sensitive data in logs
- Make dependency updates a routine
Wrap-up
Before introducing a special product or a large framework, just tightening these seven areas - privileges, signing, secrets, communication, input, DLL loading, and logs - already changes the security picture significantly. Start by not shipping unsafe defaults as-is.
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
How to Isolate Only the Administrator-Required Work in a Windows App
A practical design for splitting the administrator-only work in a Windows app into a separate EXE: an administrator broker pattern coveri...
Best Practices for Avoiding Plaintext Secrets in Windows App Config Files
On Windows desktop apps, leaving passwords or tokens in plaintext config is risky. This post lays out where DPAPI (ProtectedData) actuall...
Checklist for Unexpected Exceptions - A Quick Decision Table for Whether to Exit or Keep Running
A practical guide for deciding whether an app should exit or keep running when an unexpected exception occurs. Three options and a decisi...
Where to `catch`, log, and handle exceptions — sorting out call-hierarchy boundaries and responsibilities for real-world code
A practical breakdown of where in the call hierarchy you should catch exceptions, where the primary log belongs, and where to decide betw...
How DLL Name Resolution Works on Windows: A Practical Look at Search Order, Known DLLs, API Sets, and SxS
A practical walkthrough of Windows DLL name resolution covering redirection, API sets, SxS manifests, Known DLLs, the loaded-module list,...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.
Technical Consulting & Design Review
We help clarify design direction, architectural boundaries, lifetime ownership, and how to handle legacy Windows assets.