Security Code Scan - static code analyzer for .NET

Quick Facts

Open Source

Detects various security vulnerability patterns: SQL Injection, Cross-Site Scripting (XSS), Cross-Site Request Forgery (CSRF), XML eXternal Entity Injection (XXE), etc.

Inter-procedural taint analysis for input data.

Continuous Integration (CI) support for GitHub and GitLab pipelines. Stand-alone runner or through MSBuild for custom integrations.

Analyzes .NET and .NET Core projects in a background (IntelliSense) or during a build.

Works with Visual Studio 2019 or higher. Visual Studio Community, Professional and Enterprise editions are supported. Other editors that support Roslyn based analyzers like Rider or OmniSharp should work too.

Installation

⚠️Warning: Security Code Scan (SCS) is not a Linter. It is a real static analysis tool that does extensive computations. Thus installing it as a Visual Studio extension or NuGet package will slow down your Visual Studio IDE. The VS extension installation is intented for security engineers and researchers who need to scan different software products and having SCS always running is convenient for the use case. The more common use case of SCS would be running it in CI/CD pipeline. For this purpose there are GitHub and GitLab integrations. For custom integrations there is a Stand-alone runner.

SCS can be installed as:

  • Visual Studio extension. Use the link or open “Tools > Extensions and Updates…” Select “Online” in the tree on the left and search for SecurityCodeScan in the right upper field. Click “Download” and install.
  • NuGet package.
    • Right-click on the root item in your solution. Select “Manage NuGet Packages for Solution…”. Select “Browse” on the top and search for SecurityCodeScan.VS2019. Select project you want to install into and click “Install”.
    • Another option is to install the package into all projects in a solution: use “Tools > NuGet Package Manager > Package Manager Console”. Run the command Get-Project -All | Install-Package SecurityCodeScan.VS2019.
  • Stand-alone runner. Install with dotnet tool install --global security-scan and run security-scan /your/solution.sln. For older .NET 4.x please use security-scan4x.zip from GitHub Releases.

Installing it as NuGet package allows to choose projects in a solution that should be analyzed. It is a good idea to exclude test projects, because they do not make it into a final product.

⚠️Note: In previous versions of .NET Core, if you added a reference to a project that had a Roslyn analyzer as NuGet package, it was automatically added to the dependent project too. To disable this behavior, for example if the dependent project is a unit test project, make sure the NuGet package is added as private in the .csproj or .vbproj file of the referenced project:

<PackageReference Include="SecurityCodeScan.VS2019" Version="5.0.0" PrivateAssets="all" />

⚠️ If during the analysis you run into warning CS8032: An instance of analyzer SecurityCodeScan.Analyzers.****** cannot be created from... Could not load file or assembly 'Microsoft.CodeAnalysis, Version=******'. The system cannot find the file specified.. most likely there is a mismatch between the used compiler toolset/SDK and the version of Roslyn analyzer library used by SCS. You may work-around the issue by:
a. Adding the latest Microsoft.Net.Compilers.Toolset NuGet package to the project: dotnet add package microsoft.net.compilers.toolset. Please note as per Microsoft “This package is primarily intended as a method for rapidly shipping hotfixes to customers. Using it as a long term solution for providing newer compilers on older MSBuild installations is explicitly not supported. That can and will break on a regular basis. The supported mechanism for providing new compilers in a build enviroment is updating to the newer .NET SDK or Visual Studio Build Tools SKU.
b. Upgrading the project to the newer .NET SDK/Compiler version.
c. Using an older version of SCS.

The NuGet version runs during a build and in background as IntelliSense (VS extension provides IntelliSense only) and can be integrated to any Continuous Integration (CI) server that supports MSBuild.

When SCS is installed as Visual Studio extension or added to a project as NuGet package it does static analysis in background as you type or read the code. Running SCS as stand-alone tool gives more control when the analysis starts and finishes. The stand-alone tool allows customizing different parameters and, for example, exclude unit test projects:

Stand-alone tool options

Integration with Continuous Integration (CI) builds and third-party tools

CI support for GitHub and GitLab pipelines. Stand-alone runner or through MSBuild for custom integrations. For custom integrations SCS is capable of producing results in SARIF format and displaying warnings with other build messages in the build output. SCS warnings are in the form of
[source file](line,column): warning SCS[rule id]: [warning description] [project_file]

A script is available for importing the analysis results into DefectDojo.

Configuration

Background analysis scope

Background analysis scope is a Visual Studio feature that enables you to choose whether you see code analysis issues only in open Visual C# or Visual Basic files in your solution, or in both open and closed Visual C# or Visual Basic files in your solution. For performance reasons it is disabled by default. It is not needed if SCS is installed as NuGet package, because it will run during a build, but if it is enabled you’ll see the warnings as IntelliSense from NuGet too. In VS extension case open Tools > Options in Visual Studio. Select Text Editor > C# (or Basic) > Advanced. Make sure the “Entire solution” is selected:

Background analysis scope
Since Entire solution for IntelliSense has performance impact this is another reason to use SCS during a build only as a NuGet instead of Visual Studio extension. Microsoft has some additional information on the configuration option.

Testing on WebGoat.NET

Download an intentionally vulnerable project WebGoat.NET for testing. Open the solution. If you have installed SCS as a VS extension you should see warning after few seconds in the “Errors” tab. Make sure IntelliSense results are not filtered in the window:

Intellisense filter

If SCS is installed as NuGet package and Entire solution is disabled you’ll need to build the solution. Then you should see the warning in the “Errors” and “Output” tabs:

Intellisense output

Analyzing .aspx and web.config Files

To enable analysis of these files you need to modify all C#(.csproj) and VB.NET(.vbproj) projects in a solution and add “AdditionalFileItemNames” element as shown below:

<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    [..]
    <TargetFrameworkProfile />
    <!-- Add the line below -->
    <AdditionalFileItemNames>$(AdditionalFileItemNames);Content</AdditionalFileItemNames>
  </PropertyGroup>

