Note. Currently, the C# analyzer supports annotations only for taint analysis. User annotations for general purposes will be supported later.
Ways to register the annotation file
You can learn more about how to enable the annotation file in this documentation.
The file content is a JSON object consisting of three mandatory fields: language, version, and annotations.
The language field must receive the value 'csharp'. The version field takes an integer-type value and specifies the version of the mechanism. Depending on the value, the markup file can be processed differently. Currently, only the value 1 is supported.
The annotations field is an array of "annotation" objects:
{
"language": "csharp",
"version": 1,
"annotations":
[
{
...
},
{
...
}
]
}
Annotations can be of three types:
The PVS-Studio analyzer provides a range of annotations for taint analysis, which can be used to track taint sources and sinks. It is also possible to mark up methods/constructors that validate tainted data. Therefore, if the tainted data has been validated, the analyzer will not issue a warning when the data reaches the sink.
A different diagnostic rule is used to handle each type of vulnerability. At the moment, the analyzer provides the following diagnostic rules for identifying tainted data:
Each diagnostic rule has special annotations to mark taint sinks and methods/constructors that validate tainted data.
As for taint data sources, they are common to all diagnostic rules. However, such data can also be annotated.
Note: The attributes for taint annotations are detailed in the following documentation sections.
It's important to note that, in addition to user annotations, the analyzer already provides a range of taint annotations for various libraries. To give an example, passing the result of the System.Console.ReadLine method to the System.Data.SqlClient.SqlCommand constructor can potentially lead to SQL injection. The analyzer provides annotations that indicate System.Console.ReadLine as a source of tainted data and System.Data.SqlClient.SqlCommand as a sink where this tainted data could lead to SQL injection.
Thus, if we annotate the source of tainted data, the analyzer will recognize its exposure to existing sinks, and vice versa. If the sink is annotated, the analyzer will issue a warning when it encounters previously marked tainted data sources, such as System.Console.ReadLine.
Note: The method annotation object must contain at least one optional field.
The method annotation object consists of the following fields:
The mandatory field. It takes a string with the method value.
The mandatory field. It takes a string specifying the name of the namespace that contains the method.
The mandatory field. It takes a string specifying the name of the class where the method is defined.
The mandatory field. It takes a string with the name of the method.
The optional field. The array of strings that specifies the properties of an entity.
# |
Attribute name |
Attribute description |
---|---|---|
1 |
not_apply_to_child_class |
The annotation is not applied when the annotated method is called on an object of a child class. |
2 |
caller_is_xml_parser |
The object calling the method is an XML parser, which could be vulnerable (V5614, V5615). |
The optional field. This field is described in the "Parameter annotations" section.
Note. The return value annotation object must either include both the 'namespace_name' and 'type_name' fields or have both fields absent (or set to null). If both fields are absent, the type of the return value will not be considered when selecting an annotation.
The optional field. The return value object consists of the following fields:
The optional field. It takes a string specifying the name of the namespace that contains the type of the method return value.
The optional field. It takes a string specifying the name of the class where the type of the method return value is defined.
The optional field. The array of strings that specifies the properties of the method return value.
Possible return value attributes
# |
Attribute name |
Attribute description |
---|---|---|
1 |
not_apply_to_child_class |
The annotation does not apply to the method if its return value type is a child of the annotated type. |
2 |
always_taint |
The method returns tainted data. |
3 |
transfer_annotations_from_caller |
If the caller object has an annotation, it will be propagated to the method return value. |
Note. The constructor annotation object must include at least one optional field.
The constructor annotation object consists of the following fields:
The mandatory field. It takes a string with the ctor value.
The mandatory field. It takes a string specifying the name of the namespace that contains the constructor.
The mandatory field. It takes a string specifying the name of the class where the constructor is defined.
The optional field. The array of strings that specifies the properties of an entity.
# |
Attribute name |
Attribute description |
---|---|---|
1 |
not_apply_to_child_class |
The annotation does not apply to child implementations of the annotated constructor. |
2 |
create_taint_object |
The object created by the constructor is taint. |
The optional field. This field is described in the "Parameter annotations" section.
The property annotation object consists of the following fields:
The mandatory field. It takes a string with the property value.
The mandatory field. It takes a string specifying the name of the namespace that contains the property.
The mandatory field. It takes a string specifying the name of the class where the property is defined.
The optional field. The array of strings that specifies the properties of an entity.
Note: Each taint sink attribute has a link to the diagnostic rule.
# |
Attribute name |
Attribute description |
---|---|---|
1 |
not_apply_to_child_class |
The annotation does not apply when accessing the annotated property of a child class object. |
2 |
transfer_annotation_to_return_value |
If the caller object has an annotation, it will be propagated to the return value. |
3 |
transfer_annotation_to_caller |
When a value is assigned to a property, the annotations of that value are applied to the property object that calls it. |
4 |
return_taint |
The property returns tainted data. |
5 |
sql_injection_target |
Writing tainted data to this property leads to SQL injection (V5608). |
6 |
path_traversal_target |
Writing tainted data to this property leads to a path traversal vulnerability (V5609). |
7 |
xss_injection_target |
Writing tainted data to this property leads to XSS injection (V5610). |
8 |
insecure_deserialization_target |
Writing tainted data to this property leads to insecure deserialization (V5611). |
9 |
command_injection_target |
Writing tainted data to this property leads to command injection (V5616). |
10 |
ssrf_target |
Writing tainted data to this property leads to server-side request forgery (V5618). |
11 |
log_injection_target |
Writing tainted data to this property leads to log injection (V5619). |
12 |
ldapi_injection_target |
Writing tainted data to this property leads to LDAP injection (V5620). |
13 |
xpath_injection_target |
Writing tainted data to this property leads to XPath injection (V5622). |
14 |
open_redirect_target |
Writing tainted data to this property leads to an open redirect vulnerability (V5623). |
15 |
configuration_attack_target |
Writing tainted data to this property leads to a configuration attack (5624). |
16 |
nosql_injection_target |
Writing tainted data to this property leads to NoSQL injection (5627). |
17 |
redos_target |
Writing tainted data to this property leads to a ReDoS (V5626). |
18 |
zipslip_target |
Writing tainted data to this property leads to a Zip Slip vulnerability (V5628). |
Note 1. A parameter annotation object can only reside in the 'params' array, method annotation object or constructor.
Note 2. The parameter annotation object must either contain the 'namespace_name' and 'type_name' fields, or both fields must be absent (or set to null).
The parameter annotation object consists of the following fields:
The mandatory field. It takes a string specifying the name of the namespace that contains the parameter type.
The mandatory field. It takes a string specifying the name of the class where the parameter type is defined.
The optional field. The array of strings that specifies the properties of an entity.
Note. Each taint sink and taint validation attribute have a link to the diagnostic rule.
# |
Attribute name |
Attribute description |
---|---|---|
1 |
ignore_current_and_next |
The current and next parameters will not be considered when selecting the annotation; only the last argument can have this annotation. |
2 |
transfer_annotation_to_return_value |
If the parameter has an annotation, it will be propagated to the method return value. |
3 |
object_creation_infector |
Tainting of a newly created object occurs through this parameter (applicable only for constructors). |
4 |
sql_injection_target |
Passing tainted data to this parameter leads to SQL injection (V5608). |
5 |
sql_injection_validation |
Calling the method resets the SQL injection taint status for this parameter (V5608). |
6 |
path_traversal_target |
Passing tainted data to this parameter leads to a path traversal vulnerability (V5609). |
7 |
path_traversal_validation |
Calling the method resets the path traversal taint status for this parameter (V5609). |
8 |
xss_injection_target |
Passing tainted data to this parameter leads to XSS Injection (V5610). |
9 |
xss_injection_validation |
Calling the method resets the XSS Injection taint status for this parameter (V5610). |
10 |
insecure_deserialization_target |
Passing tainted data to this parameter leads to insecure deserialization (V5611). |
11 |
insecure_deserialization_validation |
Calling the method resets the insecure deserialization taint status for this parameter (V5611). |
12 |
command_injection_target |
Passing tainted data to this parameter leads to command injection (V5616). |
13 |
command_injection_validation |
Calling the method resets the command injection taint status for this parameter (V5616). |
14 |
xml_source_to_parse |
The parameter is the XML source that will be parsed. It can be the XML file itself, the path to the file, the XML file stream, a parser that includes the XML file stream, and so on (V5614, V5615). |
15 |
transfer_xml_settings_to_return |
It passes the XML parser settings from this argument to the return value (V5614, V5615). |
16 |
ssrf_target |
Passing tainted data to this parameter leads to server-side request forgery (V5618). |
17 |
ssrf_validation |
Calling the method resets the server-side request forgery taint status for this parameter (V5618). |
18 |
log_injection_target |
Passing tainted data to this parameter leads to log injection (V5619). |
19 |
log_injection_validation |
Calling the method resets the log injection taint status for this parameter (V5619). |
20 |
ldapi_injection_target |
Passing tainted data to this parameter leads to LDAP injection (V5620). |
21 |
ldapi_injection_validation |
Calling the method resets the LDAP injection taint status for this parameter (V5620). |
22 |
xpath_injection_target |
Passing tainted data to this parameter leads to XPath injection (V5622). |
23 |
xpath_injection_validation |
Calling the method resets the XPath injection taint status for this parameter (V5622). |
24 |
open_redirect_target |
Passing tainted data to this parameter leads to an open redirect vulnerability (V5623). |
25 |
open_redirect_validation |
Calling the method resets the open redirect taint status for this parameter (V5623). |
26 |
configuration_attack_target |
Passing tainted data to this parameter leads to a configuration attack (5624). |
27 |
configuration_attack_validation |
Calling the method resets the configuration attack taint status for this parameter (5624). |
28 |
nosql_injection_target |
Passing tainted data to this parameter leads to NoSQL injection (5627). |
29 |
nosql_injection_validation |
Calling the method resets the NoSQL injection taint status for this parameter (V5627). |
30 |
redos_target |
A string that is parsed using a regular expression. Passing tainted data to this parameter leads to a ReDoS (V5626). |
31 |
redos_validation |
Calling the method resets the ReDoS taint status for this parameter (V5626). |
32 |
zipslip_target |
A string that can be used as a path to extract a file from the archive. Passing tainted data to this parameter leads to a Zip Slip vulnerability (V5628). |
33 |
zipslip_validation |
Calling the method resets the Zip Slip taint status for this parameter (V5628). |
34 |
regex |
The parameter is a regular expression. |
To ignore the type of a parameter, do not specify the 'namespace_name' and 'type_name', or set both fields to null.
JSON Schema is included in the distribution kit or can be accessed via the link.
Look at the method:
namespace MyNamespace
{
public class MyClass
{
public string GetUserInput()
{
....
}
}
}
Assume this method returns user input that may include tainted data. An annotation explaining this for the analyzer would be as follows:
{
"version": 1,
"language": "csharp",
"annotations": [
{
"type": "method",
"namespace_name": "MyNamespace",
"type_name": "MyClass",
"method_name": "GetUserInput",
"returns": {
"attributes": [ "always_taint" ]
}
}
]
}
Look at the constructor:
namespace MyNamespace
{
public class MyClass
{
public MyClass()
{
....
}
}
}
Assume this constructor creates an object that may contain tainted data. An annotation explaining this for the analyzer would be as follows:
{
"version": 1,
"language": "csharp",
"annotations": [
{
"type": "ctor",
"namespace_name": "MyNamespace",
"type_name": "MyClass",
"attributes": [ "create_taint_object" ]
}
]
}
Look at the property:
namespace MyNamespace
{
public class MyClass
{
public string UserInput
{
get
{
....
}
}
}
}
Assume this property returns user input that may include tainted data. An annotation explaining this for the analyzer would be as follows:
{
"version": 1,
"language": "csharp",
"annotations": [
{
"type": "property",
"namespace_name": "MyNamespace",
"type_name": "MyClass",
"property_name": "UserInput",
"attributes": [ "return_taint" ]
}
]
}
Note. A method annotation is provided as an example. We can ignore the parameter type in the same way by not specifying 'type_name' and 'namespace_name' in the parameter annotation.
Here are two overloads of the 'GetUserInput' method:
namespace MyNamespace
{
public class MyClass
{
public string GetUserInput(string str)
{
....
}
public string GetUserInput(int index)
{
....
}
}
}
Assume this method returns user input that may include tainted data, regardless of the parameter type. An annotation explaining this for the analyzer would be as follows:
{
"version": 1,
"language": "csharp",
"annotations": [
{
"type": "method",
"namespace_name": "MyNamespace",
"type_name": "MyClass",
"method_name": "GetUserInput",
"params": [
{ }
],
"returns": {
"attributes": [ "always_taint" ]
}
}
]
}
In this case, there is no annotation for the first parameter. Additionally, when selecting a method annotation, the type of the first parameter is not important. As a result, the parameter annotation is represented by an empty object.
Note. A method annotation is provided as an example. We can ignore the parameter type in the same way by using the 'ignore_current_and_next' annotation.
Here are two overloads of the 'GetUserInput' method:
namespace MyNamespace
{
public class MyClass
{
public string GetUserInput(string str)
{
....
}
public string GetUserInput(string str, bool flag1, bool flag2)
{
....
}
}
}
Assume this method returns user input that may contain tainted data when an overload with one or more parameters. Additionally, if tainted data is passed to the first parameter, it will result in SQL injection. An annotation explaining this for the analyzer would be as follows:
{
"version": 1,
"language": "csharp",
"annotations": [
{
"type": "method",
"namespace_name": "MyNamespace",
"type_name": "MyClass",
"method_name": "GetUserInput",
"params": [
{
"namespace_name": "System",
"type_name": "String",
"attributes": [ "sql_injection_target" ]
},
{
"attributes": [ "ignore_current_and_next" ]
}
],
"returns": {
"attributes": [ "always_taint" ]
}
}
]
}
There is the 'ignore_current_and_next' annotation for the second parameter. It enables us to disregard the number of parameters (including the annotated one) when processing the annotation.