Skip to content

Semgrep

Semgrep

Auto Testing:

semgrep --metrics=off --config=auto $(pwd)
#semgrep --metrics=off --config "p/security-audit" --config "p/owasp-top-ten" --config "p/auto" --config "p/mobsfscan" --config "p/java" v1.0.0+32548-jadx/sources/

Manual Config Testing

Manual Code Testing

Master Command:

semgrep -c "p/ci" -c "p/clientside-js" -c "p/django" -c "p/docker" -c "p/docker-compose" -c "p/dockerfile" -c "p/eslint-plugin-security" -c "p/expressjs" -c "p/flask" -c "p/insecure-transport" -c "p/javascript" -c "p/jwt" -c "p/kubernetes" -c "p/lockfiles" -c "p/nginx" -c "p/nodejs" -c "p/nodejsscan" -c "p/phpcs-security-audit" -c "p/python" -c "p/r2c" -c "p/r2c-ci" -c "p/react" -c "p/sql-injection" -c "p/terraform" -c "p/trailofbits" -c "p/typescript" -c "p/xss" -c "p/gitlab-bandit" -c "p/command-injection" -c "p/secrets" -c "p/owasp-top-ten" -c "p/r2c-security-audit" -c "p/gitlab-eslint" $(pwd)

Configurations:

semgrep --config "p/r2c" --config "p/r2c-ci" --config "p/docker-compose" --config "p/dockerfile" --config "p/kubernetes" --config "p/nginx" --config "p/terraform" --config "p/lockfiles" $(pwd)

Testing an Javascript Codebase:

semgrep --config "p/ci" --config "p/r2c" --config "p/r2c-ci"  --config "p/eslint-plugin-security" --config "gitlab-eslint" --config "cleintside-js" --config "p/typescript" --config "p/javascript" --config "p/react" $(pwd)

Testing an Nodejs Codebase:

semgrep --config "p/ci" --config "p/typescript"  --config "p/sql-injection" --config "p/eslint-plugin-security" --config "p/gitlab-eslint" --config "p/nodejsscan" --config "p/expressjs" --config "p/nodejs" --config "p/react"

Testing an Rust Codebase:

semgrep --config "p/ci"
# Runs Semgrep rules from the /home/semgrep-rules directory
#semgrep -f /home/semgrep-rules

Testing an Android Codebase:

semgrep --config "p/ci" --config "p/mobsfscan" --config "p/koltin"

Testing an iOS Codebase:

semgrep --config "p/ci"

Testing a Java Codebase:

semgrep --config "p/ci" --config "p/sql-injection" --config "p/java

Testing an Python Codebase:

semgrep --config "p/ci" --config "p/gitlab-bandit" --config "p/trailofbits" --config "p/python" --config "p/django" --config "p/flask"

Testing an PHP Codebase:

semgrep --config "p/ci" --config "p/phpcs-security-audit"

Testing an Go Codebase:

semgrep --config "p/ci" --config "p/semgrep-go" --config "trailofbits" --config "golang"

Testing an Ruby Codebase:

semgrep --config "p/ci" --config "ruby"

Testing a C Codebase:


Testing a C++ Codebase:


Making Rules

Simple Rules

Match Inside Function:

def $FUNC(...):
  ...
  requests.$METHOD(...)

Match Variable used later:

$FD = open($FILENAME, 'r', ...)
...
$FD.$METHOD(...)

Match Arguments:

open($FILENAME, $RW, ...)
requests.get("...", timeout=$SEC, verify=True)

Advanced Rules

Semgrep OR:

rules:
  - id: use-string-equals
    message: In Java, do not use == with strings. Use String.equals() instead.
    pattern-either:
      - pattern: if ($X == "...") ...
      - pattern: if ("..." == $X) ...

Semgrep Limit Match:

rules:
  - id: subprocess-call
    patterns:
    - pattern: subprocess.call(...)
    # This says never match if first argument is a string
    - pattern-not: subprocess.call("...", ...)

Check Pattern within Pattern:

rules:
  - id: http-responsewriter-write
    patterns:
    - pattern-inside: |
        func $FUNC(...) {
          ...
        }
    - pattern: $WRITER.Write(...)

Check Pattern that does not have line:

rules:
  - id: secure-flag-not-set
    patterns:
    - pattern: $RESPONSE.addCookie($COOKIE);
    - pattern-not-inside: |
        $COOKIE.setSecure(true);
        ...

Source Sync Rules

Sample Source and Sync Taint:

rules:
  - id: tmw24-net-http-path-traversal-taint
  message: Path Traversal Vulnerability
  severity: ERROR
  languages:
    - go
  mode: taint
  pattern-sources:
    - patterns:
      - pattern: $REQ.$FIELD
      - metavarable-type:
        metavarable: $REQ
        type: |
          *http.Request
      - metavarable-regex:
          metavariable: $FIELD
          regex: ^(basicAuth|Body|Cookie)
  pattern-sinks:
    - pattern: os.Open(...)

Sample Source and Sync Taint with Sanitizers:

rules:
  - id: tmw24-express-taint
  message: Express XSS Vuln
  severity: ERROR
  languages:
    - javascript
  mode: taint
  pattern-sources:
    - patterns:
      - pattern: |
        $APP.$METHOD($PATH, function($REQ, $RES)) {
          ...
        })
      - focus-metavariable: $REQ
  pattern-sanitizers:
    - pattern: cleanXSS(...)
    - pattern: path.basename(...)
  pattern-sinks:
    - pattern: res.sendFile(...)
    - pattern: res.write(...)

Taint with Propagators:

rules:
  - id: tmw24-formated sqlstring
  message: Java SQL injection Vuln
  severity: ERROR
  languages:
    - java
  mode: taint
  pattern-sources:
    - pattern: (HttpServletRequest $REQ)
  pattern-propagators:
    - pattern: (myStringList $S).append($X)
      from: $X
      to: $S
  pattern-sinks:
    - patterns: 
        - pattern: $Q.$SQLQUERY(...)
        - metavarable-regex: 
          metavarible: $SQLQUERY
          regex: execute|execureQuery

Taint with labels:

rules:
  - id: tm24-ruameL-deseriauzation-probIem
  message: "Insecure deserialization (catted pickling in pytnon) is when
user-controllable data Is deseriaUzed by an application. "
  severity: ERROR
  languages:
    - python
  mode: taint
  pattern-sources:
    - label: USER_INPUT
      pattern: self-path
    - label: TYP_UNSAFE
      pattern: ruyaml.yaml.YAML(..., typ="unsafe", ...)
    - label: TOOO
      pattern: TOOO
  pattern-sinks:
    - requires: USER_INPUT and TYP_UNSAFE
      pattern: $YML.load(...)

Language Rules


Solidity Rules
C Rules
Mobile Rules
XSS Rules
Android Rules
Android Rules
Mobile Rules

PHP

SQLI Examples

Example Rule:

rules:
- id: test
  languages:
    - php
  severity: ERROR
  message: test
  patterns:
    - pattern-inside: |
        function $FUNC(...,$PAR,...) {
          ...
        }     
    - pattern: $AAAA . <... $PAR ...> . $BBBB;

Check for name of varable matches regex:

rules:
  - id: use-decimalfield-for-money
    patterns:
    - pattern-inside: |
        class $M(...):
          ...
    - pattern: $F = django.db.models.FloatField(...)
    - metavariable-regex:
        metavariable: '$F'
        regex: '.*(price|fee|salary).*'
    message: Found a FloatField used for variable $F. Use DecimalField for currency fields to avoid float-rounding errors.
    languages: [python]
    severity: ERROR
  

Inverse Regex Match:

rules:
  - id: invalid-base-url
    message:
      The 'baseURL' is invalid. This may cause links to not work if deployed. Include the scheme (e.g., https://).
    patterns:
      - pattern: baseURL = "..."
      - pattern-not-regex: http(s)?://.*
    languages: [generic]

Integer Condition:

rules:
  - id: use-of-weak-rsa-key
    message: RSA keys should be at least 2048 bits based on NIST recommendation.
    patterns:
      - pattern: |
          KeyPairGenerator $KEY = $G.getInstance("RSA");
          ...
          $KEY.initialize($BITS);
      - metavariable-comparison:
          comparison: $BITS < 2048
          metavariable: $BITS
    languages: [java]
    severity: WARNING

Whitelist Options for variables:

rules:
  - id: disallow-old-tls-versions2
    message: Detected an old tls version
    patterns:
      - pattern: |
          $CONST = require('crypto');
          ...
          $OPTIONS = $OPTS;
          ...
          https.createServer($OPTIONS, ...);
      - metavariable-pattern:
          metavariable: $OPTS
          patterns:
            - pattern-not: >
                {secureOptions: $CONST.SSL_OP_NO_SSLv2 | $CONST.SSL_OP_NO_SSLv3
                | $CONST.SSL_OP_NO_TLSv1}
    languages:
      - javascript
    severity: WARNING

Make a Fix to the code:

rules:
  - id: use-sys-exit
    pattern: exit($X)
    message: |
      Use "sys.exit" over the python shell "exit" built-in. "exit" is not available on all Python implementations.
    languages: [python]
    severity: WARNING
    fix: sys.exit($X)
  

Multi Pattern Match:

rules:
  - id: user-eval
    patterns:
    - pattern-inside: |
        def $F(...):
          ...
    - pattern-either:
      - pattern: eval(..., request.$W.get(...), ...)
      - pattern: |
          $V = request.$W.get(...)
          ...
          eval(..., $V, ...)
      - pattern: eval(..., request.$W(...), ...)
      - pattern: |
          $V = request.$W(...)
          ...
          eval(..., $V, ...)
      - pattern: eval(..., request.$W[...], ...)
      - pattern: |
          $V = request.$W[...]
          ...
          eval(..., $V, ...)