BinSkim: a compiler settings scanner for PE and ELF binaries
A binary static analysis tool that provides security and correctness results for Windows Portable Executable and *nix ELF binary formats
At a glance
- What is it?
- BinSkim is a static analysis tool that checks the security-relevant characteristics of a compiled binary, chiefly the compiler and linker flags it was built with, across both Windows Portable Executable and ELF formats. It reports in SARIF and reads its policy from a configuration file, so it drops into an existing pipeline without a custom output format.
- Who is it for?
- Use BinSkim when you need to prove that your binaries were compiled with the hardening flags you intended, because it reads the flags out of the artefact itself rather than trusting the build script, and it covers both PE and ELF so one policy can span a mixed estate. Do not expect it to find vulnerabilities in your code, since it judges the toolchain configuration rather than the logic.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What it checks and what it ignores
BinSkim is a Portable Executable light-weight scanner that validates compiler and linker settings and other security-relevant binary characteristics, and the repository description widens that to the Windows Portable Executable and ELF binary formats. So the subject is the artefact rather than the source. The tool reads a compiled binary and asks what it was built with: whether the linker was told to enable control flow guard, whether the compiler produced position independent code, whether the binary has the expected mitigations for its platform. That is a narrow and useful thing to check, because the flags that matter are set once in a build definition and then apply to every artefact that comes out of it, and a mistake there is invisible in a code review and permanent in every binary you ship.
Running it from the NuGet package
BinSkim is distributed through NuGet as Microsoft.CodeAnalysis.BinSkim, and the README documents a path for running it without installing anything. You download the package, rename the .nupkg extension to .zip, unzip it, and the executables are in the OS specific folder under the tools directory, for example tools/netcoreapp3.1 with folders like linux-x64, win-x64 and osx-x64. From there the invocations are as follows.
binskim.exe analyze c:\bld\*.dll --recurse true --output MyRun.sarif./BinSkim analyze /someDirectory/testBinary -o MyRun.sarifOn macOS the command is the same as on Linux, and there is a fourth form using the dotnet SDK against binskim.dll. So the analyser runs anywhere the .NET runtime runs, and the same arguments work across platforms.
SARIF as the output, a config file as the policy
The output format is the Static Analysis Results Interchange Format, and the README points at both the SARIF specification and the SARIF SDK. That choice is what makes the tool drop into an existing pipeline rather than need one built for it. Results also go to the console and to a log file, and the input side is just as configurable: the config argument, with short form -c, points at a policy file used to configure the analysis, and passing the value default, or omitting the argument, invokes the built-in settings. So a team can run with the defaults to see what fires, then write a policy file that encodes its own rules and ship that file alongside the code. The target side is a list of specifiers resolving to one or more binaries to analyse, and the recurse option controls whether subdirectories are walked.
Filtering results by level and by kind
Two filters shape what you see, and the set of kinds is the interesting one. The level filter takes Error, Warning and Note. The kind filter takes Fail, for literal scan results, and also Pass, Review, Open, NotApplicable and Informational. That last list is a deliberate design choice: a scanner that reports only failures cannot tell you whether a rule was checked and found nothing, which is different from a rule that did not apply. The kinds separate those cases, so a policy can be written to require that every binary is checked rather than merely that no check failed. The Review and Open kinds also let a team record a finding it has accepted without silencing it.
The options that write data about your machine
Several options record information about the run rather than about the binary. The trace option emits execution traces to the console and the log file, with valid values PdbLoad, ScanTime, RuleScanTime, PeakWorkingSet, TargetsScanned and ResultsSummary, which is how you find out which rule is slow. The insert option adds data to the log file, with values including Hashes, TextFiles, BinaryFiles, EnvironmentVariables, RegionSnippets, Guids, VersionControlDetails and NondeterministicProperties. The environment option logs machine environment details of the run to the output file, and it carries an explicit warning: this option records potentially sensitive information, such as all environment variable values, to the log file. That warning is the one to read before enabling it on a build agent that has credentials in its environment.
Baselines, plugins and exit codes
Three more capabilities shape how the tool fits a pipeline. The baseline option takes a SARIF file to use as a baseline, so a scan can be compared against a previous run and only new findings reported, which is the pattern most teams need for a build gate. The plugin option takes paths to a plugin, as a semicolon-delimited list, that will be invoked against all targets in the analysis set, so an organisation can add its own checks alongside the built-in ones. The rich-return-code option changes the exit code from a plain zero for success or one for failure into a series of flags about the execution, which lets a pipeline distinguish between a scan that found nothing, a scan that could not run, and a scan that crashed.
The developer workflow and the release cadence
The contributor instructions are precise. You fork the repository, read the Rule Contributions Guide, load and compile src\BinSkim.sln to develop changes, and execute BuildAndTest.cmd at the root of the enlistment to validate before submitting a pull request. Running that script ensures the tests pass, the release build succeeds and the NuGet packages are created, and the pull request goes to the develop branch. The repository has both BuildAndTest.cmd and BuildAndTest.sh, plus a .devcontainer, a .pipelines directory for CI, a .nuget directory, and a scripts directory. The release history shows a steady stream of patch versions under a 4.4.x line, with v4.4.9.13 published on 2026-10-06, v4.4.9.7 on 2026-03-30 and v4.4.8 on 2025-11-13, and a ReleaseHistory.md file at the root alongside a SECURITY.md.
Where BinSkim is the wrong choice
Four limits apply. It says nothing about whether your code is correct, so it complements a source analyser rather than replacing one, and a project that wants findings on logic will still need a different tool. It reports on the binary, which means it can only confirm what the toolchain recorded, and a source build that sets a flag conditionally can produce artefacts that pass or fail for reasons invisible in the source. The SARIF output is a strength for pipelines but a burden for anyone who wants to read the results in a terminal without a SARIF viewer, though the console output covers the simple case. And the plugin mechanism, while it exists, means custom rules are code you write against an interface rather than configuration you write, which puts a maintenance burden on whoever owns them.
Editorial conclusion
Use BinSkim when you need to prove that your binaries were compiled with the hardening flags you intended, because it reads the flags out of the artefact itself rather than trusting the build script, and it covers both PE and ELF so one policy can span a mixed estate. Do not expect it to find vulnerabilities in your code, since it judges the toolchain configuration rather than the logic. Verify first that your build actually sets the flags the rules assume, since the common finding will be a mismatch rather than a defect, that your SARIF consumer accepts the levels and kinds BinSkim emits, which include Pass and Review alongside Fail, and that you understand what the environment logging option writes, because the documentation warns it records potentially sensitive information such as all environment variable values.
Frequently asked questions
What does BinSkim check?
It is a static analysis tool for Windows Portable Executable and ELF binaries that validates compiler and linker settings and other security-relevant binary characteristics, reading the settings out of the compiled artefact rather than the build script.
How do I run BinSkim without installing it?
Download the Microsoft.CodeAnalysis.BinSkim package from NuGet, rename the .nupkg to .zip, unzip it, and run the executable in the OS specific folder under tools/netcoreapp3.1, for example binskim.exe analyze on Windows or ./BinSkim analyze on Linux and macOS. The dotnet SDK form runs binskim.dll directly.
What output format does BinSkim use?
SARIF, the Static Analysis Results Interchange Format. The output path is set with the -o or --output argument, and results also go to the console and the log file. A previous SARIF file can be supplied with the --baseline option to report only new findings.
Which result kinds can BinSkim report?
The kind filter takes Fail for literal scan results, plus Pass, Review, Open, NotApplicable and Informational. The level filter separately takes Error, Warning and Note, so a policy can distinguish a rule that found nothing from one that did not apply.
What licence is BinSkim released under?
The repository's licence field carries a custom classification GitHub cannot label, and the LICENSE file at the repository root governs. Releases ship through NuGet as Microsoft.CodeAnalysis.BinSkim, with v4.4.9.13 published on 2026-10-06, and there is a SECURITY.md file describing how to report problems.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/microsoft-binskim)Was this useful?