The helper PowerShell script can be used to do it automatically for all projects in a subfolder:

  Get-ChildItem *.csproj -Recurse | ForEach-Object {
    $content = [xml] (Get-Content $_)
    $propertyGroups = $content.SelectNodes("//Project/PropertyGroup")

    if (-not $propertyGroups[0].AdditionalFileItemNames) {
      Write-Host "AdditionalFileItemNames missing in $_"
      $additionalFileItemNamesElt = $content.CreateElement("AdditionalFileItemNames")
      $additionalFileItemNamesElt.set_InnerText('$(AdditionalFileItemNames);Content')
      $propertyGroups[0].AppendChild($additionalFileItemNamesElt)
    }

    Set-ItemProperty $_ -name IsReadOnly -value $false
    $content.Save($_)
    # Normalize line endings
    (Get-Content $_ -Encoding UTF8) | Set-Content $_ -Encoding UTF8
  }

External Configuration Files

There are two types of external configuration files that can be used together: per user account and per project. It allows you to customize settings from built-in configuration or add new rules. Global settings file location is %LocalAppData%\SecurityCodeScan\config-3.1.yml on Windows and $XDG_DATA_HOME/.local/share on Unix.

For project specific settings add a file named SecurityCodeScan.config.yml into a project.

⚠️Note: The file doesn’t have a version number in the name. Instead it must have Version: 3.1 configuration setting in it’s content. If the setting is missing you will get a runtime analysis exception.

Go to file properties and set the Build Action to AdditionalFiles:

Additional files property

Custom taint source, sinks, sanitizers and validators

An example of user’s (per OS user) config-3.1.yml with custom sink function (method that shouldn’t be called with untrusted data without first being sanitized):

Sinks:
  - Type: System.Messaging.BinaryMessageFormatter
    TaintTypes:
      - SCS0028
    Methods:
    - Name: Read
      Arguments:
        - message

An example of the same rule in SecurityCodeScan.config.yml (per project):

Version: 3.1

Sinks:
  - Type: System.Messaging.BinaryMessageFormatter
    TaintTypes:
      - SCS0028
    Methods:
    - Name: Read
      Arguments:
        - message

See the configuration file for comments and examples of usage.

Audit Mode

Audit mode is off by default. It can be turned on in an external configuration file to get more potentially false positive warnings about data with unknown taint state.

Suppressing and Fixing the Warnings

If Code Fixer is not implemented for the warning the link “Show potential fixes” won’t work. For many warnings there are too many options to resolve the issue, so the code has to be modified manually. If the warning is false positive it can be suppressed that is standard functionality for Visual Studio however the UI not very intuitive, because you have to click on the underlined piece of code, only then a bubble appears at the beginning of the line where suppress menu is available:

Suppress in context menu

Another place where the menu is available is Error List:

Suppress in error list

It is possible to filter shown item in Error List by different criteria: warning id, project name, etc. You can permanently suppress entire warning type for a project by setting it’s warning id severity to None. Microsoft has it’s own documentation about suppressions, rule sets and severities.

Severity

Each warning severity is configurable: expand References > Analyzers > SecurityCodeScan under the project in a Solution window, right click on a warning ID and modify the severity. WebGoat.NET.ruleset will be automatically saved in the project’s directory:

Intellisense

Troubleshooting

If no SCS warnings are displayed, temporarily disable other installed analyzers. A buggy analyzer may affect results from other analyzers.

Rules

Injection

References

OWASP: Top 10 2013-A1-Injection

SCS0001 - Command Injection

The dynamic value passed to the command execution should be validated.

Risk

If a malicious user controls either the FileName or Arguments, he might be able to execute unwanted commands or add unwanted argument. This behavior would not be possible if input parameter are validate against a white-list of characters.

Vulnerable Code

var p = new Process();
p.StartInfo.FileName = "exportLegacy.exe";
p.StartInfo.Arguments = " -user " + input + " -role user";
p.Start();

Solution

Regex rgx = new Regex(@"^[a-zA-Z0-9]+$");
if(rgx.IsMatch(input))
{
    var p = new Process();
    p.StartInfo.FileName = "exportLegacy.exe";
    p.StartInfo.Arguments = " -user " + input + " -role user";
    p.Start();
}

References

CWE-78: Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)
OWASP: Command Injection
OWASP: Top 10 2013-A1-Injection

SCS0002 - SQL Injection

SQL injection flaws are introduced when software developers create dynamic database queries that include user supplied input.

Risk

Malicious user might get direct read and/or write access to the database. If the database is poorly configured the attacker might even get Remote Code Execution (RCE) on the machine running the database.

Vulnerable Code

var cmd = "SELECT * FROM Users WHERE username = '" + input + "' and role='user'";
ctx.Database.ExecuteSqlCommand(
    cmd);

Solution

Use parametrized queries to mitigate SQL injection.

var cmd = "SELECT * FROM Users WHERE username = @username and role='user'";
ctx.Database.ExecuteSqlCommand(
    cmd,
    new SqlParameter("@username", input));

References

CWE-89: Improper Neutralization of Special Elements used in an SQL Command (‘SQL Injection’)
WASC-19: SQL Injection
OWASP: SQL Injection Prevention Cheat Sheet
OWASP: Query Parameterization Cheat Sheet
CAPEC-66: SQL Injection
Bobby Tables: A guide to preventing SQL injection

SCS0003 - XPath Injection

The dynamic value passed to the XPath query should be validated.

Risk

If the user input is not properly filtered, a malicious user could extend the XPath query.

Vulnerable Code

var doc = new XmlDocument {XmlResolver = null};
doc.Load("/config.xml");
var results = doc.SelectNodes("/Config/Devices/Device[id='" + input + "']");

Solution

Regex rgx = new Regex(@"^[a-zA-Z0-9]+$");
if(rgx.IsMatch(input)) //Additional validation
{
    XmlDocument doc = new XmlDocument {XmlResolver = null};
    doc.Load("/config.xml");
    var results = doc.SelectNodes("/Config/Devices/Device[id='" + input + "']");
}

References

CWE-643: Improper Neutralization of Data within XPath Expressions (‘XPath Injection’)
WASC-39: XPath Injection
OWASP: XPATH Injection
Black Hat Europe 2012: Hacking XPath 2.0

SCS0007 - XML eXternal Entity Injection (XXE)

The XML parser is configured incorrectly. The operation could be vulnerable to XML eXternal Entity (XXE) processing.

