Transitive Software Composition Analysis (SCA)
Raises an issue per NuGet package with known GitHub security advisories (https://github.com/advisories?query=+ecosystem%3Anuget) used by a package used by the application — hence transitive, unlike the rule Software Composition Analysis (SCA). The issue is reported on the first type (alphabetically) using a third-party assembly using the affected package.
Flagged Code
Flagged Code
<!-- Acme.Sdk 2.1.0 depends on Newtonsoft.Json 12.0.1 (advisory GHSA-5crp-9r3c-p9vr) --> <!-- Newtonsoft.Json is not referenced directly: the advisory is transitive --> <ItemGroup> <PackageReference Include="Acme.Sdk" Version="2.1.0" /> </ItemGroup>Fixed Code
<!-- Acme.Sdk 2.2.0 depends on Newtonsoft.Json 13.0.1, which has no known advisory --> <ItemGroup> <PackageReference Include="Acme.Sdk" Version="2.2.0" /> </ItemGroup> <!-- Alternative when no such Acme.Sdk version exists: pin the transitive package --> <ItemGroup> <PackageReference Include="Acme.Sdk" Version="2.1.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> </ItemGroup>
How to fix
Update the package containing DirectAsm to a version not using a package with known security advisories.
CQLinq source
This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.
// <Name>Transitive Software Composition Analysis (SCA)</Name>
// <Id>ND3121:SoftwareCompositionAnalysisTransitive</Id>
warnif count > 0
// Use this hashset to avoid to have several SAC issues on a type
let hashset = new HashSet<IType>()
let thirdPartyAsmNames = ThirdParty.Assemblies.Select(a => a.Name).ToHashSetEx(StringComparer.OrdinalIgnoreCase)
// Avoid reporting packages reported by the non-transitive SAC rule
let directPackageNamesWithAdvisories =
(from asm in ThirdParty.Assemblies
let advisories = asm.GetSecurityAdvisories()
where advisories.Count > 0
select (string)advisories.First().PackageName).ToHashSetEx(StringComparer.OrdinalIgnoreCase)
// Gather assembly references used by third-party assemblies
// with one or several GitHub Security Advisories
let indirectAsmWithAdvisories =
from directAsm in ThirdParty.Assemblies
// Assemblies from Microsoft.NetCore.App.Runtime pkg reference version
// are always X.0.0.0 (like 8.0.0.0 or 9.0.0.0)
// Thus this rule cannot detect if patched version is referenced.
where !directAsm.Name.StartsWithAny("System.","Microsoft.")
from indirectAsm in directAsm.AssemblyReferences
where !indirectAsm.Name.StartsWithAny("System.","Microsoft.")
// Don't match assemblies directly used by the app
where !thirdPartyAsmNames.Contains(indirectAsm.Name)
let advisories = indirectAsm.GetSecurityAdvisories()
where advisories.Count > 0
let PackageName = (string)advisories.First().PackageName
// Avoid reporting packages reported by the non-transitive SAC rule
where !directPackageNamesWithAdvisories.Contains(PackageName)
select new {
directAsm,
indirectAsm,
advisories,
PackageName
}
// Merge assemblies references within the same NuGet Package
from x in indirectAsmWithAdvisories.ToLookup(a1 => a1.PackageName)
// Gather data useful to describe the advisories and how to fix
let HighestSeverity = x.SelectMany(r => r.advisories).Max(ad => ad.Severity)
let AdvisoryWithHighestSeverity = x.SelectMany(r => r.advisories).First(ad => ad.Severity == HighestSeverity)
let ThirdPartyAssembliesImpacted = x.Select(x1 => x1.directAsm).Distinct().ToArray()
// Application AND test assemblies: a vulnerable package referenced only by tests is still a vulnerability
let AppAssembliesUser = ApplicationAndTestCode.Assemblies.UsingAny(ThirdPartyAssembliesImpacted)
// The issue appears on the first type using one culprit third-party assembly
let typeUsers = ApplicationAndTestCode.Types.UsingAny(ThirdPartyAssembliesImpacted)
.Where(t => !t.IsGeneratedByCompiler || t.Name.StartsWith("Program+")).ToArray()
let FirstAppTypeUser = (typeUsers.Length == 0 ? ApplicationAndTestCode.Types : typeUsers ) // Make sure at least one type else we get an exception!
.Aggregate((minElement, nextElement) =>
string.Compare(nextElement.Name, minElement.Name, StringComparison.Ordinal) < 0 && !hashset.Contains(nextElement)
? nextElement
: minElement)
let fillHashset = hashset.Add(FirstAppTypeUser)
select new {
FirstAppTypeUser,
DirectAsm = x.First().directAsm,
DirectAsmVersion = x.First().directAsm.Version,
PackageName = x.Key,
PackageVersion = x.First().indirectAsm.Version,
ThirdPartyAssembliesImpacted,
AppAssembliesUser,
PatchAllAdvisoriesVersion = x.First().advisories.Max(ad => ad.PatchedVersion),
HighestSeverity,
AdvisoryWithHighestSeverity = AdvisoryWithHighestSeverity.Url,
AdvisorySummary = AdvisoryWithHighestSeverity.Summary,
NbAdvisory = x.First().advisories.Count,
AdvisoriesUrl = x.First().advisories.Select(ad=> ad.Url).Except(AdvisoryWithHighestSeverity.Url).Aggregate(" ; "),
Debt = 20.ToMinutes().ToDebt()
}
//<Expl>
// The application uses the **{1} version {2}** that uses the NuGet Package **{3} version {4}** which is affected by {11} Github security advisor{11?y:ies}.
//
// **Recommended Action:** Update the package of the *{1}* to a version that uses at least *{3}* version *{7}* or higher that has no known security advisory.
//
// Advisory with highest severity *{8}* is {9} : **{10}**. {11?:Other advisory url: }{12}
//
// The *{0}* is the first type (alphabetically) in the application that uses the *{1}*.
//</Expl>
//<Desc>
// Raises an issue per NuGet package with known GitHub security advisories
// (https://github.com/advisories?query=+ecosystem%3Anuget) used by a package
// used by the application — hence **transitive**, unlike the rule *Software
// Composition Analysis (SCA)*. The issue is reported on the first type
// (alphabetically) using a third-party assembly using the affected package.
//
// **Flagged Code**
// ```xml
// <!-- Acme.Sdk 2.1.0 depends on Newtonsoft.Json 12.0.1 (advisory GHSA-5crp-9r3c-p9vr) -->
// <!-- Newtonsoft.Json is not referenced directly: the advisory is transitive -->
// <ItemGroup>
// <PackageReference Include="Acme.Sdk" Version="2.1.0" />
// </ItemGroup>
// ```
//
// **Fixed Code**
// ```xml
// <!-- Acme.Sdk 2.2.0 depends on Newtonsoft.Json 13.0.1, which has no known advisory -->
// <ItemGroup>
// <PackageReference Include="Acme.Sdk" Version="2.2.0" />
// </ItemGroup>
// <!-- Alternative when no such Acme.Sdk version exists: pin the transitive package -->
// <ItemGroup>
// <PackageReference Include="Acme.Sdk" Version="2.1.0" />
// <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
// </ItemGroup>
// ```
//</Desc>
//<HowToFix>
// Update the package containing *DirectAsm* to a version not using a
// package with known security advisories.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Security: all 39 items
- Software Composition Analysis (SCA) ND3120
- Transitive Software Composition Analysis (SCA) ND3121
- Don't hard-code secrets in constants ND3114
- Review credentials built from hard-coded values ND3115
- Don't use insecure deserializers ND3110
- Don't use weak hash algorithms (MD5, SHA1) ND3109
- Don't use DES/3DES/RC2 weak cipher algorithms ND3102
- Don't use weak password-based key derivation ND3123
- Don't use the ECB encryption mode ND3132
- Don't disable certificate validation ND3103
- Don't hard-code TLS/SSL protocol versions ND3122
- Review commands vulnerable to SQL injection ND3107
- Review data adapters vulnerable to SQL injection ND3108
- Review raw SQL built from composed strings ND3128
- Review LDAP filters composed from strings ND3137
- Don't enable external XML entity resolution (XXE) ND3111
- Review processes started with a composed arguments string ND3124
- Review web endpoints building file paths from their parameters ND3129
- Review custom archive extraction (Zip Slip) ND3135
- Review assemblies and types loaded from runtime-provided names ND3125
- Review web endpoints without [Authorize] nor [AllowAnonymous] ND3118
- Review state-changing endpoints opened to anonymous callers ND3130
- Review state-changing MVC actions without anti-forgery validation ND3119
- Review HTML-encoding bypasses ND3133
- Review explicitly disabled request validation ND3134
- Review redirects to a URL that is not validated as local ND3126
- Review request-influenced outbound HTTP calls (SSRF) ND3136
- Review insecure ASP.NET Core CORS policies and unguarded developer exception page ND3116
- Review cookies created without HttpOnly and Secure flags ND3117
- Review regular expressions without a match timeout (ReDoS) ND3112
- Review secrets compared with non-constant-time equality ND3113
- Review secrets passed to logging methods ND3127
- Review security operations that log nothing ND3131
- Don't use System.Random for security purposes ND3101
- Don't use CoSetProxyBlanket and CoInitializeSecurity ND3100
- Review publicly visible event handlers ND3104
- Pointers should not be publicly visible ND3105
- Seal methods that satisfy non-public interfaces ND3106
- Restrict sensitive APIs to reviewed components ND3138