AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Binskim Scan

skill-dotnet-arcade-skills-binskim-scan · by dotnet

>

No reviews yet
0 installs
6 views
0.0% view→install

Install

$ agentstack add skill-dotnet-arcade-skills-binskim-scan

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-dotnet-arcade-skills-binskim-scan)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Binskim Scan? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

BinSkim Local Scanning

Run BinSkim locally against a dotnet repository to find binary security issues. This skill covers installing BinSkim, building the repo, discovering what the official pipeline scans, running BinSkim with matching targeting, and interpreting results.

> Local scans are an approximation. The official pipeline runs BinSkim via Guardian with additional filtering. Local scans produce a superset of official findings. For understanding what the portal reports vs what BinSkim finds, use the binskim-analysis skill. For authoritative pass/fail confirmation, recommend the user manually queue the official CI pipeline against their branch — SDL does not run on PR validation builds.

When to Use This Skill

  • Running BinSkim locally to scan binaries for security issues
  • Verifying a fix for a BinSkim rule violation before pushing
  • Checking whether a repo's scan config covers everything it ships
  • Iterating on a fix with fast local feedback

Not for: interpreting official pipeline results (use binskim-analysis), source code security (CodeQL), or credential scanning (CredScan).

Prerequisites

  • BinSkim: See [references/binskim-install.md](references/binskim-install.md) for installation.
  • Windows: ~\.binskim\extracted\tools\net9.0\win-x64\BinSkim.exe
  • Linux: ~/.binskim/extracted/tools/net9.0/linux-x64/BinSkim
  • Build toolchain: .NET SDK (managed builds). For native code: MSVC + CMake on Windows, gcc/clang + CMake on Linux. See [references/build-prereqs.md](references/build-prereqs.md).
  • Repo cloned locally: Typically under C:\git\ (Windows) or ~/git/ (Linux).

Local Scan Workflow

Step 1: Discover Pipeline BinSkim Configuration

Before scanning, read the repo's pipeline YAML to understand what the official scan targets.

  1. Find the pipeline YAML — look for azure-pipelines-official.yml, vsts-ci.yml, .vsts-ci.yml, azure-pipelines.yml, or .ado.yml at the repo root or under eng/pipelines/. SDL is typically only in the CI/official pipeline, not the PR one.
  2. Find the sdl.binskim section:

``yaml sdl: binskim: enabled: true scanOutputDirectoryOnly: true ``

  1. Check for sdl.binskim.additionalRunConfigParams — custom flags/exclusions.
  2. Identify what artifacts are published — look for PublishPipelineArtifact steps. The scan targets these.

> Report what you find. Tell the user: "The official pipeline scans X with config Y. I'll reproduce that locally."

> No SDL config? Some repos have no sdl.binskim section at all. In that case, identify what the pipeline publishes as artifacts (e.g., **\bin\Release\**) and scan that. Note to the user: "This repo has no explicit BinSkim/SDL configuration. Scanning the published artifact directory as a best-effort approximation. Results may differ from any central SDL portal findings."

Step 2: Build the Repo

BinSkim scans built/packaged binaries, not source code. You must build (and often pack) the repo.

# Windows
build.cmd -c Release -pack

# Linux
./build.sh -c Release -pack

What to build depends on pipeline config:

| Pipeline config | Build command | Scan target | |---|---|---| | scanOutputDirectoryOnly + publishes pkgassets | build.cmd -c Release -pack | artifacts\pkgassets\** | | scanOutputDirectoryOnly + publishes NuGet packages | build.cmd -pack then extract .nupkg | Extracted .nupkg contents | | Explicit analyzeTargetGlob | build.cmd -c Release | Use the glob from YAML | | Autobaselining only | build.cmd -c Release | artifacts\bin\** (best guess) |

Extracting .nupkg for scanning (mirrors eng/common/sdl/extract-artifact-packages.ps1):

$nupkgDir = [System.IO.Path]::Combine("artifacts", "packages", "Release", "Shipping")
$extractDir = Join-Path "artifacts" "extracted-for-scan"
Add-Type -AssemblyName System.IO.Compression.FileSystem
Get-ChildItem (Join-Path $nupkgDir "*.nupkg") | ForEach-Object {
    $dest = Join-Path $extractDir $_.BaseName
    New-Item -ItemType Directory -Path $dest -Force | Out-Null
    $zip = [System.IO.Compression.ZipFile]::OpenRead($_.FullName)
    $zip.Entries | Where-Object { $_.Name -match '\.(dll|exe|pdb)$' } | ForEach-Object {
        $target = Join-Path $dest $_.FullName
        New-Item -ItemType Directory -Path (Split-Path $target) -Force | Out-Null
        [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $target, $true)
    }
    $zip.Dispose()
}

> Only extract Shipping packages unless you have reason to scan NonShipping too.