Risk

Vulnerable Code

Prior to .NET 4.5.2

// DTD expansion is enabled by default
XmlReaderSettings settings = new XmlReaderSettings();
XmlReader reader = XmlReader.Create(inputXml, settings);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(pathToXmlFile);
Console.WriteLine(xmlDoc.InnerText);

Solution

Prior to .NET 4.5.2

var settings = new XmlReaderSettings();
// Prior to .NET 4.0
settings.ProhibitDtd = true; // default is false!
// .NET 4.0 - .NET 4.5.2
settings.DtdProcessing = DtdProcessing.Prohibit; // default is DtdProcessing.Parse!

XmlReader reader = XmlReader.Create(inputXml, settings);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = null; // Setting this to NULL disables DTDs - Its NOT null by default.
xmlDoc.Load(pathToXmlFile);
Console.WriteLine(xmlDoc.InnerText);

.NET 4.5.2 and later

In .NET Framework versions 4.5.2 and up, XmlTextReader’s internal XmlResolver is set to null by default, making the XmlTextReader ignore DTDs by default. The XmlTextReader can become unsafe if if you create your own non-null XmlResolver with default or unsafe settings.

References

CWE-611: Improper Restriction of XML External Entity Reference (‘XXE’)
OWASP.org: XML External Entity (XXE) Prevention Cheat Sheet (.NET)
CERT: IDS10-J. Prevent XML external entity attacks
OWASP.org: XML External Entity (XXE) Processing
WS-Attacks.org: XML Entity Expansion
WS-Attacks.org: XML External Entity DOS
WS-Attacks.org: XML Entity Reference Attack
Identifying Xml eXternal Entity vulnerability (XXE)

SCS0018 - Path Traversal

A path traversal attack (also known as directory traversal) aims to access files and directories that are stored outside the expected directory.By manipulating variables that reference files with “dot-dot-slash (../)” sequences and its variations or by using absolute file paths, it may be possible to access arbitrary files and directories stored on file system including application source code or configuration and critical system files.

Risk

With a malicious relative path, an attacker could reach a secret file.

Vulnerable Code

[RedirectingAction]
public ActionResult Download(string fileName)
{
    byte[] fileBytes = System.IO.File.ReadAllBytes(Server.MapPath("~/ClientDocument/") + fileName);
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

The following request downloads a file of the attacker choice: http://www.address.com/Home/Download?fileName=../../somefile.txt

Solution

Do not try to strip invalid characters. Fail if any unexpected character is detected.

private static readonly char[] InvalidFilenameChars = Path.GetInvalidFileNameChars();

[RedirectingAction]
public ActionResult Download(string fileName)
{
    if (fileName.IndexOfAny(InvalidFilenameChars) >= 0)
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        
    byte[] fileBytes = System.IO.File.ReadAllBytes(Server.MapPath("~/ClientDocument/") + fileName);
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

If the input is not supplied by user or a validation is in place the warning can be suppressed.

References

CWE-22: Improper Limitation of a Pathname to a Restricted Directory (‘Path Traversal’)
OWASP: Path Traversal
OS Command Injection, Path Traversal & Local File Inclusion Vulnerability - Notes

SCS0029 - Cross-Site Scripting (XSS)

A potential XSS was found. The endpoint returns a variable from the client input that has not been encoded. To protect against stored XSS attacks, make sure any dynamic content coming from user or data store cannot be used to inject JavaScript on a page. Most modern frameworks will escape dynamic content by default automatically (Razor for example) or by using special syntax (<%: content %>, <%= HttpUtility.HtmlEncode(content) %>).

Risk

XSS could be used to execute unwanted JavaScript in a client’s browser. XSS can be used to steal the cookie containing the user’s session ID. There is rarely a good reason to read or manipulate cookies in client-side JavaScript, so consider marking cookies as HTTP-only, meaning that cookies will be received, stored, and sent by the browser, but cannot be modified or read by JavaScript.

Vulnerable Code

public class TestController : Controller
{
    [HttpGet(""{myParam}"")]
    public string Get(string myParam)
    {
        return "value " + myParam;
    }
}

Solution

public class TestController : Controller
{
    [HttpGet(""{myParam}"")]
    public string Get(string myParam)
    {
        return "value " + HttpUtility.HtmlEncode(myParam);
    }
}

References

CWE-79: Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’)
WASC-8: Cross Site Scripting
OWASP: XSS Prevention Cheat Sheet
OWASP: Top 10 2013-A3: Cross-Site Scripting (XSS)

SCS0026 - LDAP Distinguished Name Injection

The dynamic value passed to the LDAP query should be validated.

Risk

If the user input is not properly filtered, a malicious user could extend the LDAP query.

Vulnerable Code

var dir = new DirectoryEntry();
dir.Path = $"GC://DC={input},DC=com";

Solution

Use proper encoder (LdapFilterEncode or LdapDistinguishedNameEncode) from AntiXSS library:

var dir = new DirectoryEntry();
dir.Path = $"GC://DC={Encoder.LdapDistinguishedNameEncode(input)},DC=com";

References

CWE-90: Improper Neutralization of Special Elements used in an LDAP Query (‘LDAP Injection’)
WASC-29: LDAP Injection
OWASP: LDAP Injection
OWASP: LDAP Injection Prevention Cheat Sheet
MSDN Blog - Security Tools: LDAP Injection and mitigation

SCS0031 - LDAP Filter Injection

The dynamic value passed to the LDAP query should be validated.

Risk

If the user input is not properly filtered, a malicious user could extend the LDAP query.

Vulnerable Code

var searcher = new DirectorySearcher();
searcher.Filter = "(cn=" + input + ")";

Solution

Use proper encoder (LdapFilterEncode or LdapDistinguishedNameEncode) from AntiXSS library:

var searcher = new DirectorySearcher();
searcher.Filter = "(cn=" + Encoder.LdapFilterEncode(input) + ")";

References

CWE-90: Improper Neutralization of Special Elements used in an LDAP Query (‘LDAP Injection’)
WASC-29: LDAP Injection
OWASP: LDAP Injection
OWASP: LDAP Injection Prevention Cheat Sheet
MSDN Blog - Security Tools: LDAP Injection and mitigation

Cryptography

SCS0004 - Certificate Validation Disabled

Certificate Validation has been disabled. The communication could be intercepted.

Risk

Disabling certificate validation is often used to connect easily to a host that is not signed by a root certificate authority. As a consequence, this is vulnerable to Man-in-the-middle attacks since the client will trust any certificate.

Vulnerable Code

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

Solution

  • Make sure the validation is disabled only in testing environment or
  • Use certificate pinning for development or
  • Use properly signed certificates for development
#if DEBUG
    ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
#endif

References

CWE-295: Improper Certificate Validation
WASC-04: Insufficient Transport Layer Protection

SCS0005 - Weak Random Number Generator

The random numbers generated could be predicted.

Risk

The use of a predictable random value can lead to vulnerabilities when used in certain security critical contexts.

Vulnerable Code

var rnd = new Random();
byte[] buffer = new byte[16];
rnd.GetBytes(buffer);
return BitConverter.ToString(buffer);

Solution

using System.Security.Cryptography;
var rnd = RandomNumberGenerator.Create();

References

CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)
OWASP: Insecure Randomness

