This article shows you how to analyze your applications written in C# using NG SAST. It assumes that you have already set up and authenticated with ShiftLeft.


See Prerequisites for more information.

Machine requirements

We recommend running NG SAST on a machine with a minimum of 4 GB RAM and 2 CPU Cores. For each subsequent 100,000 lines of code that you submit for analysis, we recommend an additional 2 GB RAM and 1+ CPU Core.

Lines of codeCPUsRAM
<100k3 cores6 GB
>100k4 cores8 GB
> 200k5 cores10 GB
+100k+1 core+2 GB

For example, if your application contains 200,000 lines of code, we recommend that the machine you're using have 8 GB RAM and 4 CPU cores.

SCA requirements

To identify open-source vulnerabilities in C# applications, ShiftLeft CORE requires one of the following package formats: .csproj, packages.config.

Determining your MSBuild version

You can determine the version of MSBuild installed by:

  1. Launching the Developer Command Prompt for Visual Studio
  2. Running msbuild /version in the newly-launched prompt

Preparing your application for analysis

Before analyzing your code with NG SAST, we recommend either:

  • Restoring the dependencies of your application;
  • Building your application (since this will implicitly restore your application's dependencies and produce additional artifacts that may be useful for analysis).

You can restore and build a .NET application as follows:

  1. Launch a command prompt
  2. Navigate to your project location
  3. Restore NuGet packages by running dotnet restore <MySolution.sln>
  4. Start the build by running dotnet build --no-restore <MySolution.sln>


dotnet restore [<path to .sln>]
dotnet build [<path to .sln>]

You can restore and build a .NET Framework application with the following:

  1. Launch the Developer Command Prompt for Visual Studio
  2. Navigate to your project location
  3. Restore NuGet packages by running nuget.exe restore <MySolution.sln>
  4. Start the build by running msbuild <MySolution.sln>.


nuget restore [<path to .sln>]
msbuild [<path to .sln>]

For both .NET and .NET Framework, you may need to apply additional options depending on your environment.

It is possible to analyze your applications even if you cannot restore the dependencies or build your application on a particular system. However, we do not recommend this course of action since your results will likely not be as accurate as they would otherwise be.

Analyzing your C# application


ShiftLeft offers a sample application that you can use to run and test NG SAST. It also includes a functioning configuration file to demonstrate how you can leverage Azure Pipelines or GitHub Actions to automate code analysis whenever you open a new Pull Request (PR).

To analyze your C# application, use the options of sl.exe analyze as explained in the table below.

--app <name>The name of the application to be analyzed
--csharpThe flag identifying the application's language
--dotnet-framework, --dotnet, or (deprecated) --dotnet-coreIf you're running ShiftLeft on a Windows machine with .NET Framework 4.7.2 installed, use --dotnet-framework*;
otherwise, use --dotnet for .NET applications and (deprecated) --dotnet-core for .NET Core applications;
defaults to --dotnet-framework
<path>The location of the application's .csproj or .sln (for .NET Framework app only) file to be analyzed


sl.exe analyze --app <name> --csharp --dotnet [<path to .sln or .csproj>]
sl.exe analyze --app <name> --csharp --dotnet-core [<path to .sln or .csproj>]
sl.exe analyze --app <name> --csharp [<path to .sln or .csproj>]
sl.exe analyze --app <name> --csharp --dotnet-framework [<path to .sln or .csproj>]

See the CLI reference for additional sl.exe analyze options.

Non-Windows users should invoke the ShiftLeft CLI using sl instead of sl.exe.

* Even if the application to be analyzed is .NET or .NET Core, as long as packages can be restored on Windows. This is a general recommendation, so if packages cannot be restored on Windows, use --dotnet and (deprecated) --dotnet-core.


To identify open-source vulnerabilities, ShiftLeft CORE automatically searches for build manifests in the project path you provided when running sl.exe analyze. However, depending on how your project repo is structured, you may need to provide --oss-project-dir <project-path> so that ShiftLeft CORE can identify where your dependencies are located.

Choosing files to analyze

We recommend analyzing the .csproj files for speed and robust results. When doing so, be sure to use the following flag when invoking sl.exe analyze: -- --ignore-tests

Analyzing on a machine without a required runtime

If you're running ShiftLeft on a machine without any of our required runtimes, append --csharp2cpg-download-url <url_appropriate_for_your_os> to sl analyze.

  1. Obtain the download URL appropriate for your operating system by running the following in the terminal:

    • Windows: Invoke-WebRequest -Uri https://cdn.shiftleft.io/download/csharp2cpg-net-win-x64.json

    • Linux: curl https://cdn.shiftleft.io/download/csharp2cpg-net-linux-x64.json

    • macOS: curl https://cdn.shiftleft.io/download/csharp2cpg-net-osx-x64.json

    In the JSON response, save the downloadURL value. You can also save it as a local variable for future use.

  2. Include the downloadURL you saved in the previous step when calling sl analyze using the --csharp2cpg-download-url flag:

    # Windows
    sl.exe analyze --app <name> --csharp ... --csharp2cpg-download-url YOUR_DOWNLOAD_URL [<path to .sln or .csproj>]
    # Linux/macOS
    sl analyze --app <name> --csharp ... --csharp2cpg-download-url YOUR_DOWNLOAD_URL [<path to .sln or .csproj>]

Combining C# projects for analysis

When working with .NET apps, you can combine multiple C# projects for analysis as follows:

sl.exe analyze --app Xyz --csharp [--dotnet|--dotnet-core|--dotnet-framework] --dep lib.csproj --dep component.csproj app.csproj

Note that you can include --dep multiple times for libs, subprojects, components, etc. The --dep option allows you to filter the subprojects/dependencies to include with the primary .csproj project for analysis. This allows you to adopt the middle ground between analyzing just the primary project:

sl.exe analyze --app Xyz --csharp app.csproj

and analyzing the primary file with all of its dependencies/subprojects:

sl.exe analyze --app Xyz --csharp <path-to-project-file>

Passing in build parameters

You can pass custom build parameters as part of your sl.exe analyze command to replicate your build configuration.

All parameters present after -- are passed directly to the build configuration process. For example, if the build requires a custom parameter for the C# build configuration (/p:configuration or /p:platform), run:

sl.exe analyze --app Xyz --csharp [--dotnet|--dotnet-core|--dotnet-framework] <path-to-project-file> -- /p:configuration="Release" /p:platform="Any CPU"

Tagging results with your branch name

To include the branch name in your NG SAST results, allowing you to distinguish one set of results from another, add the following to your invocation of ShiftLeft:

sl.exe analyze --tag branch=`git symbolic-ref --short HEAD`

If you're working in a GitHub environment (e.g., GitHub Actions), you can also use --tag branch=${{ github.head_ref }} to populate your branch name.

If you don't provide a branch name, but ShiftLeft detects one available in your environment, it will use that name.

Recursively finding and scanning your solution/project files

The following example shows you how to modify the sl.exe analyze invocation to recursively find all .sln files and scan them with ShiftLeft:

# Recursively find all .sln files and scan them with ShiftLeft CORE
# Be sure to change the app.group value from "test-appgroup" to your preferred name
Get-ChildItem -Path . -Filter *.sln -Recurse -ErrorAction SilentlyContinue -Force | ForEach-Object {
sl.exe analyze --csharp --oss-project-dir $($_.Directory) --tag app.group=test-appgroup --app $($_.Name -replace '.sln', '') $($_.FullName)

Alternatively, you can recursively find and scan all .csproj files if .sln-based scans are taking too long:

# Recursively find all .csproj files and scan them with ShiftLeft CORE
# Use this when .sln based scans are taking too long
# Be sure to change the app.group value from ß"test-appgroup" to your preferred name
Get-ChildItem -Path . -Filter *.csproj -Recurse -ErrorAction SilentlyContinue -Force | ForEach-Object {
sl.exe analyze --csharp --oss-project-dir $($_.Directory) --tag app.group=test-appgroup --app $($_.Name -replace '.csproj', '') $($_.FullName)

Apps utilizing MSBuild project files

If your primary application refers to dependencies (e.g., dll files), ShiftLeft's default code analysis mode will not look into the dependency files. However, if the csproj files with source code for dependencies are available, you can modify the parameters passed to sl.exe analyze to ensure that ShiftLeft analyzes all relevant dependencies.

In short, ShiftLeft can look at dependencies and dependencies of dependencies (which we call a transitive dependency) during the code analysis process.

To scan your primary solution and its dependencies, include the following flag after initial double ellipsis: --msbuild-proj <path-to-proj-file>. Note that a project file ends with the .proj suffix.

For example:

sl.exe analyze --app yourApp --csharp --dotnet <path-to-sln-or-csproj> -- --msbuild-proj <path-to-proj-file>

However, if your solution refers to dependencies that, in turn, rely on dependencies, you can indicate to ShiftLeft that you would like such dependencies included in the analysis. Including the flag --msbuild-proj-iter <integer> allows you to provide the integer specifying the levels of transitive dependencies you want to be included in your scan.

For example, let's say that your sl.exe analyze command is as follows:

sl.exe analyze --app yourApp --csharp --dotnet <path-to-sln-or-csproj> -- --msbuild-proj <path-to-proj-file> --msbuild-proj-iter 2

ShiftLeft will look at your primary project file, any direct dependencies, and any dependencies of direct dependencies. ShiftLeft will ignore any further references.

Example usage

Let's say that you have TheApp, which is structured as follows:

├── TheApp
│ └── TheApp.csproj
├── TheLib
| └── TheLib.csproj
├── AnotherLib
│ └── AnotherLib
│ └── AnotherLib
│ └── AnotherLib.csproj
├── CoolClassLib
│ └── CoolClassLib
│ └── CoolClassLib
│ └── CoolClassLib.csproj
├── NotUsedLib
└── NotUsedLib
└── NotUsedLib
└── NotUsedLib.csproj

The app's .sln file only mentions the TheApp.csproj:

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.810.8
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheApp", "TheApp\TheApp.csproj", "{E776BD21-3B47-4184-93B7-7DA198474F1E}"

TheApp.csproj references its dependencies through a <Reference>item, instead of a <ProjectReference> item (that is, it references .dll files). Its direct dependencies are TheLib and AnotherLib:

<Project Sdk="Microsoft.NET.Sdk.Web">
<Reference Include="TheLib">
<Reference Include="AnotherLib">

However, AnotherLib references CoolClassLib, making CoolClassLib a transitive dependency of TheApp:

<Project Sdk="Microsoft.NET.Sdk">
<None Remove="CoolClassLib" />
<Reference Include="CoolClassLib">

To ensure that ShiftLeft looks into all of TheApp's dependencies, you must have an MSBuild project file (this is a build specification for all such dependencies). The following is a sample project file called TheAppFullBuild.proj:

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<Target Name="Assemblies">
<MSBuild Properties="… Projects="

Therefore, the sl.exe analyze command to scan TheApp is:

sl.exe analyze --app TheApp --csharp --dotnet TheApp.sln -- --msbuild-proj TheAppFullBuild.proj --msbuild-proj-iter 2

Including Razor pages in your analysis of C# apps (experimental)

ShiftLeft CORE includes an experimental feature offering support for Razor Pages (*.cshtml files) that you submit as part of your C# project.

To enable this feature, include the --enable-razor flag in your sl analyze command (note that this flag must follow a double dash used after you provide the location of your project files):

sl.exe analyze --csharp --app yourAppName exampleProject.RazorPages.csproj -- --enable-razor


  • We currently support only *.cshtml files with @page directives (full support for any *.cshtml file is forthcoming).
  • We currently do not support Tag Helpers. If the files you submit contain Tag Helpers, you'll see a message saying that ShiftLeft found unsupported features in .cshtml files. However, ShiftLeft CORE will continue to parse and scan such files.
  • Line numbers shown for the version control integration, where the ShiftLeft dashboard includes URLs directing you to the source code lines where the vulnerability occurs, may not be accurate at this time.

Enabling log information

By default, we print logs at the Information level. If you would like more detailed information, pass in the --verbose flag:

sl.exe analyze --csharp --verbose --app Xyz app.csproj


If you have any issues scanning your project, please see our general troubleshooting page, as well as our C#-specific suggestions that follow.

Build requirements

The workstation on which ShiftLeft runs should have MSBuild and the appropriate .NET SDK; it should also be able to build your project/solution.

You can verify this by invoking:

dotnet build .sln
msbuild .sln

You do not need to build your project before invoking sl.exe analyze; ShiftLeft will perform a build before code analysis, so you only need to run the .NET or MSBuild restore step beforehand:

dotnet restore .sln
nuget restore .sln // for .NET Framework

Do not proceed with sl.exe analyze until this step passes.

Please note that the build step performed as part of code analysis may be slower for the following reasons:

  • Your project uses a mix of .NET Core versions or combines the usage of the .NET Framework with .NET Core
  • Your project uses private dependencies from NuGet servers (fetching dependencies adds to the time required)
  • Your project uses special pre- or post-build events to copy .dll files or artifacts

Which files to analyze

We recommend analyzing the .csproj files for speed and more robust results. Be sure to use the following two flags when invoking sl.exe analyze:

-- --with-ProjectReference --ignore-tests

If you opt to analyze your .sln files, omit both --ignore-tests and --with-ProjectReference.

Artifact and dll not found errors

If you see the errors that look like this:

fail: Buildalyzer.Logging.EventProcessor[0]
System.IO.FileNotFoundException: Could not find file '/Users/prabhu/Downloads/EU-OutageStatusQuery/AzureFunctions/OutageStatusFunctions/OmsData.Peco/bin/Debug/netcoreapp3.1/bin/OmsData.Peco.dll'.
File name: '/Users/prabhu/Downloads/EU-OutageStatusQuery/AzureFunctions/OutageStatusFunctions/OmsData.Peco/bin/Debug/netcoreapp3.1/bin/OmsData.Peco.dll'
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
at System.IO.FileStream.OpenHandle(FileMode mode, FileShare share, FileOptions options)

Or this:

fail[39m[22m[49m: Buildalyzer.Logging.EventProcessor[0]
2021-02-03T18:39:57.5318095Z Metadata file '/src/src/app/Fool.Marthetron.Shared/bin/Release/netstandard2.1/Fool.Marthetron.Shared.dll' could not be found

This means that you must pass additional build parameters to sl.exe analyze to ensure that the dependent projects can be built successfully. Typically, the developer should be able to provide the necessary build parameters, but we've found the following five flags to be helpful:

sl.exe analyze --app app-name /
--verbose /
--csharp /
--dotnet "sln file name" /
-- /p:BuildProjectReferences="true" /
/p:SkipCompilerExecution="false" /
/p:CopyBuildOutputToOutputDirectory="true" /
/p:CopyOutputSymbolsToOutputDirectory="true" /

If the project fails to rebuild after three attempts, even with the addition of build flags, please contact Support for further assistance.

Windows logs

You can find the logs generated by ShiftLeft in the Windows temp directory.