> Native builds may require extra setup. If native code fails to build, you can still scan pre-built native DLLs from the NuGet cache. Many rules (including BA2008) don't need PDBs. See [references/build-prereqs.md](references/build-prereqs.md). > > NuGet cache limitation: This only covers third-party native blobs consumed via NuGet. It misses first-party native code compiled from source, managed assemblies the repo builds, and pack-only artifacts. For repos where all findings are on NuGet-sourced binaries (e.g., machinelearning's Intel DLLs), this is sufficient. For repos that compile native code from source, a full build is needed.

Step 3: Run BinSkim

Preferred: Use the helper script (from the skill's scripts/ directory, or provide its full path):

$script = [System.IO.Path]::Combine("plugins", "dotnet-dnceng", "skills", "binskim-scan", "scripts", "Invoke-BinSkimScan.ps1")

# Scan a directory:
& $script -RepoRoot C:\git\machinelearning -ScanDir (Join-Path "artifacts" "pkgassets")

# Filter to portal-reported rules only:
& $script -RepoRoot C:\git\machinelearning -ScanDir (Join-Path "artifacts" "pkgassets") -PortalRulesFrom C:\temp\Results.sarif

# Auto-discover scan targets:
& $script -RepoRoot C:\git\machinelearning

Manual invocation:

# Adjust path to your platform – see binskim-install.md for installation
$binskim = [System.IO.Path]::Combine($HOME, ".binskim", "tools", "net9.0", "linux-x64", "BinSkim")   # Linux
# $binskim = [System.IO.Path]::Combine($HOME, ".binskim", "tools", "net9.0", "win-x64", "BinSkim.exe") # Windows
$targetGlob = Join-Path "artifacts" "pkgassets" "**"
& $binskim analyze $targetGlob --recurse --output binskim-results.sarif --log PrettyPrint --force --Hashes False

> Don't filter to *.dll only — scan ** and let BinSkim decide what's analyzable. This catches .exe, .sys, .so, .dylib, and extensionless Mach-O executables. BinSkim identifies binary format by magic bytes, not file extension.

Step 4: Analyze Results

$sarif = Get-Content -Raw binskim-results.sarif | ConvertFrom-Json
# IMPORTANT: Results.sarif may have multiple runs (BinSkim, roslynanalyzers, etc.)
# Filter to the BinSkim run by tool name — don't assume runs[0]
$binskimRun = $sarif.runs | Where-Object { $_.tool.driver.name -like '*BinSkim*' } | Select-Object -First 1
if (-not $binskimRun) { $binskimRun = $sarif.runs[0] }  # fallback
$results = $binskimRun.results
$errors = $results | Where-Object { $_.level -eq 'error' }
$warnings = $results | Where-Object { $_.level -eq 'warning' }
Write-Host "Errors: $($errors.Count), Warnings: $($warnings.Count)"
$errors | Group-Object ruleId | Sort-Object Count -Descending | Format-Table Count, Name

Present results as:

  1. Summary table: rule ID, count, severity
  2. Per-binary breakdown for errors
  3. For each finding: first-party (built in repo) or third-party (from NuGet)?

Step 5: Compare with Official Results (if applicable)

If the user provides official results, map findings and flag:

  • Gaps: findings in official but not local (packaging differences)
  • Extras: findings local but not official (scanning too broadly, or Guardian filtering)

Local scans are a superset — more findings than the portal is expected. Use -PortalRulesFrom to filter local results to match portal rules.

Cross-Platform

BinSkim ships for Windows, Linux (x64, arm64), and macOS (x64):

  • Windows: tools/net9.0/win-x64/BinSkim.exe
  • Linux: tools/net9.0/linux-x64/BinSkim (chmod +x)
  • macOS: tools/net9.0/osx-x64/BinSkim (x64 only — no arm64 runtime in package; use Rosetta on Apple Silicon)

Each OS build produces different native binaries with potentially different BinSkim findings. If the repo ships native binaries for multiple platforms, you need to scan binaries from each target OS — not just Windows.

Use build.sh on Linux/macOS to build for those platforms. If the official pipeline only runs BinSkim on Windows legs, flag this as a coverage gap — the pipeline should scan all OS configurations that produce shipped native artifacts.

Cross-platform scanning — any binary on any OS

BinSkim can scan PE, ELF, and Mach-O binaries on any OS. BinSkim identifies binary format by magic bytes (not file extension or host OS). The Windows build can analyze Linux .so files and macOS .dylib files, and vice versa. All the binary parsing is pure managed code with no platform-specific dependencies.

This means you can:

  • Scan macOS .dylib files on a Windows dev machine
  • Scan Linux .so files on a Windows dev machine
  • Download official build artifacts from any platform and scan them locally, regardless of your OS

The key requirement is passing the right file patterns. BinSkim discovers files via glob patterns you supply (e.g., *.dll). If you only pass *.dll, it won't find .dylib or .so files — not because it can't analyze them, but because the glob doesn't match. Use ** (all files) or explicit patterns like *.dylib *.so to scan non-PE binaries.

> Why do official pipelines miss non-Windows binaries? The 1ES/Guardian SDL template invokes BinSkim with Windows-centric glob patterns (matching .dll, .exe, .sys). Mach-O and ELF binaries are never enumerated — they aren't "rejected", they're simply never passed to BinSkim. This is a configuration gap in how the pipeline invokes BinSkim, not a BinSkim limitation.

Scanning downloaded official artifacts

There are two main scenarios for local BinSkim scanning:

  • Verifying a local fix: Build the repo (or sub-repo) locally and scan the output. This is the normal workflow.
  • Analyzing platforms not covered by official SDL: If official runs don't scan certain platforms (e.g., Linux/macOS binaries), you can download official build artifacts and scan them locally on any OS — BinSkim can analyze PE, ELF, and Mach-O binaries on any platform. This is also useful for initial triage before fixing anything.

For the artifact download approach, official BinSkim and Guardian SARIF files from the SDL artifacts give you the same information without re-scanning. Re-scanning downloaded artifacts is only needed when official SDL doesn't cover a platform. BinSkim can analyze binaries from any platform on any OS, so you don't need a macOS machine to scan .dylib files.

To scan downloaded artifacts:

  1. Download build artifacts from AzDO (use ado-dnceng-pipelines_download_artifact or REST API)
  2. Extract native binaries — artifacts often contain .tar.gz inside .nupkg or zip files
  • For .tar.gz extraction: use tar.exe (built into Windows 10+) or 7-Zip
  • PowerShell 7.4+ on .NET 8+ also supports tar via [System.Formats.Tar.TarFile]::ExtractToDirectory()
  1. Identify native binaries by file header magic bytes (ELF: \x7fELF, Mach-O: \xfe\xed\xfa\xce/\xcf\xfa\xed\xfe)
  2. Scan with BinSkim using the appropriate platform binary

Before/After Comparison

To prove a fix works, scan before and after:

# Baseline on main, then fix branch
$before = (Get-Content -Raw binskim-before.sarif | ConvertFrom-Json).runs[0].results | Where-Object { $_.level -eq 'error' }
$after  = (Get-Content -Raw binskim-after.sarif  | ConvertFrom-Json).runs[0].results | Where-Object { $_.level -eq 'error' }
Write-Host "Before: $($before.Count) errors, After: $($after.Count) errors"

> This requires two full builds. Only use when the user needs proof a fix works.

Fix Strategies

Classify the finding first

  1. Search the repo for the binary name — is there a project that produces it?
  2. Check NuGet packages — is it from a PackageReference?
  3. Check for `` — is it a pre-built file being copied?

Fix by origin

| Binary origin | Example | Fix approach | |---|---|---| | C++ source (.vcxproj) | EtwClrProfiler.dll | Add compiler/linker flags (e.g., /guard:cf) | | Pre-built native from NuGet | Intel MKL/TBB, WiX winterop.dll | Cannot fix here — update package, file upstream, or suppress | | Test framework | xunit.*.dll | Fix scan scope — exclude from shipped artifacts | | Managed C# assembly | Most .dll from .csproj | BA2008 not applicable (BinSkim skips IL-only) |

> Guard in a .csproj does nothing. This MSBuild property only works in .vcxproj (MSVC C++).

VMR fix ownership

In the VMR (dotnet/dotnet), look at the SARIF artifact path to find the source sub-repo (e.g., src/arcade/artifacts/... means the fix goes to dotnet/arcade).

Anti-Patterns

> Don't scan artifacts\bin\ if the pipeline uses scanOutputDirectoryOnly — you'll get findings from test dependencies that aren't shipped.

> Don't skip the pack step — many shippable binaries only materialize during packing.

> Don't assume the native build is required — scan NuGet-cached DLLs if native build fails locally.

> Don't report NuGet transitive dependency findings as repo issues — if libSkiaSharp.dll fails BA2008, that's SkiaSharp's issue.

> Don't be alarmed by extra local findings — use -PortalRulesFrom to filter to portal-reported rules. For rules reference and Guardian filtering details, see the binskim-analysis skill.

References

  • Installing BinSkim: [references/binskim-install.md](references/binskim-install.md)
  • Build prerequisites: [references/build-prereqs.md](references/build-prereqs.md)
  • Per-repo pipeline configs: Use the binskim-analysis skill for known pipeline names, SDL artifact patterns, and local repro notes per repo
  • Arcade SDL infrastructure: Use the binskim-analysis skill for configure-sdl-tool.ps1 and extract-artifact-packages.ps1 details
  • Rules reference and Guardian filtering: See the binskim-analysis skill

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.