SCS0006 - Weak hashing function

MD5 or SHA1 have known collision weaknesses and are no longer considered strong hashing algorithms.

Vulnerable Code

var hashProvider = new SHA1CryptoServiceProvider();
var hash = hashProvider.ComputeHash(str);

Solution

Use SHA256 or SHA512. Notice, that hashing algorithms are designed to be fast and shouldn’t be used directly for hashing passwords. Use adaptive algorithms for the purpose.

var hashProvider = SHA256Managed.Create();
var hash = hashProvider.ComputeHash(str);

References

CWE-327: Use of a Broken or Risky Cryptographic Algorithm
MSDN: SHA256 Class documentation
Salted Password Hashing - Doing it Right

SCS0010 - Weak cipher algorithm

DES and 3DES are not considered a strong cipher for modern applications. Currently, NIST recommends the usage of AES block ciphers instead.

Risk

Broken or deprecated ciphers have typically known weakness. A attacker might be able to brute force the secret key use for the encryption. The confidentiality and integrity of the information encrypted is at risk.

Vulnerable Code

DES DESalg = DES.Create();

// Create a string to encrypt. 
byte[] encrypted;
ICryptoTransform encryptor = DESalg.CreateEncryptor(key, zeroIV);

// Create the streams used for encryption. 
using (MemoryStream msEncrypt = new MemoryStream())
{
    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt,
                                                     encryptor,
                                                     CryptoStreamMode.Write))
    {
        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
        {
            //Write all data to the stream.
            swEncrypt.Write(Data);
        }
        encrypted = msEncrypt.ToArray();
        return encrypted;
    }
}

Solution

Use AES for symmetric encryption.

// Create a string to encrypt. 
byte[] encrypted;
var encryptor = new AesManaged();
encryptor.Key = key;
encryptor.GenerateIV();
var iv = encryptor.IV;

// Create the streams used for encryption. 
using (MemoryStream msEncrypt = new MemoryStream())
{
    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt,
                                                     encryptor.CreateEncryptor(),
                                                     CryptoStreamMode.Write))
    {
        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
        {
            //Write all data to the stream.
            swEncrypt.Write(Data);
        }
        encrypted = msEncrypt.ToArray();
        return encrypted;
    }
}

Notice that AES itself doesn’t protect from encrypted data tampering. For an example of authenticated encryption see the Solution in Weak Cipher Mode

References

CWE-327: Use of a Broken or Risky Cryptographic Algorithm
NIST Withdraws Outdated Data Encryption Standard
StackOverflow: Authenticated encryption example

SCS0013 - Potential usage of weak CipherMode mode

The cipher text produced is susceptible to alteration by an adversary.

Risk

The cipher provides no way to detect that the data has been tampered with. If the cipher text can be controlled by an attacker, it could be altered without detection. The use of AES in CBC mode with a HMAC is recommended guaranteeing integrity and confidentiality.

Vulnerable Code

using (var aes = new AesManaged {
    KeySize = KeyBitSize,
    BlockSize = BlockBitSize,
    Mode = CipherMode.OFB,
    Padding = PaddingMode.PKCS7
})
{
    using (var encrypter = aes.CreateEncryptor(cryptKey, new byte[16]))
    using (var cipherStream = new MemoryStream())
    {
        using (var cryptoStream = new CryptoStream(cipherStream, encrypter, CryptoStreamMode.Write))
        using (var binaryWriter = new BinaryWriter(cryptoStream))
        {
            //Encrypt Data
            binaryWriter.Write(secretMessage);
        }
        cipherText = cipherStream.ToArray();
    }
}
//Missing HMAC suffix to assure integrity

Solution

Using bouncy castle:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;

public static readonly int BlockBitSize = 128;
public static readonly int KeyBitSize = 256;

public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] key)
{
    //User Error Checks
    if (key == null || key.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");

    if (secretMessage == null || secretMessage.Length == 0)
        throw new ArgumentException("Secret Message Required!", "secretMessage");

    //Using random nonce large enough not to repeat
    var nonce = new byte[NonceBitSize / 8];
    Random.NextBytes(nonce, 0, nonce.Length);

    var cipher = new GcmBlockCipher(new AesFastEngine());
    var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, new byte[0]);
    cipher.Init(true, parameters);

    //Generate Cipher Text With Auth Tag
    var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
    var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
    cipher.DoFinal(cipherText, len);

    //Assemble Message
    using (var combinedStream = new MemoryStream())
    {
        using (var binaryWriter = new BinaryWriter(combinedStream))
        {
            //Prepend Nonce
            binaryWriter.Write(nonce);
            //Write Cipher Text
            binaryWriter.Write(cipherText);
        }
        return combinedStream.ToArray();
    }
}

Custom implementation of Encrypt and HMAC:

using System.IO;
using System.Security.Cryptography;
public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] cryptKey, byte[] authKey, byte[] nonSecretPayload = null)
{
    //User Error Checks
    if (cryptKey == null || cryptKey.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "cryptKey");

    if (authKey == null || authKey.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "authKey");

    if (secretMessage == null || secretMessage.Length < 1)
        throw new ArgumentException("Secret Message Required!", "secretMessage");

    byte[] cipherText;
    byte[] iv;
    using (var aes = new AesManaged {
        KeySize = KeyBitSize,
        BlockSize = BlockBitSize,
        Mode = CipherMode.CBC,
        Padding = PaddingMode.PKCS7
    })
    {
        //Use random IV
        aes.GenerateIV();
        iv = aes.IV;
        using (var encrypter = aes.CreateEncryptor(cryptKey, iv))
        using (var cipherStream = new MemoryStream())
        {
            using (var cryptoStream = new CryptoStream(cipherStream, encrypter, CryptoStreamMode.Write))
            using (var binaryWriter = new BinaryWriter(cryptoStream))
            {
            //Encrypt Data
            binaryWriter.Write(secretMessage);
            }
            cipherText = cipherStream.ToArray();
        }
    }
    //Assemble encrypted message and add authentication
    using (var hmac = new HMACSHA256(authKey))
    using (var encryptedStream = new MemoryStream())
    {
        using (var binaryWriter = new BinaryWriter(encryptedStream))
        {
            //Prepend IV
            binaryWriter.Write(iv);
            //Write Ciphertext
            binaryWriter.Write(cipherText);
            binaryWriter.Flush();
            //Authenticate all data
            var tag = hmac.ComputeHash(encryptedStream.ToArray());
            //Postpend tag
            binaryWriter.Write(tag);
        }
        return encryptedStream.ToArray();
    }
}

References

CWE-327: Use of a Broken or Risky Cryptographic Algorithm
Padding Oracles for the masses (by Matias Soler)
Wikipedia: Authenticated encryption
NIST: Authenticated Encryption Modes
CAPEC: Padding Oracle Crypto Attack
Wikipedia: ECB mode

Cookies

It is recommended to specify the Secure flag to new cookie.

Risk

The Secure flag is a directive to the browser to make sure that the cookie is not sent by unencrypted channel

Vulnerable Code

The requireSSL value is explicitly set to false or the default is left.

<httpCookies requireSSL="false" [..] />
// default is left
var cookie = new HttpCookie("test");
// or explicitly set to false
var cookie = new HttpCookie("test");
cookie.Secure = false;

Solution

<httpCookies requireSSL="true" [..] />
var cookie = new HttpCookie("test");
cookie.Secure = true; //Add this flag
cookie.HttpOnly = true;

References

CWE-614: Sensitive Cookie in HTTPS Session Without ‘Secure’ Attribute
OWASP: Secure Flag
Rapid7: Missing Secure Flag From SSL Cookie

It is recommended to specify the HttpOnly flag to new cookie.

Risk

Cookies that doesn’t have the flag set are available to JavaScript running on the same domain. When a user is the target of a “Cross-Site Scripting”, the attacker would benefit greatly from getting the session id.

Vulnerable Code

The httpOnlyCookies value is explicitly set to false or the default is left.

<httpCookies httpOnlyCookies="false" [..] />
// default is left
var cookie = new HttpCookie("test");
// or explicitly set to false
var cookie = new HttpCookie("test");
cookie.HttpOnly = false;

Solution

<httpCookies httpOnlyCookies="true" [..] />
var cookie = new HttpCookie("test");
cookie.Secure = true;
cookie.HttpOnly = true; //Add this flag

References

CWE-1004: Sensitive Cookie Without ‘HttpOnly’ Flag
Coding Horror blog: Protecting Your Cookies: HttpOnly
OWASP: HttpOnly
Rapid7: Missing HttpOnly Flag From Cookie

View State

SCS0023 - View State Not Encrypted

The viewStateEncryptionMode is not set to Always in configuration file.

Risk

Web Forms controls use hidden base64 encoded fields to store state information. If sensitive information is stored there it may be leaked to the client side.

Vulnerable Code

The default value is Auto:

<system.web>
   ...
   <pages [..] viewStateEncryptionMode="Auto" [..]/>
   ...
</system.web>

or

<system.web>
   ...
   <pages [..] viewStateEncryptionMode="Never" [..]/>
   ...
</system.web>

Solution

Explicitly set to Always and encrypt with with the .NET machine key:

<system.web>
   ...
   <pages [..] viewStateEncryptionMode="Always" [..]/>
   ...
</system.web>

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: pages Element (ASP.NET Settings Schema)
MSDN: ViewStateEncryptionMode Property
MSDN: machineKey Element (ASP.NET Settings Schema)

SCS0024 - View State MAC Disabled

The enableViewStateMac is disabled in configuration file. (This feature cannot be disabled starting .NET 4.5.1)

Risk

The view state could be altered by an attacker.

Vulnerable Code

<system.web>
   ...
   <pages [..] enableViewStateMac="false" [..]/>
   ...
</system.web>

Solution

The default value is secure - true. Or set it explicitly:

<system.web>
   ...
   <pages [..] enableViewStateMac="true" [..]/>
   ...
</system.web>

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: pages Element (ASP.NET Settings Schema)

Request Validation

SCS0017 - Request Validation Disabled (Attribute)

Request validation is disabled. Request validation allows the filtering of some XSS patterns submitted to the application.

Risk

XSS

Vulnerable Code

public class TestController
{
    [HttpPost]
    [ValidateInput(false)]
    public ActionResult ControllerMethod(string input) {
        return f(input);
    }
}

Solution

Although it performs blacklisting (that is worse than whitelisting by definition) and you should not rely solely on it for XSS protection, it provides a first line of defense for your application. Do not disable the validation:

public class TestController
{
    [HttpPost]
    public ActionResult ControllerMethod(string input) {
        return f(input);
    }
}

Always user proper encoder (Html, Url, etc.) before displaying or using user supplied data (even if it is loaded from database).

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: Request Validation in ASP.NET
OWASP: ASP.NET Request Validation
See XSS references.

SCS0021 - Request Validation Disabled (Configuration File)

The validateRequest which provides additional protection against XSS is disabled in configuration file.

Risk

XSS

Vulnerable Code

<system.web>
   ...
   <pages [..] validateRequest="false" [..]/>
   ...
</system.web>

Solution

