├── .gitignore ├── CONTRIBUTING.md ├── Default (Linux).sublime-keymap ├── Default (OSX).sublime-keymap ├── Default (Windows).sublime-keymap ├── DevSkim-Common ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── guidance │ ├── DS101155.md │ ├── DS101159.md │ ├── DS104456.md │ ├── DS106864.md │ ├── DS108330.md │ ├── DS108647.md │ ├── DS109501.md │ ├── DS109733.md │ ├── DS111237.md │ ├── DS112266.md │ ├── DS113286.md │ ├── DS113853.md │ ├── DS114352.md │ ├── DS117838.md │ ├── DS121708.md │ ├── DS126858.md │ ├── DS127101.md │ ├── DS128921.md │ ├── DS132779.md │ ├── DS132780.md │ ├── DS132790.md │ ├── DS134411.md │ ├── DS137038.md │ ├── DS141863.md │ ├── DS144436.md │ ├── DS148264.md │ ├── DS149435.md │ ├── DS154189.md │ ├── DS156431.md │ ├── DS161085.md │ ├── DS162092.md │ ├── DS165348.md │ ├── DS165746.md │ ├── DS168931.md │ ├── DS169125.md │ ├── DS169126.md │ ├── DS173237.md │ ├── DS175862.md │ ├── DS176209.md │ ├── DS179924.md │ ├── DS181021.md │ ├── DS181731.md │ ├── DS181865.md │ ├── DS182720.md │ ├── DS184626.md │ ├── DS185832.md │ ├── DS187371.md │ ├── DS188250.md │ ├── DS189424.md │ ├── DS191340.md │ ├── DS196098.md │ ├── DS197800.md │ └── DS197836.md └── rules │ └── default │ └── security │ ├── api │ ├── dangerous_api.json │ ├── misused_api.json │ ├── suggested_api.json │ └── tests │ │ ├── DS179924.test │ │ └── DS181731.test │ ├── attack_surface │ └── outbound_network.json │ ├── control_flow │ ├── dynamic_execution.json │ ├── format_string.json │ └── permission_evelation.json │ ├── cryptography │ ├── certificate.json │ ├── ciphers.json │ ├── general.json │ ├── hash_algorithm.json │ ├── initialization_vector.json │ ├── protocol.json │ ├── random.json │ ├── tests │ │ ├── DS106864.test │ │ ├── DS109501.test │ │ ├── DS130821.test │ │ ├── DS134411.test │ │ ├── DS148264.test │ │ ├── DS156431.test │ │ ├── DS159369.test │ │ ├── DS169126.test │ │ └── DS182720.test │ ├── underhanded.json │ └── weak_cipher_modes.json │ ├── frameworks │ ├── aspnet5.json │ └── php.json │ ├── hygiene │ ├── localhost.json │ ├── tests │ │ └── DS162092.test │ └── todo.json │ ├── manualreview │ └── dynamiccode.json │ ├── privacy │ ├── device_restrictions.json │ └── secrets.json │ ├── storage │ └── secure_storage.json │ ├── vulnerable_libraries │ └── tests │ │ ├── DS378900.test │ │ ├── DS378901.test │ │ └── DS378902.test │ └── xml │ ├── external_entities.json │ └── tests │ └── DS132779.test ├── DevSkim.py ├── DevSkim.sublime-commands ├── DevSkim.sublime-project ├── DevSkim.sublime-settings ├── DevSkimConditionals.py ├── LICENSE.txt ├── Main.sublime-menu ├── README.md ├── css ├── dark.css └── default.css ├── doc └── DevSkim-Sublime-Demo-1.gif ├── messages.json └── messages ├── 0.1.0.txt ├── 0.2.0.txt ├── 0.2.1.txt └── install.txt /.gitignore: -------------------------------------------------------------------------------- 1 | DevSkim-Common/* 2 | __common/* -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing Issues 2 | 3 | ### Before Submitting an Issue 4 | 5 | First, please do a search of [open issues](https://github.com/Microsoft/DevSkim-Sublime-Plugin/issues) to see 6 | if the issue or feature request has already been filed. Use this 7 | [query](https://github.com/Microsoft/DevSkim-Sublime-Plugin/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc) 8 | to search for the most popular feature requests. 9 | 10 | If you find your issue already exists, make relevant comments and add your 11 | [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment. 12 | 13 | 👍 - upvote 14 | 15 | 👎 - downvote 16 | 17 | The DevSkim project is distributed across multiple repositories, so try to file the issue against the correct repository: 18 | 19 | * [DevSkim-SublimeText-Plugin](https://github.com/Microsoft/DevSkim-Sublime-Plugin/) - Sublime Text Plugin 20 | * [DevSkim-VSCode-Plugin](https://github.com/Microsoft/DevSkim-VSCode-Plugin/) - Visual Studio Code Plugin 21 | * [DevSkim-VisualStudio-Plugin](https://github.com/Microsoft/DevSkim-VisualStudio-Plugin/) - Visual Studio Plugin 22 | * [DevSkim](https://github.com/Microsoft/DevSkim/) - Common Rules and Guidance 23 | 24 | If your issue is a question then please ask the question on [Stack Overflow](https://stackoverflow.com/questions/tagged/devskim) 25 | using the tag `devskim`. 26 | 27 | If you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below. 28 | 29 | ## Writing Good Bug Reports and Feature Requests 30 | 31 | File a single issue per problem and feature request. 32 | 33 | * Do not enumerate multiple bugs or feature requests in the same issue. 34 | * Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes. 35 | * Turning on `debug` mode can be helpful in providing more information (Package Settings | DevSkim | Settings - User | set `"debug": true`) 36 | 37 | The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix. Therefore: 38 | 39 | * Provide reproducible steps, what the result of the steps was, and what you would have expected. 40 | * A description of what you expect to happen 41 | * Code that demonstrates the issue, when providing a code snippet also include it in source and not only as an image 42 | * Version of DevSkim and Sublime Text 43 | * Errors in the Sublime Text Console (View | Show Console) 44 | 45 | Don't feel bad if we can't reproduce the issue and ask for more information! 46 | 47 | ## Contributing Fixes 48 | 49 | If you are interested in fixing issues and contributing directly to the code base, 50 | please see the document [How to Contribute](https://github.com/Microsoft/DevSkim-Sublime-Plugin/wiki/How-to-Contribute). 51 | 52 | -------------------------------------------------------------------------------- /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "keys": [ "ctrl+shift+g" ], 4 | "command": "dev_skim_analyze", 5 | "context": [ 6 | ] 7 | } 8 | ] -------------------------------------------------------------------------------- /Default (OSX).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "keys": [ "ctrl+shift+g" ], 4 | "command": "dev_skim_analyze", 5 | "context": [ 6 | ] 7 | } 8 | ] -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "keys": [ "ctrl+shift+g" ], 4 | "command": "dev_skim_analyze", 5 | "context": [ 6 | ] 7 | } 8 | ] -------------------------------------------------------------------------------- /DevSkim-Common/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing Issues 2 | 3 | ### Before Submitting an Issue 4 | 5 | First, please do a search of [open issues](https://github.com/Microsoft/DevSkim-Rules/issues) to see if the issue or feature request has already been filed. 6 | 7 | If you find your issue already exists, make relevant comments and add your 8 | [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment. 9 | 10 | 👍 - upvote 11 | 12 | 👎 - downvote 13 | 14 | The DevSkim project is distributed across multiple repositories, so try to file the issue against the correct repository: 15 | 16 | * [DevSkim-SublimePlugin](https://github.com/Microsoft/DevSkim-Sublime-Plugin/) - Sublime Text Plugin 17 | * [DevSkim-VSCode](https://github.com/Microsoft/DevSkim-VSCode-Plugin/) - VSCode Plugin 18 | * [DevSkim-VisualStudio](https://github.com/Microsoft/DevSkim-VisualStudio-Plugin/) - Visual Studio Plugin 19 | * [DevSkim-Rules](https://github.com/Microsoft/DevSkim-Rules/) - Common Rules 20 | 21 | If your issue is a question then please ask the question on [Stack Overflow](https://stackoverflow.com/questions/tagged/devskim) 22 | using the tag `devskim`. 23 | 24 | If you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below. 25 | 26 | ## Writing Good Bug Reports and Feature Requests 27 | 28 | File a single issue per problem and feature request. 29 | 30 | * Do not enumerate multiple bugs or feature requests in the same issue. 31 | * Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes. 32 | * Turning on `debug` mode can be helpful in providing more information (Package Settings | DevSkim | Settings - User | set `"debug": true`) 33 | 34 | The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix. Therefore: 35 | 36 | * Provide reproducible steps, what the result of the steps was, and what you would have expected. 37 | * A description of what you expect to happen 38 | * Code that demonstrates the issue, when providing a code snippet also include it in source and not only as an image 39 | * Version of DevSkim and Sublime Text 40 | * Errors in the Sublime Text Console (View | Show Console) 41 | 42 | Don't feel bad if we can't reproduce the issue and ask for more information! 43 | 44 | ## Contributing Fixes 45 | 46 | If you are interested in fixing issues and contributing directly to the code base, 47 | please see the document [How to Contribute](https://github.com/Microsoft/DevSkim/wiki/How-to-Contribute). 48 | 49 | -------------------------------------------------------------------------------- /DevSkim-Common/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Microsoft Corporation 2 | 3 | All rights reserved. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 8 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 9 | modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 17 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /DevSkim-Common/README.md: -------------------------------------------------------------------------------- 1 | # DevSkim 2 | 3 | DevSkim is a framework of IDE extensions and Language analyzers that provide inline security analysis 4 | in the dev environment as the developer writes code. It is designed to work with multiple IDEs 5 | (VS, VS Code, Sublime Text, etc.), and has a flexible rule model that supports multiple programming 6 | languages. The idea is to give the developer notification as they are introducing a security 7 | vulnerability in order to fix the issue at the point of introduction, and to help build awareness 8 | for the developer. 9 | 10 | ### PUBLIC PREVIEW 11 | 12 | DevSkim is currently in *public preview*. We're looking forward to working with the community 13 | to improve both the scanning engines and rules over the next few months, and welcome your feedback 14 | and contributions! 15 | 16 | ### Repositories 17 | 18 | DevSkim consists of multiple repositories (one for the rules, and one per plugin): 19 | 20 | * [DevSkim](https://github.com/Microsoft/DevSkim/) - This repository, plus common rules and guidance 21 | * [DevSkim-VisualStudio-Extension](https://github.com/Microsoft/DevSkim-VisualStudio-Extension/) - Visual Studio Extension 22 | * [DevSkim-Sublime-Plugin](https://github.com/Microsoft/DevSkim-Sublime-Plugin/) - Sublime Text Plugin 23 | * [DevSkim-VSCode-Plugin](https://github.com/Microsoft/DevSkim-VSCode-Plugin/) - VS Code Plugin 24 | 25 | Please access those projects to download the plugin, open issues, or contribute content. 26 | 27 | ### Writing Rules 28 | 29 | Please see [Writing Rules](https://github.com/Microsoft/DevSkim/wiki/Writing-Rules) for 30 | instructions on how to author new rules. 31 | 32 | ### Reporting Issues 33 | 34 | Please see [CONTRIBUTING](https://github.com/Microsoft/DevSkim/blob/master/CONTRIBUTING.md) for 35 | information on reporting issues and contributing code. 36 | 37 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS101155.md: -------------------------------------------------------------------------------- 1 | ## Disabled certificate validation 2 | 3 | ### Summary 4 | Extend default certificate validation, but do not disable or override default rules. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS101159.md: -------------------------------------------------------------------------------- 1 | ## Initializing Security Context 2 | 3 | ### Summary 4 | SecurityContext initialization, look here for cryptography functions. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS104456.md: -------------------------------------------------------------------------------- 1 | ## Use of restricted functions. 2 | 3 | ### Summary 4 | Use of restricted functions. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS106864.md: -------------------------------------------------------------------------------- 1 | ## Do not use the DES symmetric block cipher. 2 | 3 | ### Summary 4 | The DES cipher was found, which is widely considered to be broken. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS108330.md: -------------------------------------------------------------------------------- 1 | ## Banned C function detected (strncat) 2 | 3 | ### Summary 4 | strncat adds the null terminator at character 'n + 1', rather than at the nth character. this frequently leads to the null terminator being added in the memory adjacent to the destination buffer, rather than in the destination buffer. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS108647.md: -------------------------------------------------------------------------------- 1 | ## Do not use broken/weak cryptographic hash algorithms 2 | 3 | ### Summary 4 | Avoid using broken or weak hash algorithms. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS109501.md: -------------------------------------------------------------------------------- 1 | ## Do not use the 3DES symmetric block cipher. 2 | 3 | ### Summary 4 | The 3DES cipher was found, which is only secure if three independent keys are used. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS109733.md: -------------------------------------------------------------------------------- 1 | ## Source implementation of a weak/broken cryptography hash function 2 | 3 | ### Summary 4 | An implementation of a weak/broken hash function was found in source code. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS111237.md: -------------------------------------------------------------------------------- 1 | ## Banned C function detected (strncpy) 2 | 3 | ### Summary 4 | strncpy is dangerous, as if the source contains 'n' or more characters, it will not null terminate the destination. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS112266.md: -------------------------------------------------------------------------------- 1 | ## ProtectedData used without additional entropy 2 | 3 | ### Summary 4 | The ProtectedData class should be used with additional entropy to reduce the risk of other application calling DPAPI to access the data. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS113286.md: -------------------------------------------------------------------------------- 1 | ## Do not include user-input directoy in format strings 2 | 3 | ### Summary 4 | Do not create NSString objects using a user-provided format string, as this could lead to a security vulnerability. https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS113853.md: -------------------------------------------------------------------------------- 1 | ## Do not set a custom execution policy. 2 | 3 | ### Summary 4 | The Set-ExecutionPolicy cmdlet has been used to dynamically change the permissions available to PowerShell. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS114352.md: -------------------------------------------------------------------------------- 1 | ## Encryption Marked 'Optional' 2 | 3 | ### Summary 4 | Optional encryption or integrity checking can be dangerous. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS117838.md: -------------------------------------------------------------------------------- 1 | ## Do not store tokens or keys in source code. 2 | 3 | ### Summary 4 | A token or key was found in source code. If this represents a secret, it should be moved somewhere else. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS121708.md: -------------------------------------------------------------------------------- 1 | ## Problematic C function detected (memcpy) 2 | 3 | ### Summary 4 | There are a number of conditions in which memcpy can introduce a vulnerability (mismatched buffer sizes, null pointers, etc.). More secure alternitives perform additional validation of the source and destination buffer 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS126858.md: -------------------------------------------------------------------------------- 1 | ## Weak/Broken Hash Algorithm 2 | 3 | ### Summary 4 | A weak or broken hash algorithm was detected. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS127101.md: -------------------------------------------------------------------------------- 1 | ## Hardcoding TLS protocol version 2 | 3 | ### Summary 4 | It's usually better to rely on the operating system configuration, rather than hardcoding a specific list of protocols. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS128921.md: -------------------------------------------------------------------------------- 1 | ## Hardcoded initialization vector size 2 | 3 | ### Summary 4 | An initialization vector was created to a static size, rather than determining it based on the encryption algorithm used. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS132779.md: -------------------------------------------------------------------------------- 1 | ## Do not enable external entity resolution. 2 | 3 | ### Summary 4 | Do not enable external entity resolution. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS132780.md: -------------------------------------------------------------------------------- 1 | ## Do not enable external entity resolution. 2 | 3 | ### Summary 4 | Do not enable external entity resolution. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS132790.md: -------------------------------------------------------------------------------- 1 | ## Do not enable external entity resolution. 2 | 3 | ### Summary 4 | Do not enable external entity resolution. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS134411.md: -------------------------------------------------------------------------------- 1 | ## Disabled certificate validation 2 | 3 | ### Summary 4 | Extend default certificate validation, but do not disable or override default rules. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS137038.md: -------------------------------------------------------------------------------- 1 | ## Notice: Outbound HTTP Connection 2 | 3 | ### Summary 4 | Inbound HTTP 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS141863.md: -------------------------------------------------------------------------------- 1 | ## Banned C function detected (strcat) 2 | 3 | ### Summary 4 | If the combination of strings is larger than the destination buffer, strcat will cbuffer overflow the destination buffer 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS144436.md: -------------------------------------------------------------------------------- 1 | ## Do not use outdated SSL/TLS protocols 2 | 3 | ### Summary 4 | It's usually better to rely on the operating system configuration, rather than hardcoding a specific SecurityProtocolType. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS148264.md: -------------------------------------------------------------------------------- 1 | ## Do not use weak/non-cryptographic random number generators 2 | 3 | ### Summary 4 | Use cryptographic random numbers generators for anything even close to a security function. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS149435.md: -------------------------------------------------------------------------------- 1 | ## Do not seed randomness based on system time or a static value. 2 | 3 | ### Summary 4 | Passing a predicable value to srand() is very insecure and should be avoided. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS154189.md: -------------------------------------------------------------------------------- 1 | ## Banned C function detected 2 | 3 | ### Summary 4 | These functions are historically error-prone and have been associated with a significant number of vulnerabilities. Most of these functions have safer alternatives, such as replacing 'strcpy' with 'strlcpy' or 'strcpy_s'. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS156431.md: -------------------------------------------------------------------------------- 1 | ## Do not use the RC2 symmetric block cipher. 2 | 3 | ### Summary 4 | The RC2 cipher was found, which is considered to be broken. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS161085.md: -------------------------------------------------------------------------------- 1 | ## Problematic C function detected (malloc) 2 | 3 | ### Summary 4 | If the value provided to malloc is the result of unsafe integer math, it can result in an exploitable condition. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS162092.md: -------------------------------------------------------------------------------- 1 | ## Do not leave debug code in production 2 | 3 | ### Summary 4 | Accessing localhost could indicate debug code, or could hinder scaling. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS165348.md: -------------------------------------------------------------------------------- 1 | ## Do not attempt to access device UDID 2 | 3 | ### Summary 4 | Access to the device UDID (via [[UIDevice currentDevice] uniqueIdentifier]) is deprecated as of iOS 5 and should not be used or relied upon. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS165746.md: -------------------------------------------------------------------------------- 1 | ## Do not execute user-provided JavaScript 2 | 3 | ### Summary 4 | This line of code shows the dynamic evaluation of JavaScript, sourced from a string. It's important that this string not contain unsanitized user-supplied data, as it could be a vector for a cross-site scripting (XSS) attack. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS168931.md: -------------------------------------------------------------------------------- 1 | ## Do not use broken/weak cryptographic hash algorithms 2 | 3 | ### Summary 4 | A potentially weak hashing algorithm was used. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS169125.md: -------------------------------------------------------------------------------- 1 | ## Do not use outdated SSL/TLS protocols 2 | 3 | ### Summary 4 | An outdated SSL/TLS protocol version is specified. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS169126.md: -------------------------------------------------------------------------------- 1 | ## An Outdated or Banned SSL/TLS Protocol is Used 2 | 3 | ### Summary 4 | An Outdated or Banned SSL/TLS Protocol is Used 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS173237.md: -------------------------------------------------------------------------------- 1 | ## Do not store tokens or keys in source code. 2 | 3 | ### Summary 4 | A token or key was found in source code. If this represents a secret, it should be moved somewhere else. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS175862.md: -------------------------------------------------------------------------------- 1 | ## Do not use the mcrypt module, use OpenSSL instead. 2 | 3 | ### Summary 4 | The PHP mcrypt module is based on libmcrypt, which has been abanonded since 2007. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS176209.md: -------------------------------------------------------------------------------- 1 | ## Suspicious comment 2 | 3 | ### Summary 4 | A "TODO" or similar was left in source code, possibly indicating incomplete functionality 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS179924.md: -------------------------------------------------------------------------------- 1 | ## Do not copy a FILE object (CERT FIO38-C) 2 | 3 | ### Summary 4 | The CERT Secure Coding Standard recommends that FILE objects not be copied. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS181021.md: -------------------------------------------------------------------------------- 1 | ## Banned C function detected (gets) 2 | 3 | ### Summary 4 | gets will read in as many bytes as are provided, regardless of the size of buffer recieving the bytes. This allows for conditions that cause a buffer overlow in the destination buffer. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS181731.md: -------------------------------------------------------------------------------- 1 | ## Don't pass user input to this function 2 | 3 | ### Summary 4 | Don't pass user input to this function. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS181865.md: -------------------------------------------------------------------------------- 1 | ## Disabled certificate validation 2 | 3 | ### Summary 4 | Extend default certificate validation, but do not disable or override default rules. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS182720.md: -------------------------------------------------------------------------------- 1 | ## A weak cipher mode of operation was used 2 | 3 | ### Summary 4 | A potentially weak cipher mode of operation was used. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS184626.md: -------------------------------------------------------------------------------- 1 | ## All Controllers Should Derive From Controller. 2 | 3 | ### Summary 4 | All Controllers Should Derive From Controller. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS185832.md: -------------------------------------------------------------------------------- 1 | ## Banned C function detected (strcpy) 2 | 3 | ### Summary 4 | strcpy is frequently dangerous, as it will cause a buffer overflow if the source is larger than the destination. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS187371.md: -------------------------------------------------------------------------------- 1 | ## A weak cipher mode of operation was used 2 | 3 | ### Summary 4 | A potentially weak cipher mode of operation was used. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS188250.md: -------------------------------------------------------------------------------- 1 | ## Missing initialization vector 2 | 3 | ### Summary 4 | The mcrypt_encrypt function was used without an initialization vector. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS189424.md: -------------------------------------------------------------------------------- 1 | ## Review eval for untrusted data 2 | 3 | ### Summary 4 | If untrusted data is included in an eval statement it can allow an attacker to inject code into the application. Each usage of eval should be reviewed to ensure that no data generated outside of the application (from HTML requests, shared databases, etc.) can find its way into the eval statement 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS191340.md: -------------------------------------------------------------------------------- 1 | ## Do not store sensitive data in NSUserDefaults. 2 | 3 | ### Summary 4 | Do not store sensitive data in NSUserDefaults. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS196098.md: -------------------------------------------------------------------------------- 1 | ## Do not use broken/weak cryptographic hash algorithms 2 | 3 | ### Summary 4 | Avoid using broken or weak hash algorithms. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS197800.md: -------------------------------------------------------------------------------- 1 | ## Weak/Broken Hash Algorithm 2 | 3 | ### Summary 4 | A weak or broken hash algorithm was detected. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/guidance/DS197836.md: -------------------------------------------------------------------------------- 1 | ## Do not take the hash of low-entropy content. 2 | 3 | ### Summary 4 | Taking a hash of a time value is suspicious, as there is insufficient entropy to protect against brute-force attacks. 5 | 6 | ### Details 7 | TO DO - put more details of problem and solution here 8 | 9 | ### Severity Considerations 10 | TO DO - put more details on the severity of the issue here. Generally how big of a problem is this, and what makes it more or less of a problem? 11 | 12 | -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/api/dangerous_api.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Banned C function detected", 4 | "id": "DS154189", 5 | "description": "These functions are historically error-prone and have been associated with a significant number of vulnerabilities. Most of these functions have safer alternatives, such as replacing 'strcpy' with 'strlcpy' or 'strcpy_s'.", 6 | "recommendation": "", 7 | "applies_to": [ 8 | "c", 9 | "cpp", 10 | "objective-c" 11 | ], 12 | "tags": [ 13 | "API.DangerousAPI.BannedFunction" 14 | ], 15 | "severity": "moderate", 16 | "_comment": "", 17 | "rule_info": "DS154189.md", 18 | "patterns": [ 19 | { 20 | "pattern": "(sprintf|_getts|_getws|_snprintf|_sntprintf|_snwprintf|_stprintf|_tcsat|_tcscpy|_tcslen|_tcsncpy|_vsnprintf|_vsntprintf|_vsnwprintf|_vstprintf|alloca|asctime|atof|atoi|atoll|bsearch|ctime|fopen|fprintf|freopen|fscanf|fwprintf|fwscanf|getenv|getwd|gmtime|localtime|lstrcat|lstrcpy|mbsrtowcs|mbstowcs|memmove|mktemp|printf|qsort|rewind|scanf|setbuf|sscanf|strcatbuff|strerror|strtok|swprintf|swscanf|tmpnam|vfprintf|vfscanf|vfwscanf|vprintf|vscanf|vsnprintf|vsprintf|vsscanf|vswprintf|vswscanf|vwprintf|vwscanf|wcrtomb|wcrtombs|wcscat|wcscpy|wcslen|wcsncat|wcsncpy|wcsrtombs|wcstok|wctomb|wmemcpy|wmemmove|wnsprintf|wprintf|wscanf|wsprintf|wvnsprintf|wvsprintf)", 21 | "type": "regex-word", 22 | "scopes": [ 23 | "code" 24 | ], 25 | "_comment": "" 26 | } 27 | ] 28 | }, 29 | { 30 | "name": "Banned C function detected (strcpy)", 31 | "id": "DS185832", 32 | "description": "strcpy is frequently dangerous, as it will cause a buffer overflow if the source is larger than the destination.", 33 | "recommendation": "Use strcpy_s or strlcpy if possible. If no safe function is viable, strcpy/strncpy should be proceeded by conditional checks to verify tha that the source string will fit in the destination with a null termnator.", 34 | "overrides": [ 35 | "DS154189" 36 | ], 37 | "applies_to": [ 38 | "c", 39 | "cpp", 40 | "objective-c" 41 | ], 42 | "tags": [ 43 | "API.DangerousAPI.BannedFunction" 44 | ], 45 | "severity": "important", 46 | "_comment": "", 47 | "rule_info": "DS185832.md", 48 | "patterns": [ 49 | { 50 | "pattern": "\\bstrcpy\\s*\\(([^,]+),([^,]+)\\)", 51 | "type": "regex", 52 | "scopes": [ 53 | "code" 54 | ], 55 | "_comment": "" 56 | } 57 | ], 58 | "fix_its": [ 59 | { 60 | "name": "Change to strcpy_s (Recommended for VC++)", 61 | "type": "regex-replace", 62 | "_comment": "", 63 | "replacement": "strcpy_s($1, , $2)", 64 | "pattern": { 65 | "pattern": "\\bstrcpy\\s*\\(([^,]+),([^,]+)\\)", 66 | "type": "regex", 67 | "scopes": [ 68 | "code" 69 | ], 70 | "_comment": "" 71 | } 72 | }, 73 | { 74 | "name": "Change to strlcpy", 75 | "type": "regex-replace", 76 | "_comment": "", 77 | "replacement": "strlcpy($1, $2, )", 78 | "pattern": { 79 | "pattern": "\\bstrcpy\\s*\\(([^,]+),([^,]+)\\)", 80 | "type": "regex", 81 | "scopes": [ 82 | "code" 83 | ], 84 | "_comment": "" 85 | } 86 | } 87 | ] 88 | }, 89 | { 90 | "name": "Banned C function detected (strncpy)", 91 | "id": "DS111237", 92 | "description": "strncpy is dangerous, as if the source contains 'n' or more characters, it will not null terminate the destination.", 93 | "recommendation": "Use strcpy_s or strlcpy if possible. If no safe function is viable, strcpy/strncpy should be proceeded by conditional checks to verify tha that the source string will fit in the destination with a null termnator.", 94 | "overrides": [ 95 | "DS154189" 96 | ], 97 | "applies_to": [ 98 | "c", 99 | "cpp", 100 | "objective-c" 101 | ], 102 | "tags": [ 103 | "API.DangerousAPI.BannedFunction" 104 | ], 105 | "severity": "important", 106 | "_comment": "", 107 | "rule_info": "DS111237.md", 108 | "patterns": [ 109 | { 110 | "pattern": "\\bstrncpy\\s*\\(([^,]+),([^,]+),([^,]+)\\)+", 111 | "type": "regex", 112 | "scopes": [ 113 | "code" 114 | ], 115 | "_comment": "" 116 | } 117 | ], 118 | "fix_its": [ 119 | { 120 | "name": "Change to strcpy_s (Recommended for VC++)", 121 | "type": "regex-replace", 122 | "_comment": "", 123 | "replacement": "strcpy_s($1, $3, $2)", 124 | "pattern": { 125 | "pattern": "\\bstrncpy\\s*\\(([^,]+),([^,]+),([^,]+)\\)+", 126 | "type": "regex", 127 | "scopes": [ 128 | "code" 129 | ], 130 | "_comment": "" 131 | } 132 | }, 133 | { 134 | "name": "Change to strlcpy", 135 | "type": "regex-replace", 136 | "_comment": "", 137 | "replacement": "strlcpy($1, $2, $3)", 138 | "pattern": { 139 | "pattern": "\\bstrncpy\\s*\\(([^,]+),([^,]+),([^,]+)\\)+", 140 | "type": "regex", 141 | "scopes": [ 142 | "code" 143 | ], 144 | "_comment": "" 145 | } 146 | } 147 | ] 148 | }, 149 | { 150 | "name": "Banned C function detected (strcat)", 151 | "id": "DS141863", 152 | "description": "If the combination of strings is larger than the destination buffer, strcat will cbuffer overflow the destination buffer", 153 | "recommendation": "Use strcat_s or strlcat if possible. strncat's size parameter excludes the null terminator, which leads to frequent mistakes", 154 | "overrides": [ 155 | "DS154189" 156 | ], 157 | "applies_to": [ 158 | "c", 159 | "cpp", 160 | "objective-c" 161 | ], 162 | "tags": [ 163 | "API.DangerousAPI.BannedFunction" 164 | ], 165 | "severity": "important", 166 | "_comment": "", 167 | "rule_info": "DS141863.md", 168 | "patterns": [ 169 | { 170 | "pattern": "\\bstrcat\\s*\\(([^,]+),([^,]+)\\)", 171 | "type": "regex", 172 | "scopes": [ 173 | "code" 174 | ], 175 | "_comment": "" 176 | } 177 | ], 178 | "fix_its": [ 179 | { 180 | "name": "Change to strcat_s (Recommended for VC++)", 181 | "type": "regex-replace", 182 | "_comment": "", 183 | "replacement": "strcat_s($1, , $2)", 184 | "pattern": { 185 | "pattern": "\\bstrcat\\s*\\(([^,]+),([^,]+)\\)", 186 | "type": "regex", 187 | "scopes": [ 188 | "code" 189 | ], 190 | "_comment": "" 191 | } 192 | }, 193 | { 194 | "name": "Change to strlcat", 195 | "type": "regex-replace", 196 | "_comment": "", 197 | "replacement": "strlcat($1, $2, )", 198 | "pattern": { 199 | "pattern": "\\bstrcat\\s*\\(([^,]+),([^,]+)\\)", 200 | "type": "regex", 201 | "scopes": [ 202 | "code" 203 | ], 204 | "_comment": "" 205 | } 206 | } 207 | ] 208 | }, 209 | { 210 | "name": "Banned C function detected (strncat)", 211 | "id": "DS108330", 212 | "description": "strncat adds the null terminator at character 'n + 1', rather than at the nth character. this frequently leads to the null terminator being added in the memory adjacent to the destination buffer, rather than in the destination buffer.", 213 | "recommendation": "Use strcat_s or strlcat if possible. ", 214 | "overrides": [ 215 | "DS154189" 216 | ], 217 | "applies_to": [ 218 | "c", 219 | "cpp", 220 | "objective-c" 221 | ], 222 | "tags": [ 223 | "API.DangerousAPI.BannedFunction" 224 | ], 225 | "severity": "important", 226 | "_comment": "", 227 | "rule_info": "DS108330.md", 228 | "patterns": [ 229 | { 230 | "pattern": "\\bstrncat\\s*\\(([^,]+),([^,]+),([^,]+)\\)+", 231 | "type": "regex", 232 | "scopes": [ 233 | "code" 234 | ], 235 | "_comment": "" 236 | } 237 | ], 238 | "fix_its": [ 239 | { 240 | "name": "Change to strcat_s (Recommended for VC++)", 241 | "type": "regex-replace", 242 | "_comment": "", 243 | "replacement": "strcat_s($1, $3, $2)", 244 | "pattern": { 245 | "pattern": "\\bstrncat\\s*\\(([^,]+),([^,]+),([^,]+)\\)+", 246 | "type": "regex", 247 | "scopes": [ 248 | "code" 249 | ], 250 | "_comment": "" 251 | } 252 | }, 253 | { 254 | "name": "Change to strlcat", 255 | "type": "regex-replace", 256 | "_comment": "", 257 | "replacement": "strlcat($1, $2, $3)", 258 | "pattern": { 259 | "pattern": "\\bstrncat\\s*\\(([^,]+),([^,]+),([^,]+)\\)+", 260 | "type": "regex", 261 | "scopes": [ 262 | "code" 263 | ], 264 | "_comment": "" 265 | } 266 | } 267 | ] 268 | }, 269 | { 270 | "name": "Banned C function detected (gets)", 271 | "id": "DS181021", 272 | "description": "gets will read in as many bytes as are provided, regardless of the size of buffer recieving the bytes. This allows for conditions that cause a buffer overlow in the destination buffer.", 273 | "recommendation": "Use gets_s or fgets if possible. fgets has different behavior from gets (may include newline for example), so care should be taken if it is used.", 274 | "overrides": [ 275 | "DS154189" 276 | ], 277 | "applies_to": [ 278 | "c", 279 | "cpp", 280 | "objective-c" 281 | ], 282 | "tags": [ 283 | "API.DangerousAPI.BannedFunction" 284 | ], 285 | "severity": "important", 286 | "_comment": "", 287 | "rule_info": "DS181021.md", 288 | "patterns": [ 289 | { 290 | "pattern": "\\bgets\\s*\\(([^,\\)]+)\\)", 291 | "type": "regex", 292 | "scopes": [ 293 | "code" 294 | ], 295 | "_comment": "" 296 | } 297 | ], 298 | "fix_its": [ 299 | { 300 | "name": "Change to gets_s (Recommended for VC++)", 301 | "type": "regex-replace", 302 | "_comment": "", 303 | "replacement": "gets_s($1, )", 304 | "pattern": { 305 | "pattern": "\\bgets\\s*\\(([^,\\)]+)\\)", 306 | "type": "regex", 307 | "scopes": [ 308 | "code" 309 | ], 310 | "_comment": "" 311 | } 312 | }, 313 | { 314 | "name": "Change to fgets", 315 | "type": "regex-replace", 316 | "_comment": "", 317 | "replacement": "fgets($1, , stdin)", 318 | "pattern": { 319 | "pattern": "\\bgets\\s*\\(([^,\\)]+)\\)", 320 | "type": "regex", 321 | "scopes": [ 322 | "code" 323 | ], 324 | "_comment": "" 325 | } 326 | } 327 | ] 328 | } 329 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/api/misused_api.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Do not copy a FILE object (CERT FIO38-C)", 4 | "id": "DS179924", 5 | "description": "The CERT Secure Coding Standard recommends that FILE objects not be copied.", 6 | "recommendation": "Copy a pointer to the FILE object instead.", 7 | "applies_to": [ 8 | "cpp", 9 | "c" 10 | ], 11 | "tags": [ 12 | "CERT.FIO38-C", 13 | "C.DangerousFunctionCall" 14 | ], 15 | "severity": "important", 16 | "_comment": "", 17 | "rule_info": "DS179924.md", 18 | "patterns": [ 19 | { 20 | "pattern": "FILE [a-z0-9_][^=]*=\\s*\\*", 21 | "type": "regex", 22 | "scopes": [ 23 | "code" 24 | ], 25 | "_comment": "" 26 | } 27 | ] 28 | }, 29 | { 30 | "name": "Don't pass user input to this function", 31 | "id": "DS181731", 32 | "description": "Don't pass user input to this function.", 33 | "recommendation": "Validate this data before passing it to the function.", 34 | "applies_to": [ 35 | "php" 36 | ], 37 | "tags": [ 38 | "PHP.Injection" 39 | ], 40 | "severity": "critical", 41 | "_comment": "", 42 | "rule_info": "DS181731.md", 43 | "patterns": [ 44 | { 45 | "pattern": "(include|require|include_once|require_once|passthru)\\s*\\(.*\\$\\_(GET|POST|REQUEST|COOKIES|FILES)", 46 | "type": "regex", 47 | "scopes": [ 48 | "code" 49 | ], 50 | "_comment": "" 51 | } 52 | ] 53 | } 54 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/api/suggested_api.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Problematic C function detected (malloc)", 4 | "id": "DS161085", 5 | "description": "If the value provided to malloc is the result of unsafe integer math, it can result in an exploitable condition. ", 6 | "recommendation": "calloc handles the most common integer math in memory allocation (# of elements * their size) with error handling to prevent overflows in most implementations, and zeros out memory", 7 | "applies_to": [ 8 | "c", 9 | "cpp", 10 | "objective-c" 11 | ], 12 | "tags": [ 13 | "API.DangerousAPI.ProblematicFunction" 14 | ], 15 | "severity": "best-practice", 16 | "_comment": "", 17 | "rule_info": "DS161085.md", 18 | "patterns": [ 19 | { 20 | "pattern": "\\bmalloc\\s*\\(([^,\\)]+)\\)", 21 | "type": "regex", 22 | "scopes": [ 23 | "code" 24 | ], 25 | "_comment": "" 26 | } 27 | ], 28 | "fix_its": [ 29 | { 30 | "name": "Change to calloc ", 31 | "type": "regex-replace", 32 | "_comment": "", 33 | "replacement": "calloc(, )", 34 | "pattern": { 35 | "pattern": "\\bmalloc\\s*\\(([^,\\)]+)\\)", 36 | "type": "regex", 37 | "scopes": [ 38 | "code" 39 | ], 40 | "_comment": "" 41 | } 42 | } 43 | ] 44 | }, 45 | { 46 | "name": "Problematic C function detected (memcpy)", 47 | "id": "DS121708", 48 | "description": "There are a number of conditions in which memcpy can introduce a vulnerability (mismatched buffer sizes, null pointers, etc.). More secure alternitives perform additional validation of the source and destination buffer", 49 | "recommendation": "Use memcpy_s if possible.", 50 | "applies_to": [ 51 | "c", 52 | "cpp", 53 | "objective-c" 54 | ], 55 | "tags": [ 56 | "API.DangerousAPI.ProblematicFunction" 57 | ], 58 | "severity": "best-practice", 59 | "_comment": "", 60 | "rule_info": "DS121708.md", 61 | "patterns": [ 62 | { 63 | "pattern": "\\bmemcpy\\s*\\(([^,]+),([^,]+),([^,\\)]+)\\)", 64 | "type": "regex", 65 | "scopes": [ 66 | "code" 67 | ], 68 | "_comment": "" 69 | } 70 | ], 71 | "fix_its": [ 72 | { 73 | "name": "Change to memcpy_s (Recommended for VC++)", 74 | "type": "regex-replace", 75 | "_comment": "", 76 | "replacement": "memcpy_s($1, , $2, $3)", 77 | "pattern": { 78 | "pattern": "\\bmemcpy\\s*\\(([^,]+),([^,]+),([^,\\)]+)\\)", 79 | "type": "regex", 80 | "scopes": [ 81 | "code" 82 | ], 83 | "_comment": "" 84 | } 85 | } 86 | ] 87 | }, 88 | { 89 | "name": "Problematic C function detected (strlen)", 90 | "id": "DS140021", 91 | "description": "If a string is missing a null terminator, strlen will read past the end of the buffer", 92 | "recommendation": "In instances where you know the maximum size of a string's buffer, use strlen_s or strnlen to prevent over-reading", 93 | "overrides": [ 94 | "DS154189" 95 | ], 96 | "applies_to": [ 97 | "c", 98 | "cpp", 99 | "objective-c" 100 | ], 101 | "tags": [ 102 | "API.DangerousAPI.ProblematicFunction" 103 | ], 104 | "severity": "best-practice", 105 | "_comment": "", 106 | "rule_info": "DS140021.md", 107 | "patterns": [ 108 | { 109 | "pattern": "\\bstrlen\\s*\\(([^,\\)]+)\\)", 110 | "type": "regex", 111 | "scopes": [ 112 | "code" 113 | ], 114 | "_comment": "" 115 | } 116 | ], 117 | "fix_its": [ 118 | { 119 | "name": "Change to strlen_s (Recommended for VC++)", 120 | "type": "regex-replace", 121 | "_comment": "", 122 | "replacement": "strlen_s($1, )", 123 | "pattern": { 124 | "pattern": "\\bstrlen\\s*\\(([^,\\)]+)\\)", 125 | "type": "regex", 126 | "scopes": [ 127 | "code" 128 | ], 129 | "_comment": "" 130 | } 131 | }, 132 | { 133 | "name": "Change to strnlen", 134 | "type": "regex-replace", 135 | "_comment": "", 136 | "replacement": "strnlen($1, )", 137 | "pattern": { 138 | "pattern": "\\bstrlen\\s*\\(([^,\\)]+)\\)", 139 | "type": "regex", 140 | "scopes": [ 141 | "code" 142 | ], 143 | "_comment": "" 144 | } 145 | } 146 | ] 147 | } 148 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/api/tests/DS179924.test: -------------------------------------------------------------------------------- 1 | /* FLAG */ 2 | FILE tdout = *stdout; 3 | 4 | /* NO FLAG */ 5 | FILE *my_stdout = stdout; 6 | -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/api/tests/DS181731.test: -------------------------------------------------------------------------------- 1 | /* FLAG */ 2 | include($_GET['t']); 3 | include($_POST['t']); 4 | require_once($_POST['t']); 5 | 6 | /* NO FLAG */ 7 | include("lib/file.php"); 8 | require_once("lib/file.php"); 9 | -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/attack_surface/outbound_network.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Notice: Outbound HTTP Connection", 4 | "id": "DS137038", 5 | "description": "Inbound HTTP", 6 | "recommendation": "", 7 | "applies_to": [ 8 | "ruby" 9 | ], 10 | "tags": [ 11 | "ThreatModel.Integration.HTTP" 12 | ], 13 | "severity": "manual-review", 14 | "_comment": "", 15 | "rule_info": "DS137038.md", 16 | "patterns": [ 17 | { 18 | "pattern": "Net::HTTP", 19 | "type": "string", 20 | "scopes": [ 21 | "code" 22 | ], 23 | "_comment": "" 24 | } 25 | ] 26 | }, 27 | { 28 | "name": "Insecure URL", 29 | "id": "DS137138", 30 | "description": "An HTTP-based URL without TLS was detected.", 31 | "recommendation": "Update to an HTTPS-based URL if possible.", 32 | "tags": [ 33 | "ThreatModel.Integration.HTTP" 34 | ], 35 | "severity": "moderate", 36 | "_comment": "", 37 | "rule_info": "DS137138.md", 38 | "patterns": [ 39 | { 40 | "pattern": "http:", 41 | "type": "substring", 42 | "scopes": [ 43 | "code" 44 | ], 45 | "modifiers": ["i"], 46 | "_comment": "" 47 | } 48 | ], 49 | "conditions" : [ 50 | { 51 | "pattern" : 52 | { 53 | "pattern": "xmlns", 54 | "type": "regex", 55 | "scopes": [ 56 | "code" 57 | ], 58 | "_comment": "" 59 | }, 60 | "negate_finding": true, 61 | "_comment": "" 62 | } 63 | ], 64 | "fix_its": [ 65 | { 66 | "name": "Change to HTTPS ", 67 | "type": "regex-replace", 68 | "_comment": "", 69 | "replacement": "https:", 70 | "pattern": { 71 | "pattern": "http:", 72 | "type": "regex", 73 | "scopes": [ 74 | "code" 75 | ], 76 | "modifiers": ["i"], 77 | "_comment": "" 78 | } 79 | } 80 | ] 81 | } 82 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/control_flow/dynamic_execution.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Do not execute user-provided JavaScript", 4 | "id": "DS165746", 5 | "description": "This line of code shows the dynamic evaluation of JavaScript, sourced from a string. It's important that this string not contain unsanitized user-supplied data, as it could be a vector for a cross-site scripting (XSS) attack.", 6 | "recommendation": "", 7 | "applies_to": [ 8 | "objective-c" 9 | ], 10 | "tags": [ 11 | "Design.Mobile.iOS.WebView.DynamicJavaScript" 12 | ], 13 | "severity": "important", 14 | "_comment": "", 15 | "rule_info": "DS165746.md", 16 | "patterns": [ 17 | { 18 | "pattern": "stringByEvaluatingJavaScriptFromString", 19 | "type": "string", 20 | "scopes": [ 21 | "code" 22 | ], 23 | "_comment": "" 24 | } 25 | ] 26 | } 27 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/control_flow/format_string.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Do not include user-input directoy in format strings", 4 | "id": "DS113286", 5 | "description": "Do not create NSString objects using a user-provided format string, as this could lead to a security vulnerability. https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings", 6 | "recommendation": "", 7 | "applies_to": [ 8 | "objective-c" 9 | ], 10 | "tags": [ 11 | "ControlFlow.Injection.FormatString", 12 | "cert:FIO30-C" 13 | ], 14 | "severity": "important", 15 | "_comment": "", 16 | "rule_info": "DS113286.md", 17 | "patterns": [ 18 | { 19 | "pattern": "\\[NSString stringWithFormat:\\s*([^@\\\"\\]]+\\])", 20 | "type": "regex", 21 | "scopes": [ 22 | "code" 23 | ], 24 | "_comment": "" 25 | } 26 | ], 27 | "fix_its": [ 28 | { 29 | "name": "Use a predefined format string", 30 | "type": "regex-replace", 31 | "_comment": "", 32 | "replacement": "[NSString stringWithFormat:@\"%@\", $1", 33 | "pattern": { 34 | "pattern": "\\[NSString stringWithFormat:\\s*([^@\\\"\\]]+\\])", 35 | "type": "regex", 36 | "scopes": [ 37 | "code" 38 | ], 39 | "_comment": "" 40 | } 41 | } 42 | ] 43 | } 44 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/control_flow/permission_evelation.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Do not set a custom execution policy.", 4 | "id": "DS113853", 5 | "description": "The Set-ExecutionPolicy cmdlet has been used to dynamically change the permissions available to PowerShell.", 6 | "recommendation": "Avoid elevating privileges if possible.", 7 | "applies_to": [ 8 | "powershell" 9 | ], 10 | "tags": [ 11 | "ControlFlow.Permission.Evalation" 12 | ], 13 | "severity": "moderate", 14 | "_comment": "", 15 | "rule_info": "DS113853.md", 16 | "patterns": [ 17 | { 18 | "pattern": "Set-ExecutionPolicy", 19 | "type": "string", 20 | "scopes": [ 21 | "code" 22 | ], 23 | "_comment": "" 24 | } 25 | ] 26 | }, 27 | { 28 | "name": "Use of restricted functions.", 29 | "id": "DS104456", 30 | "description": "Use of restricted functions.", 31 | "recommendation": "", 32 | "applies_to": [ 33 | "powershell" 34 | ], 35 | "tags": [ 36 | "Implementation.Scripting.PowerShell.DangeousFunction" 37 | ], 38 | "severity": "important", 39 | "_comment": "", 40 | "rule_info": "DS104456.md", 41 | "patterns": [ 42 | { 43 | "pattern": "GetDelegateForFunctionPointer", 44 | "type": "string", 45 | "scopes": [ 46 | "code" 47 | ], 48 | "_comment": "" 49 | }, 50 | { 51 | "pattern": "System.Runtime.InteropServices.Marshal", 52 | "type": "string", 53 | "scopes": [ 54 | "code" 55 | ], 56 | "_comment": "" 57 | }, 58 | { 59 | "pattern": "WriteByte", 60 | "type": "string", 61 | "scopes": [ 62 | "code" 63 | ], 64 | "_comment": "" 65 | }, 66 | { 67 | "pattern": "Microsoft.Win32.UnsafeNativeMethods", 68 | "type": "string", 69 | "scopes": [ 70 | "code" 71 | ], 72 | "_comment": "" 73 | }, 74 | { 75 | "pattern": "PtrToStructure", 76 | "type": "string", 77 | "scopes": [ 78 | "code" 79 | ], 80 | "_comment": "" 81 | }, 82 | { 83 | "pattern": "StructureToPtr", 84 | "type": "string", 85 | "scopes": [ 86 | "code" 87 | ], 88 | "_comment": "" 89 | }, 90 | { 91 | "pattern": "(NtCreateThreadEx|CreateRemoteThread)", 92 | "type": "regex-word", 93 | "scopes": [ 94 | "code" 95 | ], 96 | "_comment": "" 97 | }, 98 | { 99 | "pattern": "Invoke", 100 | "type": "string", 101 | "scopes": [ 102 | "code" 103 | ], 104 | "_comment": "" 105 | }, 106 | { 107 | "pattern": "VirtualProtect", 108 | "type": "string", 109 | "scopes": [ 110 | "code" 111 | ], 112 | "_comment": "" 113 | }, 114 | { 115 | "pattern": "iex", 116 | "type": "string", 117 | "scopes": [ 118 | "code" 119 | ], 120 | "_comment": "" 121 | }, 122 | { 123 | "pattern": "&\"", 124 | "type": "string", 125 | "scopes": [ 126 | "code" 127 | ], 128 | "_comment": "" 129 | }, 130 | { 131 | "pattern": "& $", 132 | "type": "string", 133 | "scopes": [ 134 | "code" 135 | ], 136 | "_comment": "" 137 | } 138 | ] 139 | } 140 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/certificate.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Encryption Marked 'Optional'", 4 | "id": "DS114352", 5 | "description": "Optional encryption or integrity checking can be dangerous.", 6 | "recommendation": "As a best practice, always enable strong encryption and integrity checking.", 7 | "tags": [ 8 | "Cryptography.Optional" 9 | ], 10 | "severity": "important", 11 | "_comment": "", 12 | "rule_info": "DS114352.md", 13 | "patterns": [ 14 | { 15 | "pattern": "Integrity.*optional", 16 | "type": "regex", 17 | "scopes": [ 18 | "code" 19 | ], 20 | "_comment": "" 21 | }, 22 | { 23 | "pattern": "Encryption.*optional", 24 | "type": "regex", 25 | "scopes": [ 26 | "code" 27 | ], 28 | "_comment": "" 29 | } 30 | ] 31 | }, 32 | { 33 | "name": "Disabled certificate validation", 34 | "id": "DS181865", 35 | "description": "Extend default certificate validation, but do not disable or override default rules.", 36 | "recommendation": "Always use a valid certificate, even during testing.", 37 | "applies_to": [ 38 | "objective-c" 39 | ], 40 | "tags": [ 41 | "Cryptography.Certificate.Validation" 42 | ], 43 | "severity": "critical", 44 | "_comment": "", 45 | "rule_info": "DS181865.md", 46 | "patterns": [ 47 | { 48 | "pattern": "setValidatesSecureCertificate:\\s*NO", 49 | "type": "regex", 50 | "scopes": [ 51 | "code" 52 | ], 53 | "_comment": "" 54 | }, 55 | { 56 | "pattern": "setAllowsAnyHTTPSCertificate:\\s*YES", 57 | "type": "regex", 58 | "scopes": [ 59 | "code" 60 | ], 61 | "_comment": "" 62 | }, 63 | { 64 | "pattern": "allowsAnyHTTPSCertificate\\s*=\\s*YES", 65 | "type": "regex", 66 | "scopes": [ 67 | "code" 68 | ], 69 | "_comment": "" 70 | }, 71 | { 72 | "pattern": "setValidatesSecureCertificate:\\s*NO", 73 | "type": "regex", 74 | "scopes": [ 75 | "code" 76 | ], 77 | "_comment": "" 78 | }, 79 | { 80 | "pattern": "validatesSecureCertificate\\s*=\\s*NO", 81 | "type": "regex", 82 | "scopes": [ 83 | "code" 84 | ], 85 | "_comment": "" 86 | }, 87 | { 88 | "pattern": "continueWithoutCredentialForAuthenticationChallenge", 89 | "type": "string", 90 | "scopes": [ 91 | "code" 92 | ], 93 | "_comment": "" 94 | }, 95 | { 96 | "pattern": "kCFStreamSSL(Level|AllowsExpiredCertificates|AllowsExpiredRoots|AllowsAnyRoot|ValidatesCertificateChain|PeerName)", 97 | "type": "regex", 98 | "scopes": [ 99 | "code" 100 | ], 101 | "_comment": "" 102 | }, 103 | { 104 | "pattern": "kCFStreamPropertySSLSettings", 105 | "type": "string", 106 | "scopes": [ 107 | "code" 108 | ], 109 | "_comment": "" 110 | } 111 | ] 112 | }, 113 | { 114 | "name": "Disabled certificate validation", 115 | "id": "DS176603", 116 | "description": "Extend default certificate validation, but do not disable or override default rules.", 117 | "recommendation": "Always use a valid certificate, even during testing.", 118 | "applies_to": [ 119 | "ruby" 120 | ], 121 | "tags": [ 122 | "Cryptography.Certificate.Validation" 123 | ], 124 | "severity": "critical", 125 | "_comment": "", 126 | "rule_info": "DS114352.md", 127 | "patterns": [ 128 | { 129 | "pattern": "OpenSSL::SSL::VERIFY_NONE", 130 | "type": "string", 131 | "scopes": [ 132 | "code" 133 | ], 134 | "_comment": "" 135 | } 136 | ] 137 | }, 138 | { 139 | "name": "Disabled certificate validation", 140 | "id": "DS130822", 141 | "description": "Extend default certificate validation, but do not disable or override default rules.", 142 | "recommendation": "Always use a valid certificate, even during testing.", 143 | "applies_to": [ 144 | "python" 145 | ], 146 | "tags": [ 147 | "Cryptography.Certificate.Validation" 148 | ], 149 | "severity": "critical", 150 | "_comment": "", 151 | "rule_info": "DS130822.md", 152 | "patterns": [ 153 | { 154 | "pattern": "\\.check_hostname\\s*=\\s*False", 155 | "type": "regex", 156 | "scopes": [ 157 | "code" 158 | ], 159 | "_comment": "" 160 | }, 161 | { 162 | "pattern": "disable_ssl_certificate_validation\\s*=\\s*True", 163 | "type": "string", 164 | "scopes": [ 165 | "code" 166 | ], 167 | "_comment": "" 168 | } 169 | ] 170 | }, 171 | { 172 | "name": "Disabled certificate validation", 173 | "id": "DS159369", 174 | "description": "Extend default certificate validation, but do not disable or override default rules.", 175 | "recommendation": "Always use a valid certificate, even during testing.", 176 | "applies_to": [ 177 | "cpp" 178 | ], 179 | "tags": [ 180 | "Cryptography.Certificate.Validation" 181 | ], 182 | "severity": "critical", 183 | "_comment": "", 184 | "rule_info": "DS114352.md", 185 | "patterns": [ 186 | { 187 | "pattern": "SECURITY_FLAG_IGNORE_CERT_CN_INVALID", 188 | "type": "string", 189 | "scopes": [ 190 | "code" 191 | ], 192 | "_comment": "" 193 | }, 194 | { 195 | "pattern": "SECURITY_FLAG_IGNORE_CERT_DATE_INVALID", 196 | "type": "string", 197 | "scopes": [ 198 | "code" 199 | ], 200 | "_comment": "" 201 | }, 202 | { 203 | "pattern": "SECURITY_FLAG_IGNORE_REVOCATION", 204 | "type": "string", 205 | "scopes": [ 206 | "code" 207 | ], 208 | "_comment": "" 209 | }, 210 | { 211 | "pattern": "SECURITY_FLAG_IGNORE_UNKNOWN_CA", 212 | "type": "string", 213 | "scopes": [ 214 | "code" 215 | ], 216 | "_comment": "" 217 | }, 218 | { 219 | "pattern": "SECURITY_FLAG_IGNORE_WRONG_USAGE", 220 | "type": "string", 221 | "scopes": [ 222 | "code" 223 | ], 224 | "_comment": "" 225 | }, 226 | { 227 | "pattern": "SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE", 228 | "type": "string", 229 | "scopes": [ 230 | "code" 231 | ], 232 | "_comment": "" 233 | } 234 | ] 235 | }, 236 | { 237 | "name": "Disabled certificate validation", 238 | "id": "DS101940", 239 | "description": "Extend default certificate validation, but do not disable or override default rules.", 240 | "recommendation": "Always use a valid certificate, even during testing.", 241 | "applies_to": [ 242 | ".config" 243 | ], 244 | "tags": [ 245 | "Cryptography.Certificate.Validation" 246 | ], 247 | "severity": "critical", 248 | "_comment": "", 249 | "rule_info": "DS114352.md", 250 | "patterns": [ 251 | { 252 | "pattern": "certificateValidationMode=\"None\"", 253 | "type": "string", 254 | "scopes": [ 255 | "code" 256 | ], 257 | "_comment": "" 258 | }, 259 | { 260 | "pattern": "checkCertificateName=\"false\"", 261 | "type": "string", 262 | "scopes": [ 263 | "code" 264 | ], 265 | "_comment": "" 266 | }, 267 | { 268 | "pattern": "checkCertificateRevocationList=\"false\"", 269 | "type": "string", 270 | "scopes": [ 271 | "code" 272 | ], 273 | "_comment": "" 274 | }, 275 | { 276 | "pattern": "encryptionPolicy=\"(AllowNoEncryption|NoEncryption)", 277 | "type": "regex", 278 | "scopes": [ 279 | "code" 280 | ], 281 | "_comment": "" 282 | } 283 | ] 284 | }, 285 | { 286 | "name": "Disabled certificate validation", 287 | "id": "DS125134", 288 | "description": "Extend default certificate validation, but do not disable or override default rules.", 289 | "recommendation": "Always use a valid certificate, even during testing.", 290 | "applies_to": [ 291 | "javascript" 292 | ], 293 | "tags": [ 294 | "Cryptography.Certificate.Validation" 295 | ], 296 | "severity": "critical", 297 | "_comment": "", 298 | "rule_info": "DS114352.md", 299 | "patterns": [ 300 | { 301 | "pattern": "NODE_TLS_REJECT_UNAUTHORIZED|rejectUnauthorized", 302 | "type": "regex", 303 | "scopes": [ 304 | "code" 305 | ], 306 | "_comment": "" 307 | } 308 | ] 309 | }, 310 | { 311 | "name": "Disabled certificate validation", 312 | "id": "DS152094", 313 | "description": "Extend default certificate validation, but do not disable or override default rules.", 314 | "recommendation": "Always use a valid certificate, even during testing.", 315 | "applies_to": [ 316 | "java" 317 | ], 318 | "tags": [ 319 | "Cryptography.Certificate.Validation" 320 | ], 321 | "severity": "critical", 322 | "_comment": "", 323 | "rule_info": "DS114352.md", 324 | "patterns": [ 325 | { 326 | "pattern": "(TrustManager|getInsecure|HostnameVerifier|AbstractVerifier|AllowAllHostnameVerifier|BrowserCompatHostnameVerifier|StrictHostnameVerifier|onReceivedSslError|insecuresocketfactory|customhostnameverifier)", 327 | "type": "regex", 328 | "scopes": [ 329 | "code" 330 | ], 331 | "_comment": "" 332 | } 333 | ] 334 | }, 335 | { 336 | "name": "Disabled certificate validation", 337 | "id": "DS126185", 338 | "description": "Extend default certificate validation, but do not disable or override default rules.", 339 | "recommendation": "Always use a valid certificate, even during testing.", 340 | "applies_to": [ 341 | "powershell" 342 | ], 343 | "tags": [ 344 | "Cryptography.Certificate.Validation" 345 | ], 346 | "severity": "critical", 347 | "_comment": "", 348 | "rule_info": "DS114352.md", 349 | "patterns": [ 350 | { 351 | "pattern": "::ServerCertificateValidationCallback\\s*=\\s*{\\s*\\$true\\s*}", 352 | "type": "regex", 353 | "scopes": [ 354 | "code" 355 | ], 356 | "_comment": "" 357 | } 358 | ] 359 | } 360 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/ciphers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Do not use the mcrypt module, use OpenSSL instead.", 4 | "id": "DS175862", 5 | "description": "The PHP mcrypt module is based on libmcrypt, which has been abanonded since 2007.", 6 | "recommendation": "OpenSSL", 7 | "applies_to": [ 8 | "php" 9 | ], 10 | "tags": [ 11 | "Cryptography.Library.Abandoned" 12 | ], 13 | "severity": "moderate", 14 | "_comment": "", 15 | "rule_info": "DS175862.md", 16 | "patterns": [ 17 | { 18 | "pattern": "mcrypt", 19 | "type": "string", 20 | "scopes": [ 21 | "code" 22 | ], 23 | "_comment": "" 24 | } 25 | ] 26 | }, 27 | { 28 | "name": "Do not use the 3DES symmetric block cipher.", 29 | "id": "DS109501", 30 | "description": "The 3DES cipher was found, which is only secure if three independent keys are used.", 31 | "recommendation": "Use AES instead.", 32 | "overrides": [ 33 | "DS106864" 34 | ], 35 | "applies_to": [ 36 | "csharp" 37 | ], 38 | "tags": [ 39 | "Cryptography.Symmetric.PotentiallyWeakAlgorithm" 40 | ], 41 | "severity": "moderate", 42 | "_comment": "", 43 | "rule_info": "DS109501.md", 44 | "patterns": [ 45 | { 46 | "pattern": "TripleDESCryptoServiceProvider", 47 | "type": "string", 48 | "scopes": [ 49 | "code" 50 | ], 51 | "_comment": "" 52 | } 53 | ], 54 | "fix_its": [ 55 | { 56 | "name": "Change to AESCryptoServiceProvider", 57 | "type": "regex-replace", 58 | "_comment": "", 59 | "replacement": "AESCryptoServiceProvider", 60 | "pattern": { 61 | "pattern": "TripleDESCryptoServiceProvider", 62 | "type": "regex", 63 | "scopes": [ 64 | "code" 65 | ], 66 | "_comment": "" 67 | } 68 | } 69 | ] 70 | }, 71 | { 72 | "name": "Do not use the DES symmetric block cipher.", 73 | "id": "DS106864", 74 | "description": "The DES cipher was found, which is widely considered to be broken.", 75 | "recommendation": "Use AES instead.", 76 | "applies_to": [ 77 | "csharp" 78 | ], 79 | "tags": [ 80 | "Cryptography.Symmetric.WeakOrBrokenAlgorithm" 81 | ], 82 | "severity": "critical", 83 | "_comment": "", 84 | "rule_info": "DS106864.md", 85 | "patterns": [ 86 | { 87 | "pattern": "DESCryptoServiceProvider", 88 | "type": "string", 89 | "scopes": [ 90 | "code" 91 | ], 92 | "_comment": "" 93 | } 94 | ], 95 | "fix_its": [ 96 | { 97 | "name": "Change to AESCryptoServiceProvider", 98 | "type": "regex-replace", 99 | "_comment": "", 100 | "replacement": "AESCryptoServiceProvider", 101 | "pattern": { 102 | "pattern": "DESCryptoServiceProvider", 103 | "type": "regex", 104 | "scopes": [ 105 | "code" 106 | ], 107 | "_comment": "" 108 | } 109 | } 110 | ] 111 | }, 112 | { 113 | "name": "Do not use the RC2 symmetric block cipher.", 114 | "id": "DS156431", 115 | "description": "The RC2 cipher was found, which is considered to be broken.", 116 | "recommendation": "Use AES instead.", 117 | "applies_to": [ 118 | "csharp" 119 | ], 120 | "tags": [ 121 | "Cryptography.Symmetric.WeakOrBrokenAlgorithm" 122 | ], 123 | "severity": "critical", 124 | "_comment": "", 125 | "rule_info": "DS156431.md", 126 | "patterns": [ 127 | { 128 | "pattern": "RC2CryptoServiceProvider", 129 | "type": "string", 130 | "scopes": [ 131 | "code" 132 | ], 133 | "_comment": "" 134 | } 135 | ], 136 | "fix_its": [ 137 | { 138 | "name": "Change to AESCryptoServiceProvider", 139 | "type": "regex-replace", 140 | "_comment": "", 141 | "replacement": "AESCryptoServiceProvider", 142 | "pattern": { 143 | "pattern": "RC2CryptoServiceProvider", 144 | "type": "regex", 145 | "scopes": [ 146 | "code" 147 | ], 148 | "_comment": "" 149 | } 150 | } 151 | ] 152 | } 153 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/general.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Disabled certificate validation", 4 | "id": "DS101155", 5 | "description": "Extend default certificate validation, but do not disable or override default rules.", 6 | "recommendation": "Always use a valid certificate, even during testing.", 7 | "tags": [ 8 | "Cryptography.Certificate.Validation" 9 | ], 10 | "severity": "critical", 11 | "_comment": "", 12 | "rule_info": "DS101155.md", 13 | "patterns": [ 14 | { 15 | "pattern": "encrypt=false", 16 | "type": "string", 17 | "scopes": [ 18 | "code" 19 | ], 20 | "_comment": "" 21 | }, 22 | { 23 | "pattern": "encryption=false", 24 | "type": "string", 25 | "scopes": [ 26 | "code" 27 | ], 28 | "_comment": "" 29 | }, 30 | { 31 | "pattern": "unencrypted.*password", 32 | "type": "regex", 33 | "scopes": [ 34 | "code" 35 | ], 36 | "_comment": "" 37 | }, 38 | { 39 | "pattern": "TODO.*crypt", 40 | "type": "regex", 41 | "scopes": [ 42 | "code" 43 | ], 44 | "_comment": "" 45 | } 46 | ] 47 | }, 48 | { 49 | "name": "Initializing Security Context", 50 | "id": "DS101159", 51 | "description": "SecurityContext initialization, look here for cryptography functions.", 52 | "recommendation": "", 53 | "applies_to": [ 54 | "cpp" 55 | ], 56 | "tags": [ 57 | "Cryptography.SecurityContext.Initialization" 58 | ], 59 | "severity": "manual-review", 60 | "_comment": "", 61 | "rule_info": "DS101159.md", 62 | "patterns": [ 63 | { 64 | "pattern": "InitializeSecurityContext", 65 | "type": "string", 66 | "scopes": [ 67 | "code" 68 | ], 69 | "_comment": "" 70 | } 71 | ] 72 | } 73 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/hash_algorithm.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Weak/Broken Hash Algorithm", 4 | "id": "DS126858", 5 | "description": "A weak or broken hash algorithm was detected.", 6 | "recommendation": "Consider switching to use SHA-256 or SHA-512 instead.", 7 | "tags": [ 8 | "Cryptography.BannedHashAlgorithm" 9 | ], 10 | "severity": "critical", 11 | "_comment": "", 12 | "rule_info": "DS126858.md", 13 | "patterns": [ 14 | { 15 | "pattern": "(MD2|MD4|MD5|RIPEMD|RIPEMD(128|256|160|320)|(SHA0|SHA-0|SHA1|SHA-1))", 16 | "type": "regex", 17 | "scopes": [ 18 | "code" 19 | ], 20 | "_comment": "" 21 | } 22 | ], 23 | "fix_its": [ 24 | { 25 | "name": "Change to \"SHA256\"", 26 | "type": "regex-replace", 27 | "_comment": "", 28 | "replacement": "SHA256", 29 | "pattern": { 30 | "pattern": "(MD2|MD4|MD5|RIPEMD|RIPEMD(128|256|160|320)|(SHA0|SHA-0|SHA1|SHA-1))", 31 | "type": "regex", 32 | "scopes": [ 33 | "code" 34 | ], 35 | "_comment": "" 36 | } 37 | }, 38 | { 39 | "name": "Change to \"SHA512\"", 40 | "type": "regex-replace", 41 | "_comment": "", 42 | "replacement": "SHA512", 43 | "pattern": { 44 | "pattern": "(MD2|MD4|MD5|RIPEMD|RIPEMD(128|256|160|320)|(SHA0|SHA-0|SHA1|SHA-1))", 45 | "type": "regex", 46 | "scopes": [ 47 | "code" 48 | ], 49 | "_comment": "" 50 | } 51 | } 52 | ] 53 | }, 54 | { 55 | "name": "Weak/Broken Hash Algorithm", 56 | "id": "DS197800", 57 | "description": "A weak or broken hash algorithm was detected.", 58 | "recommendation": "Use CC_SHA256 or CC_SHA512 instead.", 59 | "overrides": [ 60 | "DS126858" 61 | ], 62 | "applies_to": [ 63 | "objective-c" 64 | ], 65 | "tags": [ 66 | "Cryptography.HashAlgorithm.BrokenOrWeak" 67 | ], 68 | "severity": "critical", 69 | "_comment": "", 70 | "rule_info": "DS197800.md", 71 | "patterns": [ 72 | { 73 | "pattern": "CC_(MD2|MD4|MD5|SHA1)", 74 | "type": "regex", 75 | "scopes": [ 76 | "code" 77 | ], 78 | "_comment": "" 79 | } 80 | ], 81 | "fix_its": [ 82 | { 83 | "name": "Change to SHA-256", 84 | "type": "regex-replace", 85 | "_comment": "", 86 | "replacement": "CC_SHA256", 87 | "pattern": { 88 | "pattern": "CC_(MD2|MD4|MD5|SHA1)", 89 | "type": "regex", 90 | "scopes": [ 91 | "code" 92 | ], 93 | "_comment": "" 94 | } 95 | }, 96 | { 97 | "name": "Change to SHA-512", 98 | "type": "regex-replace", 99 | "_comment": "", 100 | "replacement": "CC_SHA512", 101 | "pattern": { 102 | "pattern": "CC_(MD2|MD4|MD5|SHA1)", 103 | "type": "regex", 104 | "scopes": [ 105 | "code" 106 | ], 107 | "_comment": "" 108 | } 109 | } 110 | ] 111 | }, 112 | { 113 | "name": "Weak/Broken Hash Algorithm", 114 | "id": "DS128420", 115 | "description": "A weak or broken hash algorithm was detected.", 116 | "recommendation": "When using hash(), use sha256 or sha512 as the algorithms instead", 117 | "overrides": [ 118 | "DS126858" 119 | ], 120 | "applies_to": [ 121 | "php" 122 | ], 123 | "tags": [ 124 | "Cryptography.HashAlgorithm.BrokenOrWeak" 125 | ], 126 | "severity": "critical", 127 | "_comment": "", 128 | "rule_info": "DS128420.md", 129 | "patterns": [ 130 | { 131 | "pattern": "hash\\s*\\(\\s*[\\'\\\"](md2|md4|md5|sha1|sha224|ripemd128|ripemd160|ripemd256|ripemd320)[\\'\\\"](.*)\\)\\s*;", 132 | "type": "regex", 133 | "scopes": [ 134 | "code" 135 | ], 136 | "_comment": "" 137 | } 138 | ], 139 | "fix_its": [ 140 | { 141 | "name": "Change to SHA-256", 142 | "type": "regex-replace", 143 | "_comment": "", 144 | "replacement": "hash('sha256'$2);", 145 | "pattern": { 146 | "pattern": "hash\\s*\\(\\s*[\\'\\\"](md2|md4|md5|sha1|sha224|ripemd128|ripemd160|ripemd256|ripemd320)[\\'\\\"](.*)\\)\\s*;", 147 | "type": "regex", 148 | "scopes": [ 149 | "code" 150 | ], 151 | "_comment": "" 152 | } 153 | }, 154 | { 155 | "name": "Change to SHA-512", 156 | "type": "regex-replace", 157 | "_comment": "", 158 | "replacement": "hash('sha512'$2);", 159 | "pattern": { 160 | "pattern": "hash\\s*\\(\\s*[\\'\\\"](md2|md4|md5|sha1|sha224|ripemd128|ripemd160|ripemd256|ripemd320)[\\'\\\"](.*)\\)\\s*;", 161 | "type": "regex", 162 | "scopes": [ 163 | "code" 164 | ], 165 | "_comment": "" 166 | } 167 | } 168 | ] 169 | }, 170 | { 171 | "name": "Do not use broken/weak cryptographic hash algorithms", 172 | "id": "DS108647", 173 | "description": "Avoid using broken or weak hash algorithms.", 174 | "recommendation": "Use Digest::SHA256 or Digest::SHA512", 175 | "applies_to": [ 176 | "ruby" 177 | ], 178 | "tags": [ 179 | "Cryptography.HashAlgorithm.BrokenOrWeak" 180 | ], 181 | "severity": "critical", 182 | "_comment": "", 183 | "rule_info": "DS108647.md", 184 | "patterns": [ 185 | { 186 | "pattern": "Digest::(MD5|RMD160|SHA1)", 187 | "type": "regex", 188 | "scopes": [ 189 | "code" 190 | ], 191 | "_comment": "" 192 | } 193 | ], 194 | "fix_its": [ 195 | { 196 | "name": "Change to SHA-256", 197 | "type": "regex-replace", 198 | "_comment": "", 199 | "replacement": "Digest::SHA256", 200 | "pattern": { 201 | "pattern": "Digest::(MD5|RMD160|SHA1)", 202 | "type": "regex", 203 | "scopes": [ 204 | "code" 205 | ], 206 | "_comment": "" 207 | } 208 | }, 209 | { 210 | "name": "Change to SHA-512", 211 | "type": "regex-replace", 212 | "_comment": "", 213 | "replacement": "Digest::SHA512", 214 | "pattern": { 215 | "pattern": "Digest::(MD5|RMD160|SHA1)", 216 | "type": "regex", 217 | "scopes": [ 218 | "code" 219 | ], 220 | "_comment": "" 221 | } 222 | } 223 | ] 224 | }, 225 | { 226 | "name": "Do not use broken/weak cryptographic hash algorithms", 227 | "id": "DS196098", 228 | "description": "Avoid using broken or weak hash algorithms.", 229 | "recommendation": "Use hashlib.sha256 instead.", 230 | "overrides": [ 231 | "DS126858" 232 | ], 233 | "applies_to": [ 234 | "python" 235 | ], 236 | "tags": [ 237 | "Cryptography.HashAlgorithm.BrokenOrWeak" 238 | ], 239 | "severity": "critical", 240 | "_comment": "", 241 | "rule_info": "DS196098.md", 242 | "patterns": [ 243 | { 244 | "pattern": "(md5|sha)\\.new\\(", 245 | "type": "regex", 246 | "scopes": [ 247 | "code" 248 | ], 249 | "_comment": "" 250 | } 251 | ], 252 | "fix_its": [ 253 | { 254 | "name": "Change to hashlib.sha256", 255 | "type": "regex-replace", 256 | "_comment": "", 257 | "replacement": "hashlib.sha256(", 258 | "pattern": { 259 | "pattern": "(md5|sha)\\.new\\(", 260 | "type": "regex", 261 | "scopes": [ 262 | "code" 263 | ], 264 | "_comment": "" 265 | } 266 | }, 267 | { 268 | "name": "Change to hashlib.sha512", 269 | "type": "regex-replace", 270 | "_comment": "", 271 | "replacement": "hashlib.sha512(", 272 | "pattern": { 273 | "pattern": "(md5|sha)\\.new\\(", 274 | "type": "regex", 275 | "scopes": [ 276 | "code" 277 | ], 278 | "_comment": "" 279 | } 280 | } 281 | ] 282 | }, 283 | { 284 | "name": "Do not use broken/weak cryptographic hash algorithms", 285 | "id": "DS168931", 286 | "description": "A potentially weak hashing algorithm was used.", 287 | "recommendation": "Use SHA-256 instead.", 288 | "overrides": [ 289 | "DS126858" 290 | ], 291 | "applies_to": [ 292 | "csharp" 293 | ], 294 | "tags": [ 295 | "Cryptography.HashAlgorithm.BrokenOrWeak" 296 | ], 297 | "severity": "critical", 298 | "_comment": "", 299 | "rule_info": "DS168931.md", 300 | "patterns": [ 301 | { 302 | "pattern": "MD5CryptoServiceProvider", 303 | "type": "substring", 304 | "scopes": [ 305 | "code" 306 | ], 307 | "_comment": "" 308 | } 309 | ], 310 | "fix_its": [ 311 | { 312 | "name": "Change to SHA-256", 313 | "type": "regex-replace", 314 | "_comment": "", 315 | "replacement": "SHA256CryptoServiceProvider", 316 | "pattern": { 317 | "pattern": "MD5CryptoServiceProvider", 318 | "type": "regex", 319 | "scopes": [ 320 | "code" 321 | ], 322 | "_comment": "" 323 | } 324 | }, 325 | { 326 | "name": "Change to SHA-512", 327 | "type": "regex-replace", 328 | "_comment": "", 329 | "replacement": "SHA512CryptoServiceProvider", 330 | "pattern": { 331 | "pattern": "MD5CryptoServiceProvider", 332 | "type": "regex", 333 | "scopes": [ 334 | "code" 335 | ], 336 | "_comment": "" 337 | } 338 | } 339 | ] 340 | }, 341 | { 342 | "name": "Do not take the hash of low-entropy content.", 343 | "id": "DS197836", 344 | "description": "Taking a hash of a time value is suspicious, as there is insufficient entropy to protect against brute-force attacks.", 345 | "recommendation": "", 346 | "tags": [ 347 | "Cryptography.HashAlgorithm.InsufficientEntropy" 348 | ], 349 | "severity": "important", 350 | "_comment": "", 351 | "rule_info": "DS197836.md", 352 | "patterns": [ 353 | { 354 | "pattern": "(MD4|MD5|(SHA(1|224|256|384|512))).*Time", 355 | "type": "regex", 356 | "scopes": [ 357 | "code" 358 | ], 359 | "_comment": "" 360 | } 361 | ] 362 | } 363 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/initialization_vector.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Missing initialization vector", 4 | "id": "DS188250", 5 | "description": "The mcrypt_encrypt function was used without an initialization vector.", 6 | "recommendation": "Add an initialization vector or consider a different cipher mode", 7 | "applies_to": [ 8 | "php" 9 | ], 10 | "tags": [ 11 | "Cryptography.Symmetric.InitializationVector.Missing" 12 | ], 13 | "severity": "important", 14 | "_comment": "", 15 | "rule_info": "DS188250.md", 16 | "patterns": [ 17 | { 18 | "pattern": "mcrypt_encrypt\\s*\\([^,]+,[^,]+,[^,]+,[^,]+\\);", 19 | "type": "regex", 20 | "scopes": [ 21 | "code" 22 | ], 23 | "_comment": "" 24 | } 25 | ], 26 | "fix_its": [ 27 | { 28 | "name": "Add initialization vector", 29 | "type": "regex-replace", 30 | "_comment": "", 31 | "replacement": "$1, <$iv>$2", 32 | "pattern": { 33 | "pattern": "(mcrypt_encrypt\\s*\\([^,]+,[^,]+,[^,]+,[^,]+)(\\);)", 34 | "type": "regex", 35 | "scopes": [ 36 | "code" 37 | ], 38 | "_comment": "" 39 | } 40 | } 41 | ] 42 | }, 43 | { 44 | "name": "Hardcoded initialization vector size", 45 | "id": "DS128921", 46 | "description": "An initialization vector was created to a static size, rather than determining it based on the encryption algorithm used.", 47 | "recommendation": "Use mcrypt_get_iv_size to get the correct IV size based on the cipher and mode.", 48 | "applies_to": [ 49 | "php" 50 | ], 51 | "tags": [ 52 | "Cryptography.Symmetric.InitializationVector.HardcodedSize" 53 | ], 54 | "severity": "moderate", 55 | "_comment": "", 56 | "rule_info": "DS128921.md", 57 | "patterns": [ 58 | { 59 | "pattern": "mcrypt_create_iv\\s*\\(\\s*\\d.*", 60 | "type": "regex", 61 | "scopes": [ 62 | "code" 63 | ], 64 | "_comment": "" 65 | } 66 | ] 67 | } 68 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/protocol.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Do not use outdated SSL/TLS protocols", 4 | "id": "DS144436", 5 | "description": "It's usually better to rely on the operating system configuration, rather than hardcoding a specific SecurityProtocolType.", 6 | "recommendation": "Either leave off or set to SecurityProtocolType.Tls12;", 7 | "applies_to": [ 8 | "csharp" 9 | ], 10 | "tags": [ 11 | "Cryptography.Protocol.TLS" 12 | ], 13 | "severity": "important", 14 | "_comment": "", 15 | "rule_info": "DS144436.md", 16 | "patterns": [ 17 | { 18 | "pattern": "SecurityProtocolType\\.(Ssl3|Tls|Tls11)", 19 | "type": "regex-word", 20 | "scopes": [ 21 | "code" 22 | ], 23 | "_comment": "" 24 | } 25 | ], 26 | "fix_its": [ 27 | { 28 | "name": "Change to SecurityProtocolType.Tls12", 29 | "type": "regex-replace", 30 | "_comment": "", 31 | "replacement": "SecurityProtocolType.Tls12", 32 | "pattern": { 33 | "pattern": "\\bSecurityProtocolType\\.(Ssl3|Tls|Tls11)\\b", 34 | "type": "regex", 35 | "scopes": [ 36 | "code" 37 | ], 38 | "_comment": "" 39 | } 40 | } 41 | ] 42 | }, 43 | { 44 | "name": "Hardcoding TLS protocol version", 45 | "id": "DS127101", 46 | "description": "It's usually better to rely on the operating system configuration, rather than hardcoding a specific list of protocols.", 47 | "recommendation": "", 48 | "applies_to": [ 49 | "cpp" 50 | ], 51 | "tags": [ 52 | "Cryptography.Protocol.TLS" 53 | ], 54 | "severity": "moderate", 55 | "_comment": "", 56 | "rule_info": "DS127101.md", 57 | "patterns": [ 58 | { 59 | "pattern": "SecPkgCred_SupportedProtocols", 60 | "type": "regex-word", 61 | "scopes": [ 62 | "code" 63 | ], 64 | "_comment": "" 65 | } 66 | ] 67 | }, 68 | { 69 | "name": "Do not use outdated SSL/TLS protocols", 70 | "id": "DS169125", 71 | "description": "An outdated SSL/TLS protocol version is specified.", 72 | "recommendation": "Use TLS 1.2", 73 | "tags": [ 74 | "Cryptography.Protocol.TLS" 75 | ], 76 | "severity": "important", 77 | "_comment": "", 78 | "rule_info": "DS169125.md", 79 | "patterns": [ 80 | { 81 | "pattern": "(SSLv?2|SSLv?3|TLSv?1|TLSv?10)", 82 | "type": "regex-word", 83 | "scopes": [ 84 | "code" 85 | ], 86 | "_comment": "" 87 | } 88 | ] 89 | }, 90 | { 91 | "name": "An Outdated or Banned SSL/TLS Protocol is Used", 92 | "id": "DS169126", 93 | "description": "An Outdated or Banned SSL/TLS Protocol is Used", 94 | "recommendation": "Use TLS 1.2", 95 | "tags": [ 96 | "Cryptography.Protocol.Banned" 97 | ], 98 | "severity": "important", 99 | "_comment": "", 100 | "rule_info": "DS169126.md", 101 | "patterns": [ 102 | { 103 | "pattern": "(SSL|TLS)v(2|23|3|1)_(client|server)", 104 | "type": "regex", 105 | "scopes": [ 106 | "code" 107 | ], 108 | "_comment": "" 109 | }, 110 | { 111 | "pattern": "SSLv2", 112 | "type": "string", 113 | "scopes": [ 114 | "code" 115 | ], 116 | "_comment": "" 117 | }, 118 | { 119 | "pattern": "SSLv3", 120 | "type": "string", 121 | "scopes": [ 122 | "code" 123 | ], 124 | "_comment": "" 125 | }, 126 | { 127 | "pattern": "TLSv1", 128 | "type": "string", 129 | "scopes": [ 130 | "code" 131 | ], 132 | "_comment": "" 133 | }, 134 | { 135 | "pattern": "TLSv10", 136 | "type": "string", 137 | "scopes": [ 138 | "code" 139 | ], 140 | "_comment": "" 141 | } 142 | ] 143 | }, 144 | { 145 | "name": "An Outdated or Banned SSL/TLS Protocol is Used", 146 | "id": "DS169127", 147 | "description": "An Outdated or Banned SSL/TLS Protocol is Used", 148 | "recommendation": "Use TLS 1.2", 149 | "applies_to": [ 150 | "cpp", 151 | "objective-c" 152 | ], 153 | "tags": [ 154 | "Cryptography.Protocol.Banned" 155 | ], 156 | "severity": "important", 157 | "_comment": "", 158 | "rule_info": "DS169126.md", 159 | "patterns": [ 160 | { 161 | "pattern": "SECURITY_FLAG_40BIT", 162 | "type": "string", 163 | "scopes": [ 164 | "code" 165 | ], 166 | "_comment": "" 167 | }, 168 | { 169 | "pattern": "SECURITY_FLAG_56BIT", 170 | "type": "string", 171 | "scopes": [ 172 | "code" 173 | ], 174 | "_comment": "" 175 | }, 176 | { 177 | "pattern": "SECURITY_FLAG_NORMALBITNESS", 178 | "type": "string", 179 | "scopes": [ 180 | "code" 181 | ], 182 | "_comment": "" 183 | }, 184 | { 185 | "pattern": "SECURITY_FLAG_PCT", 186 | "type": "string", 187 | "scopes": [ 188 | "code" 189 | ], 190 | "_comment": "" 191 | }, 192 | { 193 | "pattern": "SECURITY_FLAG_PCT4", 194 | "type": "string", 195 | "scopes": [ 196 | "code" 197 | ], 198 | "_comment": "" 199 | }, 200 | { 201 | "pattern": "SECURITY_FLAG_SSL", 202 | "type": "string", 203 | "scopes": [ 204 | "code" 205 | ], 206 | "_comment": "" 207 | }, 208 | { 209 | "pattern": "SECURITY_FLAG_SSL3", 210 | "type": "string", 211 | "scopes": [ 212 | "code" 213 | ], 214 | "_comment": "" 215 | }, 216 | { 217 | "pattern": "SECURITY_FLAG_STRENGTH_MEDIUM", 218 | "type": "string", 219 | "scopes": [ 220 | "code" 221 | ], 222 | "_comment": "" 223 | }, 224 | { 225 | "pattern": "SECURITY_FLAG_STRENGTH_WEAK", 226 | "type": "string", 227 | "scopes": [ 228 | "code" 229 | ], 230 | "_comment": "" 231 | }, 232 | { 233 | "pattern": "SECURITY_FLAG_UNKNOWNBIT", 234 | "type": "string", 235 | "scopes": [ 236 | "code" 237 | ], 238 | "_comment": "" 239 | }, 240 | { 241 | "pattern": "WINHTTP_FLAG_SECURE_PROTOCOL_SSL2", 242 | "type": "string", 243 | "scopes": [ 244 | "code" 245 | ], 246 | "_comment": "" 247 | }, 248 | { 249 | "pattern": "WINHTTP_FLAG_SECURE_PROTOCOL_SSL3", 250 | "type": "string", 251 | "scopes": [ 252 | "code" 253 | ], 254 | "_comment": "" 255 | }, 256 | { 257 | "pattern": "WINHTTP_FLAG_SECURE_PROTOCOL_TLS1", 258 | "type": "string", 259 | "scopes": [ 260 | "code" 261 | ], 262 | "_comment": "" 263 | }, 264 | { 265 | "pattern": "WINHTTP_FLAG_SECURE_PROTOCOL_ALL", 266 | "type": "string", 267 | "scopes": [ 268 | "code" 269 | ], 270 | "_comment": "" 271 | }, 272 | { 273 | "pattern": "SECURITY_FLAG_STRENGTH_MEDIUM", 274 | "type": "string", 275 | "scopes": [ 276 | "code" 277 | ], 278 | "_comment": "" 279 | }, 280 | { 281 | "pattern": "SECURITY_FLAG_STRENGTH_WEAK", 282 | "type": "string", 283 | "scopes": [ 284 | "code" 285 | ], 286 | "_comment": "" 287 | }, 288 | { 289 | "pattern": "SP_PROT_(PCT1|SSL2|SSL3|TLS1|TLS1_0)_(CLIENT|SERVER)", 290 | "type": "regex", 291 | "scopes": [ 292 | "code" 293 | ], 294 | "_comment": "" 295 | }, 296 | { 297 | "pattern": "NSStreamSocketSecurityLevelNone", 298 | "type": "string", 299 | "scopes": [ 300 | "code" 301 | ], 302 | "_comment": "" 303 | }, 304 | { 305 | "pattern": "NSStreamSocketSecurityLevelSSLv2", 306 | "type": "string", 307 | "scopes": [ 308 | "code" 309 | ], 310 | "_comment": "" 311 | }, 312 | { 313 | "pattern": "NSStreamSocketSecurityLevelSSLv3", 314 | "type": "string", 315 | "scopes": [ 316 | "code" 317 | ], 318 | "_comment": "" 319 | }, 320 | { 321 | "pattern": "NSStreamSocketSecurityLevelTLSv1", 322 | "type": "string", 323 | "scopes": [ 324 | "code" 325 | ], 326 | "_comment": "" 327 | }, 328 | { 329 | "pattern": "kCFStreamSocketSecurityLevelNone", 330 | "type": "string", 331 | "scopes": [ 332 | "code" 333 | ], 334 | "_comment": "" 335 | }, 336 | { 337 | "pattern": "kCFStreamSocketSecurityLevelSSLv2", 338 | "type": "string", 339 | "scopes": [ 340 | "code" 341 | ], 342 | "_comment": "" 343 | }, 344 | { 345 | "pattern": "kCFStreamSocketSecurityLevelSSLv3", 346 | "type": "string", 347 | "scopes": [ 348 | "code" 349 | ], 350 | "_comment": "" 351 | }, 352 | { 353 | "pattern": "kCFStreamSocketSecurityLevelTLSv1", 354 | "type": "string", 355 | "scopes": [ 356 | "code" 357 | ], 358 | "_comment": "" 359 | }, 360 | { 361 | "pattern": "kSSLProtocolUnknown ", 362 | "type": "string", 363 | "scopes": [ 364 | "code" 365 | ], 366 | "_comment": "" 367 | }, 368 | { 369 | "pattern": "kSSLProtocol3", 370 | "type": "string", 371 | "scopes": [ 372 | "code" 373 | ], 374 | "_comment": "" 375 | }, 376 | { 377 | "pattern": "kTLSProtocol1", 378 | "type": "string", 379 | "scopes": [ 380 | "code" 381 | ], 382 | "_comment": "" 383 | }, 384 | { 385 | "pattern": "kDTLSProtocol1", 386 | "type": "string", 387 | "scopes": [ 388 | "code" 389 | ], 390 | "_comment": "" 391 | }, 392 | { 393 | "pattern": "kSSLProtocol2", 394 | "type": "string", 395 | "scopes": [ 396 | "code" 397 | ], 398 | "_comment": "" 399 | }, 400 | { 401 | "pattern": "kSSLProtocol3Only", 402 | "type": "string", 403 | "scopes": [ 404 | "code" 405 | ], 406 | "_comment": "" 407 | }, 408 | { 409 | "pattern": "kTLSProtocol1Only", 410 | "type": "string", 411 | "scopes": [ 412 | "code" 413 | ], 414 | "_comment": "" 415 | }, 416 | { 417 | "pattern": "kSSLProtocolAll", 418 | "type": "string", 419 | "scopes": [ 420 | "code" 421 | ], 422 | "_comment": "" 423 | } 424 | ] 425 | }, 426 | { 427 | "name": "An Outdated or Banned SSL/TLS Protocol is Used", 428 | "id": "DS169128", 429 | "description": "An Outdated or Banned SSL/TLS Protocol is Used", 430 | "recommendation": "Use TLS 1.2", 431 | "applies_to": [ 432 | "python" 433 | ], 434 | "tags": [ 435 | "Cryptography.Protocol.Banned" 436 | ], 437 | "severity": "important", 438 | "_comment": "", 439 | "rule_info": "DS169126.md", 440 | "patterns": [ 441 | { 442 | "pattern": "PROTOCOL_SSLv2", 443 | "type": "string", 444 | "scopes": [ 445 | "code" 446 | ], 447 | "_comment": "" 448 | }, 449 | { 450 | "pattern": "PROTOCOL_SSLv23", 451 | "type": "string", 452 | "scopes": [ 453 | "code" 454 | ], 455 | "_comment": "" 456 | }, 457 | { 458 | "pattern": "PROTOCOL_SSLv3", 459 | "type": "string", 460 | "scopes": [ 461 | "code" 462 | ], 463 | "_comment": "" 464 | }, 465 | { 466 | "pattern": "PROTOCOL_TLSv1", 467 | "type": "string", 468 | "scopes": [ 469 | "code" 470 | ], 471 | "_comment": "" 472 | } 473 | ] 474 | } 475 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/random.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Do not use weak/non-cryptographic random number generators", 4 | "id": "DS148264", 5 | "description": "Use cryptographic random numbers generators for anything even close to a security function.", 6 | "recommendation": "Replacements depend on language.", 7 | "tags": [ 8 | "Cryptography.PRNG.Weak" 9 | ], 10 | "severity": "important", 11 | "_comment": "", 12 | "rule_info": "DS148264.md", 13 | "patterns": [ 14 | { 15 | "pattern": "DUAL_EC_DRBG", 16 | "type": "string", 17 | "scopes": [ 18 | "code" 19 | ], 20 | "_comment": "" 21 | }, 22 | { 23 | "pattern": "pseudoRandomBytes", 24 | "type": "string", 25 | "scopes": [ 26 | "code" 27 | ], 28 | "_comment": "" 29 | }, 30 | { 31 | "pattern": "\\brand\\(", 32 | "type": "regex", 33 | "scopes": [ 34 | "code" 35 | ], 36 | "_comment": "" 37 | }, 38 | { 39 | "pattern": "random_shuffle\\(", 40 | "type": "regex", 41 | "scopes": [ 42 | "code" 43 | ], 44 | "_comment": "" 45 | }, 46 | { 47 | "pattern": "\\bshuffle\\(", 48 | "type": "regex", 49 | "scopes": [ 50 | "code" 51 | ], 52 | "_comment": "" 53 | }, 54 | { 55 | "pattern": "RAND_MAX", 56 | "type": "string", 57 | "scopes": [ 58 | "code" 59 | ], 60 | "_comment": "" 61 | }, 62 | { 63 | "pattern": "\\brand\\(\\s*\\)\\s*%", 64 | "type": "regex", 65 | "scopes": [ 66 | "code" 67 | ], 68 | "_comment": "" 69 | }, 70 | { 71 | "pattern": "mwc1616", 72 | "type": "string", 73 | "scopes": [ 74 | "code" 75 | ], 76 | "_comment": "" 77 | }, 78 | { 79 | "pattern": "(32969|18273)", 80 | "type": "regex-word", 81 | "scopes": [ 82 | "code" 83 | ], 84 | "_comment": "" 85 | }, 86 | { 87 | "pattern": "System.Random", 88 | "type": "string", 89 | "scopes": [ 90 | "code" 91 | ], 92 | "_comment": "" 93 | }, 94 | { 95 | "pattern": "\\bRandom\\(", 96 | "type": "regex-word", 97 | "scopes": [ 98 | "code" 99 | ], 100 | "_comment": "" 101 | }, 102 | { 103 | "pattern": "arc4random", 104 | "type": "string", 105 | "scopes": [ 106 | "code" 107 | ], 108 | "_comment": "" 109 | } 110 | ] 111 | }, 112 | { 113 | "name": "Do not seed randomness based on system time or a static value.", 114 | "id": "DS149435", 115 | "description": "Passing a predicable value to srand() is very insecure and should be avoided.", 116 | "recommendation": "", 117 | "tags": [ 118 | "Cryptography.WeakRandomness" 119 | ], 120 | "severity": "critical", 121 | "_comment": "", 122 | "rule_info": "DS149435.md", 123 | "patterns": [ 124 | { 125 | "pattern": "\\bsrand\\(\\s*time\\(", 126 | "type": "regex", 127 | "scopes": [ 128 | "code" 129 | ], 130 | "_comment": "" 131 | }, 132 | { 133 | "pattern": "\\bsrand\\(\\s*\\d+\\s*\\)", 134 | "type": "regex", 135 | "scopes": [ 136 | "code" 137 | ], 138 | "_comment": "" 139 | } 140 | ] 141 | } 142 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/tests/DS106864.test: -------------------------------------------------------------------------------- 1 | using (var myDES = new DESCryptoServiceProvider()) 2 | { 3 | ... 4 | 5 | } 6 | -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/tests/DS109501.test: -------------------------------------------------------------------------------- 1 | using (var myTripleDES = new TripleDESCryptoServiceProvider()) 2 | { 3 | ... 4 | 5 | } 6 | -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/tests/DS130821.test: -------------------------------------------------------------------------------- 1 | requests.get('https://kennethreitz.com', 2 | verify=False) -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/tests/DS134411.test: -------------------------------------------------------------------------------- 1 | HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter(); 2 | filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted); 3 | filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired); 4 | filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain); 5 | filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.WrongUsage); 6 | filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName); 7 | filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationInformationMissing); 8 | filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationFailure); -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/tests/DS148264.test: -------------------------------------------------------------------------------- 1 | # $sha1->add($$ , time() , rand(time) ); 2 | 3 | $md5->add($$ , time() , rand(time) ); -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/tests/DS156431.test: -------------------------------------------------------------------------------- 1 | using (var myRC2 = new RC2CryptoServiceProvider()) 2 | { 3 | ... 4 | 5 | } 6 | -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/tests/DS159369.test: -------------------------------------------------------------------------------- 1 | SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/tests/DS169126.test: -------------------------------------------------------------------------------- 1 | SP_PROT_PCT1_CLIENT 2 | SP_PROT_PCT1_SERVER 3 | SP_PROT_SSL2_CLIENT 4 | SP_PROT_SSL2_SERVER 5 | SP_PROT_SSL3_CLIENT 6 | SP_PROT_SSL3_SERVER 7 | SP_PROT_TLS1_CLIENT 8 | SP_PROT_TLS1_SERVER 9 | SP_PROT_TLS1_0_CLIENT 10 | SP_PROT_TLS1_0_SERVER 11 | 12 | SP_PROT_TLS_1_1_CLIENT 13 | SP_PROT_TLS_1_1_SERVER 14 | SP_PROT_TLS_1_2_CLIENT 15 | SP_PROT_TLS_1_2_SERVER 16 | 17 | 18 | TLS1 19 | SSL2 20 | SSL3 21 | 22 | 23 | InitializeSecurityContext -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/tests/DS182720.test: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/underhanded.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Source implementation of a weak/broken cryptography hash function", 4 | "id": "DS109733", 5 | "description": "An implementation of a weak/broken hash function was found in source code.", 6 | "recommendation": "Do not use MD5, and always prefer OS- or library-provided cryptography implementations.", 7 | "tags": [ 8 | "Cryptography.HashAlgorithm.WeakOrBrokenImplementation" 9 | ], 10 | "severity": "critical", 11 | "_comment": "", 12 | "rule_info": "DS109733.md", 13 | "patterns": [ 14 | { 15 | "pattern": "242070db|02441453|db702024|53144402|3572445317", 16 | "type": "regex", 17 | "scopes": [ 18 | "code" 19 | ], 20 | "_comment": "MD5" 21 | }, 22 | { 23 | "pattern": "98BADCFE|FEDCBC98|C3D2E1F0|F0E1D2C3", 24 | "type": "regex", 25 | "scopes": [ 26 | "code" 27 | ], 28 | "_comment": "SHA-1" 29 | } 30 | ] 31 | } 32 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/cryptography/weak_cipher_modes.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "A weak cipher mode of operation was used", 4 | "id": "DS187371", 5 | "description": "A potentially weak cipher mode of operation was used.", 6 | "recommendation": "Consider using CBC, CTR, or GCM.", 7 | "tags": [ 8 | "Cryptography.Symmetric.CipherMode.Weak" 9 | ], 10 | "severity": "important", 11 | "_comment": "", 12 | "rule_info": "DS187371.md", 13 | "patterns": [ 14 | { 15 | "pattern": "(ECB|OFB|CFB|CTS|PCBC|GMAC|XCBC|IACBC|IAPM|EAX|OCB|CWC|AEAD|LRW|XEX|XTS|CMC|EME|CBCMAC|OMAC|PMAC)", 16 | "type": "regex-word", 17 | "scopes": [ 18 | "code" 19 | ], 20 | "_comment": "" 21 | } 22 | ] 23 | }, 24 | { 25 | "name": "A weak cipher mode of operation was used", 26 | "id": "DS182720", 27 | "description": "A potentially weak cipher mode of operation was used.", 28 | "recommendation": "Consider using CBC, CTR, or GCM.", 29 | "applies_to": [ 30 | "php" 31 | ], 32 | "tags": [ 33 | "Cryptography.Symmetric.CipherMode.Weak" 34 | ], 35 | "severity": "important", 36 | "_comment": "", 37 | "rule_info": "DS182720.md", 38 | "patterns": [ 39 | { 40 | "pattern": "MCRYPT_MODE_(ECB|CFB|OFB|NOFB|STREAM)", 41 | "type": "regex-word", 42 | "scopes": [ 43 | "code" 44 | ], 45 | "_comment": "" 46 | } 47 | ], 48 | "fix_its": [ 49 | { 50 | "name": "Change cipher mode to CBC", 51 | "type": "regex-replace", 52 | "_comment": "", 53 | "replacement": "MCRYPT_MODE_CBC", 54 | "pattern": { 55 | "pattern": "MCRYPT_MODE_(ECB|CFB|OFB|NOFB|STREAM)", 56 | "type": "regex", 57 | "scopes": [ 58 | "code" 59 | ], 60 | "_comment": "" 61 | } 62 | } 63 | ] 64 | } 65 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/frameworks/aspnet5.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "All Controllers Should Derive From Controller.", 4 | "id": "DS184626", 5 | "description": "All Controllers Should Derive From Controller.", 6 | "recommendation": "Ensure this class derives from Controller.", 7 | "applies_to": [ 8 | "csharp" 9 | ], 10 | "tags": [ 11 | "Implementation.Web.ASPNET.ControllerWithoutExtendingController" 12 | ], 13 | "severity": "moderate", 14 | "_comment": "", 15 | "rule_info": "DS184626.md", 16 | "patterns": [ 17 | { 18 | "pattern": "class [^\\s]+Controller\\s*:\\s*(?!.*?(Controller)).*", 19 | "type": "regex", 20 | "scopes": [ 21 | "code" 22 | ], 23 | "_comment": "" 24 | }, 25 | { 26 | "pattern": "class [^\\s]+Controller[\\s{]*$", 27 | "type": "regex", 28 | "scopes": [ 29 | "code" 30 | ], 31 | "_comment": "" 32 | } 33 | ], 34 | "fix_its": [ 35 | { 36 | "name": "Change to inherit from Controller", 37 | "type": "regex-replace", 38 | "_comment": "", 39 | "replacement": "$1 : Controller", 40 | "pattern": { 41 | "pattern": "(class [^\\s]+Controller)(([\\s{]*$)|(\\s*:\\s*(?!.*?(Controller)).*))", 42 | "type": "regex", 43 | "scopes": [ 44 | "code" 45 | ], 46 | "_comment": "" 47 | } 48 | } 49 | ] 50 | } 51 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/frameworks/php.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "$_REQUEST should be avoided", 4 | "id": "DS144886", 5 | "description": "$_REQUEST combines POST, GET, and cookie values in one array, making it easy for an attacker to modify a POST or cookie value by instead putting it in a GET and sending the URL to the victim", 6 | "recommendation": "Use $_POST, $_GET, $_COOKIE to scope to the expected delivery method for a value ", 7 | "applies_to": [ 8 | "php" 9 | ], 10 | "tags": [ 11 | "Implementation.PHP" 12 | ], 13 | "severity": "moderate", 14 | "_comment": "", 15 | "rule_info": "DS144886.md", 16 | "patterns": [ 17 | { 18 | "pattern": "\\$_REQUEST", 19 | "type": "regex", 20 | "scopes": [ 21 | "code" 22 | ], 23 | "_comment": "" 24 | } 25 | ], 26 | "fix_its": [ 27 | { 28 | "name": "Change to $_GET", 29 | "type": "regex-replace", 30 | "_comment": "", 31 | "replacement": "$$_GET", 32 | "pattern": { 33 | "pattern": "\\$_REQUEST", 34 | "type": "regex", 35 | "scopes": [ 36 | "code" 37 | ], 38 | "_comment": "" 39 | } 40 | }, 41 | { 42 | "name": "Change to $_POST", 43 | "type": "regex-replace", 44 | "_comment": "", 45 | "replacement": "$$_POST", 46 | "pattern": { 47 | "pattern": "\\$_REQUEST", 48 | "type": "regex", 49 | "scopes": [ 50 | "code" 51 | ], 52 | "_comment": "" 53 | } 54 | }, 55 | { 56 | "name": "Change to $_COOKIE", 57 | "type": "regex-replace", 58 | "_comment": "", 59 | "replacement": "$$_COOKIE", 60 | "pattern": { 61 | "pattern": "\\$_REQUEST", 62 | "type": "regex", 63 | "scopes": [ 64 | "code" 65 | ], 66 | "_comment": "" 67 | } 68 | } 69 | ] 70 | }, 71 | { 72 | "name": "XSS: Do not echo unencoded GET/POST/COOKIE values", 73 | "id": "DS163877", 74 | "description": "When using $_GET/POST/COOKIE values via echo, failure to encode the values will lead to Cross Site Scription (XSS), where a malicious party can inject script into the webpage.", 75 | "recommendation": "HTML Entity Encode (for content going into HTML) or URL Encode (for content going into JavaScript variables) the data", 76 | "applies_to": [ 77 | "php" 78 | ], 79 | "tags": [ 80 | "Implementation.PHP" 81 | ], 82 | "severity": "moderate", 83 | "_comment": "", 84 | "rule_info": "DS163877.md", 85 | "patterns": [ 86 | { 87 | "pattern": "\\becho.*(\\$_(POST|GET|REQUEST|COOKIE)\\[.*\\]).*;", 88 | "type": "regex", 89 | "scopes": [ 90 | "code" 91 | ], 92 | "_comment": "" 93 | } 94 | ], 95 | "conditions" : [ 96 | { 97 | "pattern" : 98 | { 99 | "pattern": "\\b(htmlentities|htmlspecialchars|rawurlencode|urlencode)\\s*\\(.*(\\$_(POST|GET|REQUEST|COOKIE)\\[.*\\]).*\\)", 100 | "type": "regex", 101 | "scopes": [ 102 | "code" 103 | ], 104 | "_comment": "" 105 | }, 106 | "search_in":"finding-only", 107 | "negate_finding": true, 108 | "_comment": "" 109 | } 110 | ], 111 | "fix_its": [ 112 | { 113 | "name": "HTML Entity encode the data", 114 | "type": "regex-replace", 115 | "_comment": "", 116 | "replacement": "htmlentities($1)", 117 | "pattern": { 118 | "pattern": "(\\$_(POST|GET|REQUEST|COOKIE)\\[.*\\])", 119 | "type": "regex", 120 | "scopes": [ 121 | "code" 122 | ], 123 | "_comment": "" 124 | } 125 | }, 126 | { 127 | "name": "URL encode the data", 128 | "type": "regex-replace", 129 | "_comment": "", 130 | "replacement": "rawurlencode($1)", 131 | "pattern": { 132 | "pattern": "(\\$_(POST|GET|REQUEST|COOKIE)\\[.*\\])", 133 | "type": "regex", 134 | "scopes": [ 135 | "code" 136 | ], 137 | "_comment": "" 138 | } 139 | } 140 | ] 141 | } 142 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/hygiene/localhost.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Do not leave debug code in production", 4 | "id": "DS162092", 5 | "description": "Accessing localhost could indicate debug code, or could hinder scaling.", 6 | "recommendation": "", 7 | "tags": [ 8 | "Hygiene.Network.AccessingLocalhost" 9 | ], 10 | "severity": "manual-review", 11 | "_comment": "", 12 | "rule_info": "DS162092.md", 13 | "patterns": [ 14 | { 15 | "pattern": "localhost", 16 | "type": "string", 17 | "scopes": [ 18 | "code" 19 | ], 20 | "_comment": "" 21 | }, 22 | { 23 | "pattern": "127.0.0.1", 24 | "type": "string", 25 | "scopes": [ 26 | "code" 27 | ], 28 | "_comment": "" 29 | } 30 | ] 31 | } 32 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/hygiene/tests/DS162092.test: -------------------------------------------------------------------------------- 1 | var host = "localhost"; 2 | 3 | var host = "name-localhost"; 4 | 5 | var host = "127.0.0.1" 6 | 7 | HOST=localhost 8 | 9 | HOST=127.0.0.1 10 | -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/hygiene/todo.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Suspicious comment", 4 | "id": "DS176209", 5 | "description": "A \"TODO\" or similar was left in source code, possibly indicating incomplete functionality", 6 | "recommendation": "", 7 | "tags": [ 8 | "Hygiene.Comment.Suspicious" 9 | ], 10 | "severity": "manual-review", 11 | "_comment": "", 12 | "rule_info": "DS176209.md", 13 | "patterns": [ 14 | { 15 | "pattern": "(TODO|FIXME|REMOVEME|HACK|BLACK MAGIC)", 16 | "type": "regex-word", 17 | "scopes": [ 18 | "code" 19 | ], 20 | "_comment": "" 21 | } 22 | ] 23 | } 24 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/manualreview/dynamiccode.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Review eval for untrusted data", 4 | "id": "DS189424", 5 | "description": "If untrusted data (data from HTTP requests, user submitted files, etc.) is included in an eval statement it can allow enable an attacker to inject their own code.", 6 | "recommendation": "Edit the eval so that no untrusted date is included. If untrusted data is absolutely necessary a great deal of care should be taken to ensure it is properly escaped so that it cannot be executed. This is not as simple as just escaping quotes.", 7 | "applies_to": [ 8 | "python", 9 | "javascript", 10 | "typescript", 11 | "php" 12 | ], 13 | "tags": [ 14 | "Python.DangerousFunctionCall", 15 | "JavaScript.DangerousFunctionCall", 16 | "TypeScript.DangerousFunctionCall", 17 | "PHP.DangerousFunctionCall" 18 | ], 19 | "severity": "manual-review", 20 | "_comment": "", 21 | "rule_info": "DS189424.md", 22 | "patterns": [ 23 | { 24 | "pattern": "\\beval\\(([^,]+)\\)", 25 | "type": "regex", 26 | "scopes": [ 27 | "code" 28 | ], 29 | "_comment": "" 30 | } 31 | ] 32 | }, 33 | { 34 | "name": "Review setTimeout for untrusted data", 35 | "id": "DS172411", 36 | "description": "If untrusted data (data from HTTP requests, user submitted files, etc.) is included in an setTimeout statement it can allow enable an attacker to inject their own code.", 37 | "recommendation": "Edit the setTimeout so that no untrusted date is included. If untrusted data is absolutely necessary a great deal of care should be taken to ensure it is properly escaped so that it cannot be executed. This is not as simple as just escaping quotes.", 38 | "applies_to": [ 39 | "javascript", 40 | "typescript" 41 | ], 42 | "tags": [ 43 | "JavaScript.DangerousFunctionCall", 44 | "TypeScript.DangerousFunctionCall" 45 | ], 46 | "severity": "manual-review", 47 | "_comment": "", 48 | "rule_info": "DS172411.md", 49 | "patterns": [ 50 | { 51 | "pattern": "\\bsetTimeout\\(([^,]+)\\)", 52 | "type": "regex", 53 | "scopes": [ 54 | "code" 55 | ], 56 | "_comment": "" 57 | } 58 | ] 59 | }, 60 | { 61 | "name": "Review unsafe code", 62 | "id": "DS172412", 63 | "description": "The unsafe keyword denotes an unsafe context, which is required for any operation involving pointers. Unsafe code in is not necessarily dangerous; it is just code whose safety cannot be verified by the CLR.", 64 | "recommendation": "", 65 | "applies_to": [ 66 | "csharp", 67 | "vb" 68 | ], 69 | "tags": [ 70 | "Dotnet.Unsafecode" 71 | ], 72 | "severity": "manual-review", 73 | "_comment": "", 74 | "rule_info": "DS172412.md", 75 | "patterns": [ 76 | { 77 | "pattern": "unsafe", 78 | "type": "regex-word", 79 | "scopes": [ 80 | "code" 81 | ], 82 | "_comment": "" 83 | } 84 | ] 85 | } 86 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/privacy/device_restrictions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Do not attempt to access device UDID", 4 | "id": "DS165348", 5 | "description": "Access to the device UDID (via [[UIDevice currentDevice] uniqueIdentifier]) is deprecated as of iOS 5 and should not be used or relied upon.", 6 | "recommendation": "[[UIDevice currentDevice] identifierForVendor]", 7 | "applies_to": [ 8 | "objective-c" 9 | ], 10 | "tags": [ 11 | "Implementation.Mobile.iOS.DataProtection.Privacy.UDID" 12 | ], 13 | "severity": "important", 14 | "_comment": "", 15 | "rule_info": "DS165348.md", 16 | "patterns": [ 17 | { 18 | "pattern": "uniqueIdentifier", 19 | "type": "string", 20 | "scopes": [ 21 | "code" 22 | ], 23 | "_comment": "" 24 | } 25 | ] 26 | } 27 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/privacy/secrets.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Do not store tokens or keys in source code.", 4 | "id": "DS173237", 5 | "description": "A token or key was found in source code. If this represents a secret, it should be moved somewhere else.", 6 | "recommendation": "", 7 | "tags": [ 8 | "Implementation.Privacy.Token" 9 | ], 10 | "severity": "important", 11 | "_comment": "", 12 | "rule_info": "DS173237.md", 13 | "patterns": [ 14 | { 15 | "pattern": "[a-f0-9]{30,}", 16 | "type": "regex", 17 | "scopes": [ 18 | "code" 19 | ], 20 | "_comment": "" 21 | } 22 | ] 23 | }, 24 | { 25 | "name": "Do not store tokens or keys in source code.", 26 | "id": "DS117838", 27 | "description": "A token or key was found in source code. If this represents a secret, it should be moved somewhere else.", 28 | "recommendation": "", 29 | "overrides": [ 30 | "DS173237" 31 | ], 32 | "tags": [ 33 | "Implementation.Privacy.Token" 34 | ], 35 | "severity": "critical", 36 | "_comment": "", 37 | "rule_info": "DS117838.md", 38 | "patterns": [ 39 | { 40 | "pattern": "(secret|license|key|pass).*[a-f0-9]{30,}", 41 | "type": "regex", 42 | "scopes": [ 43 | "code" 44 | ], 45 | "_comment": "" 46 | } 47 | ] 48 | } 49 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/storage/secure_storage.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "ProtectedData used without additional entropy", 4 | "id": "DS112266", 5 | "description": "The ProtectedData class should be used with additional entropy to reduce the risk of other application calling DPAPI to access the data.", 6 | "recommendation": "Add additional entropy (per-application secret).", 7 | "applies_to": [ 8 | "csharp" 9 | ], 10 | "tags": [ 11 | "Storage.Windows.DPAPI" 12 | ], 13 | "severity": "moderate", 14 | "_comment": "", 15 | "rule_info": "DS112266.md", 16 | "patterns": [ 17 | { 18 | "pattern": "ProtectedData\\.Protect.*,\\s*null.*", 19 | "type": "regex", 20 | "scopes": [ 21 | "code" 22 | ], 23 | "_comment": "" 24 | } 25 | ], 26 | "fix_its": [ 27 | { 28 | "name": "Add entropy placeholder", 29 | "type": "regex-replace", 30 | "_comment": "", 31 | "replacement": "$1$2", 32 | "pattern": { 33 | "pattern": "(ProtectedData\\.Protect[^,]+,\\s*)null(.*)", 34 | "type": "regex", 35 | "scopes": [ 36 | "code" 37 | ], 38 | "_comment": "" 39 | } 40 | } 41 | ] 42 | }, 43 | { 44 | "name": "Do not store sensitive data in NSUserDefaults.", 45 | "id": "DS191340", 46 | "description": "Do not store sensitive data in NSUserDefaults.", 47 | "recommendation": "Consider another mechanism instead.", 48 | "applies_to": [ 49 | "objective-c" 50 | ], 51 | "tags": [ 52 | "Storage.Apple.iOS.UserDefaults.SensitiveData" 53 | ], 54 | "severity": "moderate", 55 | "_comment": "", 56 | "rule_info": "DS191340.md", 57 | "patterns": [ 58 | { 59 | "pattern": "NSUserDefaults \\*(.*) = \\[NSUserDefaults standardUserDefaults\\];(\\n.*){1,5}$1 .*setString:(password|key)", 60 | "type": "regex", 61 | "scopes": [ 62 | "code" 63 | ], 64 | "_comment": "" 65 | } 66 | ] 67 | } 68 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/vulnerable_libraries/tests/DS378900.test: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/vulnerable_libraries/tests/DS378901.test: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/vulnerable_libraries/tests/DS378902.test: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/xml/external_entities.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Do not enable external entity resolution.", 4 | "id": "DS132779", 5 | "description": "Do not enable external entity resolution.", 6 | "recommendation": "Set shouldResolveExternalEntities to NO.", 7 | "applies_to": [ 8 | "objective-c" 9 | ], 10 | "tags": [ 11 | "Implementation.iOS.XML.DTDEntityResolution" 12 | ], 13 | "severity": "moderate", 14 | "_comment": "", 15 | "rule_info": "DS132779.md", 16 | "patterns": [ 17 | { 18 | "pattern": "shouldResolveExternalEntities\\s*=\\s*YES", 19 | "type": "regex-word", 20 | "scopes": [ 21 | "code" 22 | ], 23 | "_comment": "" 24 | } 25 | ], 26 | "fix_its": [ 27 | { 28 | "name": "Disable external entity resolution", 29 | "type": "regex-replace", 30 | "_comment": "", 31 | "replacement": "$1NO", 32 | "pattern": { 33 | "pattern": "(shouldResolveExternalEntities\\s*=\\s*)(YES)", 34 | "type": "regex", 35 | "scopes": [ 36 | "code" 37 | ], 38 | "_comment": "" 39 | } 40 | } 41 | ] 42 | }, 43 | { 44 | "name": "Do not enable external entity resolution.", 45 | "id": "DS132780", 46 | "description": "Do not enable external entity resolution.", 47 | "recommendation": "x.setShouldResolveExternalEntities = FALSE;", 48 | "applies_to": [ 49 | "swift" 50 | ], 51 | "tags": [ 52 | "Implementation.iOS.XML.DTDEntityResolution" 53 | ], 54 | "severity": "moderate", 55 | "_comment": "", 56 | "rule_info": "DS132780.md", 57 | "patterns": [ 58 | { 59 | "pattern": "shouldResolveExternalEntities\\s*=\\s*TRUE", 60 | "type": "regex-word", 61 | "scopes": [ 62 | "code" 63 | ], 64 | "_comment": "" 65 | } 66 | ], 67 | "fix_its": [ 68 | { 69 | "name": "Disable external entity resolution", 70 | "type": "regex-replace", 71 | "_comment": "", 72 | "replacement": "$1FALSE", 73 | "pattern": { 74 | "pattern": "(shouldResolveExternalEntities\\s*=\\s*)(TRUE)", 75 | "type": "regex", 76 | "scopes": [ 77 | "code" 78 | ], 79 | "_comment": "" 80 | } 81 | } 82 | ] 83 | }, 84 | { 85 | "name": "Do not enable external entity resolution.", 86 | "id": "DS132790", 87 | "description": "Do not enable external entity resolution.", 88 | "recommendation": "[x setShouldResolveExternalEntities: NO];", 89 | "applies_to": [ 90 | "objective-c" 91 | ], 92 | "tags": [ 93 | "Implementation.iOS.XML.DTDEntityResolution" 94 | ], 95 | "severity": "moderate", 96 | "_comment": "", 97 | "rule_info": "DS132790.md", 98 | "patterns": [ 99 | { 100 | "pattern": "setShouldResolveExternalEntities:\\s*YES", 101 | "type": "regex-word", 102 | "scopes": [ 103 | "code" 104 | ], 105 | "_comment": "" 106 | } 107 | ], 108 | "fix_its": [ 109 | { 110 | "name": "Disable external entity resolution", 111 | "type": "regex-replace", 112 | "_comment": "", 113 | "replacement": "$1NO", 114 | "pattern": { 115 | "pattern": "(setShouldResolveExternalEntities:\\s*)(YES)", 116 | "type": "regex", 117 | "scopes": [ 118 | "code" 119 | ], 120 | "_comment": "" 121 | } 122 | } 123 | ] 124 | } 125 | ] -------------------------------------------------------------------------------- /DevSkim-Common/rules/default/security/xml/tests/DS132779.test: -------------------------------------------------------------------------------- 1 | /* Should match */ 2 | foo.shouldResolveExternalEntities = YES ; 3 | bar.shouldResolveExternalEntities=YES; 4 | 5 | /* Should not match */ 6 | foo.shouldResolveExternalEntities = NO ; 7 | bar.shouldResolveExternalEntities=NO; 8 | foo.shouldResolveExternalEntities = baz; 9 | -------------------------------------------------------------------------------- /DevSkim.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017 Microsoft. All rights reserved. 3 | Licensed under the MIT License. See LICENSE.txt in the project root for license information. 4 | 5 | DevSkim Sublime Text Plugin 6 | https://github.com/Microsoft/DevSkim-Sublime-Plugin 7 | """ 8 | 9 | import datetime 10 | import json 11 | import logging 12 | import re 13 | import time 14 | import os 15 | import shlex 16 | import subprocess 17 | import traceback 18 | import webbrowser 19 | 20 | try: 21 | import sublime 22 | import sublime_plugin 23 | except Exception as _: 24 | print("Unable to import Sublime Text modules. DevSkim must be run within Sublime Text.") 25 | import sys 26 | sys.exit(1) 27 | 28 | from . import DevSkimConditionals 29 | 30 | # Non-Configurable Settings 31 | MIN_ST_VERSION = 3114 32 | MARK_FLAGS = sublime.DRAW_NO_FILL | sublime.HIDE_ON_MINIMAP 33 | LOG_FORMAT = '%(asctime)-15s: %(levelname)s: %(name)s.%(funcName)s: %(message)s' 34 | SEVERITY_LIST = ["critical", "important", "moderate", "low", 35 | "defense-in-depth", "informational", "manual-review"] 36 | RULE_DIRECTORY = ['default', 'custom'] 37 | DEVSKIM_RULES_DIR_PREFIX = 'DevSkim-Common/rules/' 38 | 39 | # Minimum Sublime Text version we support 40 | if int(sublime.version()) < MIN_ST_VERSION: 41 | raise RuntimeError('DevSkim requires Sublime Text 3 v%d or later.' % 42 | MIN_ST_VERSION) 43 | 44 | # Global Properties 45 | 46 | devskim_event_listener = None 47 | 48 | # Global logger 49 | logger = logging.getLogger(__name__) 50 | 51 | # Cache of user settings (sublime-provided) 52 | user_settings = None 53 | 54 | # Global objects, used for caching 55 | rules = [] 56 | 57 | # Was the applies_to_ext_mapping already loaded from syntax files? 58 | applies_to_ext_mapping_initialized = False 59 | 60 | # Mapping between symbolic names ("csharp") and what they actually mean. 61 | # This map is updated to include runtime syntax files, so this is just 62 | # a starting point. 63 | applies_to_ext_mapping = { 64 | "aspnet": { 65 | "syntax": [], 66 | "extensions": ["aspx"] 67 | }, 68 | "powershell": { 69 | "syntax": ["Packages/PowerShell/PowerShell.sublime-syntax"], 70 | "extensions": ["ps1"] 71 | }, 72 | "ruby": { 73 | "syntax": [], 74 | "extensions": ["erb"] 75 | }, 76 | "swift": { 77 | "syntax": ["Packages/Swift/Swift.sublime-syntax"], 78 | "extensions": ["swift"] 79 | } 80 | } 81 | applies_to_ext_alias = { 82 | "c": "c++", 83 | "cpp": "c++", 84 | "csharp": "c#", 85 | "ios": "objective-c++", 86 | "objective-c": "objective-c++" 87 | } 88 | 89 | # Currently marked regions 90 | marked_regions = [] 91 | 92 | # Cached stylesheet content 93 | stylesheet_content = "" 94 | 95 | # Cache suppress days 96 | suppress_days = [] 97 | 98 | # Conditional Functions 99 | conditional_func_map = {} 100 | 101 | 102 | class DevSkimEventListener(sublime_plugin.EventListener): 103 | """Handles events from Sublime Text.""" 104 | 105 | # Reference to the current view 106 | view = None 107 | 108 | def __init__(self, *args, **kwargs): 109 | """Initialize events listener.""" 110 | super(DevSkimEventListener, self).__init__(*args, **kwargs) 111 | logger.debug("DevSkimEventListener.__init__()") 112 | 113 | def lazy_initialize(self): 114 | """Perform lazy initialization.""" 115 | global rules, user_settings, stylesheet_content, suppress_days 116 | global applies_to_ext_mapping, applies_to_ext_mapping_initialized 117 | 118 | # logger.debug('lazy_initialize') 119 | 120 | if not user_settings: 121 | user_settings = sublime.load_settings('DevSkim.sublime-settings') 122 | if not user_settings: 123 | logger.warning("Unable to load DevSkim settings.") 124 | return 125 | 126 | user_settings.clear_on_change('DevSkim') 127 | user_settings.add_on_change('DevSkim', self.lazy_initialize) 128 | 129 | if not rules or len(rules) == 0: 130 | self.load_rules() 131 | 132 | if not applies_to_ext_mapping_initialized: 133 | self.load_syntax_mapping() 134 | applies_to_ext_mapping_initialized = True 135 | 136 | if not stylesheet_content: 137 | if not user_settings: 138 | logger.warning("Unable to load DevSkim settings.") 139 | return 140 | css_file = user_settings.get('style', 'dark.css') 141 | stylesheets = sublime.find_resources(css_file) 142 | if stylesheets: 143 | stylesheet_content = sublime.load_resource(stylesheets[0]) 144 | stylesheet_content = stylesheet_content.replace('\r\n', '\n') 145 | logger.debug("Stylesheet: [%s]", stylesheet_content) 146 | else: 147 | stylesheet_content = "" 148 | logger.debug("No stylesheet found.") 149 | 150 | if not suppress_days: 151 | if not user_settings: 152 | logger.warning("Unable to load DevSkim settings.") 153 | return 154 | suppress_days = user_settings.get('suppress_days', [90, 365, -1]) 155 | logger.debug('Suppress Days: %s', suppress_days) 156 | 157 | # Initialize the logger 158 | if len(logger.handlers) == 0: 159 | root_logger = logging.getLogger() 160 | console = logging.StreamHandler() 161 | console.setFormatter(logging.Formatter(LOG_FORMAT)) 162 | 163 | if user_settings.get('debug', False): 164 | root_logger.setLevel(logging.DEBUG) 165 | else: 166 | root_logger.setLevel(logging.WARNING) 167 | 168 | logger.handlers = [] 169 | logger.addHandler(console) 170 | 171 | # Initialize the conditionals 172 | for func in dir(DevSkimConditionals): 173 | if func.startswith('condition__'): 174 | func_short = func.replace('condition__', '') 175 | conditional_func_map[func_short] = getattr(DevSkimConditionals, func) 176 | 177 | def clear_regions(self, view): 178 | """Clear all regions.""" 179 | global marked_regions, finding_list 180 | 181 | logger.debug("clear_regions()") 182 | 183 | if view: 184 | view.erase_regions("devskim-marks") 185 | marked_regions = [] 186 | finding_list = [] 187 | 188 | def on_selection_modified(self, view): 189 | """Handle selection change events.""" 190 | global marked_regions, finding_list 191 | 192 | self.lazy_initialize() 193 | 194 | try: 195 | # Get the current region (cursor start) 196 | cur_region = view.sel()[0] 197 | 198 | for region in marked_regions: 199 | if region.contains(cur_region): 200 | for finding in finding_list: 201 | if finding.get("match_region") != region: 202 | continue 203 | rule = finding.get('rule') 204 | view.set_status("DevSkim", "DevSkim: %s" % rule.get("name")) 205 | return 206 | 207 | # We're not in a marked region, clear the status bar 208 | view.erase_status("DevSkim") 209 | 210 | except Exception as msg: 211 | logger.warning("Error in on_selection_modified: %s", msg) 212 | 213 | def on_navigate(self, command): 214 | """Handle navigation events.""" 215 | global finding_list, rules, user_settings 216 | self.lazy_initialize() 217 | 218 | logger.debug("on_navigate(%s)", command) 219 | 220 | if not command: 221 | return 222 | 223 | command = command.strip() 224 | 225 | # Open a regular URL in the user's web browser 226 | if re.match("^https?://", command, re.IGNORECASE): 227 | webbrowser.open_new(command) 228 | return 229 | 230 | # Special commands, intercept and perform the fix 231 | if command.startswith('#fixit'): 232 | rule_id, fixid, region_start, region_end = command.split(',')[1:] 233 | fixid = int(fixid) 234 | region_start = int(region_start) 235 | region_end = int(region_end) 236 | 237 | for finding in finding_list: 238 | rule = finding.get('rule') 239 | 240 | # We're only searching for a specific rule id 241 | if rule.get('id') != rule_id: 242 | continue 243 | 244 | contents = self.view.substr(sublime.Region(region_start, region_end)) 245 | logger.debug("Applying fixit to contents [{0}]".format(contents)) 246 | 247 | fixit = rule.get('fix_it') 248 | if not fixit or fixid >= len(fixit): 249 | continue 250 | 251 | fixit = fixit[fixid] 252 | if not fixit: 253 | logger.warn("Tried to apply fixit #{%s}, but was not found in dict.", fixid) 254 | continue 255 | 256 | if fixit['type'] == 'regex-substitute': 257 | search = fixit.get('search') 258 | replace = fixit.get('replace') 259 | flags = self.re_modifiers_to_flags(fixit.get('modifiers', [])) 260 | 261 | for k in range(1, 9): 262 | replace = replace.replace("${0}".format(k), "\\{0}".format(k)) 263 | 264 | result = re.sub(search, replace, contents, flags=flags) 265 | logger.debug("Result of search/replace was [%s]", result) 266 | 267 | self.view.run_command('replace_text', { 268 | 'a': region_start, 269 | 'b': region_end, 270 | 'result': result 271 | }) 272 | else: 273 | logger.warn("Invalid fixit type found, {0}".format(fixit['type'])) 274 | 275 | self.view.hide_popup() 276 | self.clear_regions(self.view) 277 | self.view.sel().clear() 278 | 279 | # Only fix once 280 | break 281 | 282 | elif command.startswith('#add-reviewed'): 283 | rule_id, region_start = command.split(',')[1:] 284 | cur_line = self.view.line(int(region_start)) 285 | 286 | comment = " DevSkim: reviewed %s on %s " % (rule_id, datetime.datetime.now().strftime("%Y-%m-%d")) 287 | 288 | username = user_settings.get('manual_reviewer_name', '') 289 | if username == '': 290 | try: 291 | import getpass 292 | username = getpass.getuser() 293 | except: 294 | pass 295 | 296 | if username: 297 | comment += "by {0} ".format(username) 298 | 299 | # Add the pragma/comment at the end of the current line 300 | self.view.run_command('insert_text', { 301 | 'a': cur_line.b, 302 | 'result': comment 303 | }) 304 | 305 | # Now highlight that new section 306 | prev_sel = self.view.sel() 307 | self.view.sel().clear() 308 | self.view.sel().add(sublime.Region(cur_line.b + 1, cur_line.b + len(comment))) 309 | 310 | # Now make it a block comment 311 | self.view.run_command('toggle_comment', {'block': True}) 312 | self.view.sel().clear() 313 | self.view.sel().add_all(prev_sel) 314 | 315 | self.view.hide_popup() 316 | 317 | elif command.startswith('#add-suppression'): 318 | rule_id, region_start, suppress_day = command.split(',')[1:] 319 | cur_line = self.view.line(int(region_start)) 320 | 321 | # Ignore suppression for this many days from today 322 | try: 323 | suppress_day = int(suppress_day) 324 | except Exception as msg: 325 | suppress_day = -1 326 | 327 | if suppress_day == -1: # Permanent suppression 328 | comment = " DevSkim: ignore %s " % rule_id 329 | else: 330 | until_day = datetime.date.today() + datetime.timedelta(days=suppress_day) 331 | comment = " DevSkim: ignore %s until %s " % (rule_id, until_day.strftime("%Y-%m-%d")) 332 | 333 | # Add the pragma/comment at the end of the current line 334 | self.view.run_command('insert_text', { 335 | 'a': cur_line.b, 336 | 'result': comment 337 | }) 338 | 339 | # Now highlight that new section 340 | prev_sel = self.view.sel() 341 | self.view.sel().clear() 342 | self.view.sel().add(sublime.Region(cur_line.b + 1, cur_line.b + len(comment))) 343 | 344 | # Now make it a block comment 345 | self.view.run_command('toggle_comment', {'block': True}) 346 | self.view.sel().clear() 347 | self.view.sel().add_all(prev_sel) 348 | 349 | self.view.hide_popup() 350 | 351 | else: 352 | logger.debug("Invalid command: %s", command) 353 | 354 | def on_modified(self, view): 355 | """Handle immedate analysis (on keypress).""" 356 | global user_settings 357 | 358 | # if view.change_count() % 10 != 0: 359 | # return 360 | 361 | self.lazy_initialize() 362 | 363 | if user_settings.get('show_highlights_on_modified', False): 364 | try: 365 | self.analyze_current_view(view, show_popup=False, single_line=True) 366 | except Exception as msg: 367 | logger.warning("Error analyzing current view: %s", msg) 368 | traceback.print_exc() 369 | 370 | def on_load_async(self, view): 371 | """Handle asynchronous loading event.""" 372 | global user_settings 373 | self.lazy_initialize() 374 | 375 | if user_settings.get('show_highlights_on_load', False): 376 | try: 377 | self.analyze_current_view(view, show_popup=False) 378 | except Exception as msg: 379 | logger.warning("Error analyzing current view: %s", msg) 380 | traceback.print_exc() 381 | 382 | def on_post_save_async(self, view): 383 | """Handle post-save events.""" 384 | global user_settings 385 | self.lazy_initialize() 386 | 387 | logger.debug("on_post_save_async()") 388 | 389 | if user_settings.get('show_findings_on_save', True): 390 | try: 391 | self.analyze_current_view(view) 392 | except Exception as msg: 393 | logger.warning("Error analyzing current view: %s", msg) 394 | traceback.print_exc() 395 | 396 | def analyze_current_view(self, view, show_popup=True, single_line=False): 397 | """Kick off the analysis.""" 398 | global marked_regions, finding_list, user_settings 399 | 400 | logger.debug("analyze_current_view()") 401 | self.lazy_initialize() 402 | 403 | if view is None or view.window() is None: 404 | # Early abort if we don't have a View and Window 405 | return 406 | 407 | window = view.window() 408 | 409 | if not single_line: 410 | self.clear_regions(view) 411 | 412 | filename = window.extract_variables().get('file', '').replace('\\', '/') 413 | if filename and self.is_file_ignored(filename): 414 | logger.debug("File is ignored.") 415 | return 416 | 417 | # Time the execution of this function 418 | start_time = time.clock() 419 | 420 | self.view = view 421 | 422 | # Check for files too large to scan 423 | max_size = user_settings.get('max_size', 524288) 424 | if 0 < max_size < view.size(): 425 | logger.debug("File was too large to scan (%d bytes)", view.size()) 426 | return 427 | 428 | window = self.view.window() 429 | if window is None: 430 | return 431 | 432 | extension = window.extract_variables().get('file_extension', '') 433 | 434 | show_severity = user_settings.get('show_severity', SEVERITY_LIST) 435 | 436 | # File syntax type 437 | syntax = view.settings().get('syntax') 438 | 439 | # Reset the UI (except if analyzing only a single line) 440 | if not single_line: 441 | self.clear_regions(view) 442 | finding_list = [] 443 | 444 | # Grab the full file as a region 445 | full_region = sublime.Region(0, view.size()) 446 | 447 | # Reset the marked regions for this view 448 | if not single_line: 449 | marked_regions = [] 450 | 451 | if single_line: 452 | file_contents = view.substr(view.line(view.sel()[0])) 453 | logger.debug("Single line: [%s]", file_contents) 454 | offset = view.line(view.sel()[0]).begin() 455 | else: 456 | # Send the entire file over to DevSkim.execute 457 | file_contents = view.substr(full_region) 458 | logger.debug("File contents, size [%d]", len(file_contents)) 459 | offset = 0 460 | 461 | result_list = [] 462 | try: 463 | _v = window.extract_variables() 464 | filename = _v.get('file', '').replace('\\', '/') 465 | force_analyze = (extension == 'test' and 466 | 'DevSkim' in filename and 467 | '/tests/' in filename) 468 | result_list = self.execute(file_contents, filename, extension, syntax, 469 | show_severity, force_analyze, offset) 470 | logger.debug("DevSkim retured: [%s]", result_list) 471 | except Exception as ex: 472 | logger.warning("Error executing DevSkim: [%s]", ex) 473 | traceback.print_exc() 474 | 475 | # rule['overrides'] logic 476 | overrides_list = [] 477 | 478 | # This is a bug -- how should we handle this? 479 | for result in result_list: 480 | if 'overrides' in result['rule']: 481 | overrides_list += result['rule']['overrides'] 482 | 483 | original_result_list_count = len(result_list) 484 | for rule_id in overrides_list: 485 | # Remove all results that match a id in the overrides_list 486 | result_list = list(filter(lambda r: r['rule']['id'] != rule_id, 487 | result_list)) 488 | 489 | if original_result_list_count > len(result_list): 490 | logger.debug("Reduced result list from [%d] to [%d] by overriding rules", 491 | original_result_list_count, len(result_list)) 492 | 493 | for result in result_list: 494 | # Narrow down to just the matching part of the line 495 | scope_name = view.scope_name(result.get('match_region').begin()) 496 | 497 | scope_list = ["%s." % s for s in result.get('scope_list')] 498 | logger.debug("Current Scope: [%s], Applies to: %s", scope_name, scope_list) 499 | 500 | # Don't actually include if we're in a comment, or a quoted string, etc. 501 | if any([x in scope_name for x in scope_list]) or not scope_list: 502 | marked_regions.append(result.get('match_region')) 503 | finding_list.append(result) 504 | 505 | logger.debug("Set marked regions to: %s" % marked_regions) 506 | 507 | # Add a region (squiggly underline) 508 | view.add_regions("devskim-marks", 509 | marked_regions, 510 | "string", 511 | user_settings.get('gutter_mark', 'dot'), 512 | flags=MARK_FLAGS) 513 | 514 | shown_finding_list = [] 515 | 516 | # Sort the findings 517 | if len(marked_regions) > 0: 518 | sort_by = user_settings.get('sort_results_by', 'line_number') 519 | if sort_by == 'severity': 520 | finding_list.sort(key=lambda s: SEVERITY_LIST.index(s.get('rule').get('severity'))) 521 | elif sort_by == 'line_number': 522 | finding_list.sort(key=lambda s: view.rowcol(s.get('match_region').begin())[0]) 523 | logger.debug("Findings have been sorted.") 524 | 525 | for finding in finding_list: 526 | rule = finding.get('rule') 527 | region_start = finding.get("match_region").begin() 528 | region = view.rowcol(region_start) 529 | severity = rule.get('severity', 'informational') 530 | severity = self.severity_abbreviation(severity).upper() 531 | 532 | shown_finding_list.append([rule.get("name"), "%d: %s" % 533 | (region[0] + 1, 534 | view.substr(view.line(region_start)).strip())]) 535 | 536 | logger.debug("shown_findings_list has been created.") 537 | 538 | if show_popup: 539 | window.show_quick_panel(shown_finding_list, self.on_selected_result) 540 | 541 | end_time = time.clock() 542 | logger.debug("Elapsed time: %f" % (end_time - start_time)) 543 | 544 | def on_selected_result(self, index): 545 | """Handle when the user clicks on a finding from the popup menu.""" 546 | global finding_list, stylesheet_content, user_settings 547 | self.lazy_initialize() 548 | 549 | if index == -1: 550 | return 551 | 552 | chosen_item = finding_list[index] 553 | target_region = chosen_item.get('match_region') 554 | 555 | self.view.sel().clear() 556 | self.view.sel().add(target_region) 557 | self.view.show(target_region) 558 | 559 | rule = chosen_item['rule'] 560 | 561 | # Create a guidance popup 562 | guidance = [''] 563 | 564 | if stylesheet_content: 565 | guidance.append('' % stylesheet_content) 566 | 567 | guidance.append("

