C#

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.

Requirements

NG SAST is supported on Windows, Linux, and macOS with the specified runtimes installed:

SystemRuntime
Windows.NET Framework 4.7.2 and/or .NET 5.0
Linux/macOS.NET 5.0 and .NET Core 3.1

Your applications should have the following characteristics:

  • Written in C# 10 (or earlier)
  • Has the specification in MSBuild format (.csproj file)
  • Meets one of the following apps/build requirements:
    • .NET Framework
    • .NET Core
    • .NET

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

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>

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>.

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

note

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 based on .NET, run:

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

To analyze your C# application based on .NET Core, run:

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

To analyze your C# application based on .NET Framework, run:

msbuild [<path to .sln>]
sl.exe analyze --app <name> --csharp [<path to .sln or .csproj>]
ParameterDescription
--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

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

* 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.

SCA

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

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}"
EndProject
...

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">
<ItemGroup>
<Reference Include="TheLib">
<HintPath>..\TheLib.dll</HintPath>
</Reference>
<Reference Include="AnotherLib">
<HintPath>..\AnotherLib.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

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

<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<None Remove="CoolClassLib" />
</ItemGroup>
<ItemGroup>
<Reference Include="CoolClassLib">
<HintPath>..\..\..\CoolClassLib.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

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="
<path-to>/TheApp/TheLib/TheLib.csproj;
<path-to>/TheApp/AnotherLib/AnotherLib/AnotherLib/AnotherLib.csproj;
<path-to>/TheApp/CoolClassLib/CoolClassLib/CoolClassLib/CoolClassLib.csproj;
<path-to>/TheApp/NotUsedLib/NotUsedLib/NotUsedLib/NotUsedLib.csproj;
"/>
</Target>
</Project>

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

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

Troubleshooting

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

OS requirements

  • We require Windows for scanning .NET Framework apps.
  • We support Windows and Linux for .NET Core 3.1 apps (we support .NET Core 2.1 apps on a best-effort basis) with the --dotnet-core parameter.
  • We support Windows and Linux for .NET 5 apps with the --dotnet parameter.

.NET Core vs .NET

.NET 5.0 is the major release following .NET Core 3.1 (note the slight name change and the version number shift -- see Microsoft's announcement for more information).

We suggest migrating your applications to .NET 5 as soon as possible. Once you've migrated, please ensure that you have the .NET 5 Runtime installed to ensure that ShiftLeft works as expected.

If you haven't migrated, you can continue to use --dotnet-core only if you have .NET Core 3.1 Runtime installed, but not the .NET 5 Runtime.

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" /
/p:SkipCopyBuildProduct="false"

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.