Although it performs blacklisting (that is worse than whitelisting by definition) and you should not rely solely on it for XSS protection, it provides a first line of defense for your application. Do not disable the validation: The default value is true. Or set it explicitly:

<system.web>
   ...
   <pages [..] validateRequest="true" [..]/>
   ...
</system.web>

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: pages Element (ASP.NET Settings Schema)
MSDN: Request Validation in ASP.NET
OWASP: ASP.NET Request Validation
See XSS references.

SCS0030 - Request validation is enabled only for pages (Configuration File)

The requestValidationMode which provides additional protection against XSS is enabled only for pages, not for all HTTP requests in configuration file.

Risk

XSS

Vulnerable Code

<system.web>
   ...
   <httpRuntime [..] requestValidationMode="2.0" [..]/>
   ...
</system.web>

Solution

<system.web>
   ...
   <httpRuntime [..] requestValidationMode="4.5" [..]/>
   ...
</system.web>

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: pages Element (ASP.NET Settings Schema)
MSDN: Request Validation in ASP.NET
OWASP: ASP.NET Request Validation
MSDN: RequestValidationMode Property
See XSS references.

Password Management

SCS0015 - Hardcoded Password

The password configuration to this API appears to be hardcoded.

Risk

If hard-coded passwords are used, it is almost certain that malicious users will gain access through the account in question.

Vulnerable Code

config.setPassword("NotSoSecr3tP@ssword");

Solution

It is recommended to externalize configuration such as password to avoid leakage of secret information. The source code or its binary form is more likely to be accessible by an attacker than a production configuration. To be managed safely, passwords and secret keys should be stored encrypted in separate configuration files. The certificate for decryption should be installed as non-exportable on the server machine.

Configuration file :

<configuration>
    <appSettings>
    <add key="api_password" value="b3e521073ca276dc2b7caf6247b6ddc72d5e2d2d" />
  </appSettings>
</configuration>

Code:

string apiPassword = ConfigurationManager.AppSettings["api_password"];
config.setPassword(apiPassword);

References

CWE-259: Use of Hard-coded Password

SCS0034 - Password RequiredLength Not Set

The RequiredLength property must be set with a minimum value of 8.

Risk

Weak password can be guessed or brute-forced.

Vulnerable Code

ASP.NET Identity default is 6.

PasswordValidator pwdv = new PasswordValidator();

Solution

See the solution for Password Complexity

References

CWE-521: Weak Password Requirements
MSDN: ASP.NET Identity PasswordValidator Class

SCS0032 - Password RequiredLength Too Small

The minimal length of a password is recommended to be set at least to 8.

Risk

Weak password can be guessed or brute-forced.

Vulnerable Code

PasswordValidator pwdv = new PasswordValidator
{
    RequiredLength = 6,
};

Solution

See the solution for Password Complexity

References

CWE-521: Weak Password Requirements
MSDN: ASP.NET Identity PasswordValidator Class

SCS0033 - Password Complexity

PasswordValidator should have at least two requirements for better security (RequiredLength, RequireDigit, RequireLowercase, RequireUppercase and/or RequireNonLetterOrDigit).

Risk

Weak password can be guessed or brute-forced.

Vulnerable Code

PasswordValidator pwdv = new PasswordValidator
{
    RequiredLength = 6,
};

Solution

PasswordValidator pwdv = new PasswordValidator
{
    RequiredLength = 8,
    RequireNonLetterOrDigit = true,
    RequireDigit = true,
    RequireLowercase = true,
    RequireUppercase = true,
};

References

CWE-521: Weak Password Requirements
MSDN: ASP.NET Identity PasswordValidator Class

Other

SCS0011 - Unsafe XSLT setting used

XSLT scripting should be enabled only if you require script support and you are working in a fully trusted environment.

Risk

This issue may lead to Remote Code Execution (RCE) if the XML source is untrusted.

Vulnerable Code

XslCompiledTransform transform = new XslCompiledTransform();
XsltSettings settings = new XsltSettings() {EnableScript = true};
transform.Load(xslPath, settings, null);
// Execute the transformation.
transform.Transform(reader, writer);

References

CWE-611: Improper Restriction of XML External Entity Reference
XSLT Server Side Injection Attacks
XML Attack for C# Remote Code Execution
XsltSettings.EnableScript Property

SCS0012 - Controller method is potentially vulnerable to authorization bypass

Neither the annotation [Authorize], nor [AllowAnonymous] is present.

Risk

The endpoint is potentially accessible to not authorized users. If it contains sensitive information, like log files for example, it may lead to privilege escalation. The warning may be ignored/suppressed if the application is using other authorization checks. It is possible to customize the rule and register the additional attributes.

Vulnerable Code

public class AccountController : Controller
{
   public ActionResult Login()
   {
   }

   [Authorize]
   public ActionResult Logout()
   {
   }
}

Solution

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous]
    public ActionResult Login()
    {
    }

    public ActionResult Logout()
    {
    }
}

References

CWE-284: Improper Access Control
Access control vulnerabilities and privilege escalation
Simple authorization in ASP.NET Core

SCS0016 - Cross-Site Request Forgery (CSRF)

Anti-forgery token is missing.

Risk

An attacker could send a link to the victim. By visiting the malicious link, a web page would trigger a POST request (because it is a blind attack - the attacker doesn’t see a response from triggered request and has no use from GET request and GET requests should not change a state on the server by definition) to the website. The victim would not be able to acknowledge that an action is made in the background, but his cookie would be automatically submitted if he is authenticated to the website. This attack does not require special interaction other than visiting a website.

Vulnerable Code

public class TestController
{
    [HttpPost]
    public ActionResult ControllerMethod(string input)
    {
        //Do an action in the context of the logged in user
    }
}

Solution

In your view:

@Html.AntiForgeryToken()

In your controller:

public class TestController
{
    [HttpPost]
    [ValidateAntiForgeryToken] //Annotation added
    public ActionResult ControllerMethod(string input)
    {
        //Do an action in the context of the logged in user
    }
}

References

CWE-352: Cross-Site Request Forgery (CSRF)
OWASP: Cross-Site Request Forgery
OWASP: CSRF Prevention Cheat Sheet

SCS0019 - OutputCache Conflict