%s

" % rule.get('name', 'Missing rule name')) 568 | guidance.append('

%s

' % rule.get('description', 'Missing rule description')) 569 | 570 | if rule.get('replacement'): 571 | guidance.append('

%s

' % rule['replacement']) 572 | 573 | if rule.get('fix_it'): 574 | guidance.append('

Options:

') 575 | guidance.append("
    ") 576 | for fixid, fix in enumerate(rule.get('fix_it')): 577 | guidance.append('
  • Auto-Fix: %s
  • ' % 578 | (rule.get('id'), fixid, target_region.begin(), target_region.end(), fix.get('name'))) 579 | guidance.append("
") 580 | 581 | # Supression links 582 | this_suppression_links = [] 583 | all_suppression_links = [] 584 | for suppress_day in suppress_days: 585 | suppress_day_str = "%d days" % suppress_day if suppress_day != -1 else "permanently" 586 | this_suppression_links.append('[ %s ] ' % 587 | (rule.get('id'), target_region.a, suppress_day, suppress_day_str)) 588 | all_suppression_links.append('[ %s ] ' % 589 | (target_region.a, suppress_day, suppress_day_str)) 590 | 591 | guidance.append("
    ") 592 | if rule.get('severity') == 'manual-review': 593 | guidance.append('
  • Mark finding as reviewed
  • '.format(rule.get('id'), target_region.a)) 594 | else: 595 | if user_settings.get('allow_suppress_specific_rules'): 596 | guidance.append("
  • Supress this rule for: %s
  • " % (''.join(this_suppression_links))) 597 | if user_settings.get('allow_suppress_all_rules'): 598 | guidance.append("
  • Supress all rules for: %s
  • " % (''.join(all_suppression_links))) 599 | guidance.append('
