Annotating C# entities in JSON format
- Structure of the annotation file
- Annotations for taint analysis
- Method annotations
- Constructor annotations
- Property annotations
- Parameter annotations
- JSON Schema
- Examples:
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.
Structure of the annotation file
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:
- method annotations
- constructor annotations
- property annotations.
Annotations for taint analysis
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:
- V5608 — SQL injection
- V5609 — Path traversal vulnerability
- V5610 — XSS vulnerability
- V5611 — Insecure deserialization vulnerability
- V5614 — XXE vulnerability
- V5615 — XEE vulnerability
- V5616 — Command injection
- V5618 — Server-side request forgery
- V5619 — Log injection
- V5620 — LDAP injection
- V5622 — XPath injection
- V5623 — Open redirect vulnerability
- V5624 — Configuration vulnerability
- V5626 — ReDoS vulnerability
- V5627 — NoSQL injection
- V5628 — Zip Slip vulnerability.
How taint annotations operate
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.
Method annotations
Note: The method annotation object must contain at least one optional field.
The method annotation object consists of the following fields:
The "type" field
The mandatory field. It takes a string with the method value.
The "namespace_name" field
The mandatory field. It takes a string specifying the name of the namespace that contains the method.
The "type_name" field
The mandatory field. It takes a string specifying the name of the class where the method is defined.
The "method_name" field
The mandatory field. It takes a string with the name of the method.
The "attributes" field
The optional field. The array of strings that specifies the properties of an entity.
Possible method attributes
# |
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 "params" field
The optional field. This field is described in the "Parameter annotations" section.
The "returns" field
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 "namespace_name" field
The optional field. It takes a string specifying the name of the namespace that contains the type of the method return value.
The "type_name" field
The optional field. It takes a string specifying the name of the class where the type of the method return value is defined.
The "attributes" field
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. |
Constructor annotations
Note. The constructor annotation object must include at least one optional field.
The constructor annotation object consists of the following fields:
The "type" field
The mandatory field. It takes a string with the ctor value.
The "namespace_name" field
The mandatory field. It takes a string specifying the name of the namespace that contains the constructor.
The "type_name" field
The mandatory field. It takes a string specifying the name of the class where the constructor is defined.
The "attributes" field
The optional field. The array of strings that specifies the properties of an entity.
Possible attributes for constructors
# |
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 "params" field
The optional field. This field is described in the "Parameter annotations" section.
Property annotations
The property annotation object consists of the following fields:
The "type" field
The mandatory field. It takes a string with the property value.
The "namespace_name" field
The mandatory field. It takes a string specifying the name of the namespace that contains the property.
The "type_name" field
The mandatory field. It takes a string specifying the name of the class where the property is defined.
The "attributes" field
The optional field. The array of strings that specifies the properties of an entity.
Possible property attributes
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). |
Parameter annotations
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 "namespace_name" field
The mandatory field. It takes a string specifying the name of the namespace that contains the parameter type.
The "type_name" field
The mandatory field. It takes a string specifying the name of the class where the parameter type is defined.
The "attributes" field
The optional field. The array of strings that specifies the properties of an entity.
Possible parameter attributes
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. |
Ignoring the parameter type
To ignore the type of a parameter, do not specify the 'namespace_name' and 'type_name', or set both fields to null.
JSON Schema
JSON Schema is included in the distribution kit or can be accessed via the link.
Examples:
Method annotation
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" ]
}
}
]
}
Constructor annotation
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" ]
}
]
}
Property annotation
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" ]
}
]
}
Annotation for a method/constructor where the parameter type is disregarded
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.
Annotation for a method or constructor that disregards certain parameters
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.