Caching conflicts with authorization.

Risk

Having the annotation [OutputCache] will disable the annotation [Authorize] for the requests following the first one.

Vulnerable Code

[Authorize]
public class AdminController : Controller
{
    [OutputCache]
    public ActionResult Index()
    {
        return View();
    }
}

Solution

Remove the caching:

[Authorize]
public class AdminController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

References

CWE-524: Use of Cache Containing Sensitive Information
Improving Performance with Output Caching

SCS0022 - Event Validation Disabled

The enableEventValidation is disabled in configuration file.

Risk

This feature reduces the risk of unauthorized or malicious post-back requests and callbacks. It is strongly recommended that you do not disable event validation. When the EnableEventValidation property is set to true, ASP.NET validates that a control event originated from the user interface that was rendered by that control.

Vulnerable Code

<system.web>
   ...
   <pages [..] enableEventValidation="false" [..]/>
   ...
</system.web>

Solution

The default value is secure - true. Or set it explicitly:

<system.web>
   ...
   <pages [..] enableEventValidation="true" [..]/>
   ...
</system.web>

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: pages Element (ASP.NET Settings Schema)
MSDN: Page.EnableEventValidation Property

SCS0027 - Open Redirect

The dynamic value passed to the Redirect should be validated.

Risk

Your site may be used in phishing attacks. An attacker may craft a trustworthy looking link to your site redirecting a victim to a similar looking malicious site: https://www.yourdomain.com/loginpostback?redir=https://www.urdomain.com/login

Vulnerable Code

[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        if (MembershipService.ValidateUser(model.UserName, model.Password))
        {
            FormsService.SignIn(model.UserName, model.RememberMe);
            if (!String.IsNullOrEmpty(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        else
        {
            ModelState.AddModelError("", "The user name or password provided is incorrect.");
        }
    }
 
    // If we got this far, something failed, redisplay form
    return View(model);
}

Solution

[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        if (MembershipService.ValidateUser(model.UserName, model.Password))
        {
            FormsService.SignIn(model.UserName, model.RememberMe);
            if (Url.IsLocalUrl(returnUrl)) // Make sure the url is relative, not absolute path
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        else
        {
            ModelState.AddModelError("", "The user name or password provided is incorrect.");
        }
    }
 
    // If we got this far, something failed, redisplay form
    return View(model);
}

References

CWE-601: URL Redirection to Untrusted Site (‘Open Redirect’)
Microsoft: Preventing Open Redirection Attacks (C#)
OWASP: Unvalidated Redirects and Forwards Cheat Sheet
Hacksplaining: preventing malicious redirects

SCS0028 - Insecure Deserialization

Untrusted data passed for deserialization.

Risk

Arbitrary code execution, full application compromise or denial of service. An attacker may pass specially crafted serialized .NET object of specific class that will execute malicious code during the construction of the object.

Vulnerable Code

private void ConvertData(string json)
{
    var mySerializer = new JavaScriptSerializer(new SimpleTypeResolver());
    Object mything = mySerializer.Deserialize(json, typeof(SomeDataClass)/* the type doesn't matter */);
}

Solution

There is no simple fix. Do not deserialize untrusted data: user input, cookies or data that crosses trust boundaries.

In case it is unavoidable:
1) If serialization is done on the server side, then crosses trust boundary, but is not modified and is returned back (like cookie for example) - use signed cryptography (HMAC for instance) to ensure it wasn’t tampered.
2) Do not get the type to deserialize into from untrusted source: the serialized stream itself or other untrusted parameter. BinaryFormatter for example reads type information from serialized stream itself and can’t be used with untrusted streams:

// DO NOT DO THIS!
var thing = (MyType)new BinaryFormatter().Deserialize(untrustedStream);

JavaScriptSerializer for instance without a JavaScriptTypeResolver is safe because it doesn’t resolve types at all:

private void ConvertData(string json)
{
    var mySerializer = new JavaScriptSerializer(/* no resolver here */);
    Object mything = mySerializer.Deserialize(json, typeof(SomeDataClass));
}

Pass the expected type (may be hardcoded) to the deserialization library. Some libraries like Json.Net, DataContractJsonSerializer and FSPickler validate expected object graph before deserialization. However the check is not bulletproof if the expected type contains field or property of System.Object type somewhere nested in hierarchy.

// Json.net will inspect if the serialized data is the Expected type
var data = JsonConvert.DeserializeObject<Expected>(json, new
JsonSerializerSettings
{
    // Type information is not used, only simple types like int, string, double, etc. will be resolved
    TypeNameHandling = TypeNameHandling.None
});
// DO NOT DO THIS! The cast to MyType happens too late, when malicious code was already executed
var thing = (MyType)new BinaryFormatter().Deserialize(untrustedStream);

3) If the library supports implement a callback that verifies if the object and its properties are of expected type (don’t blacklist, use whitelist!):

class LimitedBinder : SerializationBinder
{
    List<Type> allowedTypes = new List<Type>()
    {
        typeof(Exception),
        typeof(List<Exception>),
    };

    public override Type BindToType(string assemblyName, string typeName)
    {
        var type = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName), true);
        foreach(Type allowedType in allowedTypes)
        {
            if(type == allowedType)
                return allowedType;
        }

        // Don’t return null for unexpected types –
        // this makes some serializers fall back to a default binder, allowing exploits.
        throw new Exception("Unexpected serialized type");
    }
}

var formatter = new BinaryFormatter() { Binder = new LimitedBinder () };
var data = (List<Exception>)formatter.Deserialize (fs);

Determining which types are safe is quite difficult, and this approach is not recommended unless necessary. There are many types that might allow non Remote Code Execution exploits if they are deserialized from untrusted data. Denial of service is especially common. As an example, the System.Collections.HashTable class is not safe to deserialize from an untrusted stream – the stream can specify the size of the internal “bucket” array and cause an out of memory condition.

4) Serialize simple Data Transfer Objects (DTO) only. Do not serialize/deserialize type information. For example, use only TypeNameHandling.None (the default) in Json.net:

class DataForStorage
{
    public string Id;
    public int    Count;
}

var data = JsonConvert.SerializeObject<DataForStorage>(json, new
JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.None
});