') 600 | 601 | 602 | if rule.get('rule_info'): 603 | guidance.append('

Learn More...

' % rule.get('rule_info')) 604 | elif user_settings.get('debug', False): 605 | guidance.append('

Rule: %s

' % rule.get('id')) 606 | 607 | guidance.append('') 608 | 609 | sublime.set_timeout_async(lambda: self.ds_show_popup(''.join(guidance), 610 | location=target_region.end(), 611 | max_width=860, 612 | max_height=560, 613 | on_navigate=self.on_navigate, 614 | flags=sublime.HTML), 0) 615 | 616 | def load_rules(self, force_reload=False): 617 | """Reload ruleset from the JSON configuration files.""" 618 | global rules, user_settings 619 | 620 | if not force_reload and len(rules) > 0: 621 | logger.debug("Rules already loaded, no need to reload.") 622 | return False 623 | 624 | logger.debug('DevSkimEngine.load_rules()') 625 | 626 | if not user_settings: 627 | logger.warning("Settings not found, cannot load rules.") 628 | return False 629 | 630 | json_filenames = sublime.find_resources("*.json") 631 | rule_filenames = [] 632 | for filename in json_filenames: 633 | for _dir in RULE_DIRECTORY: 634 | if (DEVSKIM_RULES_DIR_PREFIX + _dir) in filename: 635 | rule_filenames.append(filename) 636 | 637 | # Remove duplicates 638 | rule_filenames = list(set(rule_filenames)) 639 | logger.debug("Loaded %d rule files" % len(rule_filenames)) 640 | 641 | # We load rules from each rule file here. 642 | rules = [] 643 | for rule_filename in rule_filenames: 644 | try: 645 | rules += json.loads(sublime.load_resource(rule_filename)) 646 | except Exception as msg: 647 | logger.warning("Error loading [%s]: %s" % (rule_filename, msg)) 648 | if user_settings.get('debug', False): 649 | sublime.error_message("Error loading [%s]" % rule_filename) 650 | 651 | # Now we load custom rules on top of this. 652 | try: 653 | for rule_filename in user_settings.get('custom_rules', []): 654 | try: 655 | env_variables = sublime.active_window().extract_variables() 656 | rule_filename = sublime.expand_variables(rule_filename, 657 | env_variables) 658 | 659 | with open(rule_filename, encoding='utf-8') as crf: 660 | custom_rule = json.loads(crf.read()) 661 | rules += custom_rule 662 | except Exception as msg: 663 | logger.warning("Error opening [%s]: %s" % 664 | (rule_filename, msg)) 665 | except Exception as msg: 666 | logger.warning("Error opening custom rules: %s" % msg) 667 | 668 | if not user_settings: 669 | logger.warning("Settings not found, cannot load rules.") 670 | return False 671 | 672 | for rule_id in user_settings.get('suppress_rules', []): 673 | try: 674 | rules = filter(lambda s: s.get('id', '') != rule_id, rules) 675 | except Exception as msg: 676 | logger.warning("Error suppressing rules for %s: %s" % 677 | (rule_id, msg)) 678 | 679 | # Only include non-disabled rules -- if 'disabled' is not specified, assume False 680 | rules = list(filter(lambda x: not x.get('disabled', False), rules)) 681 | 682 | # Filter by tags, if specified, convert all to lowercase 683 | show_only_tags = set([k.lower().strip() 684 | for k in user_settings.get('show_only_tags', [])]) 685 | if show_only_tags: 686 | def filter_func(x): 687 | return set([k.lower().strip() 688 | for k in x.get('tags', [])]) & show_only_tags 689 | 690 | rules = list(filter(filter_func, rules)) 691 | 692 | logger.debug("Loaded %d rules" % len(rules)) 693 | 694 | return True 695 | 696 | def load_syntax_mapping(self): 697 | """Load syntax content from various installed packages.""" 698 | global applies_to_ext_mapping, applies_to_ext_alias 699 | 700 | logger.debug('DevSkimEngine.load_syntax_mapping()') 701 | 702 | def _convert_mapping_to_sets(): 703 | for k, v in applies_to_ext_mapping.items(): 704 | applies_to_ext_mapping[k]['syntax'] = \ 705 | set(applies_to_ext_mapping[k]['syntax']) 706 | applies_to_ext_mapping[k]['extensions'] = \ 707 | set(applies_to_ext_mapping[k]['extensions']) 708 | 709 | _convert_mapping_to_sets() 710 | 711 | # Iterate through all syntax files 712 | for filename in sublime.find_resources("*.sublime-syntax"): 713 | # Load the contents 714 | syntax_file = sublime.load_resource(filename) 715 | logger.debug("Loading syntax: {0}".format(filename)) 716 | 717 | applies_to_name = None 718 | 719 | # Look for all extensions 720 | in_file_extensions = False 721 | 722 | for line in syntax_file.splitlines(): 723 | # Clean off whitepsace 724 | line = line.strip() 725 | 726 | name_match = re.match(r'name: (.*)', line) 727 | if name_match: 728 | applies_to_name = name_match.group(1).replace("\"", "").lower().strip() 729 | if applies_to_name not in applies_to_ext_mapping: 730 | applies_to_ext_mapping[applies_to_name] = { 731 | 'syntax': set([filename]), 732 | 'extensions': set() 733 | } 734 | continue 735 | 736 | # Are we entering? 737 | if line == 'file_extensions:': 738 | in_file_extensions = True 739 | continue 740 | 741 | # Are we in the file extension section? 742 | if in_file_extensions: 743 | if line.startswith('- '): 744 | # Add the extension to the mapping 745 | extension = line.replace("- ", "").strip() 746 | logger.debug("Added additional extension: {0}".format(extension)) 747 | applies_to_ext_mapping[applies_to_name]['extensions'].add(extension) 748 | else: 749 | in_file_extensions = False 750 | break 751 | 752 | _convert_mapping_to_sets() 753 | 754 | # Copy over alias'ed keys (e.g. "csharp" => "c#") 755 | for k, v in applies_to_ext_alias.items(): 756 | if k not in applies_to_ext_mapping: 757 | applies_to_ext_mapping[k] = { 758 | 'syntax': set(), 759 | 'extensions': set() 760 | } 761 | applies_to_ext_mapping[k]['syntax'] |= applies_to_ext_mapping[v]['syntax'] 762 | applies_to_ext_mapping[k]['extensions'] |= applies_to_ext_mapping[v]['extensions'] 763 | 764 | 765 | def re_modifiers_to_flags(self, modifiers, default=re.IGNORECASE | re.MULTILINE): 766 | """Convert modifier flags from rules to a regex flag value.""" 767 | flags = 0 768 | if modifiers: 769 | modifiers = map(lambda s: s.lower(), modifiers) 770 | 771 | # The rule here is that if a modifier is passed, 772 | # then that's the modifier used. Otherwise, we do 773 | # IGNORECASE | MULTILINE. 774 | if 'dotall' in modifiers: 775 | flags |= re.DOTALL 776 | if 'multiline' in modifiers: 777 | flags |= re.MULTILINE 778 | if 'ignorecase' in modifiers: 779 | flags |= re.IGNORECASE 780 | else: 781 | flags = default 782 | 783 | return flags 784 | 785 | def execute(self, file_contents, filename=None, extension=None, syntax=None, 786 | severities=None, force_analyze=False, offset=0): 787 | """Execute all of the rules against a given string of text.""" 788 | global rules, applies_to_ext_mapping 789 | 790 | logger.debug("execute([len=%d], [name=%s], [ext=%s], [syntax=%s], [force=%s], [offset=%d])" % 791 | (len(file_contents), filename, extension, syntax, force_analyze, offset)) 792 | 793 | filename_basename = os.path.basename(filename).strip() 794 | 795 | if not file_contents: 796 | return [] 797 | 798 | syntax_types = [] # Example: ["csharp"], from the file itself 799 | 800 | # TODO Cache this elsewhere, silly to do every time, I think. 801 | for k, v in applies_to_ext_mapping.items(): 802 | if (syntax in v.get('syntax', []) or 803 | extension in v.get('extensions', [])): 804 | k = k.replace("\"", "") # Some names are quoted 805 | syntax_types.append(k) 806 | result_list = [] 807 | syntax_types = list(set(syntax_types)) 808 | 809 | logger.debug("Loaded syntax types: {0}".format(syntax_types)) 810 | 811 | for rule in rules: 812 | logger.debug('Rule: {0}'.format(rule.get('id', None))) 813 | 814 | # Don't even scan for rules that we don't care about 815 | if not force_analyze and rule.get('severity', 'critical') not in severities: 816 | logger.debug("Ignoring rule [%s] due to severity." % rule.get('id', '')) 817 | continue 818 | 819 | # No syntax means "match any syntax" 820 | rule_applies_to = rule.get('applies_to', []) 821 | if (force_analyze or 822 | not rule_applies_to or 823 | filename_basename in rule_applies_to or 824 | set(rule_applies_to) & set(syntax_types) or 825 | '.%s' % extension in rule_applies_to): 826 | 827 | for pattern_dict in rule['patterns']: 828 | # Secondary applicability 829 | pattern_applies_to = set(pattern_dict.get('applies_to', [])) 830 | if (pattern_applies_to and 831 | not force_analyze and 832 | not pattern_applies_to & set(syntax_types) and 833 | not '.%s' % extension in pattern_applies_to): 834 | logger.debug("Ignoring rule [%s], applicability check." % rule.get('id', '')) 835 | continue 836 | 837 | pattern_str = pattern_dict.get('pattern') 838 | 839 | start = end = -1 840 | 841 | orig_pattern_str = pattern_str 842 | 843 | if pattern_dict.get('type') == 'substring': 844 | pattern_str = re.escape(pattern_str) 845 | elif pattern_dict.get('type') == 'string': 846 | pattern_str = r'\b%s\b' % re.escape(pattern_str) 847 | elif pattern_dict.get('type') == 'regex': 848 | pass 849 | elif pattern_dict.get('type') == 'regex-word': 850 | pattern_str = r'\b%s\b' % pattern_str 851 | else: 852 | logger.warning("Invalid pattern type [%s] found." % 853 | pattern_dict.get('type')) 854 | continue 855 | 856 | scope_list = pattern_dict.get('subtype', []) 857 | 858 | flags = self.re_modifiers_to_flags(pattern_dict.get('modifiers', [])) 859 | 860 | logger.debug('Searching for {0} in contents.'.format(pattern_str)) 861 | 862 | for match in re.finditer(pattern_str, file_contents, flags): 863 | 864 | if not match: 865 | logger.debug("re.finditer([%s], [%s]) => [-]" % 866 | (pattern_str, len(file_contents))) 867 | continue # Does this ever happen? 868 | 869 | logger.debug("re.finditer([%s], [%s]) => [%d, %d]" % 870 | (pattern_str, len(file_contents), 871 | match.start(), match.end())) 872 | 873 | start = match.start() 874 | end = match.end() 875 | 876 | # Check for per-row suppressions 877 | row_number = self.view.rowcol(start) 878 | line_list = [ 879 | self.view.substr(self.view.line(start)) 880 | ] 881 | if row_number[0] > 0: # Special case, ignore 882 | prev_line = self.view.text_point(row_number[0] - 1, 0) 883 | line_list.append(self.view.substr(self.view.line(prev_line))) 884 | 885 | if self.is_suppressed(rule, line_list): 886 | continue # Don't add the result to the list 887 | 888 | # If there are conditions, run them now 889 | context = { 890 | 'filename': filename, 891 | 'file_contents': file_contents, 892 | 'rule': rule, 893 | 'pattern': pattern_dict 894 | } 895 | 896 | result_details = { 897 | 'rule': rule, 898 | 'match_content': match.group(), 899 | 'match_region': sublime.Region(start + offset, end + offset), 900 | 'match_start': start + offset, 901 | 'match_end': end + offset, 902 | 'pattern': orig_pattern_str, 903 | 'scope_list': scope_list 904 | } 905 | 906 | if self.meets_conditions(context, result_details): 907 | result_list.append(result_details) 908 | else: 909 | logger.debug("Not running rule check [force={0}, rule_applies={1}, syntax={2}, ext={3},]".format( 910 | force_analyze, rule_applies_to, set(rule_applies_to) & set(syntax_types), extension)) 911 | 912 | return result_list 913 | 914 | def meets_conditions(self, context, result): 915 | """Checks to see if a finding meets specified conditions from the rule.""" 916 | pattern = context.get('pattern') 917 | if not pattern: 918 | return True # No pattern means same thing as them all passing. 919 | 920 | conditions = pattern.get('conditions') 921 | if not conditions: 922 | return True # No conditions means same as them all passing. 923 | 924 | match_start = result.get('match_start') 925 | line = self.view.substr(self.view.line(match_start)) 926 | 927 | if not line: 928 | logger.error('No line was found in meets_conditions') 929 | return True # No line means something is broken 930 | 931 | logger.debug('Found %d conditions', len(conditions)) 932 | 933 | cond_result = True 934 | 935 | for condition in conditions: 936 | name = condition.get('name', '').replace('-', '_') 937 | value = condition.get('value') 938 | invert = condition.get('invert', False) 939 | 940 | if name in conditional_func_map: 941 | kwargs = { 942 | 'view': self.view, 943 | 'line': line, 944 | 'value': value 945 | } 946 | kwargs.update(context) 947 | kwargs.update(result) 948 | 949 | r = conditional_func_map[name](**kwargs) 950 | cond_result &= not r if invert else r 951 | else: 952 | logger.warning('Invalid condition name: %s', name) 953 | 954 | return cond_result 955 | 956 | def severity_abbreviation(self, severity): 957 | """Convert a severity name into an abbreviation.""" 958 | if severity is None: 959 | return "" 960 | severity = severity.strip().lower() 961 | 962 | if severity == "critical": 963 | return "crit" 964 | elif severity == "important": 965 | return "imp." 966 | elif severity == "moderate": 967 | return "mod." 968 | elif severity == "low": 969 | return "low" 970 | elif severity == "defense-in-depth": 971 | return "did." 972 | elif severity == "informational": 973 | return "info" 974 | elif severity == "manual-review": 975 | return "rvw." 976 | return "" 977 | 978 | def is_suppressed(self, rule, lines): 979 | """Should the result be suppressed based on the given rule and line content.""" 980 | global user_settings 981 | 982 | if not rule or not lines: 983 | return False 984 | 985 | # Are suppression rules enabled at all? 986 | if not user_settings.get('allow_suppress_specific_rules') and not user_settings.get('allow_suppress_all_rules'): 987 | logger.debug('Suppression disabled via config, nothing to do.') 988 | return False 989 | 990 | for line in lines: 991 | line = line.lower() 992 | if 'devskim:' not in line: 993 | continue 994 | 995 | if user_settings.get('allow_suppress_specific_rules'): 996 | for match in re.finditer(r'ignore ([^\s]+)\s*(?!\s+until (\d{4}-\d{2}-\d{2}))', line): 997 | if match.group(1).lower() == rule.get('id').lower(): 998 | suppress_until = match.group(2) 999 | if suppress_until is None: 1000 | # Permanent suppression of this rule 1001 | return True 1002 | try: 1003 | suppress_until = datetime.datetime.strptime(suppress_until, '%Y-%m-%d') 1004 | if datetime.date.today() < suppress_until.date(): 1005 | logger.debug('Ignoring rule [%s], limited suppression.', rule.get('id')) 1006 | return True 1007 | except Exception as msg: 1008 | logger.debug("Error parsing suppression date 1: %s", msg) 1009 | 1010 | if user_settings.get('allow_suppress_all_rules'): 1011 | for match in re.finditer(r'ignore all\s*(?!\s+until (\d{4}-\d{2}-\d{2}))', line): 1012 | suppress_until = match.group(1) 1013 | if suppress_until is None: 1014 | # Permanent suppression of all rules 1015 | return True 1016 | try: 1017 | suppress_until = datetime.datetime.strptime(suppress_until, '%Y-%m-%d') 1018 | if datetime.date.today() < suppress_until.date(): 1019 | logger.debug('Ignoring rule [%s] global suppression.', rule.get('id')) 1020 | return True 1021 | except Exception as msg: 1022 | logger.debug("Error parsing suppression date 2: %s", msg) 1023 | 1024 | if rule.get('severity') == 'manual-review': 1025 | if re.search(r'reviewed ([^\s]+)\s*(?!\s+on \d{4}-\d{2}-\d{2})', line): 1026 | logger.debug('Ignoring rule [%s], manual review complete.', rule.get('id')) 1027 | return True 1028 | 1029 | return False 1030 | 1031 | def ds_show_popup(self, content, flags, location, max_width, max_height, 1032 | on_navigate=None, on_hide=None, repeat_duration_ms=50): 1033 | """Delay-load a popup to give the UI time to get to the scrolled position.""" 1034 | if self.view.is_popup_visible(): 1035 | return # OK, a popup is already being shown 1036 | 1037 | # Try to show the popup 1038 | self.view.show_popup(content=content, 1039 | flags=flags, 1040 | location=location, 1041 | max_width=max_width, 1042 | max_height=max_height, 1043 | on_navigate=on_navigate, 1044 | on_hide=on_hide) 1045 | 1046 | # Retry in case we're scrolling 1047 | sublime.set_timeout_async(lambda: self.ds_show_popup(content=content, 1048 | flags=flags, 1049 | location=location, 1050 | max_width=max_width, 1051 | max_height=max_height, 1052 | on_navigate=on_navigate, 1053 | on_hide=on_hide), repeat_duration_ms) 1054 | 1055 | def is_file_ignored(self, filename): 1056 | """Check to see if a file (by filename) is ignored from analysis.""" 1057 | global user_settings 1058 | 1059 | if not filename: 1060 | return False 1061 | 1062 | for ignore_pattern in user_settings.get('ignore_files', []): 1063 | logger.warning("Checking {0}".format(ignore_pattern)) 1064 | if re.match(ignore_pattern, filename, re.IGNORECASE): 1065 | return True 1066 | 1067 | if not user_settings.get('ignore_from_gitignore', True): 1068 | return False 1069 | 1070 | try: 1071 | if os.name == 'nt': 1072 | # Only supported on Windows 1073 | startupinfo = subprocess.STARTUPINFO() 1074 | startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 1075 | creationflags = subprocess.SW_HIDE 1076 | else: 1077 | startupinfo = None 1078 | creationflags = 0 1079 | 1080 | cwd = os.path.dirname(filename) 1081 | filename = shlex.quote(filename) 1082 | output = subprocess.check_output(["git", "check-ignore", "--no-index", filename], 1083 | cwd=cwd, stderr=subprocess.STDOUT, shell=False, 1084 | startupinfo=startupinfo, 1085 | creationflags=creationflags) 1086 | return filename in output.decode('utf-8') 1087 | except subprocess.CalledProcessError as msg: 1088 | # This is OK, just catching non-zero errorlevel 1089 | return filename in msg.output.decode('utf-8') 1090 | except Exception as msg: 1091 | logger.warning("Error checking if file is ignored: %s", msg) 1092 | 1093 | return False 1094 | 1095 | class ReplaceTextCommand(sublime_plugin.TextCommand): 1096 | """Simple function to route text changes to view.""" 1097 | 1098 | def run(self, edit, a, b, result): 1099 | """Replace given text for a region in a view.""" 1100 | logger.debug("Replacing [%s] into region (%d, %d)" % (result, a, b)) 1101 | self.view.replace(edit, sublime.Region(a, b), result) 1102 | 1103 | 1104 | class InsertTextCommand(sublime_plugin.TextCommand): 1105 | """Simple function to route text inserts to view.""" 1106 | 1107 | def run(self, edit, a, result): 1108 | """Insert given text for a region in a view.""" 1109 | self.view.insert(edit, a, result) 1110 | 1111 | 1112 | class DevSkimAnalyzeCommand(sublime_plugin.TextCommand): 1113 | """Perform an ad-hoc analysis of the open file.""" 1114 | 1115 | def run(self, edit_token, **args): 1116 | """Execute the analysis.""" 1117 | global devskim_event_listener 1118 | logger.debug("DevSkimAnalyzeCommand invoked.") 1119 | 1120 | if not devskim_event_listener: 1121 | devskim_event_listener = DevSkimEventListener() 1122 | try: 1123 | show_popup = args.get('show_popup', True) 1124 | devskim_event_listener.analyze_current_view(self.view, show_popup=show_popup) 1125 | except Exception as msg: 1126 | logger.warning("Error analyzing current view: %s" % msg) 1127 | traceback.print_exc() 1128 | 1129 | 1130 | class DevSkimReloadRulesCommand(sublime_plugin.TextCommand): 1131 | """Mark the DevSkim rules to be reloaded next time they're needed.""" 1132 | 1133 | def run(self, text): 1134 | """Execute the analysis.""" 1135 | global rules, stylesheet_content 1136 | rules = [] 1137 | stylesheet_content = "" 1138 | 1139 | def periodic_analysis_callback(): 1140 | try: 1141 | view = sublime.active_window().active_view() 1142 | view.run_command("dev_skim_analyze", args={'show_popup': False}) 1143 | frequency = sublime.load_settings('DevSkim.sublime-settings').get('show_highlights_on_time', 0) 1144 | # Re-evaluate this so changes are picked up if the user changes their config. 1145 | if frequency > 0: 1146 | sublime.set_timeout_async(periodic_analysis_callback, frequency) 1147 | 1148 | except Exception as msg: 1149 | print("Error: {0}".format(msg)) 1150 | 1151 | def plugin_loaded(): 1152 | """Handle the plugin_loaded event from ST3.""" 1153 | logger.info('DevSkim plugin_loaded(), Sublime Text v%s' % sublime.version()) 1154 | 1155 | # Schedule analysis based on configuration 1156 | frequency = sublime.load_settings('DevSkim.sublime-settings').get('show_highlights_on_time', 0) 1157 | if frequency > 0: 1158 | sublime.set_timeout_async(periodic_analysis_callback, frequency) 1159 | 1160 | def plugin_unloaded(): 1161 | """Handle the plugin_unloaded event from ST3.""" 1162 | logger.info("DevSkim plugin_unloaded()") 1163 | -------------------------------------------------------------------------------- /DevSkim.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "DevSkim: Analyze File", 4 | "command": "dev_skim_analyze" 5 | }, 6 | { 7 | "caption": "DevSkim: Reload Configuration", 8 | "command": "dev_skim_reload_rules" 9 | } 10 | ] -------------------------------------------------------------------------------- /DevSkim.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | -------------------------------------------------------------------------------- /DevSkim.sublime-settings: -------------------------------------------------------------------------------- 1 | // Don't change any setting on this file. If you want to override the default 2 | // behaviour, change the settings values on your 3 | // Packages/User/DevSkim.sublime-settings file. 4 | { 5 | 6 | /* Enable verbose output to console */ 7 | "debug": false, 8 | 9 | /* Don't analyze files greater than 512kb - set to -1 to disable */ 10 | "max_size": 524288, 11 | 12 | /* Show all severities */ 13 | "show_severity": ["critical", "important", "moderate", "low", "defense-in-depth", "informational", "manual-review"], 14 | 15 | /* Mark for the page gutter -- available options dot, circle, cross, or "" */ 16 | "gutter_mark": "dot", 17 | 18 | /* Stylesheet for popup, from package directory */ 19 | "style": "dark.css", 20 | 21 | /* Show only rules with the given tags, empty means "show all" */ 22 | "show_only_tags": [], 23 | 24 | /* Sort results by either "severity" or "line_number" */ 25 | "sort_results_by": "line_number", 26 | 27 | /* Ignore files specified in .gitignore */ 28 | "ignore_from_gitignore": true, 29 | 30 | /* Ignore additional files, each is a regular expression, escaped for JSON */ 31 | "ignore_files": [ 32 | ], 33 | 34 | /* Run analysis as soon as a file is opened. */ 35 | "show_highlights_on_load": true, 36 | 37 | /* Run analysis when the file is saved. */ 38 | "show_findings_on_save": true, 39 | 40 | /* Run analysis whenever a file is changed. */ 41 | "show_highlights_on_modified": false, 42 | 43 | /* Run analysis on a specific timer, in milliseconds, 0=disabled */ 44 | "show_highlights_on_time": 10000, 45 | 46 | /* Enable per-rule suppressions */ 47 | "allow_suppress_specific_rules": true, 48 | 49 | /* Enable global suppressions */ 50 | "allow_suppress_all_rules": true, 51 | 52 | /* Allow suppression for specific # of days, or -1 for "permanent" */ 53 | "suppress_days": [90, 365, -1], 54 | 55 | /* Name to associate with manual code reviews (optional) */ 56 | "manual_reviewer_name": "", 57 | 58 | /* List of rules files to also include. */ 59 | "custom_rules": [ 60 | ], 61 | 62 | /* Globally suppress these rules (list of rule IDs, like "DS123456") */ 63 | "suppress_rules": [ 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /DevSkimConditionals.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017 Microsoft. All rights reserved. 3 | Licensed under the MIT License. See LICENSE.txt in the project root for license information. 4 | 5 | DevSkim Sublime Text Plugin 6 | https://github.com/Microsoft/DevSkim-Sublime-Plugin 7 | """ 8 | 9 | import logging 10 | 11 | try: 12 | import sublime 13 | except Exception: 14 | print("Unable to import Sublime Text modules. DevSkim must be run within Sublime Text.") 15 | import sys 16 | sys.exit(1) 17 | 18 | logger = logging.getLogger() 19 | 20 | def condition__line_match_all(**kwargs): 21 | """Are all elements of targets substrings of line?""" 22 | line = kwargs.get('line') 23 | targets = kwargs.get('value') 24 | logger.debug('condition__line_match_all({%s}, {%s})', line, targets) 25 | 26 | line = line.lower() 27 | return all([t.lower() in line for t in targets]) 28 | 29 | def condition__line_match_any(**kwargs): 30 | """Are any elements of value substrings of line?""" 31 | line = kwargs.get('line') 32 | targets = kwargs.get('value') 33 | logger.debug('condition__line_match_any({%s}, {%s})', line, targets) 34 | 35 | line = line.lower() 36 | return any([t.lower() in line for t in targets]) 37 | 38 | def condition__line_match_none(**kwargs): 39 | """Are none of the elements of targets substrings of line?""" 40 | line = kwargs.get('line') 41 | targets = kwargs.get('value') 42 | logger.debug('condition__line_match_any({%s}, {%s})', line, targets) 43 | 44 | return not condition__line_match_any(**kwargs) 45 | 46 | def condition__match_prefix_any(**kwargs): 47 | """Are any of the targets a prefix to the matched region?""" 48 | match_start = kwargs.get('match_start') 49 | targets = kwargs.get('value') 50 | view = kwargs.get('view') 51 | match_region = kwargs.get('match_region') 52 | 53 | for target in targets: 54 | region = sublime.Region(match_region.a - len(target), match_start) 55 | if view.substr(region).lower() == target.lower(): 56 | return True 57 | return False 58 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Microsoft Corporation 2 | 3 | All rights reserved. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 8 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 9 | modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 17 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": [ 7 | { 8 | "caption": "Package Settings", 9 | "mnemonic": "P", 10 | "id": "package-settings", 11 | "children": [ 12 | { 13 | "caption": "DevSkim", 14 | "children": [ 15 | { 16 | "command": "open_file", 17 | "args": { 18 | "file": "${packages}/DevSkim-Sublime-Plugin/DevSkim.sublime-settings" 19 | }, 20 | "caption": "Settings – Default" 21 | }, 22 | { 23 | "command": "open_file", 24 | "args": { 25 | "file": "${packages}/User/DevSkim.sublime-settings" 26 | }, 27 | "caption": "Settings – User" 28 | }, 29 | { "caption": "-" }, 30 | { 31 | "command": "open_file", 32 | "args": { 33 | "file": "${packages}/DevSkim-Sublime-Plugin/Default (OSX).sublime-keymap", 34 | "platform": "OSX" 35 | }, 36 | "caption": "Key Bindings – Default" 37 | }, 38 | { 39 | "command": "open_file", 40 | "args": { 41 | "file": "${packages}/User/Default (OSX).sublime-keymap", 42 | "platform": "OSX" 43 | }, 44 | "caption": "Key Bindings – User" 45 | }, 46 | { 47 | "command": "open_file", 48 | "args": { 49 | "file": "${packages}/DevSkim-Sublime-Plugin/Default (Linux).sublime-keymap", 50 | "platform": "Linux" 51 | }, 52 | "caption": "Key Bindings – Default" 53 | }, 54 | { 55 | "command": "open_file", 56 | "args": { 57 | "file": "${packages}/User/Default (Linux).sublime-keymap", 58 | "platform": "Linux" 59 | }, 60 | "caption": "Key Bindings – User" 61 | }, 62 | { 63 | "command": "open_file", 64 | "args": { 65 | "file": "${packages}/DevSkim-Sublime-Plugin/Default (Windows).sublime-keymap", 66 | "platform": "Windows" 67 | }, 68 | "caption": "Key Bindings – Default" 69 | }, 70 | { 71 | "command": "open_file", 72 | "args": { 73 | "file": "${packages}/User/Default (Windows).sublime-keymap", 74 | "platform": "Windows" 75 | }, 76 | "caption": "Key Bindings – User" 77 | } 78 | ] 79 | } 80 | ] 81 | } 82 | ] 83 | } 84 | ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DevSkim Sublime Plugin Deprecated 2 | 3 | The DevSkim Sublime plugin has been deprecated. Original source code will continue to be available at this location, but no longer maintained. 4 | 5 | The core DevSkim project and supported plugins for Visual Studio and VSCode are available at [https://github.com/microsoft/devskim](https://github.com/microsoft/devskim). 6 | 7 | -------------- 8 | -------------- 9 | 10 | 11 | ## DevSkim Plugin for Sublime Text 12 | 13 | The plugin implements a security linter within the Sublime Text editor, leveraging the rules from the [DevSkim](https://github.com/Microsoft/DevSkim) 14 | repository. It helps software engineers to write secure code by flagging potentially dangerous calls, and gives in-context advice for remediation. 15 | 16 | ![DevSkim Demo](https://github.com/Microsoft/DevSkim-Sublime-Plugin/raw/master/doc/DevSkim-Sublime-Demo-1.gif) 17 | 18 | Requirements 19 | -------------- 20 | 21 | The plugin requires Sublime Text 3 (build >= 3114), and will function on Windows, Linux, and MacOS. 22 | 23 | Installation 24 | ------------ 25 | 26 | Install this plugin using [Package Control](https://packagecontrol.io/) from Sublime Text. The package name 27 | is `DevSkim`. 28 | 29 | Alternatively, you can clone this repository into your Sublime Text "Packages" folder. For example, under Windows: 30 | 31 | ``` 32 | cd "%APPDATA%\"Sublime Text 3\Packages" 33 | git clone https://github.com/Microsoft/DevSkim-Sublime-Plugin.git DevSkim 34 | ``` 35 | 36 | MacOS: 37 | ``` 38 | cd ~/"Library/Application Support/Sublime Text 3/Packages" 39 | git clone https://github.com/Microsoft/DevSkim-Sublime-Plugin.git DevSkim 40 | ``` 41 | 42 | Linux: 43 | ``` 44 | cd ~/.config/sublime-text-3/Packages 45 | git clone https://github.com/Microsoft/DevSkim-Sublime-Plugin.git DevSkim 46 | ``` 47 | 48 | Note if you are using the portable version of Sublime Text, the location will be different. See the 49 | [Sublime Text documentation](http://docs.sublimetext.info/en/latest/basic_concepts.html#the-data-directory) for more information. 50 | 51 | **IMPORTANT** If you already have a package called `DevSkim` installed, either remove this first, or clone this repo to a different folder. 52 | 53 | Using DevSkim 54 | ------------- 55 | 56 | By default, DevSkim will run as you type, highlighting code that fails a rule. If you click on a highlighted bit of code, you will 57 | see the rule in the status bar. 58 | 59 | You can run a full scan by pressing Ctrl-Shift-g, which will result in a popup showing all findings for the file. You can also choose 60 | `DevSkim: Analyze File` from the Command Palette. 61 | 62 | Platform support 63 | ---------------- 64 | 65 | #### Operating System: 66 | 67 | The plugin has identical behavior across Windows, MacOS, and Linux. 68 | 69 | #### Sublime Text Version: 70 | 71 | The plugin requires [Sublime Text 3](http://www.sublimetext.com/3) builds >= 3114. 72 | 73 | Settings 74 | -------- 75 | You can customize how DevSkim works through the `Settings -- User` menu item. 76 | If you change any settings, you should reload the DevSkim configuration, either 77 | by restarting Sublime Text or by running the command `DevSkim: Reload Configuration`. 78 | 79 | Rules System 80 | ------------ 81 | 82 | The plugin supports both built-in and custom rules: 83 | 84 | #### Built-In Rules 85 | 86 | Built-in rules come from the [DevSkim](https://github.com/Microsoft/DevSkim) repository, and should be stored 87 | in the `DevSkim-Common/rules` directory within the DevSkim package directory. 88 | 89 | Rules are organized by subdirectory and file, but are flattened internally when loaded. 90 | 91 | Each rule contains a set of patterns (strings and regular expressions) to match, a list of file types to 92 | apply the rule to, and, optionally, a list of possible code fixes. 93 | 94 | Information how writing rules can be found at 95 | [Writing-Rules](https://github.com/Microsoft/DevSkim/wiki/Writing-Rules) 96 | 97 | -------------------------------------------------------------------------------- /css/dark.css: -------------------------------------------------------------------------------- 1 | html { 2 | background-color: #002b36; 3 | color: #CCCCCC; 4 | } 5 | body { 6 | } 7 | a { 8 | color: #268bd2; 9 | } 10 | b { 11 | color: #b58900; 12 | } 13 | h1 { 14 | color: #2aa198; 15 | } 16 | h2 { 17 | color: #2aa198; 18 | } 19 | h3 { 20 | } 21 | h4 { 22 | } 23 | h5 { 24 | color: #2aa198; 25 | } 26 | p { 27 | margin-right: 10px; 28 | } -------------------------------------------------------------------------------- /css/default.css: -------------------------------------------------------------------------------- 1 | html { 2 | background-color: #ffffff; 3 | color: #000000; 4 | } 5 | body { 6 | font-size: 14px; 7 | } 8 | a { 9 | color: #268bd2; 10 | } 11 | b { 12 | color: #b58900; 13 | } 14 | h1 { 15 | color: #2aa198; 16 | font-size: 16px; 17 | } 18 | h2 { 19 | color: #2aa198; 20 | font-size: 14px; 21 | } 22 | h5 { 23 | color: #2aa198; 24 | font-size: 10px; 25 | } 26 | p { 27 | margin-left: 10px; 28 | margin-right: 10px; 29 | } -------------------------------------------------------------------------------- /doc/DevSkim-Sublime-Demo-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/DevSkim-Sublime-Plugin/b28eb44b1383d244a950c8184a9c43f82d1e013b/doc/DevSkim-Sublime-Demo-1.gif -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "messages/install.txt", 3 | "0.1.0": "messages/0.1.0.txt", 4 | "0.2.0": "messages/0.2.0.txt", 5 | "0.2.1": "messages/0.2.1.txt" 6 | } -------------------------------------------------------------------------------- /messages/0.1.0.txt: -------------------------------------------------------------------------------- 1 | DevSkim 0.1.0 2 | ============== 3 | 4 | 2016-12-14 - Initial public preview release of the DevSkim Sublime Text plugin. 5 | 6 | -------------------------------------------------------------------------------- /messages/0.2.0.txt: -------------------------------------------------------------------------------- 1 | DevSkim 0.2.0 2 | ============== 3 | 4 | 2017-01-17 - Minor improvements to applicability loading, 5 | plus a few minor bug fixes. 6 | 7 | -------------------------------------------------------------------------------- /messages/0.2.1.txt: -------------------------------------------------------------------------------- 1 | DevSkim 0.2.1 2 | ============== 3 | 4 | 2017-01-18 - Minor typo / bug-fix. 5 | 6 | -------------------------------------------------------------------------------- /messages/install.txt: -------------------------------------------------------------------------------- 1 | Welcome to DevSkim 2 | ================== 3 | 4 | DevSkim is a source code linter, specifically designed to flag high-risk 5 | security vulnerabilities, provide actionable recommendations (including 6 | "auto-fix" functionality) and time-limited suppressions. 7 | 8 | DevSkim comes with a pre-defined set of rules, which can be extended by 9 | users or organizations. 10 | 11 | 12 | Issues, Questions or Bugs? 13 | -------------------------- 14 | 15 | For issues with DevSkim, please open an issue for the plugin project: 16 | 17 | https://github.com/Microsoft/DevSkim-Sublime-Plugin/issues 18 | 19 | For issues with rules, please open an issue for the main DevSkim project: 20 | 21 | https://github.com/Microsoft/DevSkim/issues 22 | 23 | --------------------------------------------------------------------------------