C# Coding Violations
Cyclopt analyzes your C# code to identify coding and security violations. Each check below lists its Rule ID, a description, guidance on what to do, a default severity, and its scope.
Every check has a Rule ID (shown in code font). Use it to silence an individual finding directly in your source with a cyclopt-ignore comment, or to exclude it project-wide in the configuration file.
Scope tells you how a rule is evaluated:
- File: the check runs on each file on its own.
- Solution-wide: the check needs the whole codebase (for example, to decide a member is never used anywhere).
File-level checks
Access To Modified Closure
Rule ID: access-to-modified-closure
Description: Detects variables captured by lambdas that are modified after lambda creation
A variable is captured by a lambda and later modified. The lambda will see the modified value.
var actions = new List<Action>();
for (int i = 0; i < 3; i++)
actions.Add(() => Console.WriteLine(i));
var actions = new List<Action>();
for (int i = 0; i < 3; i++)
{
int copy = i;
actions.Add(() => Console.WriteLine(copy));
}
Access To Static Member Via Derived Type
Rule ID: access-to-static-member-via-derived-type
Description: Detects accessing static members via derived type instead of declaring type
A static member is accessed via a derived type, but is declared in a base type. Access it via the declaring type instead.
class Base { public static int Count; }
class Derived : Base { }
Derived.Count = 1;
class Base { public static int Count; }
class Derived : Base { }
Base.Count = 1;
Arrange Accessor Owner Body
Rule ID: arrange-accessor-owner-body
Description: Detects inconsistent body styles in accessor owners where both accessors are simple
Inconsistent accessor body styles in an accessor owner. Consider using a consistent style for all accessors.
Arrange Modifiers Order
Rule ID: arrange-modifiers-order
Description: Detects incorrect ordering of access and other modifiers in member declarations
Modifiers on a member are not in the correct order. Consider arranging modifiers in the conventional order for better readability.
static public void Run() { }
public static void Run() { }
Arrange Object Creation When Type Evident
Rule ID: arrange-object-creation-when-type-evident
Description: Detects object creation expressions where type is evident and can use target-typed new
Object creation type is evident from context. Consider using target-typed 'new()' for simplification.
List<int> numbers = new List<int>();
List<int> numbers = new();
Arrange Var Keywords In Deconstructing Declaration
Rule ID: arrange-var-keywords-in-deconstructing-declaration
Description: Enforces consistent 'var' usage in deconstructing declarations
Inconsistent variable declaration in deconstruction: found a mix of 'var' and explicit types. Use all 'var' or all explicit types for consistency.
(var name, int age) = person;
var (name, age) = person;
Assign Null To Not Null Attribute
Rule ID: assign-to-not-null-attribute
Description: Detects null or nullable assignments to [NotNull] properties and fields
Assignment to a [NotNull] member with a value that may be null. Consider ensuring the assigned value is not null to avoid potential issues.
[NotNull] public string Name { get; set; } = null;
[NotNull] public string Name { get; set; } = string.Empty;
Assign To The Same Variable
Rule ID: csharp-warnings-cs1717
Description: Detects assignments where a variable is assigned to itself
A variable is initialized with itself. This is likely a bug.
private int count;
public void Set(int count) => count = count;
private int count;
public void Set(int count) => this.count = count;
Assignment In Conditional Expression
Rule ID: assignment-in-conditional-expression
Description: Detects bare assignments in conditional expressions where comparison was likely intended
An assignment is used as a conditional expression. Consider using '==' for comparison.
if (result = true)
Handle();
if (result == true)
Handle();
Assignment Is Fully Discarded
Rule ID: assignment-is-fully-discarded
Description: Detects assignments whose value is never read
A variable is assigned but its value is never read. Consider removing the assignment or using the variable.
int x = GetValue();
x = 42;
Console.WriteLine(x);
int x = 42;
Console.WriteLine(x);
Async Void Lambda
Rule ID: async-void-lambda
Description: Detects async lambda expressions that effectively return void
Async lambda passed to a void-returning method is effectively async void. Exceptions cannot be caught. Consider using a Task-returning alternative.
Async Void Method
Rule ID: async-void-method
Description: Detects async methods that return void instead of Task
Async returns void. Consider returning Task instead.
async void ProcessAsync()
{
await Task.Delay(100);
}
async Task ProcessAsync()
{
await Task.Delay(100);
}
Async Without Await
Rule ID: CSharpWarnings::CS4014
Description: Detects async methods called without await
An async method is called without await. Consider awaiting the call or explicitly discarding the result to avoid lost exceptions.
async Task RunAsync()
{
DoWorkAsync();
await Task.Delay(10);
}
async Task RunAsync()
{
await DoWorkAsync();
await Task.Delay(10);
}
Async Without Await Function
Rule ID: CSharpWarnings::CS1998
Description: Detects async methods that contain no await expressions (CS1998)
An async method contains no await expressions. Consider removing the 'async' modifier or adding 'await' to asynchronous operations within the method.
async Task<int> GetValueAsync()
{
return 42;
}
Task<int> GetValueAsync()
{
return Task.FromResult(42);
}
Attribute Modifier Invalid Location
Rule ID: attribute-modifier-invalid-location
Description: Detects attributes with invalid target specifiers for their location
An attribute is applied with an invalid target specifier for its location. Consider using a valid target or removing the target specifier.
Auto Property Can Be Made Get Only
Rule ID: auto-property-can-be-made-get-only-local
Description: Detects auto-properties with setters only used in constructors
An auto-property has a setter that is only used in the constructor. Consider making it get-only or using an init accessor.
public class Order
{
public int Id { get; set; }
public Order(int id) => Id = id;
}
public class Order
{
public int Id { get; }
public Order(int id) => Id = id;
}
Bad Child Statement Indent
Rule ID: bad-child-statement-indent
Description: Detects child statements with incorrect indentation relative to parent control structures
Child statement of 'else' should be indented. Consider indenting the child statement by spaces/tab.
Bad Control Braces Indent
Rule ID: bad-control-braces-indent
Description: Detects incorrect indentation of control structure braces
The closing brace of a control structure should be indented at the same level as the control statement. Consider adjusting the indentation of the closing brace to match the control statement's indentation.
Bitwise Operator On Enum Without Flags
Rule ID: bitwise-operator-on-enum-without-flags
Description: Detects bitwise operators on enums without [Flags] attribute
A bitwise operator is used on an enum that does not have the [Flags] attribute. Consider adding [Flags] to the enum declaration if you intend to use it as a bit field, or avoid using bitwise operators with this enum if not.
enum Permission { Read = 1, Write = 2 }
var p = Permission.Read | Permission.Write;
[Flags] enum Permission { Read = 1, Write = 2 }
var p = Permission.Read | Permission.Write;
Cast To Non Nullable
Rule ID: CS8600
Description: Detects conversion of null literal to non-nullable reference type
Converting a null value to a non-nullable reference type can lead to runtime exceptions. Consider using a nullable type or ensuring the value is not null.
object? maybe = null;
string text = (string)maybe;
object? maybe = null;
string? text = (string?)maybe;
Check Namespace
Rule ID: check-namespace
Description: Checks namespace declaration matches folder structure and conventions
The namespace does not match the expected structure based on the folder hierarchy.
Collection Never Queried
Rule ID: collection-never-queried-local
Description: Detects local collection variables that are populated but never read
A local collection variable is populated but never read or queried. Consider removing it if it's not needed, or using its contents if it is needed.
var errors = new List<string>();
errors.Add("failed");
var errors = new List<string>();
errors.Add("failed");
Console.WriteLine(errors.Count);
Collection Never Updated
Rule ID: collection-never-updated-local
Description: Detects local collection variables that are read but never populated
A local collection variable is read but never populated or modified. Consider populating it before reading, or removing it if it's not needed.
var items = new List<int>();
return items.Count;
var items = new List<int> { 1, 2, 3 };
return items.Count;
Condition Is Always True Or False According To Nullable API Contract
Rule ID: ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
Description: Detects null-check conditions that are constant due to obviously non-null operands
A null-check condition is always true or false according to nullable API contract.
Conditional Access Qualifier Is Non Nullable According To API Contract
Rule ID: ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
Description: Detects conditional access whose receiver is obviously non-null
A conditional access qualifier is non-nullable according to API contract.
Conditional Ternary Equal Branch
Rule ID: conditional-ternary-equal-branch
Description: Detects ternary expressions where both branches have the same value
A conditional expression has identical branches, making the condition pointless. Consider simplifying to a single value.
var x = flag ? 1 : 1;
var x = flag ? 1 : 2;
Convert Auto Property When Possible
Rule ID: convert-auto-property-when-possible
Description: Detects properties with backing fields that can be converted to auto-properties
A property with a backing field can be converted to an auto-property if the field is only used for that property.
private int _age;
public int Age { get => _age; set => _age = value; }
public int Age { get; set; }
Convert If Statement To Null Coalescing Assignment
Rule ID: convert-if-to-null-coalescing-assignment
Description: Detects if statements that can be converted to null-coalescing assignment (??=)
An if statement can be simplified to use the null-coalescing assignment operator (??=) for cleaner code.
if (name == null)
name = "default";
name ??= "default";
Convert If Statement To Null Coalescing Expression
Rule ID: convert-if-statement-to-null-coalescing-expression
Description: Detects if statements and ternary expressions convertible to null-coalescing (??) expressions
A conditional expression can be simplified to use the null-coalescing operator (??) for cleaner code.
string result;
if (input != null)
result = input;
else
result = "n/a";
string result = input ?? "n/a";
Convert Nullable To Short Form
Rule ID: convert-nullable-to-short-form
Description: Suggests using T? instead of Nullable<T>
The type 'Nullable<T>' can be simplified to 'T?' for cleaner and more concise code.
Nullable<int> count = null;
int? count = null;
Convert Ternary Expression To Switch Expression
Rule ID: convert-conditional-ternary-expression-to-switch-expression
Description: Detects nested ternary chains that can be converted to switch expressions
A nested ternary expression can be converted to a switch expression for better readability and maintainability.
var label = n == 1 ? "one" : n == 2 ? "two" : "many";
var label = n switch { 1 => "one", 2 => "two", _ => "many" };
Convert To Using Declaration
Rule ID: convert-to-using-declaration
Description: Detects 'using' statements that can be converted to using declarations
A 'using' statement can be converted to a using declaration for cleaner code.
using (var stream = File.OpenRead(path))
{
Process(stream);
}
using var stream = File.OpenRead(path);
Process(stream);
Covariant Array Conversion
Rule ID: covariant-array-conversion
Description: Detects unsafe covariant array conversions
An array of a more specific reference type is assigned to an 'object[]' variable, which can lead to runtime exceptions if misused.
object[] items = new string[] { "a", "b" };
items[0] = 42;
string[] items = new string[] { "a", "b" };
items[0] = "c";
Cyclomatic Complexity
Rule ID: cyclomatic-complexity
Description: Reports methods exceeding cyclomatic complexity threshold
A method has high cyclomatic complexity, which can make it difficult to maintain and test.
Default Value Evident Type
Rule ID: default-value-evident-type
Description: Detects default(T) that can be simplified to default when type is evident
A 'default(T)' expression can be simplified to 'default' when the type is evident from the context for cleaner code.
int count = default(int);
int count = default;
Empty Constructor
Rule ID: empty-constructor
Description: Detects empty constructors that are provably redundant
An empty constructor that is the only constructor in a class and has no attributes, documentation, or significant initializer is redundant and can be removed for cleaner code.
public class User
{
public User() { }
}
public class User
{
}
Empty General Catch Clause
Rule ID: empty-general-catch-clause
Description: Detects empty catch clauses that catch all exceptions without handling
An empty general catch clause silently swallows all exceptions. Add exception handling, logging, or 'throw;' to rethrow.
try
{
DoWork();
}
catch { }
try
{
DoWork();
}
catch (Exception ex)
{
_logger.LogError(ex, "DoWork failed");
}
Empty Namespace
Rule ID: empty-namespace
Description: Detects empty namespace declarations
A namespace declaration is empty — it contains no type declarations.
namespace MyApp.Utilities
{
}
namespace MyApp.Utilities
{
public class Helper { }
}
Empty Statement
Rule ID: empty-statement
Description: Detects empty statements and empty control structure bodies
An empty statement is present and has no effect.
int total = ComputeTotal();;
int total = ComputeTotal();
Enum Underlying Type Is Int
Rule ID: enum-underlying-type-is-int
Description: Detects enums that explicitly specify int as the underlying type, which is redundant
Enum explicitly specifies 'int' as the underlying type, which is redundant since 'int' is the default. Consider removing the explicit base type declaration.
enum Status : int { Active, Inactive }
enum Status { Active, Inactive }
Equal Expression Comparison
Rule ID: equal-expression-comparison
Description: Detects comparisons where both sides are the same expression
A variable is compared to itself. This comparison is always true and likely indicates a bug where the same variable was used on both sides of the comparison by mistake.
if (count == count)
{
Reset();
}
if (count == expected)
{
Reset();
}
Expression Not Of Provided Type
Rule ID: CSharpWarnings::CS0184
Description: Detects 'is' expressions where the type check always returns false
A type check will always be false. This indicates a potential issue with the type hierarchy.
string name = "abc";
bool result = name is int;
object name = "abc";
bool result = name is int;
Field Can Be Made Read Only
Rule ID: field-can-be-made-readonly
Description: Detects private fields that can be marked as readonly
A private field is only assigned at declaration or in a constructor. Consider marking it as readonly for better immutability and thread-safety.
class Service
{
private ILogger _logger;
public Service(ILogger logger) => _logger = logger;
}
class Service
{
private readonly ILogger _logger;
public Service(ILogger logger) => _logger = logger;
}
For Can Be Converted To Foreach
Rule ID: for-can-be-converted-to-foreach
Description: Detects 'for' loops that can be converted to 'foreach'
A 'for' loop is iterating over a collection with an index variable that is only used for accessing elements of the collection. Consider converting it to a 'foreach' loop for better readability and less error-prone code.
for (int i = 0; i < items.Count; i++)
Console.WriteLine(items[i]);
foreach (var item in items)
Console.WriteLine(item);
Format String Problem
Rule ID: format-string-problem
Description: Detects format string issues like mismatched placeholders
Format string expects more arguments than provided. This will cause a runtime error when the format string is used.
string message = string.Format("{0} {1}", name);
string message = string.Format("{0} {1}", name, age);
Function Never Returns
Rule ID: function-never-returns
Description: Detects methods that never return normally
Function never returns normally. Consider adding [DoesNotReturn] attribute if intentional.
int GetValue()
{
while (true) { Process(); }
}
int GetValue()
{
while (_running) { Process(); }
return 0;
}
Function Recursive On All Paths
Rule ID: function-recursive-on-all-paths
Description: Detects methods that are recursive on all execution paths
A function is recursive on all execution paths and will cause a StackOverflowException.
int Factorial(int n) => n * Factorial(n - 1);
int Factorial(int n) => n <= 1 ? 1 : n * Factorial(n - 1);
Generic Enumerator Not Disposed
Rule ID: generic-enumerator-not-disposed
Description: Detects IEnumerator<T> not being disposed
An IEnumerator<T> variable is not being disposed. This can lead to resource leaks. Consider using a 'using' declaration or ensuring Dispose() is called in a finally block.
IEnumerator<int> e = items.GetEnumerator();
while (e.MoveNext())
Process(e.Current);
using IEnumerator<int> e = items.GetEnumerator();
while (e.MoveNext())
Process(e.Current);
Inheritdoc Invalid Usage
Rule ID: optional-parameter-hierarchy-mismatch
Description: Detects optional parameters with different default values in derived and base methods
An optional parameter has a different default value in the derived method compared to its base method. This can lead to unexpected behavior.
class Base { public virtual void Log(string msg, int level = 0) { } }
class Derived : Base { public override void Log(string msg, int level = 1) { } }
class Base { public virtual void Log(string msg, int level = 0) { } }
class Derived : Base { public override void Log(string msg, int level = 0) { } }
Inline Out Variable Declaration
Rule ID: inline-out-variable-declaration
Description: Detects out variable declarations that can be inlined
A variable is declared without initializer and then used as an 'out' parameter. Consider inlining the declaration using 'out' syntax for better readability.
int value;
if (int.TryParse(text, out value))
Use(value);
if (int.TryParse(text, out int value))
Use(value);
Introduce Optional Parameters
Rule ID: introduce-optional-parameters
Description: Suggests using optional parameters instead of method overloads
Method overloads with similar signatures can often be combined by using optional parameters, which can improve code readability and reduce maintenance overhead.
public void Connect(string host) => Connect(host, 8080);
public void Connect(string host, int port) { }
public void Connect(string host, int port = 8080) { }
Invoke As Extension Method
Rule ID: invoke-as-extension-method
Description: Detects static method calls that could use extension method syntax
A static method call on a known extension class can be rewritten using extension method syntax for improved readability.
var positives = Enumerable.Where(numbers, n => n > 0);
var positives = numbers.Where(n => n > 0);
Iterator Method Result Is Ignored
Rule ID: iterator-method-result-is-ignored
Description: Detects when iterator method results are not used
The result of an iterator method is not used. Iterator methods use deferred execution and have no effect unless enumerated.
IEnumerable<int> ReadLines() { yield return 1; }
void Run() => ReadLines();
IEnumerable<int> ReadLines() { yield return 1; }
void Run()
{
foreach (var line in ReadLines())
Process(line);
}
Join Declaration And Initializer
Rule ID: join-declaration-and-initializer
Description: Suggests joining variable declaration and immediate assignment into a single statement
A variable is declared without an initializer and then immediately assigned a value. Consider joining the declaration and initialization into a single statement for better readability.
int total;
total = ComputeTotal();
int total = ComputeTotal();
LINQ Expression Use Any
Rule ID: linq-expression-use-any
Description: Detects Count() comparisons that should use Any() for better performance
A Count() comparison can be simplified to an Any() call for better performance.
if (users.Count() > 0)
Notify();
if (users.Any())
Notify();
Local Variable Hides Member
Rule ID: local-variable-hides-member
Description: Detects local variables or parameters that hide class members
A variable has the same name as a member of the containing type, which can lead to confusion and bugs. Consider renaming the variable or member to avoid hiding.
class Order
{
private int count;
public void Add()
{
int count = 5;
Save(count);
}
}
class Order
{
private int count;
public void Add()
{
int itemCount = 5;
Save(itemCount);
}
}
Loop Variable Never Changes
Rule ID: loop-variable-never-changes
Description: Detects loop condition variables that never change in the loop body
A loop condition variable is never modified within the loop body, which may result in an infinite loop.
int i = 0;
while (i < 10)
Process();
int i = 0;
while (i < 10)
Process(i++);
Member Hides From Outer Class
Rule ID: member-hides-static-from-outer-class
Description: Detects when a member in a nested class hides a static member from the outer class
A member in a nested class has the same name as a static member in the outer class, which can lead to confusion. Consider renaming the member or adding the 'new' modifier if hiding is intentional.
class Outer
{
static int Count;
class Inner { int Count; }
}
class Outer
{
static int Count;
class Inner { int InnerCount; }
}
Member Initializer Value Ignored
Rule ID: member-initializer-value-ignored
Description: Detects member initializers that are immediately overwritten in all constructors
A member initializer is immediately overwritten in all constructors. Consider removing the initializer or the constructor assignment.
class Config
{
private int _timeout = 30;
public Config() { _timeout = 60; }
}
class Config
{
private int _timeout;
public Config() { _timeout = 60; }
}
Merge And Pattern
Rule ID: merge-and-pattern
Description: Detects pattern-matching conditions that can be merged with 'and' pattern
Multiple pattern checks on the same subject can be merged into a single 'and' pattern.
if (x is > 0 && x is < 100)
Accept();
if (x is > 0 and < 100)
Accept();
Merge Cast With Type Check
Rule ID: merge-cast-with-type-check
Description: Detects type checks followed by casts that can use pattern matching
A type check followed by a cast can be replaced with a pattern match.
if (obj is string)
{
var s = (string)obj;
Use(s);
}
if (obj is string s)
{
Use(s);
}
Merge Conditional Expression When Possible
Rule ID: merge-conditional-expression-when-possible
Description: Detects conditional expressions that can be simplified
A conditional expression with boolean literals can be simplified.
bool result = value > 0 ? true : false;
bool result = value > 0;
Merge Into Pattern
Rule ID: merge-into-pattern
Description: Merge null/pattern checks into complex pattern
Multiple checks on the same variable can often be merged into a single pattern match for improved readability.
if (node != null && node.Value == 5)
Handle(node);
if (node is { Value: 5 })
Handle(node);
Method Has Async Overload
Rule ID: method-has-async-overload
Description: Detects synchronous calls with known async overloads in async context
A synchronous method call has an async overload available. Consider using the async version in an async context.
async Task Save(Stream s, byte[] buffer)
{
s.Write(buffer, 0, buffer.Length);
}
async Task Save(Stream s, byte[] buffer)
{
await s.WriteAsync(buffer, 0, buffer.Length);
}
More Specific Foreach Variable Type Available
Rule ID: more-specific-foreach-variable-type-available
Description: Detects foreach loops where a more specific variable type could be used
A more specific type may be available for the foreach variable. Consider using it for improved readability and type safety.
var names = new List<string> { "a", "b" };
foreach (object name in names)
Console.WriteLine(name);
var names = new List<string> { "a", "b" };
foreach (string name in names)
Console.WriteLine(name);
Negative Equality Expression
Rule ID: negative-equality-expression
Description: Detects negated equality expressions that can be simplified
A negated equality expression can be simplified by inverting the operator for improved readability.
if (!(count == 0))
Process();
if (count != 0)
Process();
Nested String Interpolation
Rule ID: nested-string-interpolation
Description: Detects nested string interpolations
Nested string interpolation can reduce readability. Consider extracting inner interpolations to variables.
var label = $"User: {$"{firstName} {lastName}"}";
var fullName = $"{firstName} {lastName}";
var label = $"User: {fullName}";
New Protected Member Sealed Class
Rule ID: CSharpWarnings::CS0628
Description: New protected member declared in sealed class
A protected member in a sealed class is inaccessible. Consider using 'private' instead.
sealed class Account
{
protected int balance;
}
sealed class Account
{
private int balance;
}
Non Readonly Member In Get Hash Code
Rule ID: non-readonly-member-in-get-hash-code
Description: Detects usage of mutable members in GetHashCode()
A mutable field is used in GetHashCode(). If modified, hash-based collections may malfunction.
class Point
{
private int _x;
public override int GetHashCode() => _x.GetHashCode();
}
class Point
{
private readonly int _x;
public override int GetHashCode() => _x.GetHashCode();
}
Not Accessed Variable
Rule ID: not-accessed-variable.compiler
Description: Detects local variables that are assigned but never read
Variable is assigned but never read.
public void Run()
{
int result = Compute();
Console.WriteLine("done");
}
public void Run()
{
int result = Compute();
Console.WriteLine(result);
}
Null Coalescing Condition Is Always Not Null According To API Contract
Rule ID: NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
Description: Detects null-coalescing expressions where left side is obviously non-null
A null-coalescing expression has a left operand that is always non-null.
Object Creation Statement
Rule ID: object-creation-as-statement
Description: Detects object creation expressions where the result is discarded
An object is created but the result is discarded. This is likely a bug. Consider assigning it to a variable, returning it, or passing it as an argument.
public void Save()
{
new StringBuilder();
}
public void Save()
{
var builder = new StringBuilder();
Write(builder);
}
Operator Used
Rule ID: operator-used
Description: Detects potentially problematic operator usage
A bitwise operator is used in a boolean context. Consider using the logical operator for correct behavior.
if (isActive & isReady)
Start();
if (isActive && isReady)
Start();
Parameter Only Used For Pre Conditional Check
Rule ID: parameter-only-used-for-precondition-check-local
Description: Detects parameters only used in precondition checks
A parameter is only used for precondition checks and not in the actual logic of the method.
Partial Method With Single Part
Rule ID: partial-method-with-single-part
Description: Detects partial methods with only declaration or implementation
A partial method is declared with only a declaration or implementation, which may indicate incomplete code.
Pattern Never Matches
Rule ID: pattern-never-matches
Description: Detects patterns that can never match
A pattern is contradictory and can never match.
if (value is > 100 and < 10)
Handle();
if (value is > 100 or < 10)
Handle();
Possible Intended Rethrow
Rule ID: possible-intended-rethrow
Description: Detects throwing caught exception variable instead of using bare 'throw'
Throwing the caught exception variable can lose the original stack trace. Consider using a bare 'throw;' to preserve it.
try { Process(); }
catch (Exception ex)
{
Log(ex);
throw ex;
}
try { Process(); }
catch (Exception ex)
{
Log(ex);
throw;
}
Possible Invalid Operation Exception
Rule ID: possible-invalid-operation-exception
Description: Detects LINQ calls that may throw InvalidOperationException on empty sequences
A LINQ method that throws on empty sequences is used without a guard. Consider using an OrDefault variant or checking if the sequence has elements before calling it.
var first = numbers.Where(n => n > 0).First();
var first = numbers.Where(n => n > 0).FirstOrDefault();
Possible Loss Of Fraction
Rule ID: possible-loss-of-fraction
Description: Detects integer literal division assigned to floating-point type
Integer division assigned to a floating-point type will lose the fractional part. Consider casting one operand to the floating-point type.
double ratio = 1 / 2;
double ratio = 1.0 / 2;
Possible Multiple Enumeration
Rule ID: possible-multiple-enumeration
Description: Detects possible multiple enumeration of IEnumerable
An IEnumerable is enumerated multiple times, which can lead to performance issues or unexpected behavior. Consider materializing it with .ToList() if you need to enumerate it multiple times.
void Print(IEnumerable<int> items)
{
if (items.Any())
Console.WriteLine(items.Count());
}
void Print(IEnumerable<int> items)
{
var list = items.ToList();
if (list.Any())
Console.WriteLine(list.Count);
}
Possible Struct Member Modification Of Non Variable Struct
Rule ID: possible-struct-member-modification-of-non-variable
Description: Detects modifications to members of struct values returned by known properties
Modifying a member of a struct returned by a property has no effect because structs are copied by value. Store the struct in a local variable first.
Possible Unintended Reference Comparison
Rule ID: possible-unintended-reference-comparison
Description: Detects comparing new objects with == or !=
Comparing two new objects with '==' or '!=' compares references and will always return false for '==' and true for '!=' unless the operator is overloaded.
if (new object() == new object())
Handle();
if (ReferenceEquals(new object(), new object()))
Handle();
Possibly Mistaken Use Of Interpolated String Insert
Rule ID: possibly-mistaken-use-of-interpolated-string-insert
Description: Detects interpolated strings that look like string.Format patterns
Interpolated string contains sequential numeric placeholders which looks like a string.Format pattern. Consider removing the '$' prefix to use String.Format, or replace placeholders with actual expressions.
var message = $"{0} scored {1} points";
var message = string.Format("{0} scored {1} points", name, score);
Prefer While Expression
Rule ID: prefer-while-expression
Description: Detects for loops that could be while loops
A 'for' loop without an initializer and incrementor can be simplified to a 'while' loop for cleaner code.
for (; !queue.IsEmpty;)
queue.Dequeue();
while (!queue.IsEmpty)
queue.Dequeue();
Private Field Can Be Converted To Local Variable
Rule ID: private-field-can-be-converted-to-local-variable
Description: Detects private fields only used in a single method that can be local variables
A private field is only used in a single method and can be converted to a local variable.
class Calculator
{
private int _temp;
public int Square(int n)
{
_temp = n * n;
return _temp;
}
}
class Calculator
{
public int Square(int n)
{
var temp = n * n;
return temp;
}
}
Property Can Be Made Init Only
Rule ID: property-can-be-made-init-only
Description: Suggests using init accessor for properties only assigned in constructor
A property that is only assigned in constructors can be made init-only. Consider using 'init' accessor.
class User
{
public string Name { get; set; }
public User(string name) => Name = name;
}
class User
{
public string Name { get; init; }
public User(string name) => Name = name;
}
Property Not Resolved
Rule ID: property-not-resolved
Description: Detects likely property name typos
A property name appears to be a typo. Consider correcting it to a valid property name.
Public Constructor In Abstract Class
Rule ID: public-constructor-in-abstract-class
Description: Detects public constructors in abstract classes
A public constructor in an abstract class should be protected since abstract classes cannot be instantiated directly.
abstract class Shape
{
public Shape() { }
}
abstract class Shape
{
protected Shape() { }
}
Redundant Always Match Subpattern
Rule ID: redundant-always-match-subpattern
Description: Detects var _ patterns that can be simplified to _
The 'var ' pattern is redundant and can be simplified to ''.
var result = point switch
{
(0, var _) => "on axis",
_ => "off"
};
var result = point switch
{
(0, _) => "on axis",
_ => "off"
};
Redundant Anonymous Property Name
Rule ID: redundant-anonymous-property-name
Description: Detects redundant property names in anonymous objects
A property name is redundant and can be simplified.
var dto = new { Name = name, Age = age };
var dto = new { name, age };
Redundant Attribute Usage Property
Rule ID: redundant-attribute-usage-property
Description: Detects redundant properties in [AttributeUsage] attributes
A property in [AttributeUsage] has a redundant value that matches the default.
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
class MyAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Class)]
class MyAttribute : Attribute { }
Redundant Base Constructor Call
Rule ID: redundant-base-constructor-call
Description: Detects redundant parameterless base constructor calls
A constructor has a redundant parameterless base() call that can be removed.
class Manager : Employee
{
public Manager() : base() { }
}
class Manager : Employee
{
public Manager() { }
}
Redundant Bool Compare
Rule ID: redundant-bool-compare
Description: Detects redundant boolean comparisons that can be simplified
A boolean comparison is redundant and can be simplified.
if (isEnabled == true)
Run();
if (isEnabled)
Run();
Redundant Case Label
Rule ID: redundant-case-label
Description: Detects duplicate case labels in switch statements
Duplicate case labels in a switch statement are redundant and can be removed.
Redundant Cast
Rule ID: redundant-cast
Description: Detects unnecessary cast expressions where the source type matches the target type
A cast expression is redundant because the source type matches the target type.
string name = (string)"Alice";
string name = "Alice";
Redundant Catch Clause
Rule ID: redundant-catch-clause
Description: Detects catch clauses that only rethrow without additional logic
A catch clause contains only a bare rethrow and can be removed without changing behavior.
try
{
Process();
}
catch (Exception)
{
throw;
}
Process();
Redundant Default Member Initializer
Rule ID: redundant-default-member-initializer
Description: Detects redundant default value initializers
A property is initialized to its default value and can be removed.
class Config
{
public int Retries { get; set; } = 0;
}
class Config
{
public int Retries { get; set; }
}
Redundant Delegate Creation
Rule ID: redundant-delegate-creation
Description: Detects redundant delegate constructor calls wrapping method groups
A delegate constructor call wrapping a method group is redundant and can be simplified to a direct method group assignment.
button.Click += new EventHandler(OnClick);
button.Click += OnClick;
Redundant Discard
Rule ID: redundant-discard
Description: Detects redundant use of discard pattern
A discard pattern is redundant and can be removed.
(var x, _) = GetPair();
var _ = ComputeValue();
(var x, _) = GetPair();
ComputeValue();
Redundant Empty Finally Block
Rule ID: redundant-empty-finally-block
Description: Detects empty finally blocks that serve no purpose
An empty finally block does not affect program behavior and can be removed.
try
{
DoWork();
}
finally
{
}
DoWork();
Redundant Empty Object Or Collection Initializer
Rule ID: redundant-empty-object-or-collection-initializer
Description: Detects empty object or collection initializers that are redundant and can be removed
An empty initializer for an object or collection is redundant and can be removed for cleaner code.
var list = new List<int>() { };
var list = new List<int>();
Redundant Enumerable Cast Call
Rule ID: redundant-enumerable-cast-call
Description: Detects redundant Cast<T> or OfType<T> calls
A Cast<T> or OfType<T> call may be redundant if the source collection is already of the target type.
IEnumerable<string> names = source.Cast<string>();
// where source is already IEnumerable<string>
IEnumerable<string> names = source;
Redundant Explicit Array Creation
Rule ID: redundant-explicit-array-creation
Description: Detects redundant explicit array type in creation with initializer
An explicit array type in an array creation expression with an initializer is redundant when the variable declaration already specifies the array type. Consider using 'new[]' for cleaner code.
int[] numbers = new int[] { 1, 2, 3 };
int[] numbers = { 1, 2, 3 };
Redundant Explicit Params Array Creation
Rule ID: redundant-explicit-params-array-creation
Description: Detects redundant explicit array creation for params parameters of known methods
An explicit array creation for a params parameter of a known method is redundant. Pass the elements directly without 'new'.
Console.WriteLine("{0} {1}", new object[] { first, last });
Console.WriteLine("{0} {1}", first, last);
Redundant Explicit Tuple Name
Rule ID: redundant-explicit-tuple-name
Description: Detects tuple element names matching default Item1..Item7
A tuple element name matches the default 'ItemN' pattern and can be removed for cleaner code.
var pair = (Item1: 1, Item2: 2);
var pair = (1, 2);
Redundant Lambda Parameter Type
Rule ID: redundant-lambda-parameter-type
Description: Detects lambda expressions with redundant explicit parameter types
The explicit parameter types in this lambda expression are redundant and can be removed for cleaner code.
Func<int, int> square = (int x) => x * x;
Func<int, int> square = x => x * x;
Redundant Overridden Member
Rule ID: redundant-overridden-member
Description: Detects override members that only delegate to the base implementation
An overridden property that only delegates to the base implementation without adding functionality can be removed for cleaner code.
public override string ToString()
{
return base.ToString();
}
// remove the override; base implementation is used automatically
Redundant Private Accessibility
Rule ID: redundant-private-accessibility
Description: Detects redundant 'private' modifier on class members
The 'private' access modifier is redundant on class members since they are private by default. Consider removing it for cleaner code.
class Account
{
private int balance;
}
class Account
{
int balance;
}
Redundant Record Body
Rule ID: redundant-record-body
Description: Detects records with empty bodies
A record declaration has an empty body. Consider using a semicolon instead of braces for cleaner code.
public record Point(int X, int Y) { }
public record Point(int X, int Y);
Redundant String Format Call
Rule ID: redundant-string-format-call
Description: Detects redundant String.Format calls that can be simplified
A String.Format call with a format string that contains no placeholders is redundant and can be replaced with the string literal directly.
var message = string.Format("Operation completed");
var message = "Operation completed";
Redundant String Interpolation
Rule ID: redundant-string-interpolation
Description: Detects redundant string interpolation expressions that can be simplified
This string interpolation can be simplified for cleaner code.
Redundant Suppress Nullable Warning Expression
Rule ID: redundant-suppress-nullable-warning
Description: Detects redundant null-forgiving operator on provably non-null expressions
A null-forgiving operator is redundant because the expression is provably non-null.
string name = "John";
int length = name!.Length;
string name = "John";
int length = name.Length;
Redundant Ternary Expression
Rule ID: redundant-ternary-expression
Description: Detects ternary expressions that can be simplified to boolean expressions
A ternary expression that returns true or false based on a condition can be simplified to just the condition or its negation for cleaner code.
bool isValid = count > 0 ? true : false;
bool isValid = count > 0;
Redundant To String Call
Rule ID: redundant-tostring-call
Description: Detects .ToString() on values already known to be strings
A .ToString() call on a value that is already a string is redundant and can be removed for cleaner code.
string name = "John";
string result = name.ToString();
string name = "John";
string result = name;
Redundant Unsafe Context
Rule ID: redundant-unsafe-context
Description: Detects unsafe blocks without unsafe operations
An unsafe block that contains no unsafe operations is redundant and can be removed for cleaner code.
unsafe
{
int total = a + b;
}
int total = a + b;
Redundant Verbatim Prefix
Rule ID: inheritdoc-invalid-usage
Description: Detects invalid usage of <inheritdoc/> XML documentation tags
Invalid usage of <inheritdoc/> tag. Ensure it is used correctly according to C# documentation rules.
Redundant Verbatim String Prefix
Rule ID: redundant-verbatim-string-prefix
Description: Detects verbatim string prefixes that are not necessary
A verbatim string prefix is redundant if the string content does not contain characters that require verbatim treatment, such as backslashes, double quotes, or newlines. Removing the unnecessary prefix can simplify the code.
string greeting = @"Hello World";
string greeting = "Hello World";
Replace With Single Assignment (false)
Rule ID: replace-with-single-assignment-false
Description: Detects boolean init patterns that can be simplified
A boolean variable is initialized to true and then set to false in an if statement based on a condition. This pattern can be simplified to a single assignment that negates the condition for cleaner code.
bool result = true;
if (count == 0)
{
result = false;
}
bool result = count != 0;
Replace With Single Assignment (true)
Rule ID: replace-with-single-assignment-true
Description: Detects boolean init patterns that can be simplified
A boolean variable is initialized to false and then set to true in an if statement based on a condition. This pattern can be simplified to a single assignment that uses the condition directly for cleaner code.
bool result = false;
if (count > 0)
{
result = true;
}
bool result = count > 0;
Replace With Single Call To Any
Rule ID: replace-with-single-call-to-any
Description: Detects .Where(...).Any() patterns that can be simplified to .Any(...)
A call to .Where(predicate).Any() can be simplified to .Any(predicate) for cleaner and more efficient code.
bool hasAdults = people.Where(p => p.Age >= 18).Any();
bool hasAdults = people.Any(p => p.Age >= 18);
Replace With Single Call To Count
Rule ID: replace-with-single-call-to-count
Description: Detects Where().Count() that can be simplified to Count(predicate)
A call to .Where(predicate).Count() can be simplified to .Count(predicate) for cleaner and more efficient code.
int adults = people.Where(p => p.Age >= 18).Count();
int adults = people.Count(p => p.Age >= 18);
Replace With Single Call To First
Rule ID: replace-with-single-call-to-first
Description: Detects .Where(...).First/FirstOrDefault() that can be simplified
A call can be simplified by absorbing the predicate from .Where() into the subsequent call, resulting in cleaner and more efficient code.
var first = people.Where(p => p.Age >= 18).First();
var first = people.First(p => p.Age >= 18);
Replace With Single Call To First Or Default
Rule ID: replace-with-single-call-to-first-or-default
Description: Detects .Where(...).FirstOrDefault() patterns that can be simplified
A call to .Where(predicate).FirstOrDefault() can be simplified to .FirstOrDefault(predicate) for cleaner and more efficient code.
var first = people.Where(p => p.Age >= 18).FirstOrDefault();
var first = people.FirstOrDefault(p => p.Age >= 18);
Replace With Single Call To Single
Rule ID: replace-with-single-call-to-single
Description: Detects .Where(...).Single() patterns that can be simplified
A call can be simplified by absorbing the predicate from .Where() into the subsequent call, resulting in cleaner and more efficient code.
var only = people.Where(p => p.Id == id).Single();
var only = people.Single(p => p.Id == id);
Replace With Single Call To Single Or Default
Rule ID: replace-with-single-call-to-single-or-default
Description: Detects Where().SingleOrDefault() that can be simplified to SingleOrDefault(predicate)
A call can be simplified by absorbing the predicate from .Where() into the subsequent call, resulting in cleaner and more efficient code.
var only = people.Where(p => p.Id == id).SingleOrDefault();
var only = people.SingleOrDefault(p => p.Id == id);
Replace With String Is Null Or Empty
Rule ID: replace-with-string-is-null-or-empty
Description: Detects null-or-empty string checks that can use string.IsNullOrEmpty()
A string variable is being checked for both null and empty conditions separately. This can be simplified to a single call to 'string.IsNullOrEmpty(variable)' for cleaner and more efficient code.
if (name == null || name == "")
{
return;
}
if (string.IsNullOrEmpty(name))
{
return;
}
Sealed Member
Rule ID: sealed-member
Description: Detects redundant sealed modifier on members of sealed classes
A member in a sealed class is marked as sealed, which is redundant since the class itself is sealed.
sealed class Logger
{
public sealed override string ToString() => "Logger";
}
sealed class Logger
{
public override string ToString() => "Logger";
}
Simplify LINQ Expression Use All
Rule ID: simplify-linq-expression-use-all
Description: Detects LINQ expressions that can be simplified using All()
A LINQ expression is using 'Any' with a negated predicate and the whole expression is negated. This can be simplified to use 'All' with the positive predicate for cleaner and more efficient code.
bool allAdults = !people.Any(p => p.Age < 18);
bool allAdults = people.All(p => p.Age >= 18);
Simplify String Interpolation
Rule ID: simplify-string-interpolation
Description: Detects string interpolations that can be simplified
A string interpolation is calling ToString() on an expression without any format arguments. This is unnecessary since the interpolation will call ToString() implicitly, resulting in cleaner and more efficient code.
string message = $"Total: {amount.ToString()}";
string message = $"Total: {amount}";
Specify A Culture In String Conversion Explicitly
Rule ID: specify-culture-in-string-conversion
Description: Detects culture-sensitive string operations without explicit culture
A culture-sensitive method call is missing an explicit culture specification. This can lead to unexpected behavior in different locales.
string text = value.ToString();
string text = value.ToString(CultureInfo.InvariantCulture);
Static Member In Generic Type
Rule ID: static-member-in-generic-type
Description: Detects static members in generic types
A static member is declared in a generic type. This means that each closed generic type will have its own copy of this member, which may lead to unexpected behavior if the member is intended to be shared across all instances of the generic type.
class Repository<T>
{
public static int InstanceCount;
}
class Repository<T>
{
public int InstanceCount;
}
Static Member Initializer Refers To Member Below
Rule ID: static-member-initializer-references-member-below
Description: Detects static initializers referencing members declared below
A static member initializer is referencing another static member that is declared below it. Since static members are initialized in declaration order, the referenced member will have its default value at the time of initialization, which may lead to unexpected behavior.
static int Doubled = Value * 2;
static int Value = 10;
static int Value = 10;
static int Doubled = Value * 2;
String Compare Culture Specific
Rule ID: string-compare-is-culture-specific
Description: Detects String.Compare calls without StringComparison parameter
A call to 'String.Compare' is missing an explicit StringComparison or CultureInfo parameter. This can lead to unexpected behavior in different locales, as the comparison will be culture-sensitive by default.
int result = String.Compare(first, second);
int result = String.Compare(first, second, StringComparison.Ordinal);
String Index Of Is Culture Specific
Rule ID: string-indexof-is-culture-specific-3
Description: String.IndexOf with 3 parameters is culture-specific and should use StringComparison
A call to 'String.IndexOf' with 3 parameters (value, startIndex, count) is culture-sensitive by default. Consider using an overload that includes a StringComparison parameter to ensure consistent behavior across different locales.
int index = text.IndexOf("abc", 0, 5);
int index = text.IndexOf("abc", 0, 5, StringComparison.Ordinal);
String Last Index Of Is Culture Specific
Rule ID: string-last-index-of-is-culture-specific
Description: Detects LastIndexOf calls without StringComparison parameter
A call to 'String.LastIndexOf' is missing an explicit StringComparison parameter. This can lead to unexpected behavior in different locales, as the search will be culture-sensitive by default.
int index = text.LastIndexOf("abc");
int index = text.LastIndexOf("abc", StringComparison.Ordinal);
String Literal As Interpolation Argument
Rule ID: string-literal-as-interpolation-argument
Description: Detects string literals used in interpolation holes
A string literal is used directly in an interpolation hole, which is redundant. Consider removing the interpolation and using the string directly.
var message = $"{"Hello"}, world";
var message = "Hello, world";
Structured Message Template
Rule ID: structured-message-template
Description: Detects issues with structured logging message templates
Using string interpolation in logging statements can lead to loss of structured logging benefits, as the properties may not be captured correctly. Consider using message templates with named placeholders instead.
logger.LogInformation($"User {userId} logged in");
logger.LogInformation("User {UserId} logged in", userId);
Suspicious Parameter Name
Rule ID: suspicious-parameter-name
Description: Detects suspicious or problematic parameter names
A parameter is named the same as a common type, which can be confusing and may indicate a copy-paste error. Consider renaming the parameter to something more descriptive.
Too Wide Local Variable Scope
Rule ID: too-wide-local-variable-scope
Description: Detects local variables declared in a wider scope than necessary
A local variable is declared in a wider scope than necessary. Consider declaring it in the narrower scope where it's used.
int square = 0;
foreach (var n in numbers)
{
square = n * n;
Console.WriteLine(square);
}
foreach (var n in numbers)
{
int square = n * n;
Console.WriteLine(square);
}
Try Cast Always Succeeds
Rule ID: try-cast-always-succeeds
Description: Detects 'as' casts that always succeed
An 'as' cast is redundant — the expression is already of the target type.
string name = "Alice";
var text = name as string;
string name = "Alice";
var text = name;
Type Parameter Can Be Variant
Rule ID: type-parameter-can-be-variant
Description: Detects type parameters that could be covariant (out) or contravariant (in)
A type parameter can be declared as a variant to improve type safety and flexibility.
interface IProducer<T>
{
T Produce();
}
interface IProducer<out T>
{
T Produce();
}
Unassigned Get Only Auto Property
Rule ID: unassigned-get-only-auto-property
Description: Detects get-only auto properties that are never assigned
A get-only auto property is never assigned a value, which means it will always return the default value for its type. Consider assigning it a value in the constructor or adding an initializer.
class User
{
public string Name { get; }
}
class User
{
public string Name { get; } = "Unknown";
}
Unreachable Switch Case
Rule ID: unreachable-switch-case
Description: Detects unreachable switch cases
A case label appears after a default label in a switch statement, which is unreachable. Consider reordering the cases or removing the unreachable case.
Unused Field
Rule ID: unused-field-compiler
Description: Detects unused private fields (CS0169, CS0414, CS0649)
Unused private field detected. Consider removing it or using it if it's intended for future use.
class Service
{
private int _cacheSize;
public void Run() { }
}
class Service
{
public void Run() { }
}
Unused Local Function
Rule ID: unused-local-function.compiler
Description: Detects local functions that are declared but never used
A local function is declared but never used. Consider removing it or using it if it's intended for future use.
void Process()
{
void Log() => Console.WriteLine("done");
}
void Process()
{
void Log() => Console.WriteLine("done");
Log();
}
Unused Member
Rule ID: unused-member-local
Description: Detects private members never used within the class
A private member is declared but never used. Consider removing it or using it if it's intended for future use.
class Service
{
public void Run() { }
private void Helper() { }
}
class Service
{
public void Run() => Helper();
private void Helper() { }
}
Unused Parameter
Rule ID: UnusedParameter.Local
Description: Detects method and local-function parameters that are never used
A parameter is declared but never used. Consider removing it or using it if it's intended for future use.
void Log(string message, int code)
{
Console.WriteLine(message);
}
void Log(string message)
{
Console.WriteLine(message);
}
Unused Positional Parameter
Rule ID: unused-positional-parameter
Description: Detects unused positional parameters in records
A positional parameter is declared but never used. Consider removing it or using it if it's intended for future use.
Unused Type
Rule ID: UnusedType.Local
Description: Detects types declared with private/internal accessibility that are never used
A type is declared locally but never used. Consider removing it or using it if it's intended for future use.
class Program
{
private class Helper { }
static void Main() { }
}
class Program
{
static void Main() { }
}
Unused Type Parameter
Rule ID: unused-type-parameter
Description: Detects type parameters that are declared but never used
A type parameter is declared but never used. Consider removing it or using it if it's intended for future use.
public class Cache<TKey, TValue>
{
public TValue Value { get; set; }
}
public class Cache<TValue>
{
public TValue Value { get; set; }
}
Unused Variable
Rule ID: UnusedVariable
Description: Detects local variables that are declared but never used
A local variable is declared but never used. Consider removing it or using it if it's intended for future use.
void Compute()
{
int total = 5;
}
void Compute()
{
int total = 5;
Console.WriteLine(total);
}
Use Array Empty Method
Rule ID: use-array-empty-method
Description: Detects empty array allocations that can use Array.Empty<T>()
Empty array allocation can be replaced with 'Array.Empty<T>()' which is cached and avoids allocation.
int[] items = new int[0];
int[] items = Array.Empty<int>();
Use Await Using
Rule ID: use-await-using
Description: Detects 'using' statements that should use 'await using' for IAsyncDisposable types
A variable declared with 'using' may be of a type that implements IAsyncDisposable. Consider using 'await using' for proper asynchronous disposal.
async Task Save(DbConnection conn)
{
using (conn)
{
await conn.OpenAsync();
}
}
async Task Save(DbConnection conn)
{
await using (conn)
{
await conn.OpenAsync();
}
}
Use Collection Count Property
Rule ID: use-collection-count-property
Description: Detects Count() method calls that can use Count/Length property
A Count() method call can likely be replaced with a Count or Length property for better performance and cleaner code.
int n = items.Count();
int n = items.Count;
Use Compound Assignment
Rule ID: use-compound-assignment
Description: Detects assignments that can use compound operators
An assignment can be simplified using a compound operator for better readability and conciseness.
count = count + 1;
count += 1;
Use Format Specifier In Format String
Rule ID: use-format-specifier-in-format-string
Description: Detects string concatenation that could use format specifiers
String concatenation is used in a context that supports format specifiers. Using format specifiers can improve readability and performance.
Use Index From End Expression
Rule ID: use-index-from-end-expression
Description: Detects array access patterns that can use index from end (^) syntax
Using index from end syntax can make the code more readable and concise.
var last = items[items.Length - 1];
var last = items[^1];
Use Method Any
Rule ID: use-method-any
Description: Detects Count() comparisons that can be replaced with Any()
A Count() comparison can be replaced with Any() for better performance and cleaner code.
if (items.Count() > 0) { }
if (items.Any()) { }
Use Name Instead Of Type Of
Rule ID: use-name-instead-of-type-of
Description: Detects typeof(T).Name that can be replaced with nameof(T)
Using nameof() instead of typeof().Name provides compile-time safety and better support for renaming.
var name = typeof(User).Name;
var name = nameof(User);
Use Name Of Expression
Rule ID: use-nameof-expression
Description: Detects string literals that can use nameof() expression
Using nameof() instead of string literals for symbol names provides compile-time safety and better support for refactoring. Consider replacing the string literal with nameof() of the symbol.
throw new ArgumentNullException("value");
throw new ArgumentNullException(nameof(value));
Use Object Or Collection Initializer
Rule ID: use-object-or-collection-initializer
Description: Suggests using object or collection initializer syntax instead of separate assignments
Using object initializer syntax can make the code more readable and maintainable.
var user = new User();
user.Name = "Bob";
var user = new User { Name = "Bob" };
Use Pattern Matching
Rule ID: use-pattern-matching
Description: Detects code patterns that can be simplified using C# pattern matching
Using pattern matching can make the code more readable and maintainable.
if (obj is string)
{
var s = (string)obj;
}
if (obj is string s)
{
}
Use String Interpolation
Rule ID: use-string-interpolation
Description: Detects string.Format and concatenation that can use string interpolation
Using string interpolation can make the code more readable and maintainable. Consider replacing the string.Format call with an interpolated string.
var message = string.Format("Hello, {0}! You have {1} messages.", name, count);
var message = $"Hello, {name}! You have {count} messages.";
Useless Binary Operation
Rule ID: useless-binary-operation
Description: Detects binary operations with no effect
This binary operation has no effect and can be removed for cleaner code.
var result = value + 0;
var result = value;
Value Parameter Not Used
Rule ID: value-parameter-not-used
Description: Detects when the implicit 'value' parameter in a setter or event accessor is not used
The implicit 'value' parameter in a setter or event accessor is not used. This usually indicates a bug where the assigned value is being ignored. Consider using the 'value' parameter to store or process the assigned value, or remove the accessor if it's not needed.
private string _name;
public string Name
{
get => _name;
set => _name = "default";
}
private string _name;
public string Name
{
get => _name;
set => _name = value;
}
Variable Cannot Be Nullable
Rule ID: VariableCanBeNotNullable
Description: Detects nullable value types that are always assigned non-null values
This variable is declared as a nullable type but is always assigned a non-null value. Consider using the underlying type instead.
int? age = 30;
Console.WriteLine(age.Value);
int age = 30;
Console.WriteLine(age);
Variable Hides Outer Variable
Rule ID: variable-hides-outer-variable
Description: Detects variables that hide (shadow) variables from outer scopes
Variable is declared in an inner scope and hides a variable with the same name from an outer scope. Consider renaming one of the variables to improve code clarity and avoid confusion.
var count = 10;
foreach (var item in items)
{
var count = item.Length;
Console.WriteLine(count);
}
var count = 10;
foreach (var item in items)
{
var length = item.Length;
Console.WriteLine(length);
}
Virtual Member Call In Constructor
Rule ID: virtual-member-call-in-constructor
Description: Detects calls to virtual members within constructor bodies
Calling virtual methods in constructors can lead to unexpected behavior. Consider refactoring to avoid calling virtual members during construction.
class Widget
{
public Widget() => Initialize();
protected virtual void Initialize() { }
}
class Widget
{
public Widget() => Initialize();
private void Initialize() { }
}
XML Comment Ambiguous Reference
Rule ID: xml-comment-ambiguous-reference
Description: Detects ambiguous references in XML documentation
An XML documentation reference is ambiguous. Consider adding more context or parameters to clarify the reference.
XML Documentation In Non Existent Type Params
Rule ID: CSharpWarnings::CS1711
Description: Detects XML typeparam tags referencing non-existent type parameters
An XML documentation comment references a type parameter that doesn't exist on the declaration. This may indicate a documentation error.
/// <typeparam name="TKey">The key type.</typeparam>
public class Box<T> { }
/// <typeparam name="T">The item type.</typeparam>
public class Box<T> { }
Solution-wide checks
Base Method Call Default Parameter
Rule ID: BaseMethodCallWithDefaultParameter
Description: Detects base method calls that rely on default parameter values
A base method call is missing arguments for optional parameters. This can lead to unexpected behavior if the base class defaults differ from the derived class defaults. Consider explicitly passing the optional parameters to ensure the intended values are used.
Class Never Instantiated
Rule ID: class-never-instantiated
Description: Detects non-abstract, non-static classes that are never instantiated in the project
This global class is never instantiated or referenced anywhere in the project. Consider making it static if it only contains static members, making it abstract if it's meant to be a base class, or removing it if it's not needed.
Class With Virtual Members Never Inherited
Rule ID: class-with-virtual-members-never-inherited
Description: Detects classes with virtual members that are never inherited from
Collection Never Queried
Rule ID: collection-never-queried
Description: Detects collections that are populated but never queried
This collection is populated (mutated) but never queried (read from) anywhere in the project. Consider either querying the collection to utilize the stored data, or removing it if it's not needed. Unqueried collections can lead to wasted memory and may indicate incomplete implementation.
Collection Never Updated
Rule ID: collection-never-updated
Description: Detects collections that are never modified
This collection is initialized but never modified anywhere in the project. Consider making it readonly if it should not be modified after initialization, or removing it if it's not needed. Unmodified collections can indicate incomplete implementation or unnecessary code.
Event Never Invoked
Rule ID: event-never-invoked
Description: Detects events that are declared but never invoked
public class Button
{
public event EventHandler? Clicked;
}
public class Button
{
public event EventHandler? Clicked;
public void Click() => Clicked?.Invoke(this, EventArgs.Empty);
}
Event Never Subscribed To
Rule ID: event-never-subscribed-to
Description: Detects events that are declared but never subscribed to
Global event is declared but never subscribed to anywhere in the project.
Field Can Be Made Read Only
Rule ID: field-can-be-made-readonly-global
Description: Detects non-private fields that can be marked as readonly
Global field can be made readonly. It is only assigned at declaration or in constructors.
public class Config
{
protected string _path;
public Config(string path) => _path = path;
}
public class Config
{
protected readonly string _path;
public Config(string path) => _path = path;
}
Inconsistent Synchronized Field
Rule ID: inconsistently-synchronized-field
Description: Detects fields accessed inconsistently with respect to locking
Global field is accessed both inside and outside locks inconsistently.
private readonly object _sync = new();
private int _counter;
public void Increment() { lock (_sync) { _counter++; } }
public int Read() => _counter;
private readonly object _sync = new();
private int _counter;
public void Increment() { lock (_sync) { _counter++; } }
public int Read() { lock (_sync) { return _counter; } }
Introduce Optional Parameters
Rule ID: introduce-optional-parameters
Description: Detects method overloads that can be consolidated using optional parameters
Method overload delegates to another overload and can be replaced with global optional parameters.
public void Connect(string host) => Connect(host, 8080);
public void Connect(string host, int port) { }
public void Connect(string host, int port = 8080) { }
Member Can Be Private
Rule ID: member-can-be-private
Description: Detects internal members that could be made private (project-wide analysis)
A member is internal but only used within its containing type. It can be made private.
Member Can Be Protected
Rule ID: member-can-be-protected
Description: Detects public members that could be made protected
Global member is only used within the class hierarchy and can be made protected.
Method Overload With Optional Parameter
Rule ID: method-overload-with-optional-parameter
Description: Detects method overloads that can use optional parameters
Method overloads can be combined using global optional parameters
public void Log(string message) => Log(message, LogLevel.Info);
public void Log(string message, LogLevel level) { }
public void Log(string message, LogLevel level = LogLevel.Info) { }
Not Accessed Positional Library
Rule ID: not-accessed-positional-property
Description: Detects positional properties in records that are never accessed anywhere in the project
Global positional property is never accessed. Consider removing it or using it.
Optional Parameter Hierarchy Mismatch
Rule ID: OptionalParameterHierarchyMismatch
Description: Detects optional parameters with different default values between derived and base methods
Optional parameter in derived method has different default value than in base method, causing potential confusion and bugs.
class Base { public virtual void Save(bool overwrite = false) { } }
class Derived : Base { public override void Save(bool overwrite = true) { } }
class Base { public virtual void Save(bool overwrite = false) { } }
class Derived : Base { public override void Save(bool overwrite = false) { } }
Parameter Type Can Be Enumerable
Rule ID: parameter-type-can-be-enumerable
Description: Detects collection parameters that could use IEnumerable
Global parameter of concrete collection type could be IEnumerable for flexibility.
public int Sum(List<int> numbers)
{
var total = 0;
foreach (var n in numbers) total += n;
return total;
}
public int Sum(IEnumerable<int> numbers)
{
var total = 0;
foreach (var n in numbers) total += n;
return total;
}
Redundant Extends List Entry
Rule ID: redundant-extends-list-entry
Description: Detects redundant entries in class or interface base type lists
Redundant entry in base type list is detected. It is either a duplicate or inherited through another entry.
interface IRepository : ICollection<int>, IEnumerable<int> { }
interface IRepository : ICollection<int> { }
Return Type Not Nullable
Rule ID: return-type-can-be-not-nullable
Description: Detects methods with nullable return types that never return null
Method never returns null; return type can be non-nullable.
public string? GetName()
{
return "Guest";
}
public string GetName()
{
return "Guest";
}
Unassigned Field
Rule ID: unassigned-field
Description: Detects fields that are never assigned a value anywhere in the project
Global field is never assigned and will always have its default value.
Unused Member Hierarchy
Rule ID: unused-member-hierarchy
Description: Detects unused members in inheritance hierarchies
Member in inheritance hierarchy is unused. Consider removing it or using it.
Unused Type Parameter
Rule ID: unused-type-parameter
Description: Detects unused generic type parameters
Global Type parameter is never used.
public class Cache<TKey, TValue>
{
public TValue Value { get; set; }
}
public class Cache<TValue>
{
public TValue Value { get; set; }
}
Security
Cyclopt scans your C# code for security vulnerabilities, injection, insecure configuration, weak cryptography, data exposure, and more. Each finding below lists its Rule ID, what it detects and how to fix it, a severity, and the relevant CWE/OWASP classification.
LDAP Injection
Rule ID: ldap-injection
Description: Concatenating untrusted input into a DirectorySearcher.Filter string lets an attacker alter the LDAP query and exfiltrate or modify directory entries. Sanitize every component with AntiXssEncoder.LdapFilterEncode (or LdapDistinguishedNameEncode for DN segments) before assembling the filter.
CWE: CWE-90 · OWASP: A01:2017, A03:2021, A05:2025
Mass Assignment
Rule ID: mass-assignment
Description: Binding a controller action parameter to a domain model without a [Bind(...)] allow-list lets attackers over-post hidden properties (such as IsAdmin or Roles) and tamper with the underlying entity. Restrict model binding with [Bind(nameof(...))] or bind to a dedicated DTO that only exposes safe fields.
CWE: CWE-915 · OWASP: A08:2021, A08:2025
Misconfigured Lockout Option
Rule ID: misconfigured-lockout-option
Description: Calling SignInManager.PasswordSignInAsync or CheckPasswordSignInAsync with lockoutOnFailure: false disables ASP.NET Identity's lockout counter, letting attackers brute-force credentials indefinitely. Pass lockoutOnFailure: true and configure LockoutOptions with sensible MaxFailedAccessAttempts and DefaultLockoutTimeSpan values.
CWE: CWE-307 · OWASP: A07:2021, A07:2025
Missing Or Broken Authorization
Rule ID: missing-or-broken-authorization
Description: This MVC Controller is declared without an [Authorize], [Authorize(Roles=...)], [Authorize(Policy=...)], or explicit [AllowAnonymous] attribute, leaving every action implicitly reachable by anonymous callers. Annotate the controller (or register a global AuthorizeFilter) so access defaults to deny and only documented endpoints opt in to anonymous traffic.
CWE: CWE-862 · OWASP: A01:2021, A01:2025
Mvc Missing Antiforgery
Rule ID: mvc-missing-antiforgery
Description: State-changing MVC action $METHOD decorated with [HttpPost]/[HttpPut]/[HttpDelete]/[HttpPatch] is missing both [ValidateAntiForgeryToken] and a [Consumes(...)] content-type restriction, so a forged cross-site form can drive it via a CORS "simple request" without preflight. Apply [ValidateAntiForgeryToken] (or AutoValidateAntiforgeryTokenAttribute globally) and/or pin the accepted media type with [Consumes("application/json")].
CWE: CWE-352 · OWASP: A01:2021, A01:2025
Net Webconfig Debug
Rule ID: net-webconfig-debug
Description: Shipping web.config with <compilation debug="true" /> produces non-optimised binaries, disables batch="true" JIT bundling, and emits verbose stack traces in HTTP 500 responses, leaking internal paths and framework details. Set debug="false" (or drop the attribute) for production deployments.
CWE: CWE-11 · OWASP: A05:2021, A02:2025
Net Webconfig Trace Enabled
Rule ID: net-webconfig-trace-enabled
Description: Enabling <trace enabled="true" /> under <system.web> makes ASP.NET's trace handler publish detailed request, session, and server-variable information at Trace.axd, which is a textbook information-disclosure sink. Set enabled="false" (or remove the element entirely) in production web.config files.
CWE: CWE-1323 · OWASP: A05:2021
Open Directory Listing
Rule ID: open-directory-listing
Description: Registering UseDirectoryBrowser (or AddDirectoryBrowser) exposes the raw filesystem layout of the static content folder, leaking filenames, backup files, and other artefacts that aid attackers. Remove the directory browsing middleware in production or limit it to a tightly scoped DirectoryBrowserOptions.FileProvider behind an authorization check.
CWE: CWE-548 · OWASP: A06:2017, A01:2021, A01:2025
Razor Template Injection
Rule ID: razor-template-injection
Description: Feeding a request-derived string into Razor.Parse(...) lets the RazorEngine compile and execute attacker-supplied C# inside the worker process, granting arbitrary code execution. Render only pre-defined templates by key and pass untrusted data exclusively as model properties on a sandboxed TemplateService configuration.
CWE: CWE-94 · OWASP: A03:2021, A05:2025
Razor Use Of Htmlstring
Rule ID: razor-use-of-htmlstring
Description: Wrapping a value in new HtmlString(...) (or @(new HtmlString(...))) bypasses Razor's automatic HTML encoding and emits the payload verbatim into the page, producing reflected or stored XSS when the value is attacker-influenced. Render the data with normal Razor expressions, or pre-encode it with HtmlEncoder.Default.Encode before passing it to HtmlString.
CWE: CWE-116 · OWASP: A03:2021, A05:2025
Use Deprecated Cipher Algorithm
Rule ID: use_deprecated_cipher_algorithm
Description: Instantiating a cipher through DES.Create() or RC2.Create() selects an algorithm with a 56- or 64-bit effective key that has been broken in practice and is forbidden by FIPS 140-3. Replace it with Aes.Create() plus AesGcm/AesCcm, or ChaCha20Poly1305, for an authenticated modern primitive.
CWE: CWE-327 · OWASP: A02:2021, A04:2025
Use ECB Mode
Rule ID: use_ecb_mode
Description: Selecting CipherMode.ECB (or calling EncryptEcb/DecryptEcb) on a SymmetricAlgorithm encrypts each block independently, so identical plaintext blocks produce identical ciphertext and reveal structural patterns to an observer. Switch to an authenticated mode such as AesGcm or ChaCha20Poly1305, or at minimum CipherMode.CBC with a random IV and an HMAC.
CWE: CWE-327 · OWASP: A02:2021, A04:2025
Use Weak Rng For Keygeneration
Rule ID: use_weak_rng_for_keygeneration
Description: Filling a key buffer with System.Random.NextBytes and then assigning it to SymmetricAlgorithm.Key or passing it to AesGcm/AesCcm/ChaCha20Poly1305 seeds the cipher with a predictable linear-congruential stream that an attacker can replay or rebuild. Generate keying material with RandomNumberGenerator.Fill (or RandomNumberGenerator.GetBytes) from System.Security.Cryptography.
CWE: CWE-338 · OWASP: A02:2021, A04:2025
Use Weak Rsa Encryption Padding
Rule ID: use_weak_rsa_encryption_padding
Description: Using RSAPKCS1KeyExchangeFormatter.CreateKeyExchange (or its Deformatter counterpart) wraps the session key with PKCS#1 v1.5 padding, which is vulnerable to Bleichenbacher chosen-ciphertext attacks. Migrate to RSAOAEPKeyExchangeFormatter/RSAOAEPKeyExchangeDeformatter so the exchange uses OAEP padding with SHA-256.
CWE: CWE-780 · OWASP: A02:2021, A04:2025
Web Config Insecure Cookie Settings
Rule ID: web-config-insecure-cookie-settings
Description: Setting requireSSL="false" on <httpCookies>/<forms> or cookieRequireSSL="false" on <roleManager> in web.config clears the cookie Secure flag, so session and Forms-authentication cookies travel in cleartext over any HTTP request. Force requireSSL="true" (and cookieRequireSSL="true" for the role manager) so the browser only transmits these cookies on HTTPS connections.
CWE: CWE-614 · OWASP: A05:2021, A02:2025
Xpath Injection
Rule ID: xpath-injection
Description: Building an XPath expression by string-concatenating user input into XPathNavigator.Compile, Select, or Evaluate lets an attacker rewrite the predicate and read arbitrary nodes from the XML document. Parameterise the query with XPathExpression.SetContext and an XsltArgumentList, or aggressively whitelist the input before interpolation.
CWE: CWE-643 · OWASP: A03:2021, A05:2025
Correctness Double Epsilon Equality
Rule ID: correctness-double-epsilon-equality
Description: Comparing Math.Abs(a - b) <= Double.Epsilon only detects equality when both operands are already at zero, because Double.Epsilon is the smallest positive denormal and shrinks below the ULP of any non-zero value; the constant is also platform-dependent across runtimes. Use Double.Equals, or compare against an application-defined tolerance derived from the expected magnitude.
Correctness Regioninfo Interop
Rule ID: correctness-regioninfo-interop
Description: Serialising a RegionInfo built from the two-letter ISO code $REGION across an AnonymousPipe/NamedPipe stream is unreliable, because the .NET TwoLetterISORegionName constructor resolves the code against the sender's installed culture data and may not round-trip on the receiver. Instantiate the RegionInfo with a full culture name (e.g. "en-US") before writing it through $WRITER.
Correctness Sslcertificatetrust Handshake No Trust
Rule ID: correctness-sslcertificatetrust-handshake-no-trust
Description: Passing sendTrustInHandshake: true to SslCertificateTrust.CreateForX509Collection/CreateForX509Store embeds every accepted root CA distinguished name inside the TLS CertificateRequest message, inflating the handshake and disclosing the server's trust store layout to any client. Pass false so the trusted issuers are kept private and only used locally for chain validation.
CWE: CWE-200 · OWASP: A03:2017
Csharp Sqli
Rule ID: csharp-sqli
Description: A tainted string reaches a SqlCommand/OleDbCommand/OdbcCommand/OracleCommand constructor or its CommandText property without being routed through Parameters.Add / Parameters.AddWithValue, so attacker input is concatenated directly into the executed query. Bind every variable through a SqlParameter (or the equivalent provider parameter type) before executing the command.
CWE: CWE-89 · OWASP: A01:2017, A03:2021, A05:2025
Data Contract Resolver
Rule ID: data-contract-resolver
Description: A custom DataContractResolver implementation broadens the set of types accepted during deserialization, and a permissive ResolveName override lets an attacker swap in gadget types that execute on materialization. Restrict the resolver to an explicit allowlist of safe contracts before returning a Type.
CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025
HTTP Listener Wildcard Bindings
Rule ID: http-listener-wildcard-bindings
Description: Registering HttpListener.Prefixes.Add("$PREFIX") with a top-level * or + host claims every Host header that arrives on that port, letting an attacker reach the endpoint via any DNS name pointed at the server (a common host-header spoofing vector). Bind to an explicit hostname, or use a constrained subdomain wildcard such as *.example.com that you fully control.
CWE: CWE-706 · OWASP: A01:2021, A01:2025
Insecure Binaryformatter Deserialization
Rule ID: insecure-binaryformatter-deserialization
Description: Instantiating BinaryFormatter exposes the process to deserialization gadgets that lead to remote code execution, and Microsoft has marked BinaryFormatter.Deserialize as obsolete because the type cannot be hardened against malicious payloads. Replace it with a safer serializer such as System.Text.Json or DataContractSerializer bound to a known type set.
CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025
Insecure Fastjson Deserialization
Rule ID: insecure-fastjson-deserialization
Description: Disabling BadListTypeChecking on fastJSON.JSONParameters removes the guardrail that blocks the $type discriminator from resolving arbitrary CLR types during deserialization. Leave the bad-type list active and only feed fastJSON.JSON.ToObject from trusted producers.
CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025
Insecure Fspickler Deserialization
Rule ID: insecure-fspickler-deserialization
Description: Calling FsPickler.CreateJsonSerializer with default settings enables subtype resolution, which lets a payload instantiate any reachable .NET type when piped into Deserialize. Construct the serializer with subtype resolution disabled or supply a strict ITypeNameConverter allowlist.
CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025
Insecure Javascriptserializer Deserialization
Rule ID: insecure-javascriptserializer-deserialization
Description: Passing a SimpleTypeResolver to new JavaScriptSerializer(...) lets the __type field in the incoming JSON instantiate arbitrary CLR types via JavaScriptSerializer.Deserialize, opening a direct path to remote code execution. Drop the resolver argument or implement a JavaScriptTypeResolver that returns only safe types.
CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025
Insecure Losformatter Deserialization
Rule ID: insecure-losformatter-deserialization
Description: LosFormatter.Deserialize shares the BinaryFormatter engine under the hood, so any data passed through it can carry deserialization gadgets that achieve RCE. Migrate persisted ViewState or LOS blobs to System.Text.Json or XmlSerializer with an explicit type allowlist.
CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025
Insecure Netdatacontract Deserialization
Rule ID: insecure-netdatacontract-deserialization
Description: NetDataContractSerializer.ReadObject embeds full CLR type information in the wire format and will instantiate whatever type the payload declares, making it a documented deserialization sink. Switch to DataContractSerializer with the expected root type pinned, since NetDataContractSerializer cannot be safely locked down.
CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025
Insecure Newtonsoft Deserialization
Rule ID: insecure-newtonsoft-deserialization
Description: Setting JsonSerializerSettings.TypeNameHandling to $TYPEHANDLER makes JsonConvert.DeserializeObject<T> honor the $type discriminator in the payload, so an attacker can supply any reachable CLR type and trigger code execution. Set TypeNameHandling.None, or pair the existing setting with a strict ISerializationBinder that allowlists only the polymorphic types you need.
CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025
Insecure Soapformatter Deserialization
Rule ID: insecure-soapformatter-deserialization
Description: Constructing a SoapFormatter wires up the same vulnerable formatter pipeline as BinaryFormatter, so a crafted SOAP envelope passed to SoapFormatter.Deserialize can execute arbitrary code in the host. Move SOAP message handling to XmlSerializer or WCF data contracts with a fixed set of known types.
CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025
Insecure Typefilterlevel Full
Rule ID: insecure-typefilterlevel-full
Description: Configuring BinaryServerFormatterSinkProvider.TypeFilterLevel = TypeFilterLevel.Full (or Low) exposes the .NET Remoting endpoint to attacker-supplied gadget chains and is exploitable for RCE even with both levels. Migrate the channel to WCF or gRPC instead of attempting to safelist Remoting traffic.
CWE: CWE-502 · OWASP: A08:2017, A08:2021, A08:2025
JWT Tokenvalidationparameters No Expiry Validation
Rule ID: jwt-tokenvalidationparameters-no-expiry-validation
Description: Disabling TokenValidationParameters.$LIFETIME (set to $FALSE) tells JwtSecurityTokenHandler.ValidateToken to skip the exp and nbf claim checks, so expired or future-dated JWTs are still accepted. Keep both RequireExpirationTime and ValidateLifetime set to true and provide a sensible ClockSkew on the validation parameters.
CWE: CWE-613 · OWASP: A02:2017, A07:2021, A07:2025
Memory Marshal Create Span
Rule ID: memory-marshal-create-span
Description: Both MemoryMarshal.CreateSpan and MemoryMarshal.CreateReadOnlySpan skip bounds validation on the length argument and trust the caller to keep the resulting span inside the referenced memory. Verify that the length is computed from a trusted source and never exceeds the underlying buffer, or use a safe Span<T> constructor instead.
CWE: CWE-125 · OWASP: A04:2021, A06:2025
Missing Hsts Header
Rule ID: missing-hsts-header
Description: Neither IApplicationBuilder.UseHsts nor IServiceCollection.AddHsts is wired up in the ASP.NET Core pipeline, so responses never advertise the Strict-Transport-Security header and clients can be downgraded to plain HTTP. Register the HSTS middleware in Startup.Configure (and tune it in ConfigureServices) to force browsers onto HTTPS.
CWE: CWE-346 · OWASP: A07:2021, A07:2025
Open Redirect
Rule ID: open-redirect
Description: A user-controlled action parameter flows directly into Controller.Redirect, letting an attacker craft a link that bounces visitors to an arbitrary external host once it is loaded. Validate the target with Url.IsLocalUrl(...) (or use LocalRedirect) before issuing the redirect.
CWE: CWE-601 · OWASP: A01:2021, A01:2025
OS Command Injection
Rule ID: os-command-injection
Description: Passing tainted data straight into Process.Start(...), or into ProcessStartInfo.FileName / Arguments, lets the operating-system shell interpret metacharacters and run attacker-chosen executables. Hard-code the executable path, set UseShellExecute = false, and supply each user-controlled value as a separate item in ProcessStartInfo.ArgumentList so it is escaped per argument.
CWE: CWE-78 · OWASP: A01:2017, A03:2021, A05:2025
Regular Expression Dos
Rule ID: regular-expression-dos
Description: Invoking Regex.Match (or new Regex(...) followed by Match) on a public method argument without supplying a matchTimeout exposes the engine's backtracking to attacker-controlled patterns, which can spike CPU until the request times out. Always provide a bounded TimeSpan (for example TimeSpan.FromSeconds(2)) to the Regex constructor or the static Regex.Match overload.
CWE: CWE-1333 · OWASP: A01:2017
Regular Expression Dos Infinite Timeout
Rule ID: regular-expression-dos-infinite-timeout
Description: Constructing a Regex with TimeSpan.InfiniteMatchTimeout (or an excessively long TimeSpan.FromMinutes/FromHours) lets a catastrophic-backtracking pattern pin a thread on Regex.Match indefinitely. Pass a tight matchTimeout such as TimeSpan.FromSeconds(2) so the engine raises RegexMatchTimeoutException and aborts pathological inputs.
CWE: CWE-1333 · OWASP: A01:2017
SSRF
Rule ID: ssrf
Description: A method parameter flows unchecked into HttpClient.GetAsync / HttpClient.GetStringAsync, so an attacker controlling that input can pivot the server into the internal network or against the loopback address. Validate the URL against an explicit host allowlist and reject non-public schemes before issuing the request.
CWE: CWE-918 · OWASP: A10:2021, A01:2025
SSRF
Rule ID: ssrf
Description: Passing a user-controlled value into the RestSharp.RestClient constructor lets the caller dictate the base URL of every subsequent Execute call, which is a classic SSRF primitive against internal services. Construct the RestClient with a fixed base URL and treat the user input as a parameter appended through RestRequest.AddParameter.
CWE: CWE-918 · OWASP: A10:2021, A01:2025
SSRF
Rule ID: ssrf
Description: Forwarding a user-supplied address into WebClient.OpenRead, WebClient.OpenReadAsync or WebClient.DownloadString lets an attacker steer the outbound request at metadata endpoints or intranet hosts. Parse the value into a Uri, verify it resolves to an approved external host, and reject loopback / link-local addresses before dispatching the call.
CWE: CWE-918 · OWASP: A10:2021, A01:2025
SSRF
Rule ID: ssrf
Description: Building a request with WebRequest.Create from a tainted parameter hands the destination URI to the caller and turns the server into a relay for arbitrary HTTP/file/ftp requests. Resolve the input against a hard-coded base URI or compare its host against an allowlist before invoking WebRequest.GetResponse.
CWE: CWE-918 · OWASP: A10:2021, A01:2025
Stacktrace Disclosure
Rule ID: stacktrace-disclosure
Description: Calling IApplicationBuilder.UseDeveloperExceptionPage outside an IHostEnvironment.IsDevelopment guard ships verbose stack traces and source snippets to every client, including in production. Wrap the call in an if (env.IsDevelopment()) branch and configure UseExceptionHandler for non-dev environments.
CWE: CWE-209 · OWASP: A06:2017, A04:2021, A06:2025
Unsafe Path Combine
Rule ID: unsafe-path-combine
Description: Feeding $A into Path.Combine(...) and then File.Read*/File.Write* without first running it through Path.GetFileName allows an absolute path or ../ traversal to escape the intended directory, because Path.Combine discards earlier components when a later argument is rooted. Normalise the user segment with Path.GetFileName($A) (or explicitly reject paths where Path.GetFileName($A) != $A) before composing the final path.
CWE: CWE-22 · OWASP: A05:2017, A01:2021, A01:2025
Unsigned Security Token
Rule ID: unsigned-security-token
Description: Configuring TokenValidationParameters.RequireSignedTokens = false makes the JWT handler accept tokens whose alg header is none or whose signature segment is empty, allowing an attacker to forge identities by stripping the signature. Keep RequireSignedTokens = true and supply IssuerSigningKeys so the handler enforces cryptographic verification.
CWE: CWE-347 · OWASP: A02:2021, A04:2025
X509 Subject Name Validation
Rule ID: X509-subject-name-validation
Description: Comparing X509Certificate2.SubjectName.Name (or GetNameInfo(...)) with a fixed string only checks an attacker-controllable text label and skips chain, signature, and revocation verification, so any cert with a matching CN is accepted. Validate the certificate with X509Certificate2.Verify() or an X509Chain configured with the expected trust roots before trusting its subject.
CWE: CWE-295 · OWASP: A03:2017, A07:2021, A07:2025
X509Certificate2 Privkey
Rule ID: X509Certificate2-privkey
Description: Reading or assigning X509Certificate2.PrivateKey is obsolete: the setter leaves the previous CSP-backed key file on disk and the getter throws on modern algorithms like ECDsa. Read keys through GetRSAPrivateKey() / GetECDsaPrivateKey() and produce a key-bound certificate with CopyWithPrivateKey(...) instead.
CWE: CWE-310 · OWASP: A02:2021, A04:2025
Xmldocument Unsafe Parser Override
Rule ID: xmldocument-unsafe-parser-override
Description: Assigning XmlDocument.XmlResolver = new XmlUrlResolver() reactivates external-entity resolution while a tainted string is being parsed, so a crafted document can read local files or trigger SSRF via XmlDocument.Load. Leave XmlResolver as null (the .NET 4.5.2+ default) or wire in a XmlSecureResolver scoped to a trusted origin.
CWE: CWE-611 · OWASP: A04:2017, A05:2021, A02:2025
Xmlreadersettings Unsafe Parser Override
Rule ID: xmlreadersettings-unsafe-parser-override
Description: Flipping XmlReaderSettings.DtdProcessing to DtdProcessing.Parse before handing the settings to XmlReader.Create re-enables DTD parsing on user-controlled input, which is the standard XXE primitive for exfiltrating files or hitting internal endpoints. Use DtdProcessing.Prohibit (or Ignore) and clear XmlResolver on the settings instance.
CWE: CWE-611 · OWASP: A04:2017, A05:2021, A02:2025
Xmltextreader Unsafe Defaults
Rule ID: xmltextreader-unsafe-defaults
Description: Reading user-supplied XML through new XmlTextReader(...) without setting XmlTextReader.DtdProcessing = DtdProcessing.Prohibit keeps the legacy permissive defaults, so an inline DOCTYPE can pull external entities through the parser. Set DtdProcessing.Prohibit (and a null XmlResolver) before invoking any Read* method on the reader.
CWE: CWE-611 · OWASP: A04:2017, A05:2021, A02:2025
HTML Raw Json
Rule ID: html-raw-json
Description: Emitting JsonConvert.SerializeObject(...) (or Json.Encode) through @Html.Raw in a Razor view skips HTML encoding, so any </script> sequence inside the serialized payload breaks out of the surrounding script block into HTML context and enables stored XSS. Render the JSON with @Json.Serialize(...) or use a JSON-aware HTML encoder that escapes <, > and &.
CWE: CWE-79 · OWASP: A07:2017, A03:2021, A05:2025