will produce the following JSON without type information that is perfectly fine to deserialize back:

{
  "Id": null,
  "Count": 0
}

References

CWE-502: Deserialization of Untrusted Data
BlackHat USA 2017: Friday the 13th: JSON Attacks
BlueHat v17: Dangerous Contents - Securing .Net Deserialization
BlackHat USA 2012: Are you my type?
OWASP: Deserialization of untrusted data
Deserialization payload generator for a variety of .NET formatters
.NET Deserialization Passive Scanner

Release Notes

5.6.7

  • sln were not analyzed by standalone tool fix by @matteo-tosi in #262
  • added –sdk-path parameter

Full Changelog

5.6.6

  • Fixed #258 “Standalone scanner throws exception: ‘ProjectName’ is already part of the workspace”

Full Changelog

5.6.5

  • Fixed #257 “Exception on solution that contains a Solution Items section”

5.6.4

  • Support running dotnet tool against a single project
  • Better filtering by projects in the dotnet tool
  • #246 Package security-scan is not compatible with netcoreapp3.1

5.6.3

  • #248 Be able to exit with non-zero error code when warnings are found

5.6.2

  • Blue-yellow edition in support of Ukraine.

5.6.1

  • Fixed #239 “Adding custom sanitizers to a config file in stand-alone runner”.

5.6.0

  • Added support for .NET 6.0 and VS2022

5.2.1

  • New parameter --ignore-msbuild-errors for standalone runner to ignore errors from incompatible projects.
  • Bug fixes and improvements.

5.1.0

  • Standalone runner improved. My favorite way to run SCS!
  • Bug fixes and improvements.
  • A script was made by Sebastien gioria for importing the analysis results into DefectDojo.

5.0.0

  • New inter-procedural taint analysis engine.
  • New sinks and sources.
  • Bug fixes.
  • Standalone tool.

3.5.3

  • Removed EntityFramework “Interpolated” sinks that caused false positives.
  • Added configuration entry for Web Config analyzer to allow filtering file names.

3.5.2

Bugfix release.

  • Fix MissingMethodException “Method not found: ‘YamlDotNet.Serialization.IDeserializer YamlDotNet.Serialization.DeserializerBuilder.Build()’” if incompatible version of YamlDotNet is loaded by the process.

3.5.0

  • Better taint analysis in implicit string conversions case.
  • Out of range exception fix.
  • New SQL injection and Path Traversal sinks.

Thanks @watfordgnf and @indy-singh for the contributions!

3.4.0

  • XSS analyzer was rewritten. Additional sanitizers were added.
  • Added ReportAnalysisCompletion option to output a message that the analysis did run.
  • Bugfixes and improvements.

3.3.0

  • Better C# 7 handling
  • CSRF analyzer configuration made more flexible.
    Configuration file schema version has changed to 2.0, so if you had custom config settings, you’ll need to adjust to the schema and bump your file name from config-2.0.yml to config-2.1.yml or change from Version: 2.0 to Version: 2.1 if it was added to a project.
  • Bug fixes.

Thanks @kevin-montrose for the contributions!

3.2.0

Bugfix release.

  • Fixes using SCS as nuget. #117
  • One click code fixes were removed until a separate assembly is created. #71

3.1.0

The release adds support for VS2019 and bug fixes. Also:

  • Adds multiple XSS sinks for WebForms (thanks Andrei!)
  • Changes in SCS configuration file doesn’t require to restart Visual Studio anymore.
  • Warnings are suppressed for generated code.
  • Adds .NET Core cookie analyzer.

3.0.0

This is a major release that introduces configurable taint sources, sanitizers and validators. Configuration file schema version has changed to 2.0, so if you had custom config settings, you’ll need to adjust to the schema and bump your file name from config-1.0.yml to config-2.0.yml or change from Version: 1.0 to Version: 2.0 if it was added to a project.
With the introduction of taint sources and taint entry points warning are shown only for the tainted data. Unknowns are reported only in the Audit Mode.
Multiple improvements and fixes were done to Taint, Anti-CSRF token, XSS, SQL injection, Path traversal, XPath injection, Certificate validation analyzers.
New LDAP injection detection was added.
An issue was fixed that could surface as Session Terminated unexpectedly. Disabling 'Security Code Scan' might help prevent....

I would like to thank all contributors to this and previous releases. Also to everyone who has reported issues or feature requests.

2.8.0

Important: This release targets full .NET framework and may not run on Unix machines. Although as tested it runs fine in microsoft/dotnet 2.1 docker container on Linux, still for Unix based Continuous Integration builds it is better to use SecurityCodeScan.VS2017 NuGet package, that targets netstandard.

Added external configuration files: per user account and per project. It allows you to customize settings from built-in configuration or add your specific Sinks and Behaviors.

⚠️Note: Configuration schema has changed in version 3.0.0 please refer to the documentation above for examples.

Audit Mode setting (Off by default) was introduced for those interested in warnings with more false positives.

2.7.1

Couple of issues related to VB.NET fixed:

  • VB.NET projects were not analyzed when using the analyzer from NuGet.
  • ‘Could not load file or assembly ‘Microsoft.CodeAnalysis.VisualBasic, Version=1.0.0.0…’ when building C# .NET Core projects from command line with dotnet.exe

2.7.0

Insecure deserialization analyzers for multiple libraries and formatters:

Added warning for the usage of AllowHtml attribute.
Different input validation analyzer and CSRF analyzer improvements.

2.6.1

Exceptions analyzing VB.NET projects fixed.

2.6.0

XXE analysis expanded. More patterns to detect Open Redirect and Path Traversal. Weak hash analyzer fixes. Added request validation aspx analyzer. False positives reduced in hardcoded password manager.

Web.config analysis:

  • The feature was broken. See how to enable.
  • Added detection of request validation mode.
  • Diagnostic messages improved.

Taint improvements:

  • Area expanded.
  • Taint diagnostic messages include which passed parameter is untrusted.

2.5.0

Various improvements were made to taint analysis. The analysis was extended from local variables into member variables. False positive fixes in:

  • XSS analyzer.
  • Weak hash analyzer. Added more patterns.
  • Path traversal. Also added more patterns.

New features:

  • Open redirect detection.