├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── SECURITY.md ├── cq.py └── fn.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | *.pyc 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | COPY . /cq 3 | WORKDIR /cq 4 | RUN pip install regex 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cq 2 | 3 | Code Query, a universal code security scanning tool. 4 | 5 | CQ scans code for security vulnerabilities and other items of interest to security-focussed code reviewers. 6 | It outputs text files containing references to issues found, into an output directory. These output files can then be reviewed, 7 | filtered by unix command line tools such as grep, or used as a means to 'jump' into the codebase at the specified file:line reference. 8 | 9 | One popular mode of use is to consider the output files as a 'todo' list, deleting references as they are reviewed and either considered false positives, 10 | or copying the references into some report file to either review in detail or provide the basis for a bug report. 11 | 12 | The tool is extremely basic, largely manual, and assumes deep knowledge of application security vulnerabilities and code review. 13 | It does, however, have the advantages of being relatively fast and reliable, and working even when only partial code is available. 14 | 15 | CQ is Code Query, or Sécurité, or CQD, or "Seek You". 16 | 17 | ## Intended Purpose 18 | 19 | CQ is intended to be used in a security code review context by human experts. It is not intended for use in automated scenarios, 20 | although it might be applied in that context. 21 | 22 | CQ outputs plain text files, with typically one finding per line, using the convention full path:line number to 23 | represent locations in the codebase. This format is used to allow for ease of manipulation using the standard unix 24 | command line utilities, such as grep, wc, sed and similar, and the line-based facilities of many editors 25 | such as vi, Sublime Text, Atom and Visual Studio Code. 26 | 27 | The focus on reporting all items of interest results in a tool that will find many points of interest in 28 | almost any codebase, but which will also report a large number of 'false positives'. These false positives can be 29 | removed from the results either by inspection or in an automated fashion, due to the line-based reporting method. 30 | 31 | Little to no explanation of issues is provided; it's assumed that you are aware of the context, impact and 32 | characteristics of the issues reported. 33 | 34 | 35 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | Please report security vulnerabilities to security@nccgroup.com 6 | -------------------------------------------------------------------------------- /cq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import signal 4 | import sys 5 | import fn 6 | import regex 7 | 8 | # Directories / files to skip (these are regexes) 9 | 10 | SKIP_DIRS = [ 11 | regex.compile('/External/'), 12 | regex.compile('/Samples/'), 13 | regex.compile('/NuGet/'), 14 | # regex.compile('/Setup/'), 15 | regex.compile('/i18n/'), 16 | regex.compile('/li8n/'), 17 | regex.compile('/node_modules/'), 18 | regex.compile('/packages/'), 19 | regex.compile('(?i)/test/'), 20 | regex.compile('/third_party/'), 21 | regex.compile('/vendor/'), 22 | regex.compile(r'/\.svn/'), 23 | regex.compile(r'/\.git/'), 24 | regex.compile('example'), 25 | ] 26 | 27 | SKIP_EXTS = [ 28 | regex.compile(r'\.DS_Store$'), 29 | regex.compile(r'\.css$'), 30 | regex.compile(r'\.deps\.json$'), 31 | regex.compile(r'\.dll$'), 32 | regex.compile(r'\.eot$'), 33 | regex.compile(r'\.exe$'), 34 | regex.compile(r'\.gif$'), 35 | regex.compile(r'\.ico$'), 36 | regex.compile(r'\.jar$'), 37 | regex.compile(r'\.jpg$'), 38 | regex.compile(r'\.min\.js$'), 39 | regex.compile(r'\.mov$'), 40 | regex.compile(r'\.mp4$'), 41 | regex.compile(r'\.png$'), 42 | regex.compile(r'\.svg$'), 43 | regex.compile(r'\.tif$'), 44 | regex.compile(r'\.tiff$'), 45 | regex.compile(r'\.ttf$'), 46 | regex.compile(r'\.woff$'), 47 | regex.compile(r'\.zip$'), 48 | regex.compile(r'salt\.7$'), 49 | ] 50 | 51 | # files by mime type: 52 | # find . -type f -exec file --mime-type "{}" \; | awk '{ print $2 ":" $1}' 53 | 54 | CFG_FILES = ['.cfg', '.conf', '.config', '.yaml', '.ini', '.xml', '.json', '.txt'] 55 | CS_FILES = ['.cs'] 56 | C_FILES = ['.c', '.h', '.cpp', '.cxx', '.cc', '.hpp'] 57 | DOTNET_FILES = ['.config', '.cs', '.vb', '.vbs', '.xml'] 58 | GO_FILES = ['.go'] 59 | HTM_FILES = ['.htm', '.html'] 60 | JAVA_FILES = ['.java', '.jsp'] 61 | JS_FILES = ['.js'] 62 | PHP_FILES = ['.php', '.php3', '.php4', '.php5', '.phtml', '.inc', '.phpt'] 63 | PL_FILES = ['.pl', '.pm'] 64 | PY_FILES = ['.py'] 65 | RUBY_FILES = ['.rb'] 66 | 67 | APPLE_FILES = C_FILES + ['.swift', '.m', '.plist'] 68 | 69 | EXTRA_CODE_FILES = ['.ps1', '.pubxml', 'dockerfile'] 70 | 71 | ALL_CODE_FILES = CFG_FILES + C_FILES + DOTNET_FILES + EXTRA_CODE_FILES + GO_FILES + JAVA_FILES + JS_FILES + PHP_FILES + PL_FILES + PY_FILES + RUBY_FILES 72 | 73 | DF_FILES = [ 74 | 'df_c', 75 | 'df_cs', 76 | 'df_java', 77 | 'df_php', 78 | 'df_py', 79 | 'df_ruby'] 80 | 81 | GLOBAL_CHECKS = [ 82 | ('basic_start_time', fn.basic_get_time, ''), 83 | ('basic_path', fn.basic_path, ''), 84 | ('tool_extensions', fn.global_run_tool, r"find ./ -type f | grep -E '.*\.[a-zA-Z0-9]*$' | sed -e 's/.*\(\.[a-zA-Z0-9]*\)$/\1/' | sort | uniq -c | sort -n >> '{out_fname}' 2>/dev/null & "), 85 | ('tool_cloc', fn.global_run_tool, r"cloc --progress-rate=0 . >> '{out_fname}' 2>/dev/null &"), 86 | ('tool_clamav', fn.global_run_tool, r"clamscan -r . >> '{out_fname}' 2>/dev/null &"), 87 | ('tool_git_repos', fn.global_run_tool, r"find `pwd` -name .git >> '{out_fname}' 2>/dev/null &"), 88 | ('tool_dot_files', fn.global_run_tool, r"find `pwd` -name '.*' >> '{out_fname}' 2>/dev/null &"), 89 | ('tool_bandit', fn.global_run_tool, r"bandit --ignore-nosec -r . --format custom --msg-template '{{abspath}}:{{line}}: {{test_id}}[bandit]: {{severity}}: {{msg}}' >> '{out_fname}' 2>/dev/null &"), 90 | ('tool_nsp', fn.global_run_tool, 'find . -name package.json | while read i; do dirname $i; done | while read j; do echo PROJECT: $j; nsp check $j --reporter summary; done >> "{out_fname}" 2>/dev/null &'), 91 | ('tool_eslint', fn.global_run_tool, 'eslint . >> "{out_fname}" 2>/dev/null &'), 92 | ] 93 | 94 | GLOBAL_POST_CHECKS = [ 95 | ('sort_df_sources', fn.sort_df_sources_and_sinks, ''), 96 | ('gen_df_bugs', fn.gen_df_bugs, ''), 97 | ('basic_end_time', fn.basic_get_time, ''), 98 | # add dataflow searches here 99 | ] 100 | 101 | # search for regex, call fn passing fname, out_fname and arg 102 | FILE_CHECKS = [ 103 | ('exe_scan', regex.compile(r'''\.exe$'''), fn.file_scan_exe, None), 104 | ('minor_file_h5', regex.compile(r'''\.h5$'''), fn.file_exists, None), 105 | ('minor_file_hd5', regex.compile(r'''\.hd5$'''), fn.file_exists, None), 106 | ('minor_file_hdf5', regex.compile(r'''\.hdf5$'''), fn.file_exists, None), 107 | ('file_pkl', regex.compile(r'''\.pkl$'''), fn.file_exists, None), 108 | ('minor_file_pt', regex.compile(r'''\.pt$'''), fn.file_exists, None), 109 | ('file_secret', regex.compile(r'''secret'''), fn.file_exists, None), 110 | ('tool_shellcheck', regex.compile(r'''\.sh$'''), fn.file_scan_shell, None), 111 | ('minor_py_requirements', regex.compile(r'''requirements.txt'''), fn.file_run_tool, 'echo "{fname}" >> "{out_fname}"; safety check --full-report -r "{fname}" >> "{out_fname}"'), 112 | ] 113 | 114 | HASH_EXCLUSIONS = [ 115 | regex.compile('0000000000000000'), 116 | regex.compile('0123456789'), 117 | regex.compile('EXAMPLE'), 118 | regex.compile('data:image'), 119 | regex.compile('deadbeef'), 120 | regex.compile('integrity'), 121 | regex.compile('md5sum'), 122 | regex.compile('reference'), 123 | regex.compile('shasum'), 124 | regex.compile(r'''\?rev='''), 125 | ] 126 | 127 | CS_EXCLUSIONS = [regex.compile(r'''^\s*//'''), ] 128 | GO_EXCLUSIONS = [regex.compile(r'''^\s*//'''), ] 129 | 130 | LINE_CUSTOM_CHECKS = [ 131 | ] 132 | 133 | LINE_REGEX_CHECKS = [ 134 | ('apple_keychain_item', regex.compile(r'''KeychainItem.{0,200}$'''), APPLE_FILES), 135 | ('apple_ksecvaluedata', regex.compile(r'''kSecValueData.{0,200}$'''), APPLE_FILES), 136 | ('apple_secitemupdate', regex.compile(r'''SecItemUpdate.{0,200}$'''), APPLE_FILES), 137 | ('applescript_shell', regex.compile(r'''do\s+shell\s+script.{0,199}$''')), 138 | ('asan_reference', regex.compile(r'''\W(asan|address_sanitizer|no_sanitize_address)\W.{0,200}$''')), 139 | ('auth_basic', regex.compile(r'''Authorization.{0,20}Basic\s\w+.{0,200}$''')), 140 | ('boost_process', regex.compile(r'''boost::process::child.{0,200}$''')), 141 | ('c_arch_recv', regex.compile(r'''(recv|Recv|recvfrom|recvmsg|RecvFrom)\('''), C_FILES), 142 | ('c_cpy_sizeof_src1', regex.compile(r'''(strlcpy|strlcat|strncpy|strncat|strcpy_s|strcat_s)\s*\(\s*\s*[^,]+\s*,\s*([^,]+)\s*,\s*(strlen|sizeof)\s*\(\s*\2\s*\)'''), C_FILES), 143 | ('c_cpy_sizeof_src2', regex.compile(r'''(strlcpy|strlcat|strncpy|strncat|strcpy_s|strcat_s)\s*\(\s*\s*[^,]+\s*,\s*([^,]+)\s*,\s*(strlen|sizeof)\s*\2\W'''), C_FILES), 144 | ('c_cpy_sizeof_src3', regex.compile(r'''(strlcpy|strlcat|strncpy|strncat|strcpy_s|strcat_s)\s*\(\s*(\([^\)]*\))\s*[^,]+\s*,\s*([^,]+)\s*,\s*(strlen|sizeof)\s*(\()?\s*\3\s*(\))?'''), C_FILES), 145 | ('c_cpy_sizeof_src4', regex.compile(r'''\W(strlcpy|strlcat|strncpy|strncat|strcpy_s|strcat_s)\s*\([^,]+,\s*([^,]+)\s*,[^,;}]+\W\2\W'''), C_FILES), 146 | ('c_cpy_sizeof_src5', regex.compile(r'''\W(strlcpy|strlcat|strncpy|strncat|strcpy_s|strcat_s)\s*\([^,]+,\s*([^,]+)\s*,[^,;}]+\2'''), C_FILES), 147 | ('c_fmt_off_by_one', regex.compile(r'''sprintf.*\%\.\*s.{0,99}sizeof.{0,99}$'''), C_FILES), 148 | ('c_fscanf', regex.compile(r'''fscanf\s*\(.*\"[^\"]*%s.{0,99}$'''), C_FILES), 149 | ('c_gets', regex.compile(r'''\Wgets\s*\(.{0,99}$'''), C_FILES), 150 | ('c_insecure_loadlib', regex.compile(r'''\W(LoadLibrary|LoadLibraryA|LoadLibraryW|LoadLibraryEx|LoadLibraryExA|LoadLibraryExW)\([^/\n]{0,199}$'''), C_FILES), 151 | ('c_malloc_wraparound', regex.compile(r'''k?malloc\(.*([+*]|-[^>])'''), C_FILES), 152 | ('c_memcpy_wraparound', regex.compile(r'''memcpy\(.*([+*]|-[^>])'''), C_FILES), 153 | ('c_memset_insecure_zeroing', regex.compile(r'''memset\s*\([^,]*,\s*0\s*.{0,99}$'''), C_FILES), 154 | ('c_memset_zero_bytes', regex.compile(r'''memset\s*\([^,]*,[^,]*,\s*0\s*\).{0,99}$'''), C_FILES), 155 | ('c_non_const_fmt_p1', regex.compile(r'''\W(printf|vprintf)\s*\([^",]+,[^",]+,'''), C_FILES), 156 | ('c_non_const_fmt_p2', regex.compile(r'''\W(f|s|as|d|vf|vs|vas|vd)printf\s*\([^",]+,[^",]+,'''), C_FILES), 157 | ('c_non_const_fmt_p3', regex.compile(r'''\W(sn|vsn)printf\s*\([^",]+,[^",]+,[^",]+,'''), C_FILES), 158 | ('c_ntoh_length_wrap', regex.compile(r'''(length|size).*ntoh.*(-|\+|\*)'''), C_FILES), 159 | ('c_potential_fmt_off_by_one', regex.compile(r'''sprintf.*\%\.\*s.{0,200}$'''), C_FILES), 160 | ('c_scanf', regex.compile(r'''(f|s|vf|v|vs)\?scanf\s*\(.{0,99}$'''), C_FILES), 161 | ('c_scanf2', regex.compile(r'''scanf\s*\(.*\"[^\"]*%s.{0,99}$'''), C_FILES), 162 | ('c_scanf_s', regex.compile(r'''(f|s|vf|v|vs)\?scanf\s*\(.*\"[^\"]*%s.{0,99}$'''), C_FILES), 163 | ('c_snprintf_retval_use', regex.compile(r'''\+=\s*v?snprintf.{0,99}$'''), C_FILES), 164 | ('c_socket', regex.compile(r'''socket\('''), C_FILES), 165 | ('c_sprintf_ls', regex.compile(r'''sprintf\s*\(.*\"[^\"]*%ls.{0,99}$'''), C_FILES), 166 | ('c_sprintf_path', regex.compile(r'''s.?printf\(.{0,99}(/%s|%s/).{0,99}$'''), C_FILES), 167 | ('c_sprintf_s', regex.compile(r'''sprintf\s*\(.*\"[^\"]*%s.{0,99}$'''), C_FILES), 168 | ('c_sscanf_s', regex.compile(r'''sscanf\s*\(.*\"[^\"]*%s.{0,99}$'''), C_FILES), 169 | ('c_trusted_length_in_input', regex.compile(r'''len\s*=.*\*.{0,199}$'''), C_FILES), 170 | ('c_warning_supress', regex.compile(r'''#pragma\s+warning\s*\(\s*suppress'''), C_FILES), 171 | ('cfg_haproxy_plaintext_password', regex.compile(r'''insecure-password.{0,99}$'''), CFG_FILES), 172 | ('chpasswd', regex.compile(r'''chpasswd.{0,200}$''')), 173 | ('cmdi_Popen2', regex.compile(r'''\WPopen\([^)].{0,99}$''')), 174 | ('cmdi_c_process_exec', regex.compile(r'''exec[lv][epP]*\(.{0,99}$''')), 175 | ('cmdi_check_output', regex.compile(r'''\Wcheck_output\([^)].{0,99}$''')), 176 | ('cmdi_child_process', regex.compile(r'''child_process.{0,99}$''')), 177 | ('cmdi_command', regex.compile(r'''["\'](chmod|chown|cmd.exe|copy|cp|git|gzip|mkdir|mktemp|rm|ssh|tar|unzip|/bin/sh|gunzip|del|cat|sed)\s.{0,199}$''')), 178 | ('cmdi_createProcess', regex.compile(r'''\WCreateProcess\W.{0,99}$''')), 179 | ('cmdi_dotnet_process', regex.compile(r'''\.StartInfo.{0,99}$'''), CS_FILES, CS_EXCLUSIONS), 180 | ('cmdi_exe_exec', regex.compile(r'''\"\w+\.exe\".{0,99}$''')), 181 | ('cmdi_exec', regex.compile(r'''\W\.exec.{0,99}$''')), 182 | ('cmdi_exec2', regex.compile(r'''^.{0,99}\Wexec\(.{0,99}$''')), 183 | ('cmdi_lua_exec', regex.compile(r'''os\.execute.{0,99}$''')), 184 | ('cmdi_options', regex.compile(r'''^.{0,199}(("[^\n"$-]*\s--[^-])|("--\w)).{0,199}$''')), 185 | ('cmdi_perl_interp', regex.compile(r'''\Wsystem\("[^"]*\$.{0,99}$'''), PL_FILES), 186 | ('cmdi_perl_interp2', regex.compile(r'''\Wsystem\("[^"]*@.{0,99}$'''), PL_FILES), 187 | ('cmdi_popen', regex.compile(r'''popen\([^)].{0,99}$''')), 188 | ('cmdi_process_new', regex.compile(r'''new\sProcess\(.{0,99}$''')), 189 | ('cmdi_scala_cmd_bang', regex.compile(r'''\.![^!].{0,99}$''')), 190 | ('cmdi_scala_cmd_bangbang', regex.compile(r'''\.!!.{0,99}$''')), 191 | ('cmdi_scala_processbuilder', regex.compile(r'''ProcessBuilder\s*\(.{0,99}$''')), 192 | ('cmdi_shell_exec', regex.compile(r'''shell_exec.{0,99}$''')), 193 | ('cmdi_shellexec', regex.compile(r'''ShellExecute.{0,199}$''')), 194 | ('cmdi_spawn', regex.compile(r'''^.{0,99}\Wspawn\(.{0,99}$''')), 195 | ('cmdi_system_noempty', regex.compile(r'''\Wsystem\([^)].{0,99}$''')), 196 | ('cmdi_win_proc_start', regex.compile(r'''ProcessStartInfo.{0,99}$''')), 197 | ('comment_credit_card', regex.compile(r'''credit.card.{0,99}$''')), 198 | ('comment_cvv', regex.compile(r'''\Wcvv\W.{0,99}$''')), 199 | ('comment_inflate_version', regex.compile(r'''inflate.*[0123456789.]{3,}.*Copyright.*Mark.*Adler.{0,99}$''')), 200 | ('comment_luck', regex.compile(r'''\Wlucky*\W''')), 201 | ('comment_obscenities', regex.compile(r'''\W(asshole|bastard|brainfuck|cock|crap|crappy|cunt|dick|flippin|flipping|fuck|fucking|motherfucker|screwed|shit|pussy|tits)\W.{0,99}$''')), 202 | ('comment_rubocop_disable', regex.compile(r'''rubocop:disable.{0,99}$''')), 203 | ('comment_rubocop_disable_security', regex.compile(r'''rubocop:disable\s+Security.{0,99}$'''), RUBY_FILES), 204 | ('comment_security_concern', regex.compile(r'''security (concern|problem|vulnerability|issue).{0,199}$''')), 205 | ('comment_static_analysis_tool', regex.compile(r'''(?i)(NOLINT|\Wnosem\W|noinspection|safesql|coverity|fortify|veracode|Prefast|DevSkim|checkmarx|\Wnosec\W|\WNOSONAR\W|@SuppressWarnings|\Wnoqa\W).{0,99}$''')), 206 | ('comment_todos', regex.compile(r'''\W(TODO|HACK|FIXME|XXX|BROKEN)\W.{0,99}$''')), 207 | ('const_amazon_s3_url', regex.compile(r'''s3://[^\.].{3,199}$''')), 208 | ('const_amazon_s3_url2', regex.compile(r'''https://s3-.{3,299}$''')), 209 | ('const_amazon_secret_key', regex.compile(r'''["\'][A-Za-z0-9/+=]{40}["\'].{0,99}$'''), None, [regex.compile('reference')]), 210 | ('const_aws_hosts', regex.compile(r'''\S{10,199}\.amazonaws\.com.{0,199}$''')), 211 | ('cors_allow_all', regex.compile(r'''Access-Control-Allow-Origin.*"\*".{0,99}$''')), 212 | ('createEvent', regex.compile(r'''CreateEvent.{0,99}$''')), 213 | ('cred_CAPS_secret', regex.compile(r'''[A-Z0-9]{1..99}_SECRET[A-Z0-9_]*.{0,99}$''')), 214 | ('cred_access_token', regex.compile(r'''^.{0,299}x-access-token.{0,299}$''')), 215 | ('cred_access_token', regex.compile(r'''^\s*access_token:\s*[a-zA-Z0-9\.\-\_\!\?\#\&\*\:\;\@\(\)\<\>\%]{18,}\s*$''')), 216 | ('cred_api_key', regex.compile(r'''^[^=\n]{0,199}API_KEY[^\n]{7,199}$''')), 217 | ('cred_api_token', regex.compile(r'''api_token=[0-9a-f]{40}.{0,200}$''')), 218 | ('cred_auth', regex.compile(r'''"AUTH"[,\s]+"[^\n]{5,99}".{0,99}$''')), 219 | ('cred_auth_header', regex.compile(r'''Authorization:\s*\w+\s*[A-Za-z0-9.+=_@!^&*()-?]{8,200}\W''')), 220 | ('cred_aws_access_id2', regex.compile(r'''(^|[^A-Z0-9])(AKIA|ASIA)[A-Z0-9]{16}($|[^A-Z0-9]).{0,99}$''')), 221 | ('cred_aws_creds', regex.compile(r'''(AWS_ACCESS_KEY_ID|AWS_SECRET_ACCESS_KEY|AWS_DEFAULT_REGION).{20,199}$''')), 222 | ('cred_aws_secret_key', regex.compile(r'''(AWSSecretKey|AwsDevSecretKey|SecretKey|ClientSecret|BasicAWSCredentials|clientSecret|AWS_SECRET_KEY|AgentToken).{0,199}$''')), 223 | ('cred_azure_client_id', regex.compile(r'''client_id[^\n]+[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}.{0,199}$''')), 224 | ('cred_azure_client_secret', regex.compile(r'''client_secret[^\n]+\W[a-zA-Z0-9\+\-\_\/]{32}\W.{0,199}$''')), 225 | ('cred_azure_storage_key', regex.compile(r'''[Aa]zure[Ss]torage[Kk]ey.*[Aa]ccount[Kk]ey.{0,499}$''')), 226 | ('cred_azure_tenant_id', regex.compile(r'''tenant_id[^\n]+[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}.{0,199}$''')), 227 | ('cred_base64', regex.compile(r'''base64.{0,99}$''')), 228 | ('cred_bcrypt_hash', regex.compile(r'''.{0,199}$''')), 229 | ('cred_buildfile', regex.compile(r'''.{5,200}''')), 230 | ('cred_config_key', regex.compile(r'''add\s+key="\w*key\w*".{1,99}$'''), CFG_FILES), 231 | ('cred_config_password', regex.compile(r'''add\s+key="\w*password\w*".{1,99}$'''), CFG_FILES), 232 | ('cred_config_secret', regex.compile(r'''add\s+key="\w*secret\w*".{1,99}$'''), CFG_FILES), 233 | ('cred_connectionString', regex.compile(r'''ConnectionString\s*=.{0,99}$''')), 234 | ('cred_connectionstring2', regex.compile(r'''(DSN|DATASOURCE|UID|USER\sID|USER)=[^;].{1,99}(PASSWORD|PWD)=[^;].{1,99}$''')), 235 | ('cred_curl_auth', regex.compile(r'''^.{0,200}curl[^\n]{0,200}-u[^\n]{0,200}:[^\n]{0,200}$''')), 236 | ('cred_dot_secret_key', regex.compile(r'''\.SecretKey.{0,99}$''')), 237 | ('cred_dotnet_password', regex.compile(r'''^.{0,200}assword\s*=\s*"[^"]+".{0,200}$'''), CS_FILES), 238 | ('cred_env_password', regex.compile(r'''^.{0,200}ENV\s*\w*PASS\w*\s*"[^"]+".{0,200}$''')), 239 | ('cred_facebook', regex.compile(r'''(?i)facebook[^=]*=[^=]*[0-9a-f]{32}.{0,99}$''')), 240 | ('cred_github', regex.compile(r'''(?i)github[^=]*=[^=]*[0-9a-zA-Z]{35,40}.{0,99}$'''), None, HASH_EXCLUSIONS), 241 | ('cred_github_token', regex.compile(r'''GITHUB_TOKEN.{0,299}$''')), 242 | ('cred_google_clientid', regex.compile(r'''clientId.{30,80}googleusercontent.com.{0,299}$''')), 243 | ('cred_hash_1', regex.compile(r'''\$1\$\w{4,99}$\w{4,99}.{0,99}$''')), 244 | ('cred_hash_10', regex.compile(r'''\$krb5tgs\$23\$.{0,99}$''')), 245 | ('cred_hash_11', regex.compile(r'''\$md5\$.*\$.{0,99}$''')), 246 | ('cred_hash_12', regex.compile(r'''\$ml\$\d+\$.{0,99}$''')), 247 | ('cred_hash_13', regex.compile(r'''\$office\$\*2007\*.{0,99}$''')), 248 | ('cred_hash_14', regex.compile(r'''\$office\$\*2010\*.{0,99}$''')), 249 | ('cred_hash_15', regex.compile(r'''\$office\$\*2013\*.{0,99}$''')), 250 | ('cred_hash_16', regex.compile(r'''\$oldoffice\$1\*\d+.{0,99}$''')), 251 | ('cred_hash_17', regex.compile(r'''\$S\$.{0,99}$''')), 252 | ('cred_hash_19', regex.compile(r'''\W[a-f0-9]{128}:\w+\W.{0,99}$''')), 253 | ('cred_hash_2', regex.compile(r'''\$2a\$05\$.{0,99}$''')), 254 | ('cred_hash_21', regex.compile(r'''\W[a-f0-9]{32}:\w+\W.{0,99}$''')), 255 | ('cred_hash_23', regex.compile(r'''\W[a-f0-9]{40}:\w+\W.{0,99}$''')), 256 | ('cred_hash_25', regex.compile(r'''\W[a-f0-9]{64}:\w+\W.{0,99}$''')), 257 | ('cred_hash_26', regex.compile(r'''\W\w+\$[a-f0-9]{16}\W.{0,99}$''')), 258 | ('cred_hash_27', regex.compile(r'''\W\w+:\d+:[a-f0-9]{32}:[a-f0-9]{32}\W.{0,99}$''')), 259 | ('cred_hash_28', regex.compile(r'''u4-netntlm::.{0,99}$''')), 260 | ('cred_hash_29', regex.compile(r'''\{ssha1\}06\$.*\$.{0,99}$''')), 261 | ('cred_hash_2x', regex.compile(r'''\$2\w\$\d+\$[A-Za-z0-9./]{20,}.{0,99}$''')), 262 | ('cred_hash_3', regex.compile(r'''\$5\$\w{4,99}$\w{4,99}.{0,99}$''')), 263 | ('cred_hash_30', regex.compile(r'''\{ssha256\}06\$.{0,199}$''')), 264 | ('cred_hash_31', regex.compile(r'''\{SSHA512\}.{0,199}$''')), 265 | ('cred_hash_32', regex.compile(r'''\{ssha512\}06\$.{0,199}$''')), 266 | ('cred_hash_33', regex.compile(r'''\{x-issha,\s*1024\}.{0,199}$''')), 267 | ('cred_hash_4', regex.compile(r'''\$6\$\w{4,99}$\w{4,99}.{0,99}$''')), 268 | ('cred_hash_5', regex.compile(r'''\$8\$\w{4,99}$\w{4,99}.{0,99}$''')), 269 | ('cred_hash_6', regex.compile(r'''\$9\$\w{4,99}$\w{4,99}.{0,99}$''')), 270 | ('cred_hash_7', regex.compile(r'''\$apr1\$\w{4,99}$\w{4,99}.{0,99}$''')), 271 | ('cred_hash_8', regex.compile(r'''\$DCC2\$\d+#.*#.{0,99}$''')), 272 | ('cred_hash_9', regex.compile(r'''\$keepass\$\*\d+\*\d+\*\d+\*.{0,99}$''')), 273 | ('cred_hash_AIX', regex.compile(r'''\{ssha256\}[0-9a-zA-Z\$\+\/\.]{20,}\W.{0,99}$''')), 274 | ('cred_hash_AIX', regex.compile(r'''\{ssha512\}[0-9a-zA-Z\$\.\-\+\/]{20,}\W.{0,99}$''')), 275 | ('cred_hash_Android_FDE_SamsungDEK', regex.compile(r'''\W[0-9a-fA-F]{160}\W.{0,99}$''')), 276 | ('cred_hash_ArubaOS', regex.compile(r'''\W[0-9a-fA-F]{50}\W.{0,99}$''')), 277 | ('cred_hash_Atlassian', regex.compile(r'''\{PKCS5S2\}[0-9a-zA-Z]{64}\W.{0,99}$''')), 278 | ('cred_hash_Cisco_IOS_type_4', regex.compile(r'''\W[0-9a-zA-Z]{43}\W.{0,99}$''')), 279 | ('cred_hash_Cisco_PIX_MD5', regex.compile(r'''password\s+[0-9a-zA-Z\+\.\/]{16}\s+encrypted.{0,99}$''')), 280 | ('cred_hash_ColdFusion', regex.compile(r'''\W[0-9a-fA-F]{64}:[0-9a-fA-F]{64}\W.{0,99}$''')), 281 | ('cred_hash_DES_Oracle', regex.compile(r'''\W[0-9a-fA-F]{16}:[0-9a-fA-F]{10}\W.{0,99}$''')), 282 | ('cred_hash_DomainCachedCredentials', regex.compile(r'''\W[0-9a-fA-F]{32}:[0-9a-fA-F]{13}\W.{0,99}$''')), 283 | ('cred_hash_EPi', regex.compile(r'''0x[0-9a-zA-Z]{60}\W.{0,99}$'''), None, HASH_EXCLUSIONS), 284 | ('cred_hash_FileZillaServer_0.9.55', regex.compile(r'''\W[0-9a-fA-F]{128}:[0-9a-fA-F]{64}\W.{0,99}$''')), 285 | ('cred_hash_FortiGate', regex.compile(r'''\W[0-9a-zA-Z\+\.\/]{46}=\W.{0,99}$'''), None, HASH_EXCLUSIONS), 286 | ('cred_hash_HMAC_SHA256', regex.compile(r'''\W[0-9a-fA-F]{64}:[0-9a-fA-F]{8}\W.{0,99}$''')), 287 | ('cred_hash_IPB2', regex.compile(r'''\W[0-9a-fA-F]{32}:[0-9a-fA-F]{2,20}\W.{0,99}$''')), 288 | ('cred_hash_IPMI2_RAKP_HMAC_SHA1', regex.compile(r'''\W[0-9a-fA-F]{130}:[0-9a-fA-F]{40}\W.{0,99}$''')), 289 | ('cred_hash_Joomla', regex.compile(r'''\W[0-9a-fA-F]{32}:[0-9a-fA-F]{32}\W.{0,99}$''')), 290 | ('cred_hash_MSSQL_2000', regex.compile(r'''0x01[0-9a-zA-Z]{90}\W.{0,99}$''')), 291 | ('cred_hash_MSSQL_2005', regex.compile(r'''0x01[0-9a-zA-Z]{50}\W.{0,99}$''')), 292 | ('cred_hash_MSSQL_2012_2014', regex.compile(r'''0x02[0-9a-zA-Z]{138}\W.{0,99}$''')), 293 | ('cred_hash_MySQL323', regex.compile(r'''\W[0-9a-fA-F]{16}\W.{0,99}$'''), None, HASH_EXCLUSIONS), 294 | ('cred_hash_NetNTLMv1', regex.compile(r'''\W[0-9a-zA-Z]{48}:[0-9a-zA-Z]{16}\W.{0,99}$''')), 295 | ('cred_hash_OSX', regex.compile(r'''\W[0-9a-fA-F]{48}\W.{0,99}$''')), 296 | ('cred_hash_OSXv10.7', regex.compile(r'''\W[0-9a-fA-F]{136}\W.{0,99}$''')), 297 | ('cred_hash_OpenCart', regex.compile(r'''\W[0-9a-fA-F]{40}:[0-9a-fA-F]{9}\W.{0,99}$''')), 298 | ('cred_hash_Oracle11', regex.compile(r'''\W[0-9a-fA-F]{40}:[0-9a-fA-F]{20}\W.{0,99}$''')), 299 | ('cred_hash_Oracle12', regex.compile(r'''\W[0-9a-fA-F]{160}\W.{0,99}$''')), 300 | ('cred_hash_PeopleSoft', regex.compile(r'''\W[0-9a-fA-F]{40}:[0-9a-fA-F]{126}\W.{0,99}$'''), None, HASH_EXCLUSIONS), 301 | ('cred_hash_PeopleSoft2', regex.compile(r'''\W[0-9a-zA-Z]{27}=.{0,99}$'''), None, HASH_EXCLUSIONS), 302 | ('cred_hash_PostgreSQL', regex.compile(r'''\W[0-9a-zA-Z]{32}:[0-9a-zA-Z]{2,20}\W.{0,99}$''')), 303 | ('cred_hash_PunBB', regex.compile(r'''\W[0-9a-fA-F]{40}:[0-9a-fA-F]{12}\W.{0,99}$''')), 304 | ('cred_hash_Radmin2', regex.compile(r'''\W[0-9a-fA-F]{32}[^:0-9a-fA-F].{0,99}$''')), 305 | ('cred_hash_Redmine', regex.compile(r'''\W[0-9a-fA-F]{40}:[0-9a-fA-F]{32}\W.{0,99}$''')), 306 | ('cred_hash_SHA_224', regex.compile(r'''\W[0-9a-fA-F]{56}\W.{0,99}$'''), None, HASH_EXCLUSIONS), 307 | ('cred_hash_SHA_256', regex.compile(r'''\W[0-9a-fA-F]{64}\W.{0,99}$'''), None, HASH_EXCLUSIONS), 308 | ('cred_hash_SHA_384', regex.compile(r'''\W[0-9a-fA-F]{96}\W.{0,99}$'''), None, HASH_EXCLUSIONS), 309 | ('cred_hash_SHA_512', regex.compile(r'''\W[0-9a-fA-F]{128}\W.{0,99}$'''), None, HASH_EXCLUSIONS), 310 | ('cred_hash_SSHA_256', regex.compile(r'''\{SSHA256\}[0-9a-zA-Z\+\/]{47}\W.{0,99}$'''), None, HASH_EXCLUSIONS), 311 | ('cred_hash_SSHA_512', regex.compile(r'''\{SSHA512\}[0-9a-zA-Z\+]{95}\W.{0,99}$'''), None, HASH_EXCLUSIONS), 312 | ('cred_hash_SamsungAndroidPassword', regex.compile(r'''\W[0-9a-fA-F]{40}:[0-9a-fA-F]{16}\W.{0,99}$''')), 313 | ('cred_hash_SipHash', regex.compile(r'''\W[0-9a-fA-F]{16}:[0-9a-fA-F]{32}\W.{0,99}$''')), 314 | ('cred_hash_SybaseASE', regex.compile(r'''0x[0-9a-zA-Z]{84}\W.{0,99}$''')), 315 | ('cred_hash_WindowsPhone8', regex.compile(r'''\W[0-9a-fA-F]{64}:[0-9a-fA-F]{256}\W.{0,99}$''')), 316 | ('cred_hash_hMailServer', regex.compile(r'''\W[0-9a-fA-F]{70}\W.{0,99}$''')), 317 | ('cred_hash_md4_md5', regex.compile(r'''\W[0-9a-fA-F]{32}\W.{0,99}$'''), None, HASH_EXCLUSIONS), 318 | ('cred_hash_md5', regex.compile(r'''md5\$.{0,99}\$[a-zA-Z0-9].{0,99}$'''), None, HASH_EXCLUSIONS), 319 | ('cred_hash_salted_md5', regex.compile(r'''\W[0-9a-fA-F]{32}:[0-9a-fA-F]{2,20}\W.{0,99}$''')), 320 | ('cred_hash_salted_sha1', regex.compile(r'''\W[0-9a-fA-F]{40}:[0-9a-fA-F]{2,20}\W.{0,99}$''')), 321 | ('cred_hash_saltedsha512', regex.compile(r'''\W[0-9a-fA-F]{128}:[0-9a-fA-F]{10}\W.{0,99}$''')), 322 | ('cred_hash_sha1', regex.compile(r'''\W[0-9a-fA-F]{40}\W.{0,99}$'''), None, HASH_EXCLUSIONS), 323 | ('cred_hash_vBulletin', regex.compile(r'''\W[0-9a-fA-F]{32}:[0-9a-fA-F]{30}\W.{0,99}$''')), 324 | ('cred_hex_dblquotes', regex.compile(r'''^.{0,199}"[a-f0-9]{16,}".{0,199}$'''), None, HASH_EXCLUSIONS), 325 | ('cred_identified_by', regex.compile(r'''IDENTIFIED\s+BY\s+\'[^\n]{0,299}$''')), 326 | ('cred_in_url', regex.compile(r'''\w+://\w+:\w+@\w+.{0,99}$''')), 327 | ('cred_jdbc_dbl', regex.compile(r'''"jdbc:\w+://[^"]{0,99}".{0,99}$''')), 328 | ('cred_jdbc_sgl', regex.compile(r'''\'jdbc:\w+://[^\']{0,99}\'.{0,99}$''')), 329 | ('cred_key', regex.compile(r'''^\s*key:\s*[a-zA-Z0-9\.\-\_\!\?\#\&\*\:\;\@\(\)\<\>\%]{10,}\s*$''')), 330 | ('cred_key_equals', regex.compile(r'''^[^=\n]{0,199}KEY[^=\n]{0,30}=\s*[^\n\s]{7,199}\s*$''')), 331 | ('cred_keys', regex.compile(r'''\-----BEGIN[A-Z\s]*KEY[A-Z\s]*-----''')), 332 | ('cred_mysql_connect_call', regex.compile(r'''new mysqli\(.{0,99}$''')), 333 | ('cred_mysql_passwords', regex.compile(r'''\Wmysql\s.{0,99}[^-]-p[^\$\%].{0,99}$''')), 334 | ('cred_network_credential', regex.compile(r'''\WNetworkCredential\(.{0,399}$''')), 335 | ('cred_password', regex.compile(r'''^\s*password:\s*[a-zA-Z0-9\.\-\_\!\?\#\&\*\:\;\@\(\)\<\>\%]{10,}\s*$''')), 336 | ('cred_password01', regex.compile(r'''\s--password\s*=\s*[^\$\%].{0,99}$''')), 337 | ('cred_password02', regex.compile(r'''password=[^\s";.]*.{0,199}$''')), 338 | ('cred_password03', regex.compile(r'''password"[^"]*value="[^"]*.{0,199}$''')), 339 | ('cred_password04', regex.compile(r'''password"[^",\w]{0,50}"[^"]{0,50}".{0,199}$''')), 340 | ('cred_password05', regex.compile(r'''key=[^\s";.]*.{0,199}$''')), 341 | ('cred_password_config', regex.compile(r'''^\s*password\s\S{5,99}\s*$''')), 342 | ('cred_password_equals', regex.compile(r'''^[^=\n]{0,199}PASSWORD[^=\n]{0,30}=\s*[^\n\s]{7,199}\s*$''')), 343 | ('cred_password_equals', regex.compile(r'''password[^=\n]{0,30}=.{0,199}$''')), 344 | ('cred_password_equals2', regex.compile(r'''password\s*=\s*".{0,99}$''')), 345 | ('cred_postgres_pgpass_format', regex.compile(r'''^[.a-zA-Z0-9_-]+(:[.a-zA-Z0-9_-]+){4}$''')), 346 | ('cred_private_key', regex.compile(r'''privateKey.{0,99}$''')), 347 | ('cred_public_key', regex.compile(r'''publicKey.{0,99}$''')), 348 | ('cred_refreshToken', regex.compile(r'''refreshToken.{16,80}$''')), 349 | ('cred_secret', regex.compile(r'''^\s*secret:\s*[a-zA-Z0-9\.\-\_\!\?\#\&\*\:\;\@\(\)\<\>\%]{18,}\s*$''')), 350 | ('cred_secret_equals', regex.compile(r'''^[^=\n]{0,199}SECRET[^=\n]{0,30}=\s*[^\n\s]{7,199}\s*$''')), 351 | ('cred_secretname_equals', regex.compile(r'''(accesskey|secretkey|apisecret|apikey|GSUsername|GSPassword|SteamBuildMachineUsername|SteamBuildMachinePassword|S3BucketName).{0,99}[=:].{0,99}$''')), 352 | ('cred_signtool_password', regex.compile(r'''signtool.*/p.{0,99}$''')), 353 | ('cred_slack', regex.compile(r'''xox[baprs]-[^=]*=[^=]*.{0,99}$''')), 354 | ('cred_stripe_secret_token', regex.compile(r'''(?i)STRIPE[^\n]+(sk)_[0-9a-zA-Z_]{10,64}.{0,99}$''')), 355 | ('cred_stripe_token', regex.compile(r'''(?i)(sk|pk)_(test|live)_[0-9a-zA-Z]{10,32}.{0,99}$''')), 356 | ('cred_telegram', regex.compile(r'''(?i)telegram[^=]*=[^=]*[0-9]{1,12}+:[0-9a-zA-Z-]{32,44}.{0,99}$''')), 357 | ('cred_token_equals', regex.compile(r'''^[^=\n]{0,199}TOKEN[^=\n]{0,30}=\s*[^\n\s]{7,199}\s*$''')), 358 | ('cred_twitter', regex.compile(r'''(?i)twitter[^=]*=[^=]*[0-9a-zA-Z]{35,44}.{0,99}$''')), 359 | ('crypto_algorithm_name', regex.compile(r'''\W(AES|DES|SHA|SHA1|SHA2|SHA256|SHA512|blowfish|MD5|IDEA|RSA|DSA|MD4|SHA3|HMAC)\W.{0,99}$''')), 360 | ('crypto_api_call', regex.compile(r'''\W(CryptAcquireContext|CryptDeriveKey|CryptGenKey|CryptGenRandom)\W.{0,99}$''')), 361 | ('crypto_b64', regex.compile(r'''AES\.DecryptFromBase64.{0,99}$''')), 362 | ('crypto_b64_2', regex.compile(r'''AES\.DecryptFromBase64.{0,99}$''')), 363 | ('crypto_diffie_hellman', regex.compile(r'''[D|d]iffie.*[H|h]ellman.{0,99}$''')), 364 | ('cve_id', regex.compile(r'''\WCVE-\d\d\d\d-.{0,200}$''')), 365 | ('define_password', regex.compile(r'''^.{0,99}#define.{0,99}PASSWORD.{0,99}".{0,99}$'''), C_FILES, CS_EXCLUSIONS), 366 | ('df_c_sinks', regex.compile(r'''^.{0,99}\W(system|strcpy|strcat|memcpy|sprintf)\s*\(.{0,199}$'''), C_FILES), 367 | ('df_c_sources', regex.compile(r'''^.{0,99}\W(recv|argv|fread|fgets|scanf|fscanf).{0,199}$'''), C_FILES), 368 | ('df_dotnet_sinks', regex.compile(r'''^.{0,99}\W(GetAsync)\W.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 369 | ('df_dotnet_sinks', regex.compile(r'''^.{0,99}\W(WriteFile|FileSystem|SimpleDB|ExecuteSqlCommand|SqlCommand|ProcessStartInfo|CreateProcess|WriteAllText|HttpClient)\W.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 370 | ('df_dotnet_sinks', regex.compile(r'''^.{0,99}\WLIKE\s*'\%\{\w+}\%'.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 371 | ('df_dotnet_sources', regex.compile(r'''^.{0,99}\W(QueryString|Request|HttpGet|HttpPost|HttpPut|FromBase64String|Parse|Load)\W.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 372 | ('df_dotnet_sources', regex.compile(r'''^.{0,99}\W(string.Format)\W.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 373 | ('df_java_sinks', regex.compile(r'''^.{0,99}\W"\s*\+\s*[^"]{1,199}".{0,199}$'''), JAVA_FILES), 374 | ('df_java_sinks', regex.compile(r'''^.{0,99}\W(HttpHeaders|URI|setHeader|uploadFile|File|createFile|save)\W.{0,199}$'''), JAVA_FILES), 375 | ('df_java_sinks', regex.compile(r'''^.{0,99}\W(execute|HttpClient|PostMethod|exec|Runtime|executeMethod|SqlQuery|executeQuery|QueryBuilder)\W.{0,199}$'''), JAVA_FILES), 376 | ('df_java_sources', regex.compile(r'''^.{0,99}\W(FromBase64String|Parse|Load|JSONObject|InputStreamReader|BufferedReader|readLine|params|Param|RequestMapping)\W.{0,199}$'''), JAVA_FILES), 377 | ('df_java_sources', regex.compile(r'''^.{0,99}\W(PathVariable|RequestBody|requestBody|RequestHeader|queryString|RequestParam|getParameter|GetMapping)\W.{0,199}$'''), JAVA_FILES), 378 | ('df_java_sources', regex.compile(r'''^.{0,99}\W(PutMapping|PostMapping)\W.{0,199}$'''), JAVA_FILES), 379 | ('df_php_sinks', regex.compile(r'''^.{0,99}\W(assert|copy|eval|exec|file|fopen|include|mssql_query|mysqli_query|pcntl_exec|pg_query|popen|require|require_once|shell_exec|system)\s*\(.{0,199}$'''), PHP_FILES), 380 | ('df_php_sources', regex.compile(r'''^.{0,99}\W(\$_POST|\$_GET|\$_REQUEST|\$_COOKIE|readline|fscanf|fgets|file_get_contents).{0,199}$'''), PHP_FILES), 381 | ('df_py_sinks', regex.compile(r'''^.{0,99}\W(rename|makedirs|open|write|HTTPAdapter|Request|urlopen|make_response|dumps|redirect|jsonify|chdir|remove)\s*\(.{0,199}$'''), PY_FILES), 382 | ('df_py_sinks_crit', regex.compile(r'''^.{0,99}\W(system|check_output|execute|subprocess.call|Popen|popen)\s*\(.{0,199}$'''), PY_FILES), 383 | ('df_py_sources', regex.compile(r'''^.{0,99}\W(loads|load|open|route|request.args|get_json|get|read)\s*\(.{0,199}$'''), PY_FILES), 384 | ('df_py_sources', regex.compile(r'''^.{0,99}\W(request.form|session|args|environ|\+\W*\w+\W*\+).{0,199}$'''), PY_FILES), 385 | ('df_ruby_sinks', regex.compile(r'''^.{0,99}\W(IO.binread|IO.binwrite|IO.foreach|JSON.load|JSON.parse|popen|read|write|eval|exec|spawn|syscall|system|eval|constantize|render).{0,199}$'''), RUBY_FILES), 386 | ('df_ruby_sources', regex.compile(r'''^.{0,99}\W(params|query_parameters|path_parameters|get|post|query_string)\W.{0,199}$'''), RUBY_FILES), 387 | ('dllimport', regex.compile(r'''dllimport.{0,99}$''')), 388 | ('dotnet_Rfc2898DeriveBytes', regex.compile(r'''\WRfc2898DeriveBytes.{0,200}$'''), DOTNET_FILES, CS_EXCLUSIONS), 389 | ('dotnet_allow_all', regex.compile(r'''allow.{0,10}users.{0,10}\*.{0,100}$'''), DOTNET_FILES), 390 | ('dotnet_allow_users', regex.compile(r'''allow.{0,10}users.{0,10}=.{0,100}$''')), 391 | ('dotnet_allowanonymous', regex.compile(r'''\[AllowAnonymous\].{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 392 | ('dotnet_app_paths', regex.compile(r'''location.{0,10}path.{0,10}=.{0,100}$'''), DOTNET_FILES, CS_EXCLUSIONS), 393 | ('dotnet_appendformat', regex.compile(r'''\.AppendFormat.{1,80}\{\d+\}.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 394 | ('dotnet_binaryformatter_deserial_CA2300', regex.compile(r'''\WBinaryFormatter.{0,200}$'''), DOTNET_FILES, CS_EXCLUSIONS), 395 | ('dotnet_binarywrite', regex.compile(r'''\WBinaryWrite\W.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 396 | ('dotnet_certvalidation_none', regex.compile(r'''X509CertificateValidationMode\.None.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 397 | ('dotnet_cookie', regex.compile(r'''HttpCookie.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 398 | ('dotnet_crypto', regex.compile(r'''\WSystem\.Security\.Cryptography\W.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 399 | ('dotnet_dirBrowse', regex.compile(r'''directoryBrowse.{1,20}enable.{1,20}true.{0,99}$'''), DOTNET_FILES), 400 | ('dotnet_disablesecurity', regex.compile(r'''DisableSecurity.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 401 | ('dotnet_dotnet_interpolation', regex.compile(r'''string\.Format\(.*{.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 402 | ('dotnet_dotnet_net', regex.compile(r'''System\.Net.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 403 | ('dotnet_dotnet_pipes', regex.compile(r'''System\.IO\.Pipes.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 404 | ('dotnet_dotnet_saveas', regex.compile(r'''\.SaveAs\(.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 405 | ('dotnet_dotnet_string_format', regex.compile(r'''string\.Format.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 406 | ('dotnet_forms_authentication', regex.compile(r'''FormsAuthentication.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 407 | ('dotnet_insecure_rsa_padding', regex.compile(r'''\.Encrypt\(.{1,99}false.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 408 | ('dotnet_method', regex.compile(r'''\[Http(Post|Get|Patch|Put|Delete).{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 409 | ('dotnet_pageload', regex.compile(r'''Page_Load.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 410 | ('dotnet_replaceQuote', regex.compile(r'''(Replace\("\""|Replace\("\'").{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 411 | ('dotnet_request_object', regex.compile(r'''\WRequest\..{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 412 | ('dotnet_response_object', regex.compile(r'''\WResponse\..{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 413 | ('dotnet_route', regex.compile(r'''\.MapRoute\(.{0,299}$'''), DOTNET_FILES, CS_EXCLUSIONS), 414 | ('dotnet_skip_auth', regex.compile(r'''SkipAuthorization.{0,100}$'''), DOTNET_FILES, CS_EXCLUSIONS), 415 | ('dotnet_skip_ssl_validation', regex.compile(r'''ServerCertificateCustomValidationCallback.{0,299}$'''), DOTNET_FILES, CS_EXCLUSIONS), 416 | ('dotnet_sqlClient', regex.compile(r'''\W(SqlClient|SqlCommand).{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 417 | ('dotnet_sqlCmd', regex.compile(r'''\W(ExecuteSqlCommand|ExecuteSqlCommandAsync|SqlQuery).{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 418 | ('dotnet_sqlConnection', regex.compile(r'''\WSqlConnection.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 419 | ('dotnet_sqlclient', regex.compile(r'''\W(SqlClient|SqlCommand).{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 420 | ('dotnet_sqlcommand', regex.compile(r'''\W(ExecuteSqlCommand|ExecuteSqlCommandAsync|SqlQuery).{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 421 | ('dotnet_sqli_and', regex.compile(r'''".{0,99}\Wand\W.{0,99}".{0,99}\+.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 422 | ('dotnet_sqli_doubleupquote', regex.compile(r'''Replace.{0,99}\'.{0,99}\'\'.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 423 | ('dotnet_sqli_interpolation', regex.compile(r'''=\s*{.{0,200}$'''), DOTNET_FILES, CS_EXCLUSIONS), 424 | ('dotnet_sqli_select_brace', regex.compile(r'''"select.{0,199}\{.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 425 | ('dotnet_sqli_simpleDB', regex.compile(r'''\sSimpleDB\..{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 426 | ('dotnet_tripledes', regex.compile(r'''TripleDESCryptoServiceProvider.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 427 | ('dotnet_unsafe', regex.compile(r'''\sunsafe\s.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 428 | ('dotnet_validateinput_false', regex.compile(r'''\[ValidateInput.{1,20}false.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 429 | ('dotnet_weak_ecb_mode', regex.compile(r'''CipherMode\.ECB.{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 430 | ('dotnet_web_dotnet_weak_hash', regex.compile(r'''(RIPEMD160|SHA1|MD5|MD2|MD4).{0,99}(.{0,99}){0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 431 | ('dotnet_webmethod', regex.compile(r'''\[(WebMethod|WebService|ScriptMethod|ScriptService).{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 432 | ('dotnet_writefile', regex.compile(r'''\WWriteFile\W.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 433 | ('endpoints', regex.compile(r'''/endpoints/.{0,99}$''')), 434 | ('export_creds', regex.compile(r'''^(.{0,10})export .{0,99}(LOGIN|USER|KEY|SECRET|BUCKET|TOKEN|CREDS|CREDENTIAL|PASS|AUTH).{0,99}=[^$]{6,199}$''')), 435 | ('fileSystem_call', regex.compile(r'''FileSystem\W.{0,99}$''')), 436 | ('file_Stream', regex.compile(r'''FileStream.{0,99}$''')), 437 | ('file_copy', regex.compile(r'''\WFile\.Copy\(.{0,99}$''')), 438 | ('file_copyFile', regex.compile(r'''copyFile\(.{0,99}$''')), 439 | ('file_dot', regex.compile(r'''File\..{0,99}$''')), 440 | ('file_get_contents', regex.compile(r'''file_get_contents.{0,99}$''')), 441 | ('go_exec', regex.compile(r'''\Wexec\..{0,99}$'''), GO_FILES, GO_EXCLUSIONS), 442 | ('go_exec_cmdi', regex.compile(r'''\Wexec\..{0,99}(/c|-c).{0,99}$'''), GO_FILES, GO_EXCLUSIONS), 443 | ('go_http_client', regex.compile(r'''\Whttp\.(Client|Get|Post|PostForm|NewRequest)\W.{0,99}$'''), GO_FILES), 444 | ('go_http_cookie', regex.compile(r'''\Whttp\.(Cookie|SetCookie)\W.{0,99}$'''), GO_FILES), 445 | ('go_http_header', regex.compile(r'''\Whttp\.Header\W.{0,99}$'''), GO_FILES), 446 | ('go_http_server', regex.compile(r'''\Whttp\.(ListenAndServe|Handle|HandleFunc|Server)\W.{0,99}$'''), GO_FILES), 447 | ('go_http_server_plaintext_only', regex.compile(r'''\Whttp\.ListenAndServe\(\W.{0,99}$'''), GO_FILES), 448 | ('go_os', regex.compile(r'''\Wos\..{0,99}$'''), GO_FILES, GO_EXCLUSIONS), 449 | ('go_reflect', regex.compile(r'''\Wreflect\..{0,99}$'''), GO_FILES, [regex.compile(r'''(DeepEqual|ValueOf)'''), ]), 450 | ('go_sprintf_s', regex.compile(r'''Sprintf\s*\(.*\"[^\"]*%s.{0,99}$'''), GO_FILES), 451 | ('go_sqli_select', regex.compile(r'''\.Select\(.{0,99}$'''), GO_FILES), 452 | ('go_sqli_sqlmodule', regex.compile(r'''"database/sql"'''), GO_FILES), 453 | ('go_ssh_ignore_host_key', regex.compile(r'''\WInsecureIgnoreHostKey.{0,99}$'''), GO_FILES, GO_EXCLUSIONS), 454 | ('go_unsafe', regex.compile(r'''\Wunsafe\W.{0,99}$'''), GO_FILES), 455 | ('go_world_fileperms', regex.compile(r'''(Mkdir|WriteFile|Chmod|OpenFile|FileMode|\Wos\.)\W0[0-7][0-7][1-7]\W.{0,99}$'''), GO_FILES), 456 | ('go_world_write', regex.compile(r'''(Mkdir|WriteFile|Chmod|OpenFile|FileMode|\Wos\.)\W0[0-7][0-7](1|2|3|5|6|7)\W.{0,99}$'''), GO_FILES), 457 | ('go_xss_writestring', regex.compile(r'''io\.WriteString\W.{0,99}$'''), GO_FILES), 458 | ('http_user_agent', regex.compile(r'''HTTP_USER_AGENT.{0,99}$''')), 459 | ('http_x_forwarded_for', regex.compile(r'''HTTP_X_FORWARDED_FOR.{0,99}$''')), 460 | ('insecure_url', regex.compile(r'''http://([a-zA-Z0-9]+\.)+[a-zA-Z0-9]+.{0,200}$'''), None, [regex.compile(r'''^\s*(\*+|//|/*|#|;)\s+'''), regex.compile(r'''(readme|\.md|xlmns|doctype)''')]), # noqa 461 | ('insecure_url2', regex.compile(r'''^.{0,200}http://.{0,200}$'''), None, [regex.compile(r'''^\s*(\*+|//|/*|#|;)\s+'''), regex.compile(r'''(readme|\.md|\|xlmns|doctype)''')]), # noqa 462 | ('intercept_url', regex.compile(r'''intercept-url{0,200}$''')), 463 | ('java_deserialisation', regex.compile(r'''\.readObject\(.{0,99}$'''), JAVA_FILES), 464 | ('java_spring_expression_lang_injection', regex.compile(r'''(,]*\s+(false|0).{0,99}$'''), PHP_FILES), 508 | ('php_strcmp_array_bypass', regex.compile(r'''strcmp.*==.{0,200}$'''), PHP_FILES), 509 | ('php_var_func', regex.compile(r'''\$\w+\(.{0,99}$'''), PHP_FILES), 510 | ('php_var_include', regex.compile(r'''(include|require).{0,99}\$.{0,99}$'''), PHP_FILES), 511 | ('php_xss_tag', regex.compile(r'''<\w+>.*\$\w+.{0,200}$'''), PHP_FILES), 512 | ('plaintext_port', regex.compile(r'''\.createInsecure\(.{0,99}$''')), 513 | ('priv_chmod', regex.compile(r'''chmod\(.{0,199}$''')), 514 | ('priv_chown', regex.compile(r'''chown\(.{0,199}$''')), 515 | ('py_check_output', regex.compile(r'''check_output\(.{0,99}$'''), PY_FILES), 516 | ('py_deserialisation', regex.compile(r'''pickle\.loads\(.{0,99}$'''), PY_FILES), 517 | ('py_deserialisation2', regex.compile(r'''pickle\.load\(.{0,99}$'''), PY_FILES), 518 | ('py_filesystem', regex.compile(r'''require\(\'fs\'\).{0,99}$'''), PY_FILES), 519 | ('py_flask_debug_mode', regex.compile(r'''^.{0,200}app\.run.{0,100}debug\s*=\s*True.{0,200}$'''), PY_FILES), 520 | ('py_flask_autoescape', regex.compile(r'''^.{0,200}autoescape\s+false.{0,200}$'''), PY_FILES + HTM_FILES), 521 | ('py_flask_pipe_safe', regex.compile(r'''^.{0,200}\|\s*safe.{0,200}$'''), PY_FILES + HTM_FILES), 522 | ('py_flask_markup', regex.compile(r'''^.{0,200}\WMarkup\(.{0,200}$'''), PY_FILES), 523 | ('py_mktemp_banned', regex.compile(r'''^.{0,200}\Wmktemp\s*\(.{0,200}$'''), PY_FILES), 524 | ('py_shell_is_true', regex.compile(r'''shell\s*=\s*True.{0,99}$'''), PY_FILES), 525 | ('py_subprocess_call', regex.compile(r'''subprocess.call\(.{0,99}$'''), PY_FILES), 526 | ('py_subprocess_run', regex.compile(r'''subprocess.run\(.{0,99}$'''), PY_FILES), 527 | ('python_deserial', regex.compile(r'''\.loads\(.{0,99}$'''), PY_FILES), 528 | ('python_format_cmdi', regex.compile(r'''"[^"]*-[^"]\{[^"]*"\.format.{0,99}$'''), PY_FILES), 529 | ('rand_math_random', regex.compile(r'''\WMath\.random\(\W.{0,99}$''')), 530 | ('rand_net_random', regex.compile(r'''\W(System\.Random).{0,99}$''')), 531 | ('rand_new_random', regex.compile(r'''\Wnew\sRandom\(\W.{0,99}$''')), 532 | ('rand_rand', regex.compile(r'''\Wrand\s*\(\W.{0,99}$''')), 533 | ('rand_random', regex.compile(r'''\Wrandom\s*\(\W.{0,99}$''')), 534 | ('rand_time', regex.compile(r'''\W(ftime|gettimeofday|GetTickCount|GetTickCount64|QueryPerformanceCounter|GetSystemTime|GetLocalTime|GetSystemTimeAsFileTime|NtQuerySystemTime|time|uniqid|microtime)\(.{0,99}$''')), 535 | ('rand_util_random', regex.compile(r'''\Wutil\.Random\W.{0,99}$'''), JAVA_FILES), 536 | ('rand_windows_good', regex.compile(r'''\W(CryptGenRandom)\W.{0,99}$''')), 537 | ('rds_hosts', regex.compile(r'''\S{10,199}\.rds\.amazonaws\.com''')), 538 | ('rootpwd', regex.compile(r'''[\s"\'^\(\{\[]root/[a-zA-Z0-9\.\-\_\!\?\#\&\*\:\;\@\(\)\<\>\%]{12,}''')), 539 | ('routing_controller', regex.compile(r'''@Controller.{0,200}$''')), 540 | ('routing_decorator', regex.compile(r'''\[Route\(.{0,99}$''')), 541 | ('routing_decorator2', regex.compile(r'''\[RoutePrefix\(.{0,99}$''')), 542 | ('routing_flask', regex.compile(r'''\badd_resource\b'''), PY_FILES), 543 | ('routing_get', regex.compile(r'''Get\[.{0,99}$''')), 544 | ('routing_java_get', regex.compile(r'''@GET.{0,99}$'''), JAVA_FILES), 545 | ('routing_java_getmapping', regex.compile(r'''@GetMapping.{0,99}$'''), JAVA_FILES), 546 | ('routing_java_path', regex.compile(r'''@Path\(.{0,99}$'''), JAVA_FILES), 547 | ('routing_java_post', regex.compile(r'''@POST.{0,99}$'''), JAVA_FILES), 548 | ('routing_java_requestmapping', regex.compile(r'''@RequestMapping.{0,99}$'''), JAVA_FILES), 549 | ('routing_java_requestmethod', regex.compile(r'''RequestMethod\.[A-Z]+.{0,99}$'''), JAVA_FILES), 550 | ('routing_node_get', regex.compile(r'''^.{0,99}\.get\(.{0,99}$'''), JS_FILES), 551 | ('routing_node_post', regex.compile(r'''^.{0,99}\.post\(.{0,99}$'''), JS_FILES), 552 | ('routing_node_put', regex.compile(r'''^.{0,99}\.put\(.{0,99}$'''), JS_FILES), 553 | ('routing_python', regex.compile(r'''\.add_resource\W.{0,200}$'''), PY_FILES), 554 | ('routing_web', regex.compile(r'''\.route\(.{0,199}$''')), 555 | ('rpc_reg', regex.compile(r'''RpcServerRegisterIf.{0,199}$'''), C_FILES), 556 | ('ruby_bad_hash', regex.compile(r'''(Digest::MD5|Digest::SHA1)'''), RUBY_FILES), 557 | ('ruby_cmdi_backtick', regex.compile(r'''^[^"\n]*`[^`\n]*#\{[^`\n]+`'''), RUBY_FILES), 558 | ('ruby_cmdi_backtick', regex.compile(r'''^[^"\n]*`[^`\n]+`'''), RUBY_FILES), 559 | ('ruby_cmdi_backtick2', regex.compile(r'''`#\{'''), RUBY_FILES), 560 | ('ruby_cmdi_exec', regex.compile(r'''\Wexec\W'''), RUBY_FILES), 561 | ('ruby_cmdi_percent_x', regex.compile(r'''%x[\(\{]'''), RUBY_FILES), 562 | ('ruby_cmdi_percent_x', regex.compile(r'''%x[\(\{].*#\{'''), RUBY_FILES), 563 | ('ruby_cmdi_popen', regex.compile(r'''IO\.popen'''), RUBY_FILES), 564 | ('ruby_cmdi_popen', regex.compile(r'''IO\.popen.*#\{'''), RUBY_FILES), 565 | ('ruby_cmdi_popen2', regex.compile(r'''\Wpopen.{0,200}'''), RUBY_FILES), 566 | ('ruby_cmdi_spawn', regex.compile(r'''Process\.spawn'''), RUBY_FILES), 567 | ('ruby_cmdi_spawn', regex.compile(r'''Process\.spawn.*#\{'''), RUBY_FILES), 568 | ('ruby_cmdi_system', regex.compile(r'''\Wsystem\W.*#\{'''), RUBY_FILES), 569 | ('ruby_custom_header', regex.compile(r'''request\.headers\['''), RUBY_FILES), 570 | ('ruby_env', regex.compile(r'''\WENV\[".*"\]'''), RUBY_FILES), 571 | ('ruby_json_load_RCE', regex.compile(r'''JSON\.load'''), RUBY_FILES), 572 | ('ruby_rails_version', regex.compile(r'''^\s*rails\s*\([0-9\.]+\)'''), 'Gemfile.lock'), 573 | ('ruby_req_header', regex.compile(r'''\.headers\["[a-zA-Z0-9-]"\]'''), RUBY_FILES), 574 | ('ruby_route_delete', regex.compile(r'''\Wdelete\s'''), RUBY_FILES), 575 | ('ruby_route_get', regex.compile(r'''\Wget\s'''), RUBY_FILES), 576 | ('ruby_route_match', regex.compile(r'''\Wmatch\s'''), RUBY_FILES), 577 | ('ruby_route_post', regex.compile(r'''\Wpost\s'''), RUBY_FILES), 578 | ('ruby_route_put', regex.compile(r'''\Wput\s'''), RUBY_FILES), 579 | ('ruby_sqli_from', regex.compile(r'''\Wfrom\(.*#'''), RUBY_FILES), 580 | ('ruby_sqli_order', regex.compile(r'''\Worder\(.*#'''), RUBY_FILES), 581 | ('ruby_sqli_where', regex.compile(r'''\Wwhere\(.*#'''), RUBY_FILES), 582 | ('ruby_sqli_where_interp', regex.compile(r'''\.where.*#{'''), RUBY_FILES), 583 | ('ruby_string_interpolation', regex.compile(r'''"[^"#]*#\{'''), RUBY_FILES), 584 | ('ruby_url_string_interpolation', regex.compile(r'''https?://.*#\{.{0,99}$'''), RUBY_FILES), 585 | ('ruby_yaml_load_file', regex.compile(r'''\.load_file\W.{0,99}$'''), RUBY_FILES), 586 | ('secure_url', regex.compile(r'''https://([a-zA-Z0-9]+\.)+[a-zA-Z0-9]+.{0,200}$''')), 587 | ('segv_reference', regex.compile(r'''\W(segvs|segv|sigsegv)\W.{0,200}$''')), 588 | ('simpleDB', regex.compile(r'''SimpleDB.{0,99}$''')), 589 | ('sqli_brace_interpolation', regex.compile(r'''("|\')\s*(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|TRUNCATE|USE)\s.*\{\d+\}.*("|\').{0,99}$''')), 590 | ('sqli_c', regex.compile(r'''"select\s.{1,200}%s.{0,99}$'''), C_FILES), 591 | ('sqli_compileSelectWhere', regex.compile(r'''CompileSelectWhere.{0,99}$''')), 592 | ('sqli_createSQLQuery', regex.compile(r'''createSQLQuery.{0,99}$''')), 593 | ('sqli_dblink', regex.compile(r'''dblink.{0,99}$''')), 594 | ('sqli_dbms_sql_exec', regex.compile(r'''dbms_sql.execute.{0,99}$''')), 595 | ('sqli_deprecated_escape', regex.compile(r'''PQescapeString\(.{0,99}$''')), 596 | ('sqli_deprecated_escape2', regex.compile(r'''mysql_escape_string\(.{0,99}$''')), 597 | ('sqli_dollar_interpolation', regex.compile(r'''("|\')\s*(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|TRUNCATE|USE)\s.*\$.*("|\').{0,99}$''')), 598 | ('sqli_dotnet_interpolation2', regex.compile(r'''\Wselect\s+[a-zA-z0-9\.,\*]+\s+from.{1,80}{\d+}.{0,99}$'''), DOTNET_FILES), 599 | ('sqli_exec_sp', regex.compile(r'''ExecuteStoredProcedure\(.{0,99}$''')), 600 | ('sqli_import_java_sql', regex.compile(r'''import\s+java.sql.{0,99}$''')), 601 | ('sqli_in_joined_strings', regex.compile(r'''\.{0,199}strings\.Join\(.{0,199}''')), 602 | ('sqli_insert', regex.compile(r'''\Winsert\s+into\s+[a-zA-z0-9\.,\*].{0,99}$''')), 603 | ('sqli_interpolate_brace', regex.compile(r'''^.{0,199}\'\{\s*\d+\s*\}\'.{0,199}$'''), DOTNET_FILES, CS_EXCLUSIONS), 604 | ('sqli_java_concat', regex.compile(r'''"[\s\(]*\b(select|insert|update|delete)\b.{0,199}"\s*\+\s*\w+.{0,99}$'''), JAVA_FILES), 605 | ('sqli_java_sqli_append', regex.compile(r'''sql\.append\(.{0,99}$''')), 606 | ('sqli_joined_strings_sgl', regex.compile(r'''strings\.Join\(.{0,199}\'.{0,199}$''')), 607 | ('sqli_like', regex.compile(r'''LIKE.*(%'|'%).{0,99}$''')), 608 | ('sqli_oracle_execute_immediate', regex.compile(r'''\Wexecute\s+immediate\W.{0,99}$''')), 609 | ('sqli_orcl_dbms_sql_parse', regex.compile(r'''dbms_sql.parse.{0,99}$''')), 610 | ('sqli_orcl_exec_immediate', regex.compile(r'''EXECUTE\s+IMMEDIATE.{0,99}$''')), 611 | ('sqli_order_by', regex.compile(r'''order\sby.{0,99}$''')), 612 | ('sqli_partial_view', regex.compile(r'''\WPartialView\(.{0,99}$''')), 613 | ('sqli_percent_interpolation', regex.compile(r'''("|\')\s*(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|TRUNCATE|USE)\s.*\%.*("|\').{0,99}$''')), 614 | ('sqli_py_interp', regex.compile(r'''\.execute\(\s*".{0,99}\%s.{0,99}$'''), PY_FILES), 615 | ('sqli_queryBuilder', regex.compile(r'''queryBuilder.{0,99}$''')), 616 | ('sqli_queryRaw', regex.compile(r'''queryRaw\(.{0,99}$''')), 617 | ('sqli_select_from', regex.compile(r'''\Wselect\W.{0,99}\Wfrom\W.{0,99}$''')), 618 | ('sqli_simpleDBSelect', regex.compile(r'''\.SelectRequest.{0,99}$''')), 619 | ('sqli_sp_executesql', regex.compile(r'''\Wsp_executesql\W.{0,99}$''')), 620 | ('sqli_sp_xp', regex.compile(r'''\W(exec\ssp_|exec\sxp_).{0,99}$''')), 621 | ('sqli_sqlHelper', regex.compile(r'''sqlHelper.runQuery.{0,99}$''')), 622 | ('sqli_sql_apis', regex.compile(r'''\W(OleDbConnection|ADODB\.|System\.Data\.Sql|\.ResultSet).{0,99}$'''), DOTNET_FILES, CS_EXCLUSIONS), 623 | ('sqli_sql_execute', regex.compile(r'''\WEXECUTE\W.{0,99}$''')), 624 | ('sqli_where', regex.compile(r'''\s+WHERE\s+[^\n]*\$\w+.{0,99}$''')), 625 | ('ssh_disable_hostkey_check', regex.compile(r'''StrictHostKeyChecking=no.{0,99}$''')), 626 | ('ssl_disable_curl', regex.compile(r'''curl.{0,99}\s-k\W.{0,99}$''')), 627 | ('ssl_disable_java', regex.compile(r'''InsecureRequestWarning.{0,99}$''')), 628 | ('ssl_disable_mysql', regex.compile(r'''--skip-ssl.{0,99}$''')), 629 | ('ssl_disable_python', regex.compile(r'''checkServerTrusted.{0,99}$''')), 630 | ('ssl_disable_python2', regex.compile(r'''no-check-cert.{0,99}$''')), 631 | ('ssl_disable_python3', regex.compile(r'''verify\s*=\s*False.{0,99}$''')), 632 | ('ssl_disable_python4', regex.compile(r'''rejectUnauthorized.{99}[Ff]alse.{0,99}$''')), 633 | ('ssl_disable_wget', regex.compile(r'''wget.{0,200}--no-check-certificate.{0,200}$''')), 634 | ('str_dot_net', regex.compile(r'''\.Format.{1,80}\s-.{1,80}{\d+}.{0,99}$''')), 635 | ('str_dot_net2', regex.compile(r'''\.Format.{1,80}\{\d+\}.{1,80}\s-.{1,80}.{0,99}$''')), 636 | ('str_interp_brace', regex.compile(r'''\$\".{0,99}{.{0,99}\".{0,99}$''')), 637 | ('str_interp_dollar', regex.compile(r'''\".{0,99}\$.{0,99}\".{0,99}$''')), 638 | ('str_join', regex.compile(r'''string\.Join\(.{0,199}$''')), 639 | ('str_mixed_quote_dbl_sgl', regex.compile(r'''^.{0,99}\"\'.{0,99}$''')), 640 | ('str_mixed_quote_sgl_dbl', regex.compile(r'''^.{0,99}\'\".{0,99}$''')), 641 | ('str_plus', regex.compile(r'''\'\s*\+.{0,99}\+\s*\'.{0,99}$''')), 642 | ('str_scala_mkString', regex.compile(r'''\.mkString\(.{0,99}$''')), 643 | ('todo_authenticate', regex.compile(r'''TODO.*authenticate.{0,200}$''')), 644 | ('todo_encrypt', regex.compile(r'''TODO.*encrypt.{0,200}$''')), 645 | ('todo_login', regex.compile(r'''TODO.*login.{0,200}$''')), 646 | ('todo_password', regex.compile(r'''TODO.*password.{0,200}$''')), 647 | ('todo_password2', regex.compile(r'''password.*TODO.{0,200}$''')), 648 | ('trusted_plaintext_docker_repo', regex.compile(r'''trusted\s*=\s*yes.*http://.{0,99}$''')), # noqa 649 | ('uniq_ip_addresses', regex.compile(r'''[\'"]([1-2]?[0-9]?[0-9]\.){3}([1-2]?[0-9]?[0-9])[\'"]''')), 650 | ('unreal_fs', regex.compile(r'''FFileHelper::''')), 651 | ('unreal_mem', regex.compile(r'''FMemory::''')), 652 | ('unreal_module', regex.compile(r'''FModuleManager::''')), 653 | ('unreal_paths', regex.compile(r'''FPaths::''')), 654 | ('url_numeric', regex.compile(r'''^[^#]*http(s)?://\d+\.\d+\.\d+\.\d+.{0,200}$'''), None, [regex.compile('127.0.0.1')]), 655 | ('url_pattern', regex.compile(r'''url-pattern{0,200}$''')), 656 | ('useradd', regex.compile(r'''useradd.{0,200}$''')), 657 | ('username_email', regex.compile(r'''[^/]userName:\s*[\.a-zA-Z0-9\_\-]+@[\.a-zA-Z0-9\_\-]+(\.[\.a-zA-Z0-9\_\-]+)+[^\n]{0,200}$''')), 658 | ('ver_aws_sdk', regex.compile(r'''AWS_SDK_VERSION_STRING.{0,99}$''')), 659 | ('ver_bzip', regex.compile(r'''BZ_VERSION.{0,99}$''')), 660 | ('ver_jansson', regex.compile(r'''JANSSON_VERSION.{0,99}$''')), 661 | ('ver_jsoncpp', regex.compile(r'''AWS_JSONCPP_VERSION_STRING.{0,99}$''')), 662 | ('ver_libcurl', regex.compile(r'''LIBCURL_VERSION.{0,99}$''')), 663 | ('ver_libcurl_str', regex.compile(r'''#define LIBCURL_VERSION "[^"]+"''')), 664 | ('ver_libpng', regex.compile(r'''PNG_LIBPNG_VER_STRING.{0,99}$''')), 665 | ('ver_mariadb', regex.compile(r'''MARIADB_PACKAGE_VERSION.{0,99}$''')), 666 | ('ver_mdb', regex.compile(r'''(MDB_VERSION_MAJOR|MDB_VERSION_MINOR|MDB_VERSION_PATCH).{0,99}$''')), 667 | ('ver_mongoose', regex.compile(r'''MONGOOSE_VERSION.{0,99}$''')), 668 | ('ver_openssl', regex.compile(r'''OPENSSL_VERSION_TEXT.{0,99}$''')), 669 | ('ver_postgres', regex.compile(r'''(PG_MAJORVERSION|PG_VERSION|PG_VERSION_STR).{0,99}$''')), 670 | ('ver_sqlite', regex.compile(r'''SQLITE_VERSION.{0,99}$''')), 671 | ('ver_u_icu', regex.compile(r'''U_ICU_VERSION.{0,99}$''')), 672 | ('ver_zlib', regex.compile(r'''ZLIB_VERSION.{0,99}$''')), 673 | ('web_HttpServletRequest', regex.compile(r'''HttpServletRequest.{0,99}$''')), 674 | ('web_dotnet', regex.compile(r'''HttpResponseMessage.{0,99}$''')), 675 | ('web_input', regex.compile(r'''\W(FileInputStream|FilterInputStream|SequenceInputStream|StringBufferInputStream|ByteArrayInputStream|FileOutputStream).{0,99}$''')), 676 | ('web_java_custom_header', regex.compile(r'''\.getHeader\(.{0,99}$''')), 677 | ('web_net_events', regex.compile(r'''\W(Application_OnAuthenticateRequest|Application_OnAuthorizeRequest|Session_OnStart).{0,99}$''')), 678 | ('web_path', regex.compile(r'''\W(getRealPath).{0,99}$''')), 679 | ('web_remote_name', regex.compile(r'''\W(getRemoteAddr|getRemoteHost).{0,99}$''')), 680 | ('web_request_dot', regex.compile(r'''\WRequest\..{0,99}$''')), 681 | ('web_sec_override', regex.compile(r'''\W(RequestMinimum|RequestOptional|SkipVerification|UnmanagedCode).{0,99}$''')), 682 | ('win_filter_drv_reg', regex.compile(r'''FltCreateCommunicationPort.{0,199}$''')), 683 | ('win_reg_api', regex.compile(r'''(OpenSubKey|RegOpenKey|RegQueryInfoKey|RegQueryValue|RegSetValue).{0,99}$''')), 684 | ('win_reg_key', regex.compile(r'''(HKEY_LOCAL_MACHINE|HKEY_CURRENT_USER|HKEY_CLASSES_ROOT|HKEY_USERS|HKEY_CURRENT_CONFIG).{0,99}$''')), 685 | ('workzeug_debugger_active', regex.compile(r'''WERKZEUG_DEBUG_PIN.{0,200}$''')), 686 | ] 687 | 688 | BannedFunctions = ['_alloca', '_ftcscat', '_ftcscpy', '_getts', '_gettws', '_i64toa', '_i64tow', '_itoa', '_itow', '_makepath', '_mbccat', 689 | '_mbccpy', '_mbscat', '_mbscpy', '_mbslen', '_mbsnbcat', '_mbsnbcpy', '_mbsncat', '_mbsncpy', '_mbstok', '_mbstrlen', 690 | '_sntscanf', '_splitpath', '_stprintf', '_stscanf', '_tccat', '_tccpy', '_tcscat', '_tcscpy', '_tcsncat', '_tcsncpy', 691 | '_tcstok', '_tmakepath', '_tscanf', '_tsplitpath', '_ui64toa', '_ui64tot', '_ui64tow', '_ultoa', '_ultot', '_ultow', 692 | '_vstprintf', '_wmakepath', '_wsplitpath', 'alloca', 'ChangeWindowMessageFilter', 'CharToOem', 'CharToOemA', 693 | 'CharToOemBuffA', 'CharToOemBuffW', 'CharToOemW', 'CopyMemory', 'gets', 'IsBadCodePtr', 'IsBadHugeReadPtr', 694 | 'IsBadHugeWritePtr', 'IsBadReadPtr', 'IsBadStringPtr', 'IsBadWritePtr', 'lstrcat', 'lstrcatA', 'lstrcatn', 'lstrcatnA', 695 | 'lstrcatnW', 'lstrcatW', 'lstrcpy', 'lstrcpyA', 'lstrcpyn', 'lstrcpynA', 'lstrcpynW', 'lstrcpyW', 'lstrlen', 'lstrncat', 696 | 'makepath', 'memcpy', 'memcpy', 'OemToChar', 'OemToCharA', 'OemToCharW', 'RtlCopyMemory', 'scanf', 'snscanf', 'snwscanf', 697 | 'sprintf', 'sprintfA', 'sscanf', 'strcat', 'strcat', 'StrCat', 'strcatA', 'StrCatA', 'StrCatBuff', 'StrCatBuffA', 698 | 'StrCatBuffW', 'StrCatChainW', 'StrCatN', 'StrCatNA', 'StrCatNW', 'strcatW', 'StrCatW', 'strcpy', 'StrCpy', 'strcpyA', 699 | 'StrCpyA', 'StrCpyN', 'StrCpyNA', 'strcpynA', 'StrCpyNW', 'strcpyW', 'StrCpyW', 'strlen', 'StrLen', 'strncat', 'StrNCat', 700 | 'StrNCatA', 'StrNCatW', 'strncpy', 'StrNCpy', 'StrNCpyA', 'StrNCpyW', 'strtok', 'swprintf', 'swscanf', 'vsnprintf', 701 | 'vsprintf', 'vswprintf', 'wcscat', 'wcscpy', 'wcslen', 'wcsncat', 'wcsncpy', 'wcstok', 'wmemcpy', 'wnsprintf', 702 | 'wnsprintfA', 'wnsprintfW', 'wscanf', 'wsprintf', 'wsprintf', 'wsprintfA', 'wvnsprintf', 'wvnsprintfA', 'wvnsprintfW', 703 | 'wvsprintf', 'wvsprintfA', 'wvsprintfW'] 704 | 705 | 706 | def signal_handler(sig, frame): # noqa 707 | print('Exiting (CTRL-C)') 708 | sys.exit(0) 709 | 710 | 711 | def main(): 712 | signal.signal(signal.SIGINT, signal_handler) 713 | fn.do_main() 714 | 715 | 716 | if __name__ == "__main__": 717 | main() 718 | -------------------------------------------------------------------------------- /fn.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import regex 4 | import sys 5 | import os 6 | import datetime 7 | 8 | 9 | def skip_file(fname): 10 | import cq 11 | global ns 12 | if ns: 13 | return False 14 | 15 | for skip in cq.SKIP_DIRS: 16 | if skip.search(fname): 17 | return True 18 | for skip in cq.SKIP_EXTS: 19 | if skip.search(fname): 20 | return True 21 | return False 22 | 23 | 24 | def get_global_checks(re_checks_todo): 25 | import cq # noqa 26 | global_checks = [] 27 | for c in cq.GLOBAL_CHECKS: 28 | check_name = c[0] 29 | proc = c[1] 30 | arg = c[2] 31 | if re_checks_todo.search(check_name): 32 | global_checks += [(check_name, proc, arg)] 33 | return global_checks 34 | 35 | 36 | def get_global_post_checks(re_checks_todo): 37 | import cq # noqa 38 | global_checks = [] 39 | for c in cq.GLOBAL_POST_CHECKS: 40 | check_name = c[0] 41 | proc = c[1] 42 | arg = c[2] 43 | if re_checks_todo.search(check_name): 44 | global_checks += [(check_name, proc, arg)] 45 | return global_checks 46 | 47 | 48 | def get_file_checks(fname, re_checks_todo): 49 | import cq 50 | # FILENAME_CHECKS, 0 is regex, 1 is outfile 51 | file_checks = [] 52 | for c in cq.FILE_CHECKS: 53 | check_name = c[0] 54 | regex_text = c[1] 55 | proc = c[2] 56 | arg = c[3] 57 | if regex_text.search(fname): 58 | if re_checks_todo.search(check_name): 59 | file_checks += [(check_name, regex_text, proc, arg)] 60 | return file_checks 61 | 62 | 63 | def get_line_regex_checks(fname, re_checks_todo): 64 | import cq 65 | global sc, sa # noqa 66 | 67 | # compile regexes 68 | line_checks = [] 69 | for c in cq.LINE_REGEX_CHECKS: 70 | check_name = c[0] 71 | check_re = c[1] 72 | files = c[2] if len(c) > 2 else None 73 | exclusions = c[3] if len(c) > 3 else None 74 | fmt = c[4] if len(c) > 4 else None 75 | 76 | add = True 77 | if sc: 78 | files = cq.ALL_CODE_FILES 79 | 80 | if sa: 81 | add = True 82 | elif files: 83 | add = False 84 | for f in files: 85 | if fname.lower().endswith(f): 86 | add = True 87 | break 88 | 89 | if add: 90 | if re_checks_todo.search(check_name): 91 | line_checks += [(check_name, check_re, files, exclusions, fmt)] 92 | for ext in cq.C_FILES: 93 | if fname.lower().endswith(ext): 94 | for fn in cq.BannedFunctions: 95 | re = regex.compile(re_checks_todo) 96 | if re.search('banned_' + fn): 97 | line_checks += [('banned_' + fn, regex.compile(r'\W' + fn + r'\s*\(.{0,99}$'), None, None)] 98 | 99 | return line_checks 100 | 101 | 102 | def get_line_custom_checks(fname, re_checks_todo): 103 | import cq 104 | global sc, sa # noqa 105 | 106 | # compile regexes 107 | line_checks = [] 108 | for c in cq.LINE_CUSTOM_CHECKS: 109 | check_name = c[0] 110 | check_fn = c[1] 111 | files = c[2] if len(c) > 2 else None 112 | exclusions = c[3] if len(c) > 3 else None 113 | fmt = c[4] if len(c) > 4 else None 114 | 115 | add = True 116 | if sc: 117 | files = cq.ALL_CODE_FILES 118 | 119 | if sa: 120 | add = True 121 | elif files: 122 | add = False 123 | for f in files: 124 | if fname.lower().endswith(f): 125 | add = True 126 | break 127 | if add: 128 | if re_checks_todo.search(check_name): 129 | line_checks += [(check_name, check_fn, files, exclusions, fmt)] 130 | 131 | return line_checks 132 | 133 | 134 | def do_file_check(check, fname): 135 | out_fname = outdir + '/' + check[0] + '.txt' 136 | # regex_text = check[1] 137 | proc = check[2] 138 | arg = check[3] 139 | proc(fname, out_fname, arg) 140 | 141 | 142 | def do_line_regex_check(check, fname, line, line_num): 143 | try: 144 | outfile = check[0] 145 | re = check[1] 146 | # files = check[2] if len(check) > 2 else None 147 | exclusions = check[3] if len(check) > 3 else None 148 | fmt = check[4] if len(check) > 4 else '{fname}:{line_num}:{g0}' 149 | if fmt is None: fmt = '{fname}:{line_num}:{g0}' # noqa 150 | result = re.search(line) 151 | if result: 152 | skip = False 153 | if exclusions: 154 | for exclude in exclusions: 155 | res_ex = exclude.search(line) 156 | if res_ex: 157 | skip = True 158 | break 159 | if not skip: 160 | # write output in format. 161 | # string.format? 162 | g0 = result.group(0) 163 | groups = result.groups() 164 | g1 = groups[0] if len(groups) > 0 else '' 165 | g2 = groups[1] if len(groups) > 1 else '' 166 | g3 = groups[2] if len(groups) > 2 else '' 167 | 168 | msg = fmt.format(fname=fname, line_num=line_num, g0=g0, g1=g1, g2=g2, g3=g3) 169 | write_result(outfile, msg) 170 | except Exception as e: 171 | print("Exception: " + str(e)) 172 | print("") 173 | 174 | 175 | def do_line_custom_check(check, fname, line, line_num): 176 | try: 177 | outfile = check[0] 178 | fn = check[1] 179 | base_fmt = '{fname}:{line_num}:{g0}' 180 | # files = check[2] if len(check) > 2 else None 181 | # exclusions = check[3] if len(check) > 3 else None 182 | fmt = check[4] if len(check) > 4 else base_fmt 183 | if fmt is None: fmt = base_fmt # noqa 184 | results = fn(line) 185 | for result, score in results: # noqa 186 | score_str = '%02d' % score 187 | g0 = result 188 | msg = fmt.format(fname=fname, line_num=line_num, score_str=score_str, g0=g0) 189 | write_result('crit_' + outfile, msg) # noqa 190 | 191 | except Exception as e: 192 | print("Exception: " + str(e)) 193 | print("") 194 | 195 | 196 | def global_run_tool(out_fname, arg): 197 | cmd = arg.format(out_fname=out_fname) 198 | os.system(cmd) 199 | 200 | 201 | def do_global_check(check): 202 | check_name = check[0] 203 | out_fname = outdir + '/' + check_name + '.txt' 204 | proc = check[1] 205 | arg = check[2] 206 | if print_progress: 207 | print('Running Tool: ' + check_name) 208 | proc(out_fname, arg) 209 | 210 | 211 | def sort_file(filename): 212 | try: 213 | in_file = open(filename, 'r') 214 | lines = sorted(set(in_file.readlines())) 215 | in_file.close() 216 | in_file = open(filename, 'w') 217 | in_file.writelines(lines) 218 | in_file.close() 219 | except: # noqa 220 | return False 221 | 222 | 223 | def sort_df_sources_and_sinks(out_fname, arg): # noqa 224 | import cq 225 | for source_file in cq.DF_FILES: 226 | source_file = outdir + '/' + source_file + '_sources.txt' 227 | sort_file(source_file) 228 | source_file = outdir + '/' + source_file + '_sinks.txt' 229 | sort_file(source_file) 230 | 231 | 232 | def df_report_if_issue(df_file, src_result, sink_result): 233 | # True if strings match to the first colon ':' 234 | lhs = src_result.split(':') 235 | rhs = sink_result.split(':') 236 | if len(lhs) < 2 or len(rhs) < 2: 237 | return False 238 | if lhs[0] != rhs[0]: 239 | return False 240 | i_l = int(lhs[1]) 241 | i_r = int(rhs[1]) 242 | diff = abs(i_l - i_r) 243 | if diff > 1000: 244 | return False 245 | msg = lhs[0] + ':' + lhs[1] + ':SCORE:' + f'{diff:05}' 246 | write_result(df_file + '_issues.txt', msg) 247 | return True 248 | 249 | 250 | def gen_df_bugs(out_fname, arg): # noqa 251 | import cq # noqa 252 | for df_file in cq.DF_FILES: 253 | source_file = outdir + '/' + df_file + '_sources.txt' 254 | sink_file = outdir + '/' + df_file + '_sinks.txt' 255 | 256 | # for each source, advance sink to 'first after'; numeric (not alpha) comparison for line number. 257 | # compare two lines. Same file is line_number diff. 258 | # Output issues with prefix of 'score', which is this diff. 259 | try: 260 | in_file = open(source_file, 'r') 261 | src_lines = in_file.readlines() 262 | in_file.close() 263 | in_file = open(sink_file, 'r') 264 | sink_lines = in_file.readlines() 265 | in_file.close() 266 | except: # noqa 267 | continue 268 | 269 | i_src = 0 270 | i_sink = 0 271 | while (i_src < len(src_lines)) and (i_sink < len(sink_lines)): 272 | src = src_lines[i_src] 273 | sink = sink_lines[i_sink] 274 | while (sink < src) and (i_sink < len(sink_lines)): 275 | sink = sink_lines[i_sink] 276 | i_sink = i_sink + 1 277 | df_report_if_issue(df_file, src, sink) 278 | i_src = i_src + 1 279 | 280 | 281 | def basic_get_time(out_fname, arg): 282 | now = datetime.datetime.now() 283 | start = now.strftime("%Y-%m-%d %H:%M:%S") 284 | write_result_to_path(out_fname, start + arg) 285 | 286 | 287 | def basic_path(out_fname, arg): 288 | write_result_to_path(out_fname, os.path.abspath(".") + arg) 289 | 290 | 291 | def file_run_tool(fname, out_fname, arg): 292 | cmd = arg.format(fname=fname, out_fname=out_fname) 293 | os.system(cmd) 294 | 295 | 296 | def file_scan_exe(fname, out_fname, arg): # noqa 297 | write_result_to_path(out_fname, fname) 298 | 299 | 300 | def file_exists(fname, out_fname, arg): # noqa 301 | write_result_to_path(out_fname, fname) 302 | 303 | 304 | def file_scan_shell(fname, out_fname, arg): # noqa 305 | write_result_to_path(out_fname, 'Scan shell: ' + fname) 306 | cmdline = 'shellcheck "{fname}" >> "{out_fname}"' 307 | cmd = cmdline.format(fname=fname, out_fname=out_fname) 308 | os.system(cmd) 309 | 310 | 311 | def write_result(fname, result_msg): 312 | with open(outdir + '/' + fname + '.txt', 'a') as outfile: 313 | if result_msg.endswith('\n'): 314 | outfile.write(result_msg) 315 | else: 316 | outfile.write(result_msg + '\n') 317 | 318 | 319 | def write_result_to_path(fullpath, result_msg): 320 | with open(fullpath, 'a') as outfile: 321 | if result_msg.endswith('\n'): 322 | outfile.write(result_msg) 323 | else: 324 | outfile.write(result_msg + '\n') 325 | 326 | 327 | def is_binary(line): 328 | if line.find(b'\x00'): 329 | return True 330 | if line.find(b'\xff'): 331 | return True 332 | if line.find(b'\xfe'): 333 | return True 334 | return False 335 | 336 | 337 | def do_checks(re_checks_todo): 338 | if outdir == '': 339 | return 340 | if a: 341 | mode = 'rb' 342 | else: 343 | mode = 'r' 344 | 345 | global_checks = get_global_checks(re_checks_todo) 346 | for check in global_checks: 347 | do_global_check(check) 348 | 349 | for root, subdirs, files in os.walk(os.path.abspath(".")): 350 | for fn in files: 351 | fname = str(root) + "/" + str(fn) 352 | # exclude some files/paths based on verbosity options 353 | if skip_file(fname): 354 | continue 355 | if vvv or print_progress: 356 | print('Scanning ' + fname) 357 | # do checks based on filename 358 | file_checks = get_file_checks(fname, re_checks_todo) 359 | for check in file_checks: 360 | do_file_check(check, fname) 361 | 362 | # do checks based on the text of lines in a file 363 | regex_checks = get_line_regex_checks(fname, re_checks_todo) 364 | custom_checks = get_line_custom_checks(fname, re_checks_todo) 365 | if regex_checks or custom_checks: 366 | try: 367 | with open(fname, mode) as f: 368 | line_num = 1 369 | for line in f: 370 | # do all line checks 371 | if a: 372 | line = str(line) 373 | for check in regex_checks: 374 | do_line_regex_check(check, fname, line, line_num) 375 | for check in custom_checks: 376 | do_line_custom_check(check, fname, line, line_num) 377 | 378 | line_num += 1 379 | except: # noqa 380 | continue 381 | 382 | checks = get_global_post_checks(re_checks_todo) 383 | for check in checks: 384 | do_global_check(check) 385 | 386 | 387 | def syntax(): 388 | print( 389 | '''cq.py : Universal SAST Tool [ By Chris Anley ] 390 | Syntax: 391 | cq.py [options] 392 | -a : check all files, including binaries (i.e. files containing invalid utf-8 chars) 393 | -c : only run checks matching the regex, e.g. 'php' 394 | -p : print progress 395 | -v : quite verbose 396 | -vv : annoyingly verbose 397 | -vvv : pointlessly verbose 398 | -ns : no skip : don't skip files/directories that are irrelevant, like test, /vendor/, /node_modules/, .zip etc 399 | -sa : scan all files, not just recommended / code files 400 | -sc : scan all code files for all bugs, i.e. not just python bugs in python files 401 | ''') 402 | 403 | 404 | a = False 405 | v = False 406 | vv = False 407 | vvv = False 408 | ns = False 409 | sa = False 410 | sc = False 411 | print_progress = False 412 | re_checks = '.*' 413 | outdir = '/tmp/' # Note - this is always set to something else, but - just in case it isn't, put output in /tmp. 414 | 415 | 416 | def do_main(): 417 | global a, v, vv, vvv, ns, sa, sc, outdir, print_progress, re_checks 418 | argc = len(sys.argv) 419 | argv = sys.argv 420 | 421 | if argc <= 1: 422 | return syntax() 423 | 424 | for i in range(1, argc): 425 | if argv[i] == '-a': 426 | a = True 427 | ns = True # no skip directories 428 | sa = True # apply all checks to all files 429 | continue 430 | if argv[i] == '-v': 431 | v = True 432 | continue 433 | if argv[i] == '-vv': 434 | v = True 435 | vv = True 436 | continue 437 | if argv[i] == '-vvv': 438 | v = True 439 | vv = True 440 | vvv = True 441 | continue 442 | if argv[i] == '-ns': # no skip directories / files 443 | ns = True 444 | continue 445 | if argv[i] == '-sa': # apply all checks to all files 446 | sa = True 447 | continue 448 | if argv[i] == '-sc': # apply all checks to all code files 449 | sc = True 450 | continue 451 | if argv[i] == '-p': 452 | print_progress = True 453 | if i == argc - 1: 454 | outdir = argv[i] 455 | if argv[i] == '-c': 456 | re_checks = argv[i + 1] 457 | i += 1 458 | 459 | try: 460 | os.makedirs(outdir) 461 | except: # noqa 462 | print("Outdir exists") 463 | 464 | print("Starting") 465 | 466 | do_checks(regex.compile(re_checks)) 467 | --------------------------------------------------------------------------------