cast

int i = 128;
byte b = (byte) i;

A type cast expression

Configuration options

type

Checks the type that is casted to.

search:
 cast:
   type: int
 byte x = 1;
 int y = (int) x;

operand

Checks the value that is being cast.

search:
 cast:
   operand:
     type: byte
 byte x = 1;
 int y = (int) x;

Generic Expression Configuration options

type

Checks the result type of the expression.

search:
  expression:
    type: "String"
 public void doSomething() {
     this.do(
         "example"
     );
 }

See also

The examples above use shorthands, see type target for more advanced configurations

value

Sensei will try to determine what the value of the expression would be at runtime. This is particularly powerful when analyzing string expressions.

Sensei can determine the actual value of the string, even when a String has been built using StringBuilders, StringBuffers or by concatenation with other strings. The analysis also takes into account if the String cannot be determined at compile time. To do so, a special character will be added to the determined value.

The determined value will be compared against the string target.

search:
  methodcall:
    name: "log"
    args:
      1: # configured using the expression target
        value:
          contains: "bank account"
 public void doSomething(String banknumber) {

     StringBuilder builder = new StringBuilder();
     builder.append("User with bank account ");
     builder.append(banknumber);
     builder.append(" has logged in");

     this.log(builder.toString());
 }

Note

This example uses an advanced configuration for the value option.

integerValue

When the expression results as an integer value, this can be used to search for specific values. The value will be checked using the integer target.

containsUntrustedInput

This will invoke the same analysis that has to be performed for the value option. Afterward, it will check if this determined value contains untrusted input. Sensei considers everything that cannot be determined at compile time as untrusted. These include mutable fields, parameters, and other non-constant variables.

search:
  methodcall:
    name: "query"
    args:
      1: # configured using the expression target
        containsUntrustedInput: true
 public void getUser(String name) {
     String sql = "SELECT * FROM users WHERE name = '" + name "'";
     Database.query(sql);
 }

When false, this analysis can also be used to test if an expression only contains constants.

trustNonTextualsByDefault

Since concatenating numbers, booleans or other non-textual primitives with strings, entails fewer security implications, Sensei has chosen to trust them by default. However, this behavior can be changed via this property.

'trustNonTextualsByDefault' should only be used in combination with containsUntrustedInput.

search:
  methodcall:
    name: "query"
    args:
      1: # configured using the expression target
        containsUntrustedInput: true
        trustNonTextualsByDefault: false
 public void getUser(int id) {
     String sql = "SELECT * FROM users WHERE id = " + id;
     Database.query(sql);
 }

trustedSources

As explained in value, Sensei considers any value that is unknown at compile time as untrusted. However, it's possible to override this behavior and choose which elements are considered secure. This option allows users to tell Sensei that their sanitization routines are secure.

This property should only be used in combination with containsUntrustedInput.

search:
  methodcall:
    name: "query"
    args:
      1: # configured using the expression target
        containsUntrustedInput: true
        trustedSources:
        - methodcall:
          name: "htmlEncode"
public void getUser(int id) {
    String content = "<html><p>Hello " + htmlEncode(name) + "</p></html>";
    Response.sendHTML(content);
}

Note

This property is configured as a list of Targets

referenceTo

Checks if the expression is a reference.

Generic Configuration options

The following options are generic and available for every target.

anyOf

Similar to the logical operator OR: one or more descendant options should match.

search:
  <target>:
    anyOf:
    - name: "illegal"
    - name: "alsoIllegal"

allOf

Similar to the logical operator AND: all descendant options must match.

search:
  <target>:
    allOf:
    - annotation: "HttpPost"
    - annotation: "AllowUnAuthorized"

with

The only purpose to use this field is to make the recipe easier to read. It provides no additional functionality.

search:
  <target>:
    with:
      annotation: "HttpPost"

not, without

Works as the logical operator NOT. It will negate the result of the descendant options. Sensei presents the user with both options. They display the same behavior, but certain scenarios tend to read better using without.

search:
  <target>:
    not:
      annotation: "HttpPost"
search:
  <target>:
    without:
      annotation: "HttpPost"

in

Performs a structural search, this option is mainly used to narrow down recipes. Examples of this would be to only analyze and mark code inside a certain class or method that has a specific annotation. However, we haven't limited this option to only support these two scenarios. More advanced configuration can be achieved.

search:
  <target>:
    in:
      class:
        name:
          contains: "Controller"
search:
  <target>:
    in:
      method:
        annotation:
          type: "HttpPost"

label

Labels do not modify the behavior of searching elements, but they allow addressing a specific element in a quick fix.

search:
  element:
    tagName: inner
    attribute:
      name: data
    in:
      element:
        label: outerelement

availableFixes:
- name: add the 'type' attribute on the outer element
  actions:
  - add:
      attribute:
        name: type
        value: '"unsafe"'
      target: label:outerelement
- <outer>
+ <outer type="unsafe">
      <inner data="test"/>
  </outer>