libsast


Namelibsast JSON
Version 2.0.3 PyPI version JSON
download
home_pagehttps://github.com/ajinabraham/libsast
SummaryA generic SAST library built on top of semgrep and regex
upload_time2023-09-01 23:25:31
maintainer
docs_urlNone
authorAjin Abraham
requires_python>=3.8,<4.0
licenseLGPL-3.0-or-later
keywords libsast sast python sast sast api regex sast pattern matcher
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # libsast

Generic SAST for Security Engineers. Powered by regex based pattern matcher and semantic aware [semgrep](https://github.com/returntocorp/semgrep).

Made with ![Love](https://cloud.githubusercontent.com/assets/4301109/16754758/82e3a63c-4813-11e6-9430-6015d98aeaab.png) in India [![Tweet](https://img.shields.io/twitter/url?url=https://github.com/ajinabraham/libsast)](https://twitter.com/intent/tweet/?text=Generic%20SAST%20for%20Security%20Engineers.%20Powered%20by%20regex%20based%20pattern%20matcher%20and%20semantic%20aware%20semgrep%20by%20%40ajinabraham%20%40OpenSecurity_IN&url=https://github.com/ajinabraham/libsast)

[![PyPI version](https://badge.fury.io/py/libsast.svg)](https://badge.fury.io/py/libsast)
[![platform](https://img.shields.io/badge/platform-windows%2Fosx%2Flinux-green.svg)](https://github.com/ajinabraham/libsast)
[![License](https://img.shields.io/:license-lgpl3+-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0.en.html)
[![python](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![Build](https://github.com/ajinabraham/libsast/workflows/Build/badge.svg)](https://github.com/ajinabraham/libsast/actions?query=workflow%3ABuild)

### Support libsast

* **Donate via Paypal:** [![Donate via Paypal](https://user-images.githubusercontent.com/4301109/76471686-c43b0500-63c9-11ea-8225-2a305efb3d87.gif)](https://paypal.me/ajinabraham)
* **Sponsor the Project:** [![Github Sponsors](https://user-images.githubusercontent.com/4301109/95517226-9e410780-098e-11eb-9ef5-7b8c7561d725.png)](https://github.com/sponsors/ajinabraham)

## Install

`pip install libsast`

Pattern Matcher is cross-platform, but Semgrep supports only Mac and Linux.

## Command Line Options

```bash
$ libsast
usage: libsast [-h] [-o OUTPUT] [-p PATTERN_FILE] [-s SGREP_PATTERN_FILE]
               [--sgrep-file-extensions SGREP_FILE_EXTENSIONS [SGREP_FILE_EXTENSIONS ...]]
               [--file-extensions FILE_EXTENSIONS [FILE_EXTENSIONS ...]]
               [--ignore-filenames IGNORE_FILENAMES [IGNORE_FILENAMES ...]]
               [--ignore-extensions IGNORE_EXTENSIONS [IGNORE_EXTENSIONS ...]]
               [--ignore-paths IGNORE_PATHS [IGNORE_PATHS ...]]
               [--show-progress] [-v]
               [path [path ...]]

positional arguments:
  path                  Path can be file(s) or directories

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        Output filename to save JSON report.
  -p PATTERN_FILE, --pattern-file PATTERN_FILE
                        YAML pattern file, directory or url
  -s SGREP_PATTERN_FILE, --sgrep-pattern-file SGREP_PATTERN_FILE
                        sgrep rules directory
  --sgrep-file-extensions SGREP_FILE_EXTENSIONS [SGREP_FILE_EXTENSIONS ...]
                        File extensions that should be scanned with sgrep
  --file-extensions FILE_EXTENSIONS [FILE_EXTENSIONS ...]
                        File extensions that should be scanned with pattern
                        matcher
  --ignore-filenames IGNORE_FILENAMES [IGNORE_FILENAMES ...]
                        File name(s) to ignore
  --ignore-extensions IGNORE_EXTENSIONS [IGNORE_EXTENSIONS ...]
                        File extension(s) to ignore in lower case
  --ignore-paths IGNORE_PATHS [IGNORE_PATHS ...]
                        Path(s) to ignore
  --show-progress       Show scan progress
  -v, --version         Show libsast version
```


## Example Usage

```json
$ libsast -s tests/assets/rules/semantic_grep/ -p tests/assets/rules/pattern_matcher/ tests/assets/files/
{
  "pattern_matcher": {
    "test_regex": {
      "files": [
        {
          "file_path": "tests/assets/files/test_matcher.test",
          "match_lines": [
            28,
            28
          ],
          "match_position": [
            1141,
            1149
          ],
          "match_string": ".close()"
        }
      ],
      "metadata": {}
    },
    "test_regex_and": {
      "files": [
        {
          "file_path": "tests/assets/files/test_matcher.test",
          "match_lines": [
            3,
            3
          ],
          "match_position": [
            52,
            66
          ],
          "match_string": "webkit.WebView"
        },
        {
          "file_path": "tests/assets/files/test_matcher.test",
          "match_lines": [
            7,
            7
          ],
          "match_position": [
            194,
            254
          ],
          "match_string": ".loadUrl(\"file:/\" + Environment.getExternalStorageDirectory("
        }
      ],
      "metadata": {}
    },
    "test_regex_and_not": {
      "files": [
        {
          "file_path": "tests/assets/files/test_matcher.test",
          "match_lines": [
            42,
            42
          ],
          "match_position": [
            1415,
            1424
          ],
          "match_string": "WKWebView"
        },
        {
          "file_path": "tests/assets/files/test_matcher.test",
          "match_lines": [
            40,
            40
          ],
          "match_position": [
            1363,
            1372
          ],
          "match_string": "WKWebView"
        }
      ],
      "metadata": {}
    },
    "test_regex_and_or": {
      "files": [
        {
          "file_path": "tests/assets/files/test_matcher.test",
          "match_lines": [
            50,
            50
          ],
          "match_position": [
            1551,
            1571
          ],
          "match_string": "telephony.SmsManager"
        },
        {
          "file_path": "tests/assets/files/test_matcher.test",
          "match_lines": [
            58,
            58
          ],
          "match_position": [
            1973,
            1988
          ],
          "match_string": "sendTextMessage"
        }
      ],
      "metadata": {}
    },
    "test_regex_multiline_and_metadata": {
      "files": [
        {
          "file_path": "tests/assets/files/test_matcher.test",
          "match_lines": [
            52,
            52
          ],
          "match_position": [
            1586,
            1684
          ],
          "match_string": "public void onRequestPermissionsResult(int requestCode,String permissions[], int[] grantResults) {"
        },
        {
          "file_path": "tests/assets/files/test_matcher.test",
          "match_lines": [
            10,
            11
          ],
          "match_position": [
            297,
            368
          ],
          "match_string": "public static ForgeAccount add(Context context, ForgeAccount account) {"
        }
      ],
      "metadata": {
        "cwe": "CWE-1051 Initialization with Hard-Coded Network Resource Configuration Data",
        "description": "This is a rule to test regex",
        "foo": "bar",
        "masvs": "MSTG-STORAGE-3",
        "owasp-mobile": "M1: Improper Platform Usage",
        "owasp-web": "A10: Insufficient Logging & Monitoring",
        "severity": "info"
      }
    },
    "test_regex_or": {
      "files": [
        {
          "file_path": "tests/assets/files/test_matcher.test",
          "match_lines": [
            26,
            26
          ],
          "match_position": [
            1040,
            1067
          ],
          "match_string": "Context.MODE_WORLD_READABLE"
        }
      ],
      "metadata": {}
    }
  },
  "semantic_grep": {
    "errors": [
      {
        "code": 3,
        "level": "warn",
        "message": "Semgrep Core WARN - Lexical error in file tests/assets/files/test_matcher.test:40\n\tunrecognized symbols: !",
        "path": "tests/assets/files/test_matcher.test",
        "type": "Lexical error"
      },
    ],
    "matches": {
      "boto-client-ip": {
        "files": [
          {
            "file_path": "tests/assets/files/example_file.py",
            "match_lines": [
              4,
              4
            ],
            "match_position": [
              24,
              31
            ],
            "match_string": "c = boto3.client(host='8.8.8.8')"
          }
        ],
        "metadata": {
          "cwe": "CWE-1050 Excessive Platform Resource Consumption within a Loop",
          "description": "boto client using IP address",
          "owasp-web": "A8: Insecure Deserialization",
          "severity": "ERROR"
        }
      }
    }
  }
}
```

## Python API

```python
>>> from libsast import Scanner
>>> options = {'match_rules': '/Users/ajinabraham/Code/njsscan/njsscan/rules/pattern_matcher', 'sgrep_rules': '/Users/ajinabraham/Code/njsscan/njsscan/rules/semantic_grep', 'sgrep_extensions': {'', '.js'}, 'match_extensions': {'.hbs', '.sh', '.ejs', '.toml', '.mustache', '.tmpl', '.jade', '.json', '.ect', '.vue', '.yml', '.hdbs', '.tl', '.html', '.haml', '.dust', '.pug', '.tpl'}, 'ignore_filenames': {'bootstrap.min.js', '.DS_Store', 'bootstrap-tour.js', 'd3.min.js', 'tinymce.js', 'codemirror.js', 'tinymce.min.js', 'react-dom.production.min.js', 'react.js', 'jquery.min.js', 'react.production.min.js', 'codemirror-compressed.js', 'axios.min.js', 'angular.min.js', 'raphael-min.js', 'vue.min.js'}, 'ignore_extensions': {'.7z', '.exe', '.rar', '.zip', '.a', '.o', '.tz'}, 'ignore_paths': {'__MACOSX', 'jquery', 'fixtures', 'node_modules', 'bower_components', 'example', 'spec'}, 'show_progress': False}
>>> paths = ['../njsscan/tests/assets/dot_njsscan/']
>>> scanner = Scanner(options, paths)
>>> scanner.scan()
{'pattern_matcher': {'handlebar_mustache_template': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/ignore_ext.hbs', 'match_string': '{{{html}}}', 'match_position': (52, 62), 'match_lines': (1, 1)}], 'metadata': {'id': 'handlebar_mustache_template', 'description': 'The Handlebar.js/Mustache.js template has an unescaped variable. Untrusted user input passed to this variable results in Cross Site Scripting (XSS).', 'type': 'Regex', 'pattern': '{{{.+}}}|{{[ ]*&[\\w]+.*}}', 'severity': 'ERROR', 'input_case': 'exact', 'cwe': "CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')", 'owasp': 'A1: Injection'}}}, 'semantic_grep': {'matches': {'node_aes_ecb': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/lorem_scan.js', 'match_position': (16, 87), 'match_lines': (14, 14), 'match_string': "let decipher = crypto.createDecipheriv('aes-128-ecb', Buffer.from(ENCRYPTION_KEY), iv);"}], 'metadata': {'owasp': 'A9: Using Components with Known Vulnerabilities', 'cwe': 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm', 'description': 'AES with ECB mode is deterministic in nature and not suitable for encrypting large amount of repetitive data.', 'severity': 'ERROR'}}, 'node_tls_reject': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/skip_dir/skip_me.js', 'match_position': (9, 58), 'match_lines': (9, 9), 'match_string': "        process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';"}, {'file_path': '../njsscan/tests/assets/dot_njsscan/skip_dir/skip_me.js', 'match_position': (9, 55), 'match_lines': (18, 18), 'match_string': '        process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";'}], 'metadata': {'owasp': 'A6: Security Misconfiguration', 'cwe': 'CWE-295: Improper Certificate Validation', 'description': "Setting 'NODE_TLS_REJECT_UNAUTHORIZED' to 0 will allow node server to accept self signed certificates and is not a secure behaviour.", 'severity': 'ERROR'}}, 'node_curl_ssl_verify_disable': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/skip_dir/skip_me.js', 'match_position': (5, 11), 'match_lines': (45, 51), 'match_string': '    curl(url,\n\n        {\n\n            SSL_VERIFYPEER: 0\n\n        },\n\n        function (err) {\n\n            response.end(this.body);\n\n        })'}], 'metadata': {'owasp': 'A6: Security Misconfiguration', 'cwe': 'CWE-599: Missing Validation of OpenSSL Certificate', 'description': 'SSL Certificate verification for node-curl is disabled.', 'severity': 'ERROR'}}, 'regex_injection_dos': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/lorem_scan.js', 'match_position': (5, 37), 'match_lines': (25, 27), 'match_string': '    var key = req.param("key");\n\n    // Regex created from user input\n\n    var re = new RegExp("\\\\b" + key);'}], 'metadata': {'owasp': 'A1: Injection', 'cwe': 'CWE-400: Uncontrolled Resource Consumption', 'description': 'User controlled data in RegExp() can make the application vulnerable to layer 7 DoS.', 'severity': 'ERROR'}}, 'express_xss': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/skip.js', 'match_position': (9, 55), 'match_lines': (7, 10), 'match_string': '        var str = new Buffer(req.cookies.profile, \'base64\').toString();\n\n        var obj = serialize.unserialize(str);\n\n        if (obj.username) {\n\n            res.send("Hello " + escape(obj.username));'}], 'metadata': {'owasp': 'A1: Injection', 'cwe': "CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')", 'description': 'Untrusted User Input in Response will result in Reflected Cross Site Scripting Vulnerability.', 'severity': 'ERROR'}}, 'generic_path_traversal': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/lorem_scan.js', 'match_position': (5, 35), 'match_lines': (36, 37), 'match_string': "    var filePath = path.join(__dirname, '/' + req.query.load);\n\n    fileSystem.readFile(filePath); // ignore: generic_path_traversal"}, {'file_path': '../njsscan/tests/assets/dot_njsscan/lorem_scan.js', 'match_position': (5, 35), 'match_lines': (42, 43), 'match_string': "    var filePath = path.join(__dirname, '/' + req.query.load);\n\n    fileSystem.readFile(filePath); // detect this"}], 'metadata': {'owasp': 'A5: Broken Access Control', 'cwe': 'CWE-23: Relative Path Traversal', 'description': 'Untrusted user input in readFile()/readFileSync() can endup in Directory Traversal Attacks.', 'severity': 'ERROR'}}, 'express_open_redirect': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/lorem_scan.js', 'match_position': (5, 26), 'match_lines': (49, 51), 'match_string': '    var target = req.param("target");\n\n    // BAD: sanitization doesn\'t apply here\n\n    res.redirect(target); //ignore: express_open_redirect'}], 'metadata': {'owasp': 'A1: Injection', 'cwe': "CWE-601: URL Redirection to Untrusted Site ('Open Redirect')", 'description': 'Untrusted user input in redirect() can result in Open Redirect vulnerability.', 'severity': 'ERROR'}}, 'node_deserialize': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/skip.js', 'match_position': (19, 45), 'match_lines': (8, 8), 'match_string': '        var obj = serialize.unserialize(str);'}], 'metadata': {'owasp': 'A8: Insecure Deserialization', 'cwe': 'CWE-502: Deserialization of Untrusted Data', 'description': "User controlled data in 'unserialize()' or 'deserialize()' function can result in Object Injection or Remote Code Injection.", 'severity': 'ERROR'}}}, 'errors': [{'type': 'SourceParseError', 'code': 3, 'short_msg': 'parse error', 'long_msg': 'Could not parse .njsscan as javascript', 'level': 'warn', 'spans': [{'start': {'line': 2, 'col': 20}, 'end': {'line': 2, 'col': 21}, 'source_hash': 'c60298be568bfb1325d92cbb3c0bc1450a25b85bb2e4000bdc3267c05f1c8c73', 'file': '.njsscan', 'context_start': None, 'context_end': None}], 'help': 'If the code appears to be valid, this may be a semgrep bug.'}, {'type': 'SourceParseError', 'code': 3, 'short_msg': 'parse error', 'long_msg': 'Could not parse no_ext_scan as javascript', 'level': 'warn', 'spans': [{'start': {'line': 1, 'col': 3}, 'end': {'line': 1, 'col': 5}, 'source_hash': 'f002e2a715be216987dd1b134e7b9fa6eef28e3caa82dead0109c4cdc489e089', 'file': 'no_ext_scan', 'context_start': None, 'context_end': None}], 'help': 'If the code appears to be valid, this may be a semgrep bug.'}]}}
```

## Write you own Static Analysis tool

With libsast, you can write your own static analysis tools. libsast provides two matching engines:

1. **Pattern Matcher**
2. **Semantic Grep**

### Pattern Matcher

Currently Pattern Matcher supports any language.

Use [Regex 101](https://regex101.com/r/nGbAay/1) to write simple Python Regex rule patterns.

A sample rule looks like

```yaml
- id: test_regex_or
  message: This is a rule to test regex_or
  input_case: exact
  pattern:
  - MODE_WORLD_READABLE|Context\.MODE_WORLD_READABLE
  - openFileOutput\(\s*".+"\s*,\s*1\s*\)
  severity: error
  type: RegexOr
  metadata:
    owasp-web: a1
    reference: http://foo.bar
    foo: Some extra metadata
```
A rule consist of 

* `id` : A unique id for the rule.
* `message`: A description for the rule.
* `input_case`: It can be `exact`, `upper` or `lower`. Data will be converted to lower case/upper case/as it is before comparing with the regex.
* `pattern`: List of patterns depends on `type`.
* `severity`: It can be `error`, `warning` or `info`.
* `type`: Pattern Matcher supports `Regex`, `RegexAnd`, `RegexOr`, `RegexAndOr`, `RegexAndNot`.
* `metadata` (optional): Define your own custom fields that you can use as metadata along with standard mappings. 

```bash
1. Regex - if regex1 in input
2. RegexAnd - if regex1 in input and regex2 in input
3. RegexOr - if regex1 in input or regex2 in input
4. RegexAndOr -  if regex1 in input and (regex2 in input or regex3 in input)
5. RegexAndNot - if regex1 in input and not regex2 in input
```
Example: [Pattern Matcher Rule](https://github.com/ajinabraham/libsast/blob/master/tests/assets/rules/pattern_matcher/patterns.yaml)

Test your pattern matcher rules

`$ libsast -p tests/assets/rules/pattern_matcher/patterns.yaml tests/assets/files/`

#### Inbuilt Standard Mapping Support

Metadata fields also support [libsast standard mapping](https://github.com/ajinabraham/libsast/tree/master/libsast/standards).

For example, the metadata field `owasp-web: a1` will get expanded at runtime as `owasp-web: 'A1: Injection'`. 

*Currently Supports*

* [OWASP Web Top 10](https://github.com/ajinabraham/libsast/blob/master/libsast/standards/owasp_web_top10_2017.yaml)
* [OWASP Mobile Top 10](https://github.com/ajinabraham/libsast/blob/master/libsast/standards/owasp_mobile_top10_2016.yaml)
* [OWASP MASVS](https://github.com/ajinabraham/libsast/blob/master/libsast/standards/owasp_masvs.yaml)
* [CWE](https://github.com/ajinabraham/libsast/blob/master/libsast/standards/cwe.yaml)

### Semantic Grep

Semantic Grep uses [semgrep](https://github.com/returntocorp/semgrep), a fast and syntax-aware semantic code pattern search for many languages: like grep but for code.

Currently it supports Python, Java, JavaScript, Go and C.

Use [semgrep.dev](https://semgrep.dev/vAb) to write semantic grep rule patterns.

A sample rule for Python code looks like

```yaml
rules:
  - id: boto-client-ip
    patterns:
      - pattern-inside: boto3.client(host="...")
      - pattern-regex: '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
    message: "boto client using IP address"
    languages: [python]
    severity: ERROR
    metadata:
      owasp-web: a2
      owasp-mobile: m7
      cwe: cwe-1048
      foo: Some extra metadata
```

See semgrep documentation [here](https://semgrep.dev/docs/writing-rules/rule-syntax/).

Example: [Semantic Grep Rule](https://github.com/ajinabraham/libsast/blob/master/tests/assets/rules/semantic_grep/sgrep.yaml)

Test your semgrep rules

`$ libsast -s tests/assets/rules/semantic_grep/sgrep.yaml tests/assets/files/`

## Realworld Implementations

* [njsscan](https://github.com/ajinabraham/njsscan) SAST is built with libsast pattern matcher and semantic grep.
* [nodejsscan](https://github.com/ajinabraham/nodejsscan) nodejsscan is a static security code scanner for Node.js applications.
* [MobSF](https://mobsf.github.io/Mobile-Security-Framework-MobSF/) Static Code Analyzer for Android and iOS mobile applications.
* [mobsfscan](https://github.com/MobSF/mobsfscan) mobsfscan is a static security code scanner for Mobile applications built for Android (Java, Kotlin) & iOS (Swift, Objective C).

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ajinabraham/libsast",
    "name": "libsast",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "libsast,SAST,Python SAST,SAST API,Regex SAST,Pattern Matcher",
    "author": "Ajin Abraham",
    "author_email": "ajin@opensecurity.in",
    "download_url": "https://files.pythonhosted.org/packages/7e/2b/5618b1f778448ab099e26ee8684e3f87adfcda8b7d75b0551113ad949082/libsast-2.0.3.tar.gz",
    "platform": null,
    "description": "# libsast\n\nGeneric SAST for Security Engineers. Powered by regex based pattern matcher and semantic aware [semgrep](https://github.com/returntocorp/semgrep).\n\nMade with ![Love](https://cloud.githubusercontent.com/assets/4301109/16754758/82e3a63c-4813-11e6-9430-6015d98aeaab.png) in India [![Tweet](https://img.shields.io/twitter/url?url=https://github.com/ajinabraham/libsast)](https://twitter.com/intent/tweet/?text=Generic%20SAST%20for%20Security%20Engineers.%20Powered%20by%20regex%20based%20pattern%20matcher%20and%20semantic%20aware%20semgrep%20by%20%40ajinabraham%20%40OpenSecurity_IN&url=https://github.com/ajinabraham/libsast)\n\n[![PyPI version](https://badge.fury.io/py/libsast.svg)](https://badge.fury.io/py/libsast)\n[![platform](https://img.shields.io/badge/platform-windows%2Fosx%2Flinux-green.svg)](https://github.com/ajinabraham/libsast)\n[![License](https://img.shields.io/:license-lgpl3+-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0.en.html)\n[![python](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)\n[![Build](https://github.com/ajinabraham/libsast/workflows/Build/badge.svg)](https://github.com/ajinabraham/libsast/actions?query=workflow%3ABuild)\n\n### Support libsast\n\n* **Donate via Paypal:** [![Donate via Paypal](https://user-images.githubusercontent.com/4301109/76471686-c43b0500-63c9-11ea-8225-2a305efb3d87.gif)](https://paypal.me/ajinabraham)\n* **Sponsor the Project:** [![Github Sponsors](https://user-images.githubusercontent.com/4301109/95517226-9e410780-098e-11eb-9ef5-7b8c7561d725.png)](https://github.com/sponsors/ajinabraham)\n\n## Install\n\n`pip install libsast`\n\nPattern Matcher is cross-platform, but Semgrep supports only Mac and Linux.\n\n## Command Line Options\n\n```bash\n$ libsast\nusage: libsast [-h] [-o OUTPUT] [-p PATTERN_FILE] [-s SGREP_PATTERN_FILE]\n               [--sgrep-file-extensions SGREP_FILE_EXTENSIONS [SGREP_FILE_EXTENSIONS ...]]\n               [--file-extensions FILE_EXTENSIONS [FILE_EXTENSIONS ...]]\n               [--ignore-filenames IGNORE_FILENAMES [IGNORE_FILENAMES ...]]\n               [--ignore-extensions IGNORE_EXTENSIONS [IGNORE_EXTENSIONS ...]]\n               [--ignore-paths IGNORE_PATHS [IGNORE_PATHS ...]]\n               [--show-progress] [-v]\n               [path [path ...]]\n\npositional arguments:\n  path                  Path can be file(s) or directories\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -o OUTPUT, --output OUTPUT\n                        Output filename to save JSON report.\n  -p PATTERN_FILE, --pattern-file PATTERN_FILE\n                        YAML pattern file, directory or url\n  -s SGREP_PATTERN_FILE, --sgrep-pattern-file SGREP_PATTERN_FILE\n                        sgrep rules directory\n  --sgrep-file-extensions SGREP_FILE_EXTENSIONS [SGREP_FILE_EXTENSIONS ...]\n                        File extensions that should be scanned with sgrep\n  --file-extensions FILE_EXTENSIONS [FILE_EXTENSIONS ...]\n                        File extensions that should be scanned with pattern\n                        matcher\n  --ignore-filenames IGNORE_FILENAMES [IGNORE_FILENAMES ...]\n                        File name(s) to ignore\n  --ignore-extensions IGNORE_EXTENSIONS [IGNORE_EXTENSIONS ...]\n                        File extension(s) to ignore in lower case\n  --ignore-paths IGNORE_PATHS [IGNORE_PATHS ...]\n                        Path(s) to ignore\n  --show-progress       Show scan progress\n  -v, --version         Show libsast version\n```\n\n\n## Example Usage\n\n```json\n$ libsast -s tests/assets/rules/semantic_grep/ -p tests/assets/rules/pattern_matcher/ tests/assets/files/\n{\n  \"pattern_matcher\": {\n    \"test_regex\": {\n      \"files\": [\n        {\n          \"file_path\": \"tests/assets/files/test_matcher.test\",\n          \"match_lines\": [\n            28,\n            28\n          ],\n          \"match_position\": [\n            1141,\n            1149\n          ],\n          \"match_string\": \".close()\"\n        }\n      ],\n      \"metadata\": {}\n    },\n    \"test_regex_and\": {\n      \"files\": [\n        {\n          \"file_path\": \"tests/assets/files/test_matcher.test\",\n          \"match_lines\": [\n            3,\n            3\n          ],\n          \"match_position\": [\n            52,\n            66\n          ],\n          \"match_string\": \"webkit.WebView\"\n        },\n        {\n          \"file_path\": \"tests/assets/files/test_matcher.test\",\n          \"match_lines\": [\n            7,\n            7\n          ],\n          \"match_position\": [\n            194,\n            254\n          ],\n          \"match_string\": \".loadUrl(\\\"file:/\\\" + Environment.getExternalStorageDirectory(\"\n        }\n      ],\n      \"metadata\": {}\n    },\n    \"test_regex_and_not\": {\n      \"files\": [\n        {\n          \"file_path\": \"tests/assets/files/test_matcher.test\",\n          \"match_lines\": [\n            42,\n            42\n          ],\n          \"match_position\": [\n            1415,\n            1424\n          ],\n          \"match_string\": \"WKWebView\"\n        },\n        {\n          \"file_path\": \"tests/assets/files/test_matcher.test\",\n          \"match_lines\": [\n            40,\n            40\n          ],\n          \"match_position\": [\n            1363,\n            1372\n          ],\n          \"match_string\": \"WKWebView\"\n        }\n      ],\n      \"metadata\": {}\n    },\n    \"test_regex_and_or\": {\n      \"files\": [\n        {\n          \"file_path\": \"tests/assets/files/test_matcher.test\",\n          \"match_lines\": [\n            50,\n            50\n          ],\n          \"match_position\": [\n            1551,\n            1571\n          ],\n          \"match_string\": \"telephony.SmsManager\"\n        },\n        {\n          \"file_path\": \"tests/assets/files/test_matcher.test\",\n          \"match_lines\": [\n            58,\n            58\n          ],\n          \"match_position\": [\n            1973,\n            1988\n          ],\n          \"match_string\": \"sendTextMessage\"\n        }\n      ],\n      \"metadata\": {}\n    },\n    \"test_regex_multiline_and_metadata\": {\n      \"files\": [\n        {\n          \"file_path\": \"tests/assets/files/test_matcher.test\",\n          \"match_lines\": [\n            52,\n            52\n          ],\n          \"match_position\": [\n            1586,\n            1684\n          ],\n          \"match_string\": \"public void onRequestPermissionsResult(int requestCode,String permissions[], int[] grantResults) {\"\n        },\n        {\n          \"file_path\": \"tests/assets/files/test_matcher.test\",\n          \"match_lines\": [\n            10,\n            11\n          ],\n          \"match_position\": [\n            297,\n            368\n          ],\n          \"match_string\": \"public static ForgeAccount add(Context context, ForgeAccount account) {\"\n        }\n      ],\n      \"metadata\": {\n        \"cwe\": \"CWE-1051 Initialization with Hard-Coded Network Resource Configuration Data\",\n        \"description\": \"This is a rule to test regex\",\n        \"foo\": \"bar\",\n        \"masvs\": \"MSTG-STORAGE-3\",\n        \"owasp-mobile\": \"M1: Improper Platform Usage\",\n        \"owasp-web\": \"A10: Insufficient Logging & Monitoring\",\n        \"severity\": \"info\"\n      }\n    },\n    \"test_regex_or\": {\n      \"files\": [\n        {\n          \"file_path\": \"tests/assets/files/test_matcher.test\",\n          \"match_lines\": [\n            26,\n            26\n          ],\n          \"match_position\": [\n            1040,\n            1067\n          ],\n          \"match_string\": \"Context.MODE_WORLD_READABLE\"\n        }\n      ],\n      \"metadata\": {}\n    }\n  },\n  \"semantic_grep\": {\n    \"errors\": [\n      {\n        \"code\": 3,\n        \"level\": \"warn\",\n        \"message\": \"Semgrep Core WARN - Lexical error in file tests/assets/files/test_matcher.test:40\\n\\tunrecognized symbols: !\",\n        \"path\": \"tests/assets/files/test_matcher.test\",\n        \"type\": \"Lexical error\"\n      },\n    ],\n    \"matches\": {\n      \"boto-client-ip\": {\n        \"files\": [\n          {\n            \"file_path\": \"tests/assets/files/example_file.py\",\n            \"match_lines\": [\n              4,\n              4\n            ],\n            \"match_position\": [\n              24,\n              31\n            ],\n            \"match_string\": \"c = boto3.client(host='8.8.8.8')\"\n          }\n        ],\n        \"metadata\": {\n          \"cwe\": \"CWE-1050 Excessive Platform Resource Consumption within a Loop\",\n          \"description\": \"boto client using IP address\",\n          \"owasp-web\": \"A8: Insecure Deserialization\",\n          \"severity\": \"ERROR\"\n        }\n      }\n    }\n  }\n}\n```\n\n## Python API\n\n```python\n>>> from libsast import Scanner\n>>> options = {'match_rules': '/Users/ajinabraham/Code/njsscan/njsscan/rules/pattern_matcher', 'sgrep_rules': '/Users/ajinabraham/Code/njsscan/njsscan/rules/semantic_grep', 'sgrep_extensions': {'', '.js'}, 'match_extensions': {'.hbs', '.sh', '.ejs', '.toml', '.mustache', '.tmpl', '.jade', '.json', '.ect', '.vue', '.yml', '.hdbs', '.tl', '.html', '.haml', '.dust', '.pug', '.tpl'}, 'ignore_filenames': {'bootstrap.min.js', '.DS_Store', 'bootstrap-tour.js', 'd3.min.js', 'tinymce.js', 'codemirror.js', 'tinymce.min.js', 'react-dom.production.min.js', 'react.js', 'jquery.min.js', 'react.production.min.js', 'codemirror-compressed.js', 'axios.min.js', 'angular.min.js', 'raphael-min.js', 'vue.min.js'}, 'ignore_extensions': {'.7z', '.exe', '.rar', '.zip', '.a', '.o', '.tz'}, 'ignore_paths': {'__MACOSX', 'jquery', 'fixtures', 'node_modules', 'bower_components', 'example', 'spec'}, 'show_progress': False}\n>>> paths = ['../njsscan/tests/assets/dot_njsscan/']\n>>> scanner = Scanner(options, paths)\n>>> scanner.scan()\n{'pattern_matcher': {'handlebar_mustache_template': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/ignore_ext.hbs', 'match_string': '{{{html}}}', 'match_position': (52, 62), 'match_lines': (1, 1)}], 'metadata': {'id': 'handlebar_mustache_template', 'description': 'The Handlebar.js/Mustache.js template has an unescaped variable. Untrusted user input passed to this variable results in Cross Site Scripting (XSS).', 'type': 'Regex', 'pattern': '{{{.+}}}|{{[ ]*&[\\\\w]+.*}}', 'severity': 'ERROR', 'input_case': 'exact', 'cwe': \"CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')\", 'owasp': 'A1: Injection'}}}, 'semantic_grep': {'matches': {'node_aes_ecb': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/lorem_scan.js', 'match_position': (16, 87), 'match_lines': (14, 14), 'match_string': \"let decipher = crypto.createDecipheriv('aes-128-ecb', Buffer.from(ENCRYPTION_KEY), iv);\"}], 'metadata': {'owasp': 'A9: Using Components with Known Vulnerabilities', 'cwe': 'CWE-327: Use of a Broken or Risky Cryptographic Algorithm', 'description': 'AES with ECB mode is deterministic in nature and not suitable for encrypting large amount of repetitive data.', 'severity': 'ERROR'}}, 'node_tls_reject': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/skip_dir/skip_me.js', 'match_position': (9, 58), 'match_lines': (9, 9), 'match_string': \"        process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';\"}, {'file_path': '../njsscan/tests/assets/dot_njsscan/skip_dir/skip_me.js', 'match_position': (9, 55), 'match_lines': (18, 18), 'match_string': '        process.env.NODE_TLS_REJECT_UNAUTHORIZED = \"0\";'}], 'metadata': {'owasp': 'A6: Security Misconfiguration', 'cwe': 'CWE-295: Improper Certificate Validation', 'description': \"Setting 'NODE_TLS_REJECT_UNAUTHORIZED' to 0 will allow node server to accept self signed certificates and is not a secure behaviour.\", 'severity': 'ERROR'}}, 'node_curl_ssl_verify_disable': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/skip_dir/skip_me.js', 'match_position': (5, 11), 'match_lines': (45, 51), 'match_string': '    curl(url,\\n\\n        {\\n\\n            SSL_VERIFYPEER: 0\\n\\n        },\\n\\n        function (err) {\\n\\n            response.end(this.body);\\n\\n        })'}], 'metadata': {'owasp': 'A6: Security Misconfiguration', 'cwe': 'CWE-599: Missing Validation of OpenSSL Certificate', 'description': 'SSL Certificate verification for node-curl is disabled.', 'severity': 'ERROR'}}, 'regex_injection_dos': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/lorem_scan.js', 'match_position': (5, 37), 'match_lines': (25, 27), 'match_string': '    var key = req.param(\"key\");\\n\\n    // Regex created from user input\\n\\n    var re = new RegExp(\"\\\\\\\\b\" + key);'}], 'metadata': {'owasp': 'A1: Injection', 'cwe': 'CWE-400: Uncontrolled Resource Consumption', 'description': 'User controlled data in RegExp() can make the application vulnerable to layer 7 DoS.', 'severity': 'ERROR'}}, 'express_xss': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/skip.js', 'match_position': (9, 55), 'match_lines': (7, 10), 'match_string': '        var str = new Buffer(req.cookies.profile, \\'base64\\').toString();\\n\\n        var obj = serialize.unserialize(str);\\n\\n        if (obj.username) {\\n\\n            res.send(\"Hello \" + escape(obj.username));'}], 'metadata': {'owasp': 'A1: Injection', 'cwe': \"CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')\", 'description': 'Untrusted User Input in Response will result in Reflected Cross Site Scripting Vulnerability.', 'severity': 'ERROR'}}, 'generic_path_traversal': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/lorem_scan.js', 'match_position': (5, 35), 'match_lines': (36, 37), 'match_string': \"    var filePath = path.join(__dirname, '/' + req.query.load);\\n\\n    fileSystem.readFile(filePath); // ignore: generic_path_traversal\"}, {'file_path': '../njsscan/tests/assets/dot_njsscan/lorem_scan.js', 'match_position': (5, 35), 'match_lines': (42, 43), 'match_string': \"    var filePath = path.join(__dirname, '/' + req.query.load);\\n\\n    fileSystem.readFile(filePath); // detect this\"}], 'metadata': {'owasp': 'A5: Broken Access Control', 'cwe': 'CWE-23: Relative Path Traversal', 'description': 'Untrusted user input in readFile()/readFileSync() can endup in Directory Traversal Attacks.', 'severity': 'ERROR'}}, 'express_open_redirect': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/lorem_scan.js', 'match_position': (5, 26), 'match_lines': (49, 51), 'match_string': '    var target = req.param(\"target\");\\n\\n    // BAD: sanitization doesn\\'t apply here\\n\\n    res.redirect(target); //ignore: express_open_redirect'}], 'metadata': {'owasp': 'A1: Injection', 'cwe': \"CWE-601: URL Redirection to Untrusted Site ('Open Redirect')\", 'description': 'Untrusted user input in redirect() can result in Open Redirect vulnerability.', 'severity': 'ERROR'}}, 'node_deserialize': {'files': [{'file_path': '../njsscan/tests/assets/dot_njsscan/skip.js', 'match_position': (19, 45), 'match_lines': (8, 8), 'match_string': '        var obj = serialize.unserialize(str);'}], 'metadata': {'owasp': 'A8: Insecure Deserialization', 'cwe': 'CWE-502: Deserialization of Untrusted Data', 'description': \"User controlled data in 'unserialize()' or 'deserialize()' function can result in Object Injection or Remote Code Injection.\", 'severity': 'ERROR'}}}, 'errors': [{'type': 'SourceParseError', 'code': 3, 'short_msg': 'parse error', 'long_msg': 'Could not parse .njsscan as javascript', 'level': 'warn', 'spans': [{'start': {'line': 2, 'col': 20}, 'end': {'line': 2, 'col': 21}, 'source_hash': 'c60298be568bfb1325d92cbb3c0bc1450a25b85bb2e4000bdc3267c05f1c8c73', 'file': '.njsscan', 'context_start': None, 'context_end': None}], 'help': 'If the code appears to be valid, this may be a semgrep bug.'}, {'type': 'SourceParseError', 'code': 3, 'short_msg': 'parse error', 'long_msg': 'Could not parse no_ext_scan as javascript', 'level': 'warn', 'spans': [{'start': {'line': 1, 'col': 3}, 'end': {'line': 1, 'col': 5}, 'source_hash': 'f002e2a715be216987dd1b134e7b9fa6eef28e3caa82dead0109c4cdc489e089', 'file': 'no_ext_scan', 'context_start': None, 'context_end': None}], 'help': 'If the code appears to be valid, this may be a semgrep bug.'}]}}\n```\n\n## Write you own Static Analysis tool\n\nWith libsast, you can write your own static analysis tools. libsast provides two matching engines:\n\n1. **Pattern Matcher**\n2. **Semantic Grep**\n\n### Pattern Matcher\n\nCurrently Pattern Matcher supports any language.\n\nUse [Regex 101](https://regex101.com/r/nGbAay/1) to write simple Python Regex rule patterns.\n\nA sample rule looks like\n\n```yaml\n- id: test_regex_or\n  message: This is a rule to test regex_or\n  input_case: exact\n  pattern:\n  - MODE_WORLD_READABLE|Context\\.MODE_WORLD_READABLE\n  - openFileOutput\\(\\s*\".+\"\\s*,\\s*1\\s*\\)\n  severity: error\n  type: RegexOr\n  metadata:\n    owasp-web: a1\n    reference: http://foo.bar\n    foo: Some extra metadata\n```\nA rule consist of \n\n* `id` : A unique id for the rule.\n* `message`: A description for the rule.\n* `input_case`: It can be `exact`, `upper` or `lower`. Data will be converted to lower case/upper case/as it is before comparing with the regex.\n* `pattern`: List of patterns depends on `type`.\n* `severity`: It can be `error`, `warning` or `info`.\n* `type`: Pattern Matcher supports `Regex`, `RegexAnd`, `RegexOr`, `RegexAndOr`, `RegexAndNot`.\n* `metadata` (optional): Define your own custom fields that you can use as metadata along with standard mappings. \n\n```bash\n1. Regex - if regex1 in input\n2. RegexAnd - if regex1 in input and regex2 in input\n3. RegexOr - if regex1 in input or regex2 in input\n4. RegexAndOr -  if regex1 in input and (regex2 in input or regex3 in input)\n5. RegexAndNot - if regex1 in input and not regex2 in input\n```\nExample: [Pattern Matcher Rule](https://github.com/ajinabraham/libsast/blob/master/tests/assets/rules/pattern_matcher/patterns.yaml)\n\nTest your pattern matcher rules\n\n`$ libsast -p tests/assets/rules/pattern_matcher/patterns.yaml tests/assets/files/`\n\n#### Inbuilt Standard Mapping Support\n\nMetadata fields also support [libsast standard mapping](https://github.com/ajinabraham/libsast/tree/master/libsast/standards).\n\nFor example, the metadata field `owasp-web: a1` will get expanded at runtime as `owasp-web: 'A1: Injection'`. \n\n*Currently Supports*\n\n* [OWASP Web Top 10](https://github.com/ajinabraham/libsast/blob/master/libsast/standards/owasp_web_top10_2017.yaml)\n* [OWASP Mobile Top 10](https://github.com/ajinabraham/libsast/blob/master/libsast/standards/owasp_mobile_top10_2016.yaml)\n* [OWASP MASVS](https://github.com/ajinabraham/libsast/blob/master/libsast/standards/owasp_masvs.yaml)\n* [CWE](https://github.com/ajinabraham/libsast/blob/master/libsast/standards/cwe.yaml)\n\n### Semantic Grep\n\nSemantic Grep uses [semgrep](https://github.com/returntocorp/semgrep), a fast and syntax-aware semantic code pattern search for many languages: like grep but for code.\n\nCurrently it supports Python, Java, JavaScript, Go and C.\n\nUse [semgrep.dev](https://semgrep.dev/vAb) to write semantic grep rule patterns.\n\nA sample rule for Python code looks like\n\n```yaml\nrules:\n  - id: boto-client-ip\n    patterns:\n      - pattern-inside: boto3.client(host=\"...\")\n      - pattern-regex: '\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}'\n    message: \"boto client using IP address\"\n    languages: [python]\n    severity: ERROR\n    metadata:\n      owasp-web: a2\n      owasp-mobile: m7\n      cwe: cwe-1048\n      foo: Some extra metadata\n```\n\nSee semgrep documentation [here](https://semgrep.dev/docs/writing-rules/rule-syntax/).\n\nExample: [Semantic Grep Rule](https://github.com/ajinabraham/libsast/blob/master/tests/assets/rules/semantic_grep/sgrep.yaml)\n\nTest your semgrep rules\n\n`$ libsast -s tests/assets/rules/semantic_grep/sgrep.yaml tests/assets/files/`\n\n## Realworld Implementations\n\n* [njsscan](https://github.com/ajinabraham/njsscan) SAST is built with libsast pattern matcher and semantic grep.\n* [nodejsscan](https://github.com/ajinabraham/nodejsscan) nodejsscan is a static security code scanner for Node.js applications.\n* [MobSF](https://mobsf.github.io/Mobile-Security-Framework-MobSF/) Static Code Analyzer for Android and iOS mobile applications.\n* [mobsfscan](https://github.com/MobSF/mobsfscan) mobsfscan is a static security code scanner for Mobile applications built for Android (Java, Kotlin) & iOS (Swift, Objective C).\n",
    "bugtrack_url": null,
    "license": "LGPL-3.0-or-later",
    "summary": "A generic SAST library built on top of semgrep and regex",
    "version": "2.0.3",
    "project_urls": {
        "Bug Tracker": "https://github.com/ajinabraham/libsast/issues",
        "Documentation": "https://github.com/ajinabraham/libsast/blob/master/README.md",
        "Homepage": "https://github.com/ajinabraham/libsast",
        "Repository": "https://github.com/ajinabraham/libsast"
    },
    "split_keywords": [
        "libsast",
        "sast",
        "python sast",
        "sast api",
        "regex sast",
        "pattern matcher"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "fe8b7777960387270448de0667c158481fa823546ec5d9de43339811b09426a8",
                "md5": "7919f637e6e87615643dd5fe4203e028",
                "sha256": "2c70f9d94ff95c3302f0a038f05f381eb6a55c2acaeda717c5c1551006a74a2f"
            },
            "downloads": -1,
            "filename": "libsast-2.0.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "7919f637e6e87615643dd5fe4203e028",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 35751,
            "upload_time": "2023-09-01T23:25:30",
            "upload_time_iso_8601": "2023-09-01T23:25:30.158177Z",
            "url": "https://files.pythonhosted.org/packages/fe/8b/7777960387270448de0667c158481fa823546ec5d9de43339811b09426a8/libsast-2.0.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7e2b5618b1f778448ab099e26ee8684e3f87adfcda8b7d75b0551113ad949082",
                "md5": "d7b98560f8fc930187898ca9b4cd65eb",
                "sha256": "8bf0ef3ad31864fcdcf073840c5875e9a2fcdb9f895617141f30c953e361577d"
            },
            "downloads": -1,
            "filename": "libsast-2.0.3.tar.gz",
            "has_sig": false,
            "md5_digest": "d7b98560f8fc930187898ca9b4cd65eb",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 35349,
            "upload_time": "2023-09-01T23:25:31",
            "upload_time_iso_8601": "2023-09-01T23:25:31.928431Z",
            "url": "https://files.pythonhosted.org/packages/7e/2b/5618b1f778448ab099e26ee8684e3f87adfcda8b7d75b0551113ad949082/libsast-2.0.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-09-01 23:25:31",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ajinabraham",
    "github_project": "libsast",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "libsast"
}
        
Elapsed time: 0.11327s