From 9562b0080638033728a2f4450ab733a5d48b4091 Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Tue, 12 Mar 2024 13:49:42 +0100 Subject: [PATCH 1/5] Initiate subfolder plugin --- Pipfile | 2 +- config.yml | 8 + sariftoolkit/config.py | 5 + sariftoolkit/plugins/__init__.py | 1 + sariftoolkit/plugins/subfolders.py | 281 +++++++++++++++++++++++++++++ subfolders/README.md | 50 +++++ subfolders/action.yml | 39 ++++ 7 files changed, 385 insertions(+), 1 deletion(-) create mode 100644 config.yml create mode 100644 sariftoolkit/plugins/subfolders.py create mode 100644 subfolders/README.md create mode 100644 subfolders/action.yml diff --git a/Pipfile b/Pipfile index fe9c6c2..ecbcdba 100644 --- a/Pipfile +++ b/Pipfile @@ -7,4 +7,4 @@ verify_ssl = true [packages] requests = "*" - +pyyaml = "*" diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..35e3832 --- /dev/null +++ b/config.yml @@ -0,0 +1,8 @@ +- + url: https://github.com/ORG_REPO + path: src/core + token: github_pat_ +- + url: https://github.com/ORG_REPO@ + path: src/lib + token: github_pat_ \ No newline at end of file diff --git a/sariftoolkit/config.py b/sariftoolkit/config.py index eddce54..425f639 100644 --- a/sariftoolkit/config.py +++ b/sariftoolkit/config.py @@ -1,3 +1,4 @@ +import dataclasses from dataclasses import dataclass @@ -18,6 +19,10 @@ class Plugins: "Submodules", "sariftoolkit.plugins.submodules" ) + subfolders: PluginConfig = PluginConfig( + "Subfolders", "sariftoolkit.plugins.subfolders" + ) + @dataclass class Config: diff --git a/sariftoolkit/plugins/__init__.py b/sariftoolkit/plugins/__init__.py index 674f431..3358277 100644 --- a/sariftoolkit/plugins/__init__.py +++ b/sariftoolkit/plugins/__init__.py @@ -1,2 +1,3 @@ from sariftoolkit.plugins.relativepaths import RelativePaths from sariftoolkit.plugins.submodules import Submodules +from sariftoolkit.plugins.subfolders import Subfolders diff --git a/sariftoolkit/plugins/subfolders.py b/sariftoolkit/plugins/subfolders.py new file mode 100644 index 0000000..10377eb --- /dev/null +++ b/sariftoolkit/plugins/subfolders.py @@ -0,0 +1,281 @@ +import os +import copy +import gzip +import base64 +import subprocess +import urllib.parse +import yaml +from typing import List +from dataclasses import dataclass +from argparse import ArgumentParser + +import requests + +from sariftoolkit.plugin import Plugin +from sariftoolkit.sarif.sarif import exportSarif +from sariftoolkit.sarif.models import SarifModel + + +@dataclass +class SubfolderModel: + name: str = None + url: str = None + path: str = None + token: str = None + + +@dataclass +class Subfolders(Plugin): + name: str = "Subfolders" + version: str = "1.0.0" + description: str = "Git Subfolder Splitter" + + token: str = None + cleanup: bool = False + # of type SubfolderModel + config_file = [] + + mode: str = "sink" + + def arguments(self, parser: ArgumentParser): + parser.add_argument( + "--config-file", + help="The relative path to the configuration file", + ) + + parser.add_argument( + "--subfolder-disable-cleanup", + action="store_false", + help="Disable clean up newly created SARIF files", + ) + parser.add_argument( + "--subfolder-mode", + default="sink", + help="Subfolder plugin mode ('sink' or 'path')", + ) + + def run(self, arguments, **kargvs): + workspace = os.path.abspath(arguments.github_workspace) + working = os.path.abspath(arguments.working) + + self.token = arguments.github_token + self.cleanup = arguments.submodules_disable_cleanup + self.mode = arguments.submodules_mode + self.config_file = arguments.config_file + + #  Load the configuration file + with open(self.config_file) as f: + config = yaml.load(f, Loader=yaml.FullLoader) + + self.logger.debug(f"Git Workspace :: {workspace}") + self.logger.debug(f"Working :: {working}") + self.logger.info(f"config :: {config}") + + + for sarif, sarif_file in self.loadSarif("/Users/adrienpessu/workspaces/advanced-security/sarif-toolkit/examples/sarifs/python-testing-queries.sarif"): + self.processSarif(config, sarif, sarif_file) + + def processSarif( + self, + subfolder_structured: List[SubfolderModel], + sarif: SarifModel, + sarif_file: str, + ): + self.logger.info(f"Processing SARIF file: {sarif_file}") + + submodule_sarifs = {} + for sub in subfolder_structured: + submodule_sarifs[sub["url"]] = {} + + for run in sarif.runs: + print("-----------SARIF -----------") + tool = run.tool.driver + self.logger.info(f"Processing tool: {tool.name} ({tool.semanticVersion})") + + for result in run.results: + self.logger.debug(f"Rule('{result.ruleId}')") + + # Modes + if self.mode == "sink": + #  Get the sink of the query + location = result.locations[len(result.locations) - 1] + + uri = location.physicalLocation.artifactLocation.uri + self.logger.debug(f"Location('{uri}')") + + submodule, new_location_uri = self.isFileInSubfolder( + subfolder_structured, uri + ) + + if submodule: + self.logger.info(f"Result is in Submodule: {submodule.name}") + + location.physicalLocation.artifactLocation.uri = ( + new_location_uri + ) + + if not submodule_sarifs[submodule.name].get(result.ruleId): + submodule_sarifs[submodule.name][result.ruleId] = [] + + submodule_sarifs[submodule.name][result.ruleId].append(result) + + elif self.mode == "path": + #  If any of the locations in the path are in the submodule + for location in result.locations: + uri = location.physicalLocation.artifactLocation.uri + self.logger.debug(f"Location('{uri}')") + + submodule, new_location_uri = self.isFileInSubfolder( + subfolder_structured, uri + ) + + if submodule: + self.logger.info( + f"Result is in Submodule: {submodule.name}" + ) + + location.physicalLocation.artifactLocation.uri = ( + new_location_uri + ) + + if not submodule_sarifs[submodule.name].get(result.ruleId): + submodule_sarifs[submodule.name][result.ruleId] = [] + + submodule_sarifs[submodule.name][result.ruleId].append( + result + ) + + #  TODO: Pop result if --submodules-disable-autoremove is true + else: + raise Exception(f"Unknown Mode: {self.mode}") + + for name, submodule_locations in submodule_sarifs.items(): + if not submodule_locations: + continue + + submodule = next((x for x in submodules if x.name == name), None) + + self.logger.info(f"Creating SARIF file for: {name}") + # Create a deep copy of the SARIF file + submodule_sarif: SarifModel = copy.copy(sarif) + + for run in submodule_sarif.runs: + #  Clear the existing results + run.results.clear() + + for rule_id, results in submodule_locations.items(): + self.logger.debug( + f"New Submodule Result :: {rule_id} ({len(results)})" + ) + + run.results.extend(results) + + submod_file = self.createSubmoduleFileName(name, sarif_file) + exportSarif(submod_file, submodule_sarif) + + self.publishSarifFile(submodule, submodule_sarif, sarif_file=submod_file) + + if self.cleanup: + self.logger.info(f"Cleaning up SARIF file: {submod_file}") + os.remove(submod_file) + + def createSubmoduleFileName(self, name: str, sarif_file: str): + file_name, file_ext = os.path.splitext(sarif_file) + + return f"{file_name}-{name}{file_ext}" + + def isFileInSubfolder(self, structure: List[SubfolderModel], file: str): + for sub in structure: + path = sub["path"] + self.logger.info(f"isFileInSubfolder :: {file} :: {path}") + if file.startswith(sub["path"]): + new_path = file.replace(sub.path + "/", "", 1) + return (sub, new_path) + return (None, None) + + def getSubmodules(self, workspace: str): + subs = [] + command = ["git", "submodule", "status", "--recursive"] + result = subprocess.run(command, stdout=subprocess.PIPE, cwd=workspace) + data = result.stdout.decode().split("\n") + + for line in data: + line = line.strip() + if line == "" or line.startswith("-") or line.startswith("+"): + continue + + sha, path, status = line.split(" ") + name = os.path.basename(path) + full_path = os.path.join(workspace, path) + url = self.getGitRemoteUrl(full_path) + + if not url.scheme and not url.netloc: + #  Assume SSH like URL... + _, giturl = url.path.split(":") + else: + giturl = url.path.replace("/", "", 1) + + giturl = giturl.replace(".git", "") + + submodule = SubfolderModel( + name=name, + url=giturl, + path=path, + branch="refs/" + status.replace("(", "").replace(")", ""), + commit=sha, + ) + + subs.append(submodule) + + return subs + + def getGitRemoteUrl(self, path: str): + self.logger.debug(f"Git Remote Path :: {path}") + + command = ["git", "config", "--get", "remote.origin.url"] + result = subprocess.run(command, stdout=subprocess.PIPE, cwd=path) + url = result.stdout.decode().strip() + + return urllib.parse.urlparse(url) + + def packageSarif(self, path: str): + if os.path.exists(path): + with open(path, "rb") as handle: + content = gzip.compress(handle.read()) + return base64.b64encode(content).decode() + + def publishSarifFile( + self, + submodule: SubfolderModel, + sarif: SarifModel, + sarif_file: str, + instance: str = "https://github.com", + ): + if not self.token: + self.logger.warning("Failed to find access token, skipping publishing...") + return + + self.logger.info(f"Publishing SARIF to submodule: {submodule.name}") + headers = { + "Accept": "application/vnd.github.v3+json", + "Authorization": "token " + self.token, + } + owner, repo = submodule.url.split("/") + if instance == "https://github.com": + api_instance = "https://api.github.com" + else: + api_instance = instance + "/api" + + url = f"{api_instance}/repos/{owner}/{repo}/code-scanning/sarifs" + self.logger.debug(f"Publishing SARIF file to endpoint: {url}") + + data = { + "commit_sha": submodule.commit, + "ref": submodule.branch, + "sarif": self.packageSarif(sarif_file), + "tool_name": sarif.runs[0].tool.driver.name, + } + + res = requests.post(url, json=data, headers=headers) + + self.logger.info("Uploaded SARIF file to submodule") diff --git a/subfolders/README.md b/subfolders/README.md new file mode 100644 index 0000000..ac216ac --- /dev/null +++ b/subfolders/README.md @@ -0,0 +1,50 @@ +# sarif-toolkit - Subfolders + +SARIF Subfolders Tool/Action. + +This tools allows users to split up SARIF files that use subfolders into multiple SARIF files that are then published to there appropriate repositories. + +## Example / Use Case + +Your repository has a subfolder called "core" which is a subfolder pulled into your CI at runtime to build the full code base. +Your security scanning tool takes all the code present in the repository or at build time and discovers security issues that end up in "core". + +Example: `SQL Injection sink in "core"` + +You want to publish bad your results to the "core" team that develops that code base. + +## Usage + +### Actions + +This Action needs to be placed in between the point of the SARIF file(s) being created and uploaded. + + +**Simple Usage** + +```yaml +# ... SARIF file has been created +- uses: advanced-security/sarif-toolkit/Subfolders@main +# ... SARIF file is being uploaded +``` + +**Advance config** + +```yaml +#  +- uses: advanced-security/sarif-toolkit/Subfolders@main + with: + # SARIF File / Directory location + # [optional]: Default: '../results' + sarif: 'sarif-output.json' + # Working Directory (sub folder of the working directory) + # [optional]: Default: '.' (current working directory) + working: '.' + # Mode for how detecting SARIF result locations are located and how they + # should be reported. + # 'sink': Only split on sink being in the subfolder + # 'path': If any location is in the SARIF file + # [optional]: Default: 'sink' + mode: 'sink' + config-file: './config.yml' +``` diff --git a/subfolders/action.yml b/subfolders/action.yml new file mode 100644 index 0000000..a166925 --- /dev/null +++ b/subfolders/action.yml @@ -0,0 +1,39 @@ +name: "sarif-toolkit" +description: "sarif-toolkit" + +inputs: + sarif: + description: SARIF File Location + # CodeQL Location by default + default: ../results + + working: + description: Working directory + default: . + + mode: + description: Submodule Mode + default: sink + + token: + description: GitHub Personal Access Token + default: ${{ github.token }} + + config-file: + description: Relative path to the configuration file + default: config.yml + +runs: + using: "composite" + steps: + - shell: bash + run: | + PYTHONPATH=${{ github.action_path }}/.. && export PYTHONPATH=${{ github.action_path }}/.. + pip install requests + python3 ${{ github.action_path }}/../sariftoolkit/__main__.py \ + --enable-subfolder \ + --subfolder-mode "${{ inputs.mode }}" \ + --sarif "${{ inputs.sarif }}" \ + --working "${{ inputs.working }}" \ + --github-token "${{ inputs.token }}" \ + --config-file "${{ inputs.config-file }}" From e3945918d36627291740b098c35191c3b1de9e5c Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Fri, 22 Mar 2024 17:13:59 +0100 Subject: [PATCH 2/5] Update .gitignore and config.yml files --- .gitignore | 6 ++ config.yml | 6 +- sariftoolkit/plugins/subfolders.py | 91 ++++++++++++++---------------- 3 files changed, 52 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index cf2b8d9..f01f683 100644 --- a/.gitignore +++ b/.gitignore @@ -212,3 +212,9 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk + +config.yml + +# Python +venv_name/ +.python-version \ No newline at end of file diff --git a/config.yml b/config.yml index 35e3832..61276e7 100644 --- a/config.yml +++ b/config.yml @@ -1,8 +1,8 @@ -- +- name: core url: https://github.com/ORG_REPO path: src/core token: github_pat_ -- +- name: lib url: https://github.com/ORG_REPO@ path: src/lib - token: github_pat_ \ No newline at end of file + token: github_pat_ diff --git a/sariftoolkit/plugins/subfolders.py b/sariftoolkit/plugins/subfolders.py index 10377eb..5d48a14 100644 --- a/sariftoolkit/plugins/subfolders.py +++ b/sariftoolkit/plugins/subfolders.py @@ -59,9 +59,10 @@ def run(self, arguments, **kargvs): working = os.path.abspath(arguments.working) self.token = arguments.github_token - self.cleanup = arguments.submodules_disable_cleanup - self.mode = arguments.submodules_mode + self.cleanup = arguments.subfolder_disable_cleanup + self.mode = arguments.subfolder_mode self.config_file = arguments.config_file + self.sarif_path = arguments.sarif #  Load the configuration file with open(self.config_file) as f: @@ -72,7 +73,8 @@ def run(self, arguments, **kargvs): self.logger.info(f"config :: {config}") - for sarif, sarif_file in self.loadSarif("/Users/adrienpessu/workspaces/advanced-security/sarif-toolkit/examples/sarifs/python-testing-queries.sarif"): + for sarif, sarif_file in self.loadSarif(self.sarif_path): + self.logger.info(f"sarif :: {sarif}") self.processSarif(config, sarif, sarif_file) def processSarif( @@ -83,9 +85,9 @@ def processSarif( ): self.logger.info(f"Processing SARIF file: {sarif_file}") - submodule_sarifs = {} + subfolder_sarifs = {} for sub in subfolder_structured: - submodule_sarifs[sub["url"]] = {} + subfolder_sarifs[sub["name"]] = {} for run in sarif.runs: print("-----------SARIF -----------") @@ -101,85 +103,79 @@ def processSarif( location = result.locations[len(result.locations) - 1] uri = location.physicalLocation.artifactLocation.uri - self.logger.debug(f"Location('{uri}')") - submodule, new_location_uri = self.isFileInSubfolder( + subfolder, new_location_uri = self.isFileInSubfolder( subfolder_structured, uri ) - if submodule: - self.logger.info(f"Result is in Submodule: {submodule.name}") - + if subfolder: location.physicalLocation.artifactLocation.uri = ( new_location_uri ) + + if not subfolder_sarifs[subfolder['name']].get(result.ruleId): + subfolder_sarifs[subfolder['name']][result.ruleId] = [] - if not submodule_sarifs[submodule.name].get(result.ruleId): - submodule_sarifs[submodule.name][result.ruleId] = [] - - submodule_sarifs[submodule.name][result.ruleId].append(result) + subfolder_sarifs[subfolder['name']][result.ruleId].append(result) elif self.mode == "path": - #  If any of the locations in the path are in the submodule + #  If any of the locations in the path are in the subfolder for location in result.locations: uri = location.physicalLocation.artifactLocation.uri self.logger.debug(f"Location('{uri}')") - submodule, new_location_uri = self.isFileInSubfolder( + subfolder, new_location_uri = self.isFileInSubfolder( subfolder_structured, uri ) - if submodule: - self.logger.info( - f"Result is in Submodule: {submodule.name}" - ) - + if subfolder: location.physicalLocation.artifactLocation.uri = ( new_location_uri ) - if not submodule_sarifs[submodule.name].get(result.ruleId): - submodule_sarifs[submodule.name][result.ruleId] = [] + if not subfolder_sarifs[subfolder.name].get(result.ruleId): + subfolder_sarifs[subfolder.name][result.ruleId] = [] - submodule_sarifs[submodule.name][result.ruleId].append( + subfolder_sarifs[subfolder.name][result.ruleId].append( result ) - #  TODO: Pop result if --submodules-disable-autoremove is true + #  TODO: Pop result if --subfolders-disable-autoremove is true else: raise Exception(f"Unknown Mode: {self.mode}") - for name, submodule_locations in submodule_sarifs.items(): - if not submodule_locations: + for name, subfolder_locations in subfolder_sarifs.items(): + if not subfolder_locations: continue - submodule = next((x for x in submodules if x.name == name), None) + self.logger.info(f"Subfolder: {name} || {subfolder}") + subfolder = next((x for x in subfolder_structured if x['name'] == name), None) self.logger.info(f"Creating SARIF file for: {name}") # Create a deep copy of the SARIF file - submodule_sarif: SarifModel = copy.copy(sarif) + subfolder_sarif: SarifModel = copy.copy(sarif) - for run in submodule_sarif.runs: + for run in subfolder_sarif.runs: #  Clear the existing results run.results.clear() - for rule_id, results in submodule_locations.items(): + for rule_id, results in subfolder_locations.items(): self.logger.debug( - f"New Submodule Result :: {rule_id} ({len(results)})" + f"New subfolder Result :: {rule_id} ({len(results)})" ) run.results.extend(results) - submod_file = self.createSubmoduleFileName(name, sarif_file) - exportSarif(submod_file, submodule_sarif) + submod_file = self.createsubfolderFileName(name, sarif_file) + exportSarif(submod_file, subfolder_sarif) - self.publishSarifFile(submodule, submodule_sarif, sarif_file=submod_file) + self.publishSarifFile(subfolder, subfolder_sarif, sarif_file=submod_file) if self.cleanup: self.logger.info(f"Cleaning up SARIF file: {submod_file}") os.remove(submod_file) - def createSubmoduleFileName(self, name: str, sarif_file: str): + def createsubfolderFileName(self, name: str, sarif_file: str): file_name, file_ext = os.path.splitext(sarif_file) return f"{file_name}-{name}{file_ext}" @@ -187,15 +183,14 @@ def createSubmoduleFileName(self, name: str, sarif_file: str): def isFileInSubfolder(self, structure: List[SubfolderModel], file: str): for sub in structure: path = sub["path"] - self.logger.info(f"isFileInSubfolder :: {file} :: {path}") if file.startswith(sub["path"]): - new_path = file.replace(sub.path + "/", "", 1) + new_path = file.replace(path + "/", "", 1) return (sub, new_path) return (None, None) - def getSubmodules(self, workspace: str): + def getsubfolders(self, workspace: str): subs = [] - command = ["git", "submodule", "status", "--recursive"] + command = ["git", "subfolder", "status", "--recursive"] result = subprocess.run(command, stdout=subprocess.PIPE, cwd=workspace) data = result.stdout.decode().split("\n") @@ -217,7 +212,7 @@ def getSubmodules(self, workspace: str): giturl = giturl.replace(".git", "") - submodule = SubfolderModel( + subfolder = SubfolderModel( name=name, url=giturl, path=path, @@ -225,7 +220,7 @@ def getSubmodules(self, workspace: str): commit=sha, ) - subs.append(submodule) + subs.append(subfolder) return subs @@ -246,7 +241,7 @@ def packageSarif(self, path: str): def publishSarifFile( self, - submodule: SubfolderModel, + subfolder: SubfolderModel, sarif: SarifModel, sarif_file: str, instance: str = "https://github.com", @@ -255,12 +250,12 @@ def publishSarifFile( self.logger.warning("Failed to find access token, skipping publishing...") return - self.logger.info(f"Publishing SARIF to submodule: {submodule.name}") + self.logger.info(f"Publishing SARIF to subfolder: {subfolder.name}") headers = { "Accept": "application/vnd.github.v3+json", "Authorization": "token " + self.token, } - owner, repo = submodule.url.split("/") + owner, repo = subfolder.url.split("/") if instance == "https://github.com": api_instance = "https://api.github.com" else: @@ -270,12 +265,12 @@ def publishSarifFile( self.logger.debug(f"Publishing SARIF file to endpoint: {url}") data = { - "commit_sha": submodule.commit, - "ref": submodule.branch, + "commit_sha": subfolder.commit, + "ref": subfolder.branch, "sarif": self.packageSarif(sarif_file), "tool_name": sarif.runs[0].tool.driver.name, } res = requests.post(url, json=data, headers=headers) - self.logger.info("Uploaded SARIF file to submodule") + self.logger.info("Uploaded SARIF file to subfolder") From c5f211a4b427bca6ba77e5906e882944ecee39b4 Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Fri, 22 Mar 2024 17:27:48 +0100 Subject: [PATCH 3/5] Remove unnecessary logging statement in Subfolders plugin --- examples/sarifs/cpp-testing-queries.sarif | 3052 +++++++++++++++++++++ sariftoolkit/plugins/subfolders.py | 1 - 2 files changed, 3052 insertions(+), 1 deletion(-) create mode 100644 examples/sarifs/cpp-testing-queries.sarif diff --git a/examples/sarifs/cpp-testing-queries.sarif b/examples/sarifs/cpp-testing-queries.sarif new file mode 100644 index 0000000..0072d8a --- /dev/null +++ b/examples/sarifs/cpp-testing-queries.sarif @@ -0,0 +1,3052 @@ +{ + "$schema": "https://json.schemastore.org/sarif-2.1.0.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "CodeQL", + "organization": "GitHub", + "semanticVersion": "2.16.3", + "notifications": [ + { + "id": "cli/expected-extracted-files/c", + "name": "cli/expected-extracted-files/c", + "shortDescription": { + "text": "Expected extracted files" + }, + "fullDescription": { + "text": "Files appearing in the source archive that are expected to be extracted." + }, + "defaultConfiguration": { + "enabled": true + }, + "properties": { + "tags": [ + "expected-extracted-files", + "telemetry" + ], + "languageDisplayName": "C" + } + }, + { + "id": "cpp/extractor/summary", + "name": "cpp/extractor/summary", + "shortDescription": { + "text": "C++ extractor telemetry" + }, + "fullDescription": { + "text": "C++ extractor telemetry" + }, + "defaultConfiguration": { + "enabled": true + } + } + ], + "rules": [] + }, + "extensions": [ + { + "name": "codeql/cpp-queries", + "semanticVersion": "0.9.5+8a00a45b32679ddced400ab256706c79c1169e38", + "notifications": [ + { + "id": "cpp/diagnostics/extraction-warnings", + "name": "cpp/diagnostics/extraction-warnings", + "shortDescription": { + "text": "Extraction warnings" + }, + "fullDescription": { + "text": "List all extraction warnings for files in the source code directory." + }, + "defaultConfiguration": { + "enabled": true + }, + "properties": { + "description": "List all extraction warnings for files in the source code directory.", + "id": "cpp/diagnostics/extraction-warnings", + "kind": "diagnostic", + "name": "Extraction warnings" + } + }, + { + "id": "cpp/diagnostics/failed-extractor-invocations", + "name": "cpp/diagnostics/failed-extractor-invocations", + "shortDescription": { + "text": "Failed extractor invocations" + }, + "fullDescription": { + "text": "Gives the command line of compilations for which extraction did not run to completion." + }, + "defaultConfiguration": { + "enabled": true + }, + "properties": { + "description": "Gives the command line of compilations for which extraction did not run to completion.", + "id": "cpp/diagnostics/failed-extractor-invocations", + "kind": "diagnostic", + "name": "Failed extractor invocations" + } + }, + { + "id": "cpp/diagnostics/successfully-extracted-files", + "name": "cpp/diagnostics/successfully-extracted-files", + "shortDescription": { + "text": "Extracted files" + }, + "fullDescription": { + "text": "Lists all files in the source code directory that were extracted." + }, + "defaultConfiguration": { + "enabled": true + }, + "properties": { + "tags": [ + "successfully-extracted-files" + ], + "description": "Lists all files in the source code directory that were extracted.", + "id": "cpp/diagnostics/successfully-extracted-files", + "kind": "diagnostic", + "name": "Extracted files" + } + } + ], + "rules": [ + { + "id": "cpp/non-constant-format", + "name": "cpp/non-constant-format", + "shortDescription": { + "text": "Non-constant format string" + }, + "fullDescription": { + "text": "Passing a value that is not a string literal 'format' string to a printf-like function can lead to a mismatch between the number of arguments defined by the 'format' and the number of arguments actually passed to the function. If the format string ultimately stems from an untrusted source, this can be used for exploits. This query finds format strings coming from non-literal sources. Note that format strings of type `const char*` it is still considered non-constant if the value is not coming from a string literal. For example, for a parameter with type `const char*` of an exported function that is used as a format string, there is no way to ensure the originating value was a string literal." + }, + "defaultConfiguration": { + "enabled": true, + "level": "note" + }, + "help": { + "text": "# Non-constant format string\nThe `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.\n\n\n## Recommendation\nIf 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.\n\nIf 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.\n\n\n## Example\nThe following program is meant to echo its command line arguments:\n\n\n```c\n#include \nint main(int argc, char** argv) {\n for(int i = 1; i < argc; ++i) {\n printf(argv[i]);\n }\n}\n```\nThe 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:\n\n\n```c\n#include \nint main(int argc, char** argv) {\n for(int i = 1; i < argc; ++i) {\n printf(\"%s\", argv[i]);\n }\n}\n```\n\n## Example\nThe following program defines a `log_with_timestamp` function:\n\n\n```c\nvoid log_with_timestamp(const char* message) {\n struct tm now;\n time(&now);\n printf(\"[%s] \", asctime(now));\n printf(message);\n}\n\nint main(int argc, char** argv) {\n log_with_timestamp(\"Application is starting...\\n\");\n /* ... */\n log_with_timestamp(\"Application is closing...\\n\");\n return 0;\n}\n```\nIn 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:\n\n\n```c\nvoid log_with_timestamp(const char* message) {\n struct tm now;\n time(&now);\n printf(\"[%s] %s\", asctime(now), message);\n}\n\nint main(int argc, char** argv) {\n log_with_timestamp(\"Application is starting...\\n\");\n /* ... */\n log_with_timestamp(\"Application is closing...\\n\");\n return 0;\n}\n```\nAn alternative solution is to allow `log_with_timestamp` to accept format arguments:\n\n\n```c\nvoid log_with_timestamp(const char* message, ...) {\n va_list args;\n va_start(args, message);\n struct tm now;\n time(&now);\n printf(\"[%s] \", asctime(now));\n vprintf(message, args);\n va_end(args);\n}\n\nint main(int argc, char** argv) {\n log_with_timestamp(\"%s is starting...\\n\", argv[0]);\n /* ... */\n log_with_timestamp(\"%s is closing...\\n\", argv[0]);\n return 0;\n}\n```\nIn 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.\n\n\n## References\n* 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).\n* M. Howard, D. Leblanc, J. Viega, *19 Deadly Sins of Software Security: Programming Flaws and How to Fix Them*.\n* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html).\n", + "markdown": "# Non-constant format string\nThe `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.\n\n\n## Recommendation\nIf 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.\n\nIf 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.\n\n\n## Example\nThe following program is meant to echo its command line arguments:\n\n\n```c\n#include \nint main(int argc, char** argv) {\n for(int i = 1; i < argc; ++i) {\n printf(argv[i]);\n }\n}\n```\nThe 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:\n\n\n```c\n#include \nint main(int argc, char** argv) {\n for(int i = 1; i < argc; ++i) {\n printf(\"%s\", argv[i]);\n }\n}\n```\n\n## Example\nThe following program defines a `log_with_timestamp` function:\n\n\n```c\nvoid log_with_timestamp(const char* message) {\n struct tm now;\n time(&now);\n printf(\"[%s] \", asctime(now));\n printf(message);\n}\n\nint main(int argc, char** argv) {\n log_with_timestamp(\"Application is starting...\\n\");\n /* ... */\n log_with_timestamp(\"Application is closing...\\n\");\n return 0;\n}\n```\nIn 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:\n\n\n```c\nvoid log_with_timestamp(const char* message) {\n struct tm now;\n time(&now);\n printf(\"[%s] %s\", asctime(now), message);\n}\n\nint main(int argc, char** argv) {\n log_with_timestamp(\"Application is starting...\\n\");\n /* ... */\n log_with_timestamp(\"Application is closing...\\n\");\n return 0;\n}\n```\nAn alternative solution is to allow `log_with_timestamp` to accept format arguments:\n\n\n```c\nvoid log_with_timestamp(const char* message, ...) {\n va_list args;\n va_start(args, message);\n struct tm now;\n time(&now);\n printf(\"[%s] \", asctime(now));\n vprintf(message, args);\n va_end(args);\n}\n\nint main(int argc, char** argv) {\n log_with_timestamp(\"%s is starting...\\n\", argv[0]);\n /* ... */\n log_with_timestamp(\"%s is closing...\\n\", argv[0]);\n return 0;\n}\n```\nIn 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.\n\n\n## References\n* 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).\n* M. Howard, D. Leblanc, J. Viega, *19 Deadly Sins of Software Security: Programming Flaws and How to Fix Them*.\n* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html).\n" + }, + "properties": { + "tags": [ + "maintainability", + "correctness", + "security", + "external/cwe/cwe-134" + ], + "description": "Passing a value that is not a string literal 'format' string to a printf-like function can lead\n to a mismatch between the number of arguments defined by the 'format' and the number\n of arguments actually passed to the function. If the format string ultimately stems\n from an untrusted source, this can be used for exploits.\n This query finds format strings coming from non-literal sources. Note that format strings of\n type `const char*` it is still considered non-constant if the value is not coming from a string\n literal. For example, for a parameter with type `const char*` of an exported function that is\n used as a format string, there is no way to ensure the originating value was a string literal.", + "id": "cpp/non-constant-format", + "kind": "problem", + "name": "Non-constant format string", + "precision": "high", + "problem.severity": "recommendation", + "security-severity": "9.3" + } + }, + { + "id": "cpp/wrong-number-format-arguments", + "name": "cpp/wrong-number-format-arguments", + "shortDescription": { + "text": "Too few arguments to formatting function" + }, + "fullDescription": { + "text": "Calling a printf-like function with too few arguments can be a source of security issues." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Too few arguments to formatting function\nEach 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.\n\nThis 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.\n\n\n## Recommendation\nReview 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.\n\n\n## Example\n\n```cpp\nint main() {\n printf(\"%d, %s\\n\", 42); // Will crash or print garbage\n return 0;\n}\n\n```\n\n## References\n* 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).\n* cplusplus.com: [C++ Functions](http://www.tutorialspoint.com/cplusplus/cpp_functions.htm).\n* Microsoft C Runtime Library Reference: [printf, wprintf](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l).\n* Common Weakness Enumeration: [CWE-234](https://cwe.mitre.org/data/definitions/234.html).\n* Common Weakness Enumeration: [CWE-685](https://cwe.mitre.org/data/definitions/685.html).\n", + "markdown": "# Too few arguments to formatting function\nEach 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.\n\nThis 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.\n\n\n## Recommendation\nReview 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.\n\n\n## Example\n\n```cpp\nint main() {\n printf(\"%d, %s\\n\", 42); // Will crash or print garbage\n return 0;\n}\n\n```\n\n## References\n* 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).\n* cplusplus.com: [C++ Functions](http://www.tutorialspoint.com/cplusplus/cpp_functions.htm).\n* Microsoft C Runtime Library Reference: [printf, wprintf](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l).\n* Common Weakness Enumeration: [CWE-234](https://cwe.mitre.org/data/definitions/234.html).\n* Common Weakness Enumeration: [CWE-685](https://cwe.mitre.org/data/definitions/685.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "correctness", + "security", + "external/cwe/cwe-234", + "external/cwe/cwe-685" + ], + "description": "Calling a printf-like function with too few arguments can be\n a source of security issues.", + "id": "cpp/wrong-number-format-arguments", + "kind": "problem", + "name": "Too few arguments to formatting function", + "precision": "high", + "problem.severity": "error", + "security-severity": "5.0" + } + }, + { + "id": "cpp/wrong-type-format-argument", + "name": "cpp/wrong-type-format-argument", + "shortDescription": { + "text": "Wrong type of arguments to formatting function" + }, + "fullDescription": { + "text": "Calling a printf-like function with the wrong type of arguments causes unpredictable behavior." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Wrong type of arguments to formatting function\nEach 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.\n\n\n## Recommendation\nReview 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.\n\n\n## Example\n\n```cpp\nint main() {\n printf(\"%s\\n\", 42); //printf will treat 42 as a char*, will most likely segfault\n return 0;\n}\n\n```\n\n## References\n* 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).\n* cplusplus.com: [C++ Functions](http://www.tutorialspoint.com/cplusplus/cpp_functions.htm).\n* CRT Alphabetical Function Reference: [printf, _printf_l, wprintf, _wprintf_l](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l).\n* Common Weakness Enumeration: [CWE-686](https://cwe.mitre.org/data/definitions/686.html).\n", + "markdown": "# Wrong type of arguments to formatting function\nEach 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.\n\n\n## Recommendation\nReview 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.\n\n\n## Example\n\n```cpp\nint main() {\n printf(\"%s\\n\", 42); //printf will treat 42 as a char*, will most likely segfault\n return 0;\n}\n\n```\n\n## References\n* 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).\n* cplusplus.com: [C++ Functions](http://www.tutorialspoint.com/cplusplus/cpp_functions.htm).\n* CRT Alphabetical Function Reference: [printf, _printf_l, wprintf, _wprintf_l](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l).\n* Common Weakness Enumeration: [CWE-686](https://cwe.mitre.org/data/definitions/686.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "correctness", + "security", + "external/cwe/cwe-686" + ], + "description": "Calling a printf-like function with the wrong type of arguments causes unpredictable\n behavior.", + "id": "cpp/wrong-type-format-argument", + "kind": "problem", + "name": "Wrong type of arguments to formatting function", + "precision": "high", + "problem.severity": "error", + "security-severity": "7.5" + } + }, + { + "id": "cpp/overflowing-snprintf", + "name": "cpp/overflowing-snprintf", + "shortDescription": { + "text": "Potentially overflowing call to snprintf" + }, + "fullDescription": { + "text": "Using the return value from snprintf without proper checks can cause overflow." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Potentially overflowing call to snprintf\nThe 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 behavior, for example:\n\n\n## Example\n\n```cpp\n#define BUF_SIZE (32)\n\nint main(int argc, char *argv[])\n{\n\tchar buffer[BUF_SIZE];\n\tsize_t pos = 0;\n\tint i;\n\n\tfor (i = 0; i < argc; i++)\n\t{\n\t\tpos += snprintf(buffer + pos, BUF_SIZE - pos, \"%s\", argv[i]);\n\t\t\t// BUF_SIZE - pos may overflow\n\t}\n}\n\n```\n\n## Recommendation\nThe return value of `snprintf` should always be checked if it is used, and values larger than the buffer size should be accounted for.\n\n\n## Example\n\n```cpp\n#define BUF_SIZE (32)\n\nint main(int argc, char *argv[])\n{\n\tchar buffer[BUF_SIZE];\n\tsize_t pos = 0;\n\tint i;\n\n\tfor (i = 0; i < argc; i++)\n\t{\n\t\tint n = snprintf(buffer + pos, BUF_SIZE - pos, \"%s\", argv[i]);\n\t\tif (n < 0 || n >= BUF_SIZE - pos)\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tpos += n;\n\t}\n}\n\n```\n\n## References\n* cplusplus.com: [snprintf](http://www.cplusplus.com/reference/cstdio/snprintf/).\n* Red Hat Customer Portal: [The trouble with snprintf](https://access.redhat.com/blogs/766093/posts/1976193).\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-253](https://cwe.mitre.org/data/definitions/253.html).\n", + "markdown": "# Potentially overflowing call to snprintf\nThe 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 behavior, for example:\n\n\n## Example\n\n```cpp\n#define BUF_SIZE (32)\n\nint main(int argc, char *argv[])\n{\n\tchar buffer[BUF_SIZE];\n\tsize_t pos = 0;\n\tint i;\n\n\tfor (i = 0; i < argc; i++)\n\t{\n\t\tpos += snprintf(buffer + pos, BUF_SIZE - pos, \"%s\", argv[i]);\n\t\t\t// BUF_SIZE - pos may overflow\n\t}\n}\n\n```\n\n## Recommendation\nThe return value of `snprintf` should always be checked if it is used, and values larger than the buffer size should be accounted for.\n\n\n## Example\n\n```cpp\n#define BUF_SIZE (32)\n\nint main(int argc, char *argv[])\n{\n\tchar buffer[BUF_SIZE];\n\tsize_t pos = 0;\n\tint i;\n\n\tfor (i = 0; i < argc; i++)\n\t{\n\t\tint n = snprintf(buffer + pos, BUF_SIZE - pos, \"%s\", argv[i]);\n\t\tif (n < 0 || n >= BUF_SIZE - pos)\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tpos += n;\n\t}\n}\n\n```\n\n## References\n* cplusplus.com: [snprintf](http://www.cplusplus.com/reference/cstdio/snprintf/).\n* Red Hat Customer Portal: [The trouble with snprintf](https://access.redhat.com/blogs/766093/posts/1976193).\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-253](https://cwe.mitre.org/data/definitions/253.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "correctness", + "security", + "external/cwe/cwe-190", + "external/cwe/cwe-253" + ], + "description": "Using the return value from snprintf without proper checks can cause overflow.", + "id": "cpp/overflowing-snprintf", + "kind": "problem", + "name": "Potentially overflowing call to snprintf", + "precision": "high", + "problem.severity": "warning", + "security-severity": "8.1" + } + }, + { + "id": "cpp/integer-multiplication-cast-to-long", + "name": "cpp/integer-multiplication-cast-to-long", + "shortDescription": { + "text": "Multiplication result converted to larger type" + }, + "fullDescription": { + "text": "A multiplication result that is converted to a larger type can be a sign that the result can overflow the type converted from." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Multiplication result converted to larger type\nThis 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.\n\nThe 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.\n\n\n## Recommendation\nUse a cast to ensure that the multiplication is done using the larger integer type to avoid overflow.\n\n\n## Example\n\n```cpp\nint i = 2000000000;\nlong j = i * i; //Wrong: due to overflow on the multiplication between ints, \n //will result to j being -1651507200, not 4000000000000000000\n\nlong k = (long) i * i; //Correct: the multiplication is done on longs instead of ints, \n //and will not overflow\n\nlong l = static_cast(i) * i; //Correct: modern C++\n\n```\n\n## References\n* MSDN Library: [Multiplicative Operators and the Modulus Operator](https://docs.microsoft.com/en-us/cpp/cpp/multiplicative-operators-and-the-modulus-operator).\n* Cplusplus.com: [Integer overflow](http://www.cplusplus.com/articles/DE18T05o/).\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html).\n* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html).\n* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html).\n", + "markdown": "# Multiplication result converted to larger type\nThis 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.\n\nThe 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.\n\n\n## Recommendation\nUse a cast to ensure that the multiplication is done using the larger integer type to avoid overflow.\n\n\n## Example\n\n```cpp\nint i = 2000000000;\nlong j = i * i; //Wrong: due to overflow on the multiplication between ints, \n //will result to j being -1651507200, not 4000000000000000000\n\nlong k = (long) i * i; //Correct: the multiplication is done on longs instead of ints, \n //and will not overflow\n\nlong l = static_cast(i) * i; //Correct: modern C++\n\n```\n\n## References\n* MSDN Library: [Multiplicative Operators and the Modulus Operator](https://docs.microsoft.com/en-us/cpp/cpp/multiplicative-operators-and-the-modulus-operator).\n* Cplusplus.com: [Integer overflow](http://www.cplusplus.com/articles/DE18T05o/).\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html).\n* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html).\n* Common Weakness Enumeration: [CWE-681](https://cwe.mitre.org/data/definitions/681.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "correctness", + "types", + "external/cwe/cwe-190", + "external/cwe/cwe-192", + "external/cwe/cwe-197", + "external/cwe/cwe-681" + ], + "description": "A multiplication result that is converted to a larger type can\n be a sign that the result can overflow the type converted from.", + "id": "cpp/integer-multiplication-cast-to-long", + "kind": "problem", + "name": "Multiplication result converted to larger type", + "precision": "high", + "problem.severity": "warning", + "security-severity": "8.1" + } + }, + { + "id": "cpp/signed-overflow-check", + "name": "cpp/signed-overflow-check", + "shortDescription": { + "text": "Signed overflow check" + }, + "fullDescription": { + "text": "Testing for overflow by adding a value to a variable to see if it \"wraps around\" works only for unsigned integer values." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Signed overflow check\nWhen 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.\n\n\n## Recommendation\nSolutions to this problem can be thought of as falling into one of two categories:\n\n1. Rewrite the signed expression so that overflow cannot occur but the signedness remains.\n1. Change the variables and all their uses to be unsigned.\nThe following cases all fall into the first category.\n\n1. 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.\n1. 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.\n1. 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.\n\n## Example\nIn 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.\n\n\n```cpp\nbool foo(int n1, unsigned short delta) {\n return n1 + delta < n1; // BAD\n}\n\n```\nThe 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.\n\n\n```cpp\n#include \nbool foo(int n1, unsigned short delta) {\n return n1 > INT_MAX - delta; // GOOD\n}\n\n```\nIn 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).\n\n\n```cpp\nbool bar(unsigned short n1, unsigned short delta) {\n // NB: Comparison is always false\n return n1 + delta < n1; // GOOD (but misleading)\n}\n\n```\nThe 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`.\n\n\n```cpp\nbool bar(unsigned short n1, unsigned short delta) {\n return (unsigned short)(n1 + delta) < n1; // GOOD\n}\n\n```\n\n## References\n* [comp.lang.c FAQ list · Question 3.19 (Preserving rules)](http://c-faq.com/expr/preservingrules.html)\n* [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)\n* W. Dietz, P. Li, J. Regehr, V. Adve. [Understanding Integer Overflow in C/C++](https://www.cs.utah.edu/~regehr/papers/overflow12.pdf)\n* Common Weakness Enumeration: [CWE-128](https://cwe.mitre.org/data/definitions/128.html).\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n", + "markdown": "# Signed overflow check\nWhen 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.\n\n\n## Recommendation\nSolutions to this problem can be thought of as falling into one of two categories:\n\n1. Rewrite the signed expression so that overflow cannot occur but the signedness remains.\n1. Change the variables and all their uses to be unsigned.\nThe following cases all fall into the first category.\n\n1. 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.\n1. 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.\n1. 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.\n\n## Example\nIn 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.\n\n\n```cpp\nbool foo(int n1, unsigned short delta) {\n return n1 + delta < n1; // BAD\n}\n\n```\nThe 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.\n\n\n```cpp\n#include \nbool foo(int n1, unsigned short delta) {\n return n1 > INT_MAX - delta; // GOOD\n}\n\n```\nIn 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).\n\n\n```cpp\nbool bar(unsigned short n1, unsigned short delta) {\n // NB: Comparison is always false\n return n1 + delta < n1; // GOOD (but misleading)\n}\n\n```\nThe 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`.\n\n\n```cpp\nbool bar(unsigned short n1, unsigned short delta) {\n return (unsigned short)(n1 + delta) < n1; // GOOD\n}\n\n```\n\n## References\n* [comp.lang.c FAQ list · Question 3.19 (Preserving rules)](http://c-faq.com/expr/preservingrules.html)\n* [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)\n* W. Dietz, P. Li, J. Regehr, V. Adve. [Understanding Integer Overflow in C/C++](https://www.cs.utah.edu/~regehr/papers/overflow12.pdf)\n* Common Weakness Enumeration: [CWE-128](https://cwe.mitre.org/data/definitions/128.html).\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n" + }, + "properties": { + "tags": [ + "correctness", + "security", + "external/cwe/cwe-128", + "external/cwe/cwe-190" + ], + "description": "Testing for overflow by adding a value to a variable\n to see if it \"wraps around\" works only for\n unsigned integer values.", + "id": "cpp/signed-overflow-check", + "kind": "problem", + "name": "Signed overflow check", + "precision": "high", + "problem.severity": "warning", + "security-severity": "8.1" + } + }, + { + "id": "cpp/bad-addition-overflow-check", + "name": "cpp/bad-addition-overflow-check", + "shortDescription": { + "text": "Bad check for overflow of integer addition" + }, + "fullDescription": { + "text": "Checking for overflow of integer addition by comparing against one of the arguments of the addition does not work when the result of the addition is automatically promoted to a larger type." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Bad check for overflow of integer addition\nChecking 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.\n\n\n## Recommendation\nUse an explicit cast to make sure that the result of the addition is not implicitly converted to a larger type.\n\n\n## Example\n\n```cpp\nbool checkOverflow(unsigned short x, unsigned short y) {\n // BAD: comparison is always false due to type promotion\n return (x + y < x); \n}\n\n```\nOn 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.\n\nThe 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`).\n\n\n```cpp\nbool checkOverflow(unsigned short x, unsigned short y) {\n return ((unsigned short)(x + y) < x); // GOOD: explicit cast\n}\n\n```\n\n## References\n* [Preserving Rules](http://c-faq.com/expr/preservingrules.html)\n* [Understand integer conversion rules](https://www.securecoding.cert.org/confluence/plugins/servlet/mobile#content/view/20086942)\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html).\n", + "markdown": "# Bad check for overflow of integer addition\nChecking 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.\n\n\n## Recommendation\nUse an explicit cast to make sure that the result of the addition is not implicitly converted to a larger type.\n\n\n## Example\n\n```cpp\nbool checkOverflow(unsigned short x, unsigned short y) {\n // BAD: comparison is always false due to type promotion\n return (x + y < x); \n}\n\n```\nOn 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.\n\nThe 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`).\n\n\n```cpp\nbool checkOverflow(unsigned short x, unsigned short y) {\n return ((unsigned short)(x + y) < x); // GOOD: explicit cast\n}\n\n```\n\n## References\n* [Preserving Rules](http://c-faq.com/expr/preservingrules.html)\n* [Understand integer conversion rules](https://www.securecoding.cert.org/confluence/plugins/servlet/mobile#content/view/20086942)\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-192](https://cwe.mitre.org/data/definitions/192.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "correctness", + "security", + "external/cwe/cwe-190", + "external/cwe/cwe-192" + ], + "description": "Checking for overflow of integer addition by comparing\n against one of the arguments of the addition does not work\n when the result of the addition is automatically promoted\n to a larger type.", + "id": "cpp/bad-addition-overflow-check", + "kind": "problem", + "name": "Bad check for overflow of integer addition", + "precision": "very-high", + "problem.severity": "error", + "security-severity": "8.1" + } + }, + { + "id": "cpp/unsafe-use-of-this", + "name": "cpp/unsafe-use-of-this", + "shortDescription": { + "text": "Unsafe use of this in constructor" + }, + "fullDescription": { + "text": "A call to a pure virtual function using a 'this' pointer of an object that is under construction may lead to undefined behavior." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Unsafe use of this in constructor\nThis rule finds calls to pure virtual member functions in constructors and destructors. When executing the body of a constructor of class `T`, the virtual table of `T` refers to the virtual table of one of `T`'s base classes. This can produce unexpected behavior, including program abort that can lead to denial of service attacks. The same problem exists during destruction of an object.\n\n\n## Recommendation\nDo not rely on virtual dispatch in constructors and destructors. Instead, each class should be responsible for acquiring and releasing its resources. If a base class needs to refer to a derived class during initialization, use the Dynamic Binding During Initialization idiom.\n\n\n## Example\n\n```cpp\nclass Base {\nprivate:\n // pure virtual member function used for initialization of derived classes.\n virtual void construct() = 0;\npublic:\n Base() {\n // wrong: the virtual table of `Derived` has not been initialized yet. So this\n // call will resolve to `Base::construct`, which cannot be called as it is a pure\n // virtual function.\n construct();\n }\n};\n\nclass Derived: public Base {\n int field;\n\n void construct() override {\n field = 1;\n }\n};\n\n```\n\n## References\n* ISO C++ FAQ: [When my base class's constructor calls a virtual function on its this object, why doesn't my derived class's override of that virtual function get invoked?](https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctors)\n* SEI CERT C++ Coding Standard [OOP50-CPP. Do not invoke virtual functions from constructors or destructors](https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP50-CPP.+Do+not+invoke+virtual+functions+from+constructors+or+destructors)\n* ISO C++ FAQ: [Okay, but is there a way to simulate that behavior as if dynamic binding worked on the this object within my base class's constructor?](https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctor-idiom)\n* Common Weakness Enumeration: [CWE-670](https://cwe.mitre.org/data/definitions/670.html).\n", + "markdown": "# Unsafe use of this in constructor\nThis rule finds calls to pure virtual member functions in constructors and destructors. When executing the body of a constructor of class `T`, the virtual table of `T` refers to the virtual table of one of `T`'s base classes. This can produce unexpected behavior, including program abort that can lead to denial of service attacks. The same problem exists during destruction of an object.\n\n\n## Recommendation\nDo not rely on virtual dispatch in constructors and destructors. Instead, each class should be responsible for acquiring and releasing its resources. If a base class needs to refer to a derived class during initialization, use the Dynamic Binding During Initialization idiom.\n\n\n## Example\n\n```cpp\nclass Base {\nprivate:\n // pure virtual member function used for initialization of derived classes.\n virtual void construct() = 0;\npublic:\n Base() {\n // wrong: the virtual table of `Derived` has not been initialized yet. So this\n // call will resolve to `Base::construct`, which cannot be called as it is a pure\n // virtual function.\n construct();\n }\n};\n\nclass Derived: public Base {\n int field;\n\n void construct() override {\n field = 1;\n }\n};\n\n```\n\n## References\n* ISO C++ FAQ: [When my base class's constructor calls a virtual function on its this object, why doesn't my derived class's override of that virtual function get invoked?](https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctors)\n* SEI CERT C++ Coding Standard [OOP50-CPP. Do not invoke virtual functions from constructors or destructors](https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP50-CPP.+Do+not+invoke+virtual+functions+from+constructors+or+destructors)\n* ISO C++ FAQ: [Okay, but is there a way to simulate that behavior as if dynamic binding worked on the this object within my base class's constructor?](https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctor-idiom)\n* Common Weakness Enumeration: [CWE-670](https://cwe.mitre.org/data/definitions/670.html).\n" + }, + "properties": { + "tags": [ + "correctness", + "language-features", + "security", + "external/cwe/cwe-670" + ], + "description": "A call to a pure virtual function using a 'this'\n pointer of an object that is under construction\n may lead to undefined behavior.", + "id": "cpp/unsafe-use-of-this", + "kind": "path-problem", + "name": "Unsafe use of this in constructor", + "precision": "very-high", + "problem.severity": "error", + "security-severity": "7.5" + } + }, + { + "id": "cpp/alloca-in-loop", + "name": "cpp/alloca-in-loop", + "shortDescription": { + "text": "Call to alloca in a loop" + }, + "fullDescription": { + "text": "Using alloca in a loop can lead to a stack overflow" + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Call to alloca in a loop\nThe `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.\n\n\n## Recommendation\nConsider 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.\n\n\n## Example\nThe 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.\n\n\n```cpp\nchar *dir_path;\nchar **dir_entries;\nint count;\n\nfor (int i = 0; i < count; i++) {\n char *path = (char*)alloca(strlen(dir_path) + strlen(dir_entry[i]) + 2);\n // use path\n}\n\n```\nIn the revised example, `path` is allocated with `malloc` and freed at the end of the loop.\n\n\n```cpp\nchar *dir_path;\nchar **dir_entries;\nint count;\n\nfor (int i = 0; i < count; i++) {\n char *path = (char*)malloc(strlen(dir_path) + strlen(dir_entry[i]) + 2);\n // use path\n free(path);\n}\n\n```\n\n## References\n* Linux Programmer's Manual: [ALLOCA(3)](http://man7.org/linux/man-pages/man3/alloca.3.html).\n* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html).\n", + "markdown": "# Call to alloca in a loop\nThe `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.\n\n\n## Recommendation\nConsider 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.\n\n\n## Example\nThe 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.\n\n\n```cpp\nchar *dir_path;\nchar **dir_entries;\nint count;\n\nfor (int i = 0; i < count; i++) {\n char *path = (char*)alloca(strlen(dir_path) + strlen(dir_entry[i]) + 2);\n // use path\n}\n\n```\nIn the revised example, `path` is allocated with `malloc` and freed at the end of the loop.\n\n\n```cpp\nchar *dir_path;\nchar **dir_entries;\nint count;\n\nfor (int i = 0; i < count; i++) {\n char *path = (char*)malloc(strlen(dir_path) + strlen(dir_entry[i]) + 2);\n // use path\n free(path);\n}\n\n```\n\n## References\n* Linux Programmer's Manual: [ALLOCA(3)](http://man7.org/linux/man-pages/man3/alloca.3.html).\n* Common Weakness Enumeration: [CWE-770](https://cwe.mitre.org/data/definitions/770.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "correctness", + "security", + "external/cwe/cwe-770" + ], + "description": "Using alloca in a loop can lead to a stack overflow", + "id": "cpp/alloca-in-loop", + "kind": "problem", + "name": "Call to alloca in a loop", + "precision": "high", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/using-expired-stack-address", + "name": "cpp/using-expired-stack-address", + "shortDescription": { + "text": "Use of expired stack-address" + }, + "fullDescription": { + "text": "Accessing the stack-allocated memory of a function after it has returned can lead to memory corruption." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Use of expired stack-address\nThis rule finds uses of pointers that likely point to local variables in expired stack frames. A pointer to a local variable is only valid until the function returns, after which it becomes a dangling pointer.\n\n\n## Recommendation\n1. If it is necessary to take the address of a local variable, then make sure that the address is only stored in memory that does not outlive the local variable. For example, it is safe to store the address in another local variable. Similarly, it is also safe to pass the address of a local variable to another function provided that the other function only uses it locally and does not store it in non-local memory.\n1. If it is necessary to store an address which will outlive the current function scope, then it should be allocated on the heap. Care should be taken to make sure that the memory is deallocated when it is no longer needed, particularly when using low-level memory management routines such as `malloc`/`free` or `new`/`delete`. Modern C++ applications often use smart pointers, such as `std::shared_ptr`, to reduce the chance of a memory leak.\n\n## Example\n\n```cpp\nstatic const int* xptr;\n\nvoid localAddressEscapes() {\n int x = 0;\n xptr = &x;\n}\n\nvoid example1() {\n localAddressEscapes();\n const int* x = xptr; // BAD: This pointer points to expired stack allocated memory.\n}\n\nvoid localAddressDoesNotEscape() {\n int x = 0;\n xptr = &x;\n // ...\n // use `xptr`\n // ...\n xptr = nullptr;\n}\n\nvoid example2() {\n localAddressDoesNotEscape();\n const int* x = xptr; // GOOD: This pointer does not point to expired memory.\n}\n\n```\n\n## References\n* Wikipedia: [Dangling pointer](https://en.wikipedia.org/wiki/Dangling_pointer).\n* Common Weakness Enumeration: [CWE-825](https://cwe.mitre.org/data/definitions/825.html).\n", + "markdown": "# Use of expired stack-address\nThis rule finds uses of pointers that likely point to local variables in expired stack frames. A pointer to a local variable is only valid until the function returns, after which it becomes a dangling pointer.\n\n\n## Recommendation\n1. If it is necessary to take the address of a local variable, then make sure that the address is only stored in memory that does not outlive the local variable. For example, it is safe to store the address in another local variable. Similarly, it is also safe to pass the address of a local variable to another function provided that the other function only uses it locally and does not store it in non-local memory.\n1. If it is necessary to store an address which will outlive the current function scope, then it should be allocated on the heap. Care should be taken to make sure that the memory is deallocated when it is no longer needed, particularly when using low-level memory management routines such as `malloc`/`free` or `new`/`delete`. Modern C++ applications often use smart pointers, such as `std::shared_ptr`, to reduce the chance of a memory leak.\n\n## Example\n\n```cpp\nstatic const int* xptr;\n\nvoid localAddressEscapes() {\n int x = 0;\n xptr = &x;\n}\n\nvoid example1() {\n localAddressEscapes();\n const int* x = xptr; // BAD: This pointer points to expired stack allocated memory.\n}\n\nvoid localAddressDoesNotEscape() {\n int x = 0;\n xptr = &x;\n // ...\n // use `xptr`\n // ...\n xptr = nullptr;\n}\n\nvoid example2() {\n localAddressDoesNotEscape();\n const int* x = xptr; // GOOD: This pointer does not point to expired memory.\n}\n\n```\n\n## References\n* Wikipedia: [Dangling pointer](https://en.wikipedia.org/wiki/Dangling_pointer).\n* Common Weakness Enumeration: [CWE-825](https://cwe.mitre.org/data/definitions/825.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-825" + ], + "description": "Accessing the stack-allocated memory of a function\n after it has returned can lead to memory corruption.", + "id": "cpp/using-expired-stack-address", + "kind": "path-problem", + "name": "Use of expired stack-address", + "precision": "high", + "problem.severity": "error", + "security-severity": "9.3" + } + }, + { + "id": "cpp/return-stack-allocated-memory", + "name": "cpp/return-stack-allocated-memory", + "shortDescription": { + "text": "Returning stack-allocated memory" + }, + "fullDescription": { + "text": "A function returns a pointer to a stack-allocated region of memory. This memory is deallocated at the end of the function, which may lead the caller to dereference a dangling pointer." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Returning stack-allocated memory\nThis rule finds return statements that return pointers to an object allocated on the stack. The lifetime of a stack allocated memory location only lasts until the function returns, and the contents of that memory become undefined after that. Clearly, using a pointer to stack memory after the function has already returned will have undefined results.\n\n\n## Recommendation\nUse the functions of the `malloc` family to dynamically allocate memory on the heap for data that is used across function calls.\n\n\n## Example\n\n```cpp\nRecord* fixRecord(Record* r) {\n\tRecord myRecord = *r;\n\tdelete r;\n\n\tmyRecord.fix();\n\treturn &myRecord; //returns reference to myRecord, which is a stack-allocated object\n}\n```\n\n## References\n* Common Weakness Enumeration: [CWE-825](https://cwe.mitre.org/data/definitions/825.html).\n", + "markdown": "# Returning stack-allocated memory\nThis rule finds return statements that return pointers to an object allocated on the stack. The lifetime of a stack allocated memory location only lasts until the function returns, and the contents of that memory become undefined after that. Clearly, using a pointer to stack memory after the function has already returned will have undefined results.\n\n\n## Recommendation\nUse the functions of the `malloc` family to dynamically allocate memory on the heap for data that is used across function calls.\n\n\n## Example\n\n```cpp\nRecord* fixRecord(Record* r) {\n\tRecord myRecord = *r;\n\tdelete r;\n\n\tmyRecord.fix();\n\treturn &myRecord; //returns reference to myRecord, which is a stack-allocated object\n}\n```\n\n## References\n* Common Weakness Enumeration: [CWE-825](https://cwe.mitre.org/data/definitions/825.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-825" + ], + "description": "A function returns a pointer to a stack-allocated region of\n memory. This memory is deallocated at the end of the function,\n which may lead the caller to dereference a dangling pointer.", + "id": "cpp/return-stack-allocated-memory", + "kind": "path-problem", + "name": "Returning stack-allocated memory", + "precision": "high", + "problem.severity": "warning", + "security-severity": "9.3" + } + }, + { + "id": "cpp/pointer-overflow-check", + "name": "cpp/pointer-overflow-check", + "shortDescription": { + "text": "Pointer overflow check" + }, + "fullDescription": { + "text": "Adding a value to a pointer to check if it overflows relies on undefined behavior and may lead to memory corruption." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Pointer overflow check\nWhen 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.\n\n\n## Recommendation\nTo 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`.\n\n\n## Example\nAn 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.\n\n\n```cpp\nbool not_in_range(T *ptr, T *ptr_end, size_t i) {\n return ptr + i >= ptr_end || ptr + i < ptr; // BAD\n}\n\n```\nIn 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.\n\nWhile it's not the subject of this query, the expression `ptr + i < ptr_end` is also an invalid range check. It's undefined behavior in C/C++ to create a pointer that points more than one past the end of an allocation.\n\nThe next example shows how to portably check whether an unsigned number is outside the range of an allocation between `ptr` and `ptr_end`.\n\n\n```cpp\nbool not_in_range(T *ptr, T *ptr_end, size_t i) {\n return i >= ptr_end - ptr; // GOOD\n}\n```\n\n## References\n* Embedded in Academia: [Pointer Overflow Checking](https://blog.regehr.org/archives/1395).\n* LWN: [GCC and pointer overflows](https://lwn.net/Articles/278137/).\n* Common Weakness Enumeration: [CWE-758](https://cwe.mitre.org/data/definitions/758.html).\n", + "markdown": "# Pointer overflow check\nWhen 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.\n\n\n## Recommendation\nTo 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`.\n\n\n## Example\nAn 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.\n\n\n```cpp\nbool not_in_range(T *ptr, T *ptr_end, size_t i) {\n return ptr + i >= ptr_end || ptr + i < ptr; // BAD\n}\n\n```\nIn 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.\n\nWhile it's not the subject of this query, the expression `ptr + i < ptr_end` is also an invalid range check. It's undefined behavior in C/C++ to create a pointer that points more than one past the end of an allocation.\n\nThe next example shows how to portably check whether an unsigned number is outside the range of an allocation between `ptr` and `ptr_end`.\n\n\n```cpp\nbool not_in_range(T *ptr, T *ptr_end, size_t i) {\n return i >= ptr_end - ptr; // GOOD\n}\n```\n\n## References\n* Embedded in Academia: [Pointer Overflow Checking](https://blog.regehr.org/archives/1395).\n* LWN: [GCC and pointer overflows](https://lwn.net/Articles/278137/).\n* Common Weakness Enumeration: [CWE-758](https://cwe.mitre.org/data/definitions/758.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-758" + ], + "description": "Adding a value to a pointer to check if it overflows relies\n on undefined behavior and may lead to memory corruption.", + "id": "cpp/pointer-overflow-check", + "kind": "problem", + "name": "Pointer overflow check", + "precision": "high", + "problem.severity": "error", + "security-severity": "2.1" + } + }, + { + "id": "cpp/redundant-null-check-simple", + "name": "cpp/redundant-null-check-simple", + "shortDescription": { + "text": "Redundant null check due to previous dereference" + }, + "fullDescription": { + "text": "Checking a pointer for nullness after dereferencing it is likely to be a sign that either the check can be removed, or it should be moved before the dereference." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Redundant null check due to previous dereference\nThis rule finds comparisons of a pointer to null that occur after a reference of that pointer. It's likely either the check is not required and can be removed, or it should be moved to before the dereference so that a null pointer dereference does not occur.\n\n\n## Recommendation\nThe check should be moved to before the dereference, in a way that prevents a null pointer value from being dereferenced. If it's clear that the pointer cannot be null, consider removing the check instead.\n\n\n## Example\n\n```cpp\nint f(MyList *list) {\n\tlist->append(1);\n\n\t// ...\n\n\tif (list != NULL)\n\t{\n\t\tlist->append(2);\n\t}\n}\n\n```\n\n## References\n* [ Null Dereference ](https://www.owasp.org/index.php/Null_Dereference)\n* Common Weakness Enumeration: [CWE-476](https://cwe.mitre.org/data/definitions/476.html).\n", + "markdown": "# Redundant null check due to previous dereference\nThis rule finds comparisons of a pointer to null that occur after a reference of that pointer. It's likely either the check is not required and can be removed, or it should be moved to before the dereference so that a null pointer dereference does not occur.\n\n\n## Recommendation\nThe check should be moved to before the dereference, in a way that prevents a null pointer value from being dereferenced. If it's clear that the pointer cannot be null, consider removing the check instead.\n\n\n## Example\n\n```cpp\nint f(MyList *list) {\n\tlist->append(1);\n\n\t// ...\n\n\tif (list != NULL)\n\t{\n\t\tlist->append(2);\n\t}\n}\n\n```\n\n## References\n* [ Null Dereference ](https://www.owasp.org/index.php/Null_Dereference)\n* Common Weakness Enumeration: [CWE-476](https://cwe.mitre.org/data/definitions/476.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "correctness", + "security", + "external/cwe/cwe-476" + ], + "description": "Checking a pointer for nullness after dereferencing it is\n likely to be a sign that either the check can be removed, or\n it should be moved before the dereference.", + "id": "cpp/redundant-null-check-simple", + "kind": "path-problem", + "name": "Redundant null check due to previous dereference", + "precision": "high", + "problem.severity": "error", + "security-severity": "7.5" + } + }, + { + "id": "cpp/upcast-array-pointer-arithmetic", + "name": "cpp/upcast-array-pointer-arithmetic", + "shortDescription": { + "text": "Upcast array used in pointer arithmetic" + }, + "fullDescription": { + "text": "An array with elements of a derived struct type is cast to a pointer to the base type of the struct. If pointer arithmetic or an array dereference is done on the resulting pointer, it will use the width of the base type, leading to misaligned reads." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Upcast array used in pointer arithmetic\nA 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.\n\n\n## Recommendation\nOnly 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.\n\n\n## Example\n\n```cpp\nclass Base {\npublic:\n\tint x;\n}\n\nclass Derived: public Base {\npublic:\n\tint y;\n};\n\nvoid dereference_base(Base *b) {\n\tb[2].x;\n}\n\nvoid dereference_derived(Derived *d) {\n\td[2].x;\n}\n\nvoid test () {\n\tDerived[4] d;\n\tdereference_base(d); // BAD: implicit conversion to Base*\n\n\tdereference_derived(d); // GOOD: implicit conversion to Derived*, which will be the right size\n}\n\n```\n", + "markdown": "# Upcast array used in pointer arithmetic\nA 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.\n\n\n## Recommendation\nOnly 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.\n\n\n## Example\n\n```cpp\nclass Base {\npublic:\n\tint x;\n}\n\nclass Derived: public Base {\npublic:\n\tint y;\n};\n\nvoid dereference_base(Base *b) {\n\tb[2].x;\n}\n\nvoid dereference_derived(Derived *d) {\n\td[2].x;\n}\n\nvoid test () {\n\tDerived[4] d;\n\tdereference_base(d); // BAD: implicit conversion to Base*\n\n\tdereference_derived(d); // GOOD: implicit conversion to Derived*, which will be the right size\n}\n\n```\n" + }, + "properties": { + "tags": [ + "correctness", + "reliability", + "security", + "external/cwe/cwe-119", + "external/cwe/cwe-843" + ], + "description": "An array with elements of a derived struct type is cast to a\n pointer to the base type of the struct. If pointer arithmetic or\n an array dereference is done on the resulting pointer, it will\n use the width of the base type, leading to misaligned reads.", + "id": "cpp/upcast-array-pointer-arithmetic", + "kind": "path-problem", + "name": "Upcast array used in pointer arithmetic", + "precision": "high", + "problem.severity": "warning", + "security-severity": "9.3" + } + }, + { + "id": "cpp/too-few-arguments", + "name": "cpp/too-few-arguments", + "shortDescription": { + "text": "Call to function with fewer arguments than declared parameters" + }, + "fullDescription": { + "text": "A function call is passing fewer arguments than the number of declared parameters of the function. This may indicate that the code does not follow the author's intent. It is also a vulnerability, since the function is likely to operate on undefined data." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Call to function with fewer arguments than declared parameters\nA function is called with fewer arguments than there are parameters of the function.\n\nThis 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.\n\nIn 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.\n\nIf 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.\n\n\n## Recommendation\nCall the function with the correct number of arguments.\n\n\n## Example\n\n```c\nvoid one_argument();\n\nvoid calls() {\n\tone_argument(1); // GOOD: `one_argument` will accept and use the argument\n\t\n\tone_argument(); // BAD: `one_argument` will receive an undefined value\n}\n\nvoid one_argument(int x);\n\n```\n\n## References\n* 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)\n* Common Weakness Enumeration: [CWE-234](https://cwe.mitre.org/data/definitions/234.html).\n* Common Weakness Enumeration: [CWE-685](https://cwe.mitre.org/data/definitions/685.html).\n", + "markdown": "# Call to function with fewer arguments than declared parameters\nA function is called with fewer arguments than there are parameters of the function.\n\nThis 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.\n\nIn 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.\n\nIf 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.\n\n\n## Recommendation\nCall the function with the correct number of arguments.\n\n\n## Example\n\n```c\nvoid one_argument();\n\nvoid calls() {\n\tone_argument(1); // GOOD: `one_argument` will accept and use the argument\n\t\n\tone_argument(); // BAD: `one_argument` will receive an undefined value\n}\n\nvoid one_argument(int x);\n\n```\n\n## References\n* 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)\n* Common Weakness Enumeration: [CWE-234](https://cwe.mitre.org/data/definitions/234.html).\n* Common Weakness Enumeration: [CWE-685](https://cwe.mitre.org/data/definitions/685.html).\n" + }, + "properties": { + "tags": [ + "correctness", + "maintainability", + "security", + "external/cwe/cwe-234", + "external/cwe/cwe-685" + ], + "description": "A function call is passing fewer arguments than the number of\n declared parameters of the function. This may indicate\n that the code does not follow the author's intent. It is also\n a vulnerability, since the function is likely to operate on\n undefined data.", + "id": "cpp/too-few-arguments", + "kind": "problem", + "name": "Call to function with fewer arguments than declared parameters", + "precision": "very-high", + "problem.severity": "error", + "security-severity": "5.0" + } + }, + { + "id": "cpp/memset-may-be-deleted", + "name": "cpp/memset-may-be-deleted", + "shortDescription": { + "text": "Call to `memset` may be deleted" + }, + "fullDescription": { + "text": "Using the `memset` function to clear private data in a variable that has no subsequent use can make information-leak vulnerabilities easier to exploit because the compiler can remove the call." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Call to `memset` may be deleted\nCalling `memset` or `bzero` on a buffer to clear its contents may get optimized away by the compiler if the buffer is not subsequently used. This is not desirable behavior if the buffer contains sensitive data that could somehow be retrieved by an attacker.\n\n\n## Recommendation\nUse alternative platform-supplied functions that will not get optimized away. Examples of such functions include `memset_s`, `SecureZeroMemory`, and `bzero_explicit`. Alternatively, passing the `-fno-builtin-memset` option to the GCC/Clang compiler usually also prevents the optimization. Finally, you can use the public-domain `secure_memzero` function (see references below). This function, however, is not guaranteed to work on all platforms and compilers.\n\n\n## Example\nThe following program fragment uses `memset` to erase sensitive information after it is no longer needed:\n\n\n```c\nchar password[MAX_PASSWORD_LENGTH];\n// read and verify password\nmemset(password, 0, MAX_PASSWORD_LENGTH);\n\n```\nBecause of dead store elimination, the call to `memset` may be removed by the compiler (since the buffer is not subsequently used), resulting in potentially sensitive data remaining in memory.\n\nThe best solution to this problem is to use the `memset_s` function instead of `memset`:\n\n\n```c\nchar password[MAX_PASSWORD_LENGTH];\n// read and verify password\nmemset_s(password, MAX_PASSWORD_LENGTH, 0, MAX_PASSWORD_LENGTH);\n\n```\n\n## References\n* CERT C Coding Standard: [MSC06-C. Beware of compiler optimizations](https://wiki.sei.cmu.edu/confluence/display/c/MSC06-C.+Beware+of+compiler+optimizations).\n* USENIX: The Advanced Computing Systems Association: [Dead Store Elimination (Still) Considered Harmfuls](https://www.usenix.org/system/files/conference/usenixsecurity17/sec17-yang.pdf)\n* Common Weakness Enumeration: [CWE-14](https://cwe.mitre.org/data/definitions/14.html).\n", + "markdown": "# Call to `memset` may be deleted\nCalling `memset` or `bzero` on a buffer to clear its contents may get optimized away by the compiler if the buffer is not subsequently used. This is not desirable behavior if the buffer contains sensitive data that could somehow be retrieved by an attacker.\n\n\n## Recommendation\nUse alternative platform-supplied functions that will not get optimized away. Examples of such functions include `memset_s`, `SecureZeroMemory`, and `bzero_explicit`. Alternatively, passing the `-fno-builtin-memset` option to the GCC/Clang compiler usually also prevents the optimization. Finally, you can use the public-domain `secure_memzero` function (see references below). This function, however, is not guaranteed to work on all platforms and compilers.\n\n\n## Example\nThe following program fragment uses `memset` to erase sensitive information after it is no longer needed:\n\n\n```c\nchar password[MAX_PASSWORD_LENGTH];\n// read and verify password\nmemset(password, 0, MAX_PASSWORD_LENGTH);\n\n```\nBecause of dead store elimination, the call to `memset` may be removed by the compiler (since the buffer is not subsequently used), resulting in potentially sensitive data remaining in memory.\n\nThe best solution to this problem is to use the `memset_s` function instead of `memset`:\n\n\n```c\nchar password[MAX_PASSWORD_LENGTH];\n// read and verify password\nmemset_s(password, MAX_PASSWORD_LENGTH, 0, MAX_PASSWORD_LENGTH);\n\n```\n\n## References\n* CERT C Coding Standard: [MSC06-C. Beware of compiler optimizations](https://wiki.sei.cmu.edu/confluence/display/c/MSC06-C.+Beware+of+compiler+optimizations).\n* USENIX: The Advanced Computing Systems Association: [Dead Store Elimination (Still) Considered Harmfuls](https://www.usenix.org/system/files/conference/usenixsecurity17/sec17-yang.pdf)\n* Common Weakness Enumeration: [CWE-14](https://cwe.mitre.org/data/definitions/14.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-14" + ], + "description": "Using the `memset` function to clear private data in a variable that has no subsequent use\n can make information-leak vulnerabilities easier to exploit because the compiler can remove the call.", + "id": "cpp/memset-may-be-deleted", + "kind": "problem", + "name": "Call to `memset` may be deleted", + "precision": "high", + "problem.severity": "warning", + "security-severity": "7.8" + } + }, + { + "id": "cpp/incorrect-string-type-conversion", + "name": "cpp/incorrect-string-type-conversion", + "shortDescription": { + "text": "Cast from char* to wchar_t*" + }, + "fullDescription": { + "text": "Casting a byte string to a wide-character string is likely to yield a string that is incorrectly terminated or aligned. This can lead to undefined behavior, including buffer overruns." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Cast from char* to wchar_t*\nThis rule indicates a potentially incorrect cast from an byte string (`char *`) to a wide-character string (`wchar_t *`).\n\nThis cast might yield strings that are not correctly terminated; including potential buffer overruns when using such strings with some dangerous APIs.\n\n\n## Recommendation\nDo not explicitly cast byte strings to wide-character strings.\n\nFor string literals, prepend the literal string with the letter \"L\" to indicate that the string is a wide-character string (`wchar_t *`).\n\nFor 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.\n\n\n## Example\nIn the following example, an byte string literal (`\"a\"`) is cast to a wide-character string.\n\n\n```cpp\nwchar_t* pSrc;\n\npSrc = (wchar_t*)\"a\"; // casting a byte-string literal \"a\" to a wide-character string\n```\nTo fix this issue, prepend the literal with the letter \"L\" (`L\"a\"`) to define it as a wide-character string.\n\n\n## References\n* General resources: [std::mbstowcs](https://en.cppreference.com/w/cpp/string/multibyte/mbstowcs)\n* Microsoft specific resources: [Security Considerations: International Features](https://docs.microsoft.com/en-us/windows/desktop/Intl/security-considerations--international-features)\n* Common Weakness Enumeration: [CWE-704](https://cwe.mitre.org/data/definitions/704.html).\n", + "markdown": "# Cast from char* to wchar_t*\nThis rule indicates a potentially incorrect cast from an byte string (`char *`) to a wide-character string (`wchar_t *`).\n\nThis cast might yield strings that are not correctly terminated; including potential buffer overruns when using such strings with some dangerous APIs.\n\n\n## Recommendation\nDo not explicitly cast byte strings to wide-character strings.\n\nFor string literals, prepend the literal string with the letter \"L\" to indicate that the string is a wide-character string (`wchar_t *`).\n\nFor 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.\n\n\n## Example\nIn the following example, an byte string literal (`\"a\"`) is cast to a wide-character string.\n\n\n```cpp\nwchar_t* pSrc;\n\npSrc = (wchar_t*)\"a\"; // casting a byte-string literal \"a\" to a wide-character string\n```\nTo fix this issue, prepend the literal with the letter \"L\" (`L\"a\"`) to define it as a wide-character string.\n\n\n## References\n* General resources: [std::mbstowcs](https://en.cppreference.com/w/cpp/string/multibyte/mbstowcs)\n* Microsoft specific resources: [Security Considerations: International Features](https://docs.microsoft.com/en-us/windows/desktop/Intl/security-considerations--international-features)\n* Common Weakness Enumeration: [CWE-704](https://cwe.mitre.org/data/definitions/704.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-704" + ], + "description": "Casting a byte string to a wide-character string is likely\n to yield a string that is incorrectly terminated or aligned.\n This can lead to undefined behavior, including buffer overruns.", + "id": "cpp/incorrect-string-type-conversion", + "kind": "problem", + "name": "Cast from char* to wchar_t*", + "precision": "high", + "problem.severity": "error", + "security-severity": "8.8" + } + }, + { + "id": "cpp/very-likely-overrunning-write", + "name": "cpp/very-likely-overrunning-write", + "shortDescription": { + "text": "Likely overrunning write" + }, + "fullDescription": { + "text": "Buffer write operations that do not control the length of data written may overflow" + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Likely overrunning write\nThe program performs a buffer copy or write operation with no upper limit on the size of the copy. By analyzing the bounds of the expressions involved, 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.\n\n\n## Recommendation\nAlways 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.\n\n\n## Example\n\n```c\nint sayHello(uint32_t userId)\n{\n\tchar buffer[17];\n\n\tif (userId > 9999) return USER_ID_OUT_OF_BOUNDS;\n\n\t// BAD: this message overflows the buffer if userId >= 1000,\n\t// as no space for the null terminator was accounted for\n\tsprintf(buffer, \"Hello, user %d!\", userId);\n\n\tMessageBox(hWnd, buffer, \"New Message\", MB_OK);\n\t\n\treturn SUCCESS;\n}\n```\nIn this example, the call to `sprintf` writes a message of 14 characters (including the terminating null) plus the length of the string conversion of \\`userId\\` into a buffer with space for just 17 characters. While \\`userId\\` is checked to occupy no more than 4 characters when converted, there is no space in the buffer for the terminating null character if \\`userId >= 1000\\`. In this case, the null character overflows the buffer resulting in undefined behavior.\n\nTo fix this issue these changes should be made:\n\n* Control the size of the buffer by declaring it with a compile time constant.\n* Preferably, replace the call to `sprintf` with `snprintf`, using the defined constant size of the buffer or \\`sizeof(buffer)\\` as maximum length to write. This will prevent the buffer overflow.\n* Increasing the buffer size to account for the full range of \\`userId\\` and the terminating null character.\n\n## References\n* 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).\n* 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).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html).\n", + "markdown": "# Likely overrunning write\nThe program performs a buffer copy or write operation with no upper limit on the size of the copy. By analyzing the bounds of the expressions involved, 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.\n\n\n## Recommendation\nAlways 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.\n\n\n## Example\n\n```c\nint sayHello(uint32_t userId)\n{\n\tchar buffer[17];\n\n\tif (userId > 9999) return USER_ID_OUT_OF_BOUNDS;\n\n\t// BAD: this message overflows the buffer if userId >= 1000,\n\t// as no space for the null terminator was accounted for\n\tsprintf(buffer, \"Hello, user %d!\", userId);\n\n\tMessageBox(hWnd, buffer, \"New Message\", MB_OK);\n\t\n\treturn SUCCESS;\n}\n```\nIn this example, the call to `sprintf` writes a message of 14 characters (including the terminating null) plus the length of the string conversion of \\`userId\\` into a buffer with space for just 17 characters. While \\`userId\\` is checked to occupy no more than 4 characters when converted, there is no space in the buffer for the terminating null character if \\`userId >= 1000\\`. In this case, the null character overflows the buffer resulting in undefined behavior.\n\nTo fix this issue these changes should be made:\n\n* Control the size of the buffer by declaring it with a compile time constant.\n* Preferably, replace the call to `sprintf` with `snprintf`, using the defined constant size of the buffer or \\`sizeof(buffer)\\` as maximum length to write. This will prevent the buffer overflow.\n* Increasing the buffer size to account for the full range of \\`userId\\` and the terminating null character.\n\n## References\n* 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).\n* 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).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-120", + "external/cwe/cwe-787", + "external/cwe/cwe-805" + ], + "description": "Buffer write operations that do not control the length\n of data written may overflow", + "id": "cpp/very-likely-overrunning-write", + "kind": "problem", + "name": "Likely overrunning write", + "precision": "high", + "problem.severity": "error", + "security-severity": "9.3" + } + }, + { + "id": "cpp/badly-bounded-write", + "name": "cpp/badly-bounded-write", + "shortDescription": { + "text": "Badly bounded write" + }, + "fullDescription": { + "text": "Buffer write operations with a length parameter that does not match the size of the destination buffer may overflow." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Badly bounded write\nThe 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.\n\n\n## Recommendation\nUse 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.\n\n\n## Example\n\n```c\nvoid congratulateUser(const char *userName)\n{\n\tchar buffer[80];\n\n\t// BAD: even though snprintf is used, this could overflow the buffer\n\t// because the size specified is too large.\n\tsnprintf(buffer, 256, \"Congratulations, %s!\", userName);\n\n\tMessageBox(hWnd, buffer, \"New Message\", MB_OK);\n}\n```\nIn 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.\n\nTo 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.\n\n\n## References\n* 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).\n* 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).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html).\n", + "markdown": "# Badly bounded write\nThe 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.\n\n\n## Recommendation\nUse 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.\n\n\n## Example\n\n```c\nvoid congratulateUser(const char *userName)\n{\n\tchar buffer[80];\n\n\t// BAD: even though snprintf is used, this could overflow the buffer\n\t// because the size specified is too large.\n\tsnprintf(buffer, 256, \"Congratulations, %s!\", userName);\n\n\tMessageBox(hWnd, buffer, \"New Message\", MB_OK);\n}\n```\nIn 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.\n\nTo 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.\n\n\n## References\n* 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).\n* 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).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-120", + "external/cwe/cwe-787", + "external/cwe/cwe-805" + ], + "description": "Buffer write operations with a length parameter that\n does not match the size of the destination buffer may\n overflow.", + "id": "cpp/badly-bounded-write", + "kind": "problem", + "name": "Badly bounded write", + "precision": "high", + "problem.severity": "error", + "security-severity": "9.3" + } + }, + { + "id": "cpp/hresult-boolean-conversion", + "name": "cpp/hresult-boolean-conversion", + "shortDescription": { + "text": "Cast between HRESULT and a Boolean type" + }, + "fullDescription": { + "text": "Casting an HRESULT to/from a Boolean type and then using it in a test expression will yield an incorrect result because success (S_OK) in HRESULT is indicated by a value of 0." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Cast between HRESULT and a Boolean type\nThis query indicates that an `HRESULT` is being cast to a Boolean type or vice versa.\n\nThe typical success value (`S_OK`) of an `HRESULT` equals 0. However, 0 indicates failure for a Boolean type.\n\nCasting an `HRESULT` to a Boolean type and then using it in a test expression will yield an incorrect result.\n\n\n## Recommendation\nTo check if a call that returns an `HRESULT` succeeded use the `FAILED` macro.\n\n\n## Example\nIn the following example, `HRESULT` is used in a test expression incorrectly as it may yield an incorrect result.\n\n\n```cpp\nLPMALLOC pMalloc;\nHRESULT hr = CoGetMalloc(1, &pMalloc);\n\nif (!hr)\n{\n // code ...\n}\n\n```\nTo fix this issue, use the `FAILED` macro in the test expression.\n\n\n## References\n* Common Weakness Enumeration: [CWE-253](https://cwe.mitre.org/data/definitions/253.html).\n", + "markdown": "# Cast between HRESULT and a Boolean type\nThis query indicates that an `HRESULT` is being cast to a Boolean type or vice versa.\n\nThe typical success value (`S_OK`) of an `HRESULT` equals 0. However, 0 indicates failure for a Boolean type.\n\nCasting an `HRESULT` to a Boolean type and then using it in a test expression will yield an incorrect result.\n\n\n## Recommendation\nTo check if a call that returns an `HRESULT` succeeded use the `FAILED` macro.\n\n\n## Example\nIn the following example, `HRESULT` is used in a test expression incorrectly as it may yield an incorrect result.\n\n\n```cpp\nLPMALLOC pMalloc;\nHRESULT hr = CoGetMalloc(1, &pMalloc);\n\nif (!hr)\n{\n // code ...\n}\n\n```\nTo fix this issue, use the `FAILED` macro in the test expression.\n\n\n## References\n* Common Weakness Enumeration: [CWE-253](https://cwe.mitre.org/data/definitions/253.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-253" + ], + "description": "Casting an HRESULT to/from a Boolean type and then using it in a test expression will yield an incorrect result because success (S_OK) in HRESULT is indicated by a value of 0.", + "id": "cpp/hresult-boolean-conversion", + "kind": "problem", + "name": "Cast between HRESULT and a Boolean type", + "precision": "high", + "problem.severity": "error", + "security-severity": "7.5" + } + }, + { + "id": "cpp/system-data-exposure", + "name": "cpp/system-data-exposure", + "shortDescription": { + "text": "Exposure of system data to an unauthorized control sphere" + }, + "fullDescription": { + "text": "Exposing system data or debugging information helps a malicious user learn about the system and form an attack plan." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Exposure of system data to an unauthorized control sphere\nExposing system data or debugging information may help a malicious user learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in the software.\n\nThis query finds locations where system configuration information might be revealed to a remote user.\n\n\n## Recommendation\nDo not expose system configuration information to remote users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to a malicious user.\n\n\n## Example\nIn this example the value of the `PATH` environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to a malicious user who does not have legitimate access to that information.\n\n\n```cpp\nchar* path = getenv(\"PATH\");\n\n//...\n\nsprintf(buffer, \"Cannot find exe on path: %s\", path);\nsend(socket, buffer, strlen(buffer), 0);\n\n```\nThe message should be rephrased without this information, for example:\n\n\n```cpp\nchar* path = getenv(\"PATH\");\n\n//...\n\nmessage = \"An internal error has occurred. Please try again or contact a system administrator.\\n\";\nsend(socket, message, strlen(message), 0);\n```\n\n## References\n* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html).\n", + "markdown": "# Exposure of system data to an unauthorized control sphere\nExposing system data or debugging information may help a malicious user learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in the software.\n\nThis query finds locations where system configuration information might be revealed to a remote user.\n\n\n## Recommendation\nDo not expose system configuration information to remote users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to a malicious user.\n\n\n## Example\nIn this example the value of the `PATH` environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to a malicious user who does not have legitimate access to that information.\n\n\n```cpp\nchar* path = getenv(\"PATH\");\n\n//...\n\nsprintf(buffer, \"Cannot find exe on path: %s\", path);\nsend(socket, buffer, strlen(buffer), 0);\n\n```\nThe message should be rephrased without this information, for example:\n\n\n```cpp\nchar* path = getenv(\"PATH\");\n\n//...\n\nmessage = \"An internal error has occurred. Please try again or contact a system administrator.\\n\";\nsend(socket, message, strlen(message), 0);\n```\n\n## References\n* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-497" + ], + "description": "Exposing system data or debugging information helps\n a malicious user learn about the system and form an\n attack plan.", + "id": "cpp/system-data-exposure", + "kind": "path-problem", + "name": "Exposure of system data to an unauthorized control sphere", + "precision": "high", + "problem.severity": "warning", + "security-severity": "6.5" + } + }, + { + "id": "cpp/cleartext-storage-file", + "name": "cpp/cleartext-storage-file", + "shortDescription": { + "text": "Cleartext storage of sensitive information in file" + }, + "fullDescription": { + "text": "Storing sensitive information in cleartext can expose it to an attacker." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Cleartext storage of sensitive information in file\nSensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage.\n\n\n## Recommendation\nEnsure that sensitive information is always encrypted before being stored to a file or transmitted over the network. It may be wise to encrypt information before it is put into a buffer that may be readable in memory.\n\nIn general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.\n\n\n## Example\nThe 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.\n\n\n```c\nvoid writeCredentials() {\n char *password = \"cleartext password\";\n FILE* file = fopen(\"credentials.txt\", \"w\");\n \n // BAD: write password to disk in cleartext\n fputs(password, file);\n \n // GOOD: encrypt password first\n char *encrypted = encrypt(password);\n fputs(encrypted, file);\n}\n\n\n```\n\n## References\n* 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.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-260](https://cwe.mitre.org/data/definitions/260.html).\n* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html).\n", + "markdown": "# Cleartext storage of sensitive information in file\nSensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage.\n\n\n## Recommendation\nEnsure that sensitive information is always encrypted before being stored to a file or transmitted over the network. It may be wise to encrypt information before it is put into a buffer that may be readable in memory.\n\nIn general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.\n\n\n## Example\nThe 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.\n\n\n```c\nvoid writeCredentials() {\n char *password = \"cleartext password\";\n FILE* file = fopen(\"credentials.txt\", \"w\");\n \n // BAD: write password to disk in cleartext\n fputs(password, file);\n \n // GOOD: encrypt password first\n char *encrypted = encrypt(password);\n fputs(encrypted, file);\n}\n\n\n```\n\n## References\n* 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.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-260](https://cwe.mitre.org/data/definitions/260.html).\n* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-260", + "external/cwe/cwe-313" + ], + "description": "Storing sensitive information in cleartext can expose it\n to an attacker.", + "id": "cpp/cleartext-storage-file", + "kind": "path-problem", + "name": "Cleartext storage of sensitive information in file", + "precision": "high", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/cleartext-transmission", + "name": "cpp/cleartext-transmission", + "shortDescription": { + "text": "Cleartext transmission of sensitive information" + }, + "fullDescription": { + "text": "Transmitting sensitive information across a network in cleartext can expose it to an attacker." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Cleartext transmission of sensitive information\nSensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage.\n\n\n## Recommendation\nEnsure that sensitive information is always encrypted before being stored to a file or transmitted over the network. It may be wise to encrypt information before it is put into a buffer that may be readable in memory.\n\nIn general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.\n\n\n## Example\nThe 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.\n\n\n```c\nvoid writeCredentials() {\n char *password = \"cleartext password\";\n FILE* file = fopen(\"credentials.txt\", \"w\");\n \n // BAD: write password to disk in cleartext\n fputs(password, file);\n \n // GOOD: encrypt password first\n char *encrypted = encrypt(password);\n fputs(encrypted, file);\n}\n\n\n```\n\n## References\n* 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.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n", + "markdown": "# Cleartext transmission of sensitive information\nSensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage.\n\n\n## Recommendation\nEnsure that sensitive information is always encrypted before being stored to a file or transmitted over the network. It may be wise to encrypt information before it is put into a buffer that may be readable in memory.\n\nIn general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.\n\n\n## Example\nThe 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.\n\n\n```c\nvoid writeCredentials() {\n char *password = \"cleartext password\";\n FILE* file = fopen(\"credentials.txt\", \"w\");\n \n // BAD: write password to disk in cleartext\n fputs(password, file);\n \n // GOOD: encrypt password first\n char *encrypted = encrypt(password);\n fputs(encrypted, file);\n}\n\n\n```\n\n## References\n* 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.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html).\n* Common Weakness Enumeration: [CWE-359](https://cwe.mitre.org/data/definitions/359.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-319", + "external/cwe/cwe-359" + ], + "description": "Transmitting sensitive information across a network in\n cleartext can expose it to an attacker.", + "id": "cpp/cleartext-transmission", + "kind": "path-problem", + "name": "Cleartext transmission of sensitive information", + "precision": "high", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/no-space-for-terminator", + "name": "cpp/no-space-for-terminator", + "shortDescription": { + "text": "No space for zero terminator" + }, + "fullDescription": { + "text": "Allocating a buffer using 'malloc' without ensuring that there is always space for the entire string and a zero terminator can cause a buffer overrun." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# No space for zero terminator\nThis rule identifies calls to `malloc` that call `strlen` to determine the required buffer size, but do not allocate space for the zero terminator.\n\n\n## Recommendation\nThe 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).\n\nIncrease the size of the buffer being allocated by one or replace `malloc`, `strcpy` pairs with a call to `strdup`\n\n\n## Example\n\n```c\n\nvoid flawed_strdup(const char *input)\n{\n\tchar *copy;\n\n\t/* Fail to allocate space for terminating '\\0' */\n\tcopy = (char *)malloc(strlen(input));\n\tstrcpy(copy, input);\n\treturn copy;\n}\n\n\n```\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html).\n", + "markdown": "# No space for zero terminator\nThis rule identifies calls to `malloc` that call `strlen` to determine the required buffer size, but do not allocate space for the zero terminator.\n\n\n## Recommendation\nThe 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).\n\nIncrease the size of the buffer being allocated by one or replace `malloc`, `strcpy` pairs with a call to `strdup`\n\n\n## Example\n\n```c\n\nvoid flawed_strdup(const char *input)\n{\n\tchar *copy;\n\n\t/* Fail to allocate space for terminating '\\0' */\n\tcopy = (char *)malloc(strlen(input));\n\tstrcpy(copy, input);\n\treturn copy;\n}\n\n\n```\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-131", + "external/cwe/cwe-120", + "external/cwe/cwe-122" + ], + "description": "Allocating a buffer using 'malloc' without ensuring that\n there is always space for the entire string and a zero\n terminator can cause a buffer overrun.", + "id": "cpp/no-space-for-terminator", + "kind": "problem", + "name": "No space for zero terminator", + "precision": "high", + "problem.severity": "error", + "security-severity": "9.8" + } + }, + { + "id": "cpp/non-https-url", + "name": "cpp/non-https-url", + "shortDescription": { + "text": "Failure to use HTTPS URLs" + }, + "fullDescription": { + "text": "Non-HTTPS connections can be intercepted by third parties." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Failure to use HTTPS URLs\nConstructing URLs with the HTTP protocol can lead to unsecured connections.\n\n\n## Recommendation\nWhen you construct a URL, ensure that you use an HTTPS URL rather than an HTTP URL. Then, any connections that are made using that URL are secure SSL connections.\n\n\n## Example\nThe following example shows two ways of opening a connection using a URL. When the connection is opened using an HTTP URL rather than an HTTPS URL, the connection is unsecured. When the connection is opened using an HTTPS URL, the connection is a secure SSL connection.\n\n\n```cpp\n\nvoid openUrl(char *url)\n{\n\t// ...\n}\n\nopenUrl(\"http://example.com\"); // BAD\n\nopenUrl(\"https://example.com\"); // GOOD: Opening a connection to a URL using HTTPS enforces SSL.\n\n```\n\n## References\n* OWASP: [Transport Layer Protection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html).\n* OWASP Top 10: [A08:2021 - Software and Data Integrity Failures](https://owasp.org/Top10/A08_2021-Software_and_Data_Integrity_Failures/).\n* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html).\n* Common Weakness Enumeration: [CWE-345](https://cwe.mitre.org/data/definitions/345.html).\n", + "markdown": "# Failure to use HTTPS URLs\nConstructing URLs with the HTTP protocol can lead to unsecured connections.\n\n\n## Recommendation\nWhen you construct a URL, ensure that you use an HTTPS URL rather than an HTTP URL. Then, any connections that are made using that URL are secure SSL connections.\n\n\n## Example\nThe following example shows two ways of opening a connection using a URL. When the connection is opened using an HTTP URL rather than an HTTPS URL, the connection is unsecured. When the connection is opened using an HTTPS URL, the connection is a secure SSL connection.\n\n\n```cpp\n\nvoid openUrl(char *url)\n{\n\t// ...\n}\n\nopenUrl(\"http://example.com\"); // BAD\n\nopenUrl(\"https://example.com\"); // GOOD: Opening a connection to a URL using HTTPS enforces SSL.\n\n```\n\n## References\n* OWASP: [Transport Layer Protection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html).\n* OWASP Top 10: [A08:2021 - Software and Data Integrity Failures](https://owasp.org/Top10/A08_2021-Software_and_Data_Integrity_Failures/).\n* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html).\n* Common Weakness Enumeration: [CWE-345](https://cwe.mitre.org/data/definitions/345.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-319", + "external/cwe/cwe-345" + ], + "description": "Non-HTTPS connections can be intercepted by third parties.", + "id": "cpp/non-https-url", + "kind": "path-problem", + "name": "Failure to use HTTPS URLs", + "precision": "high", + "problem.severity": "warning", + "security-severity": "8.1" + } + }, + { + "id": "cpp/sql-injection", + "name": "cpp/sql-injection", + "shortDescription": { + "text": "Uncontrolled data in SQL query" + }, + "fullDescription": { + "text": "Including user-supplied data in a SQL query without neutralizing special elements can make code vulnerable to SQL Injection." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Uncontrolled data in SQL query\nThe 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.\n\n\n## Recommendation\nUse a library routine to escape characters in the user-supplied string before converting it to SQL.\n\n\n## Example\n\n```c\nint main(int argc, char** argv) {\n char *userName = argv[2];\n \n // BAD\n char query1[1000] = {0};\n sprintf(query1, \"SELECT UID FROM USERS where name = \\\"%s\\\"\", userName);\n runSql(query1);\n \n // GOOD\n char userNameSql[1000] = {0};\n encodeSqlString(userNameSql, 1000, userName); \n char query2[1000] = {0};\n sprintf(query2, \"SELECT UID FROM USERS where name = \\\"%s\\\"\", userNameSql);\n runSql(query2);\n}\n\n```\n\n## References\n* MSDN Library: [SQL Injection](https://docs.microsoft.com/en-us/sql/relational-databases/security/sql-injection).\n* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html).\n", + "markdown": "# Uncontrolled data in SQL query\nThe 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.\n\n\n## Recommendation\nUse a library routine to escape characters in the user-supplied string before converting it to SQL.\n\n\n## Example\n\n```c\nint main(int argc, char** argv) {\n char *userName = argv[2];\n \n // BAD\n char query1[1000] = {0};\n sprintf(query1, \"SELECT UID FROM USERS where name = \\\"%s\\\"\", userName);\n runSql(query1);\n \n // GOOD\n char userNameSql[1000] = {0};\n encodeSqlString(userNameSql, 1000, userName); \n char query2[1000] = {0};\n sprintf(query2, \"SELECT UID FROM USERS where name = \\\"%s\\\"\", userNameSql);\n runSql(query2);\n}\n\n```\n\n## References\n* MSDN Library: [SQL Injection](https://docs.microsoft.com/en-us/sql/relational-databases/security/sql-injection).\n* Common Weakness Enumeration: [CWE-89](https://cwe.mitre.org/data/definitions/89.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-089" + ], + "description": "Including user-supplied data in a SQL query without\n neutralizing special elements can make code vulnerable\n to SQL Injection.", + "id": "cpp/sql-injection", + "kind": "path-problem", + "name": "Uncontrolled data in SQL query", + "precision": "high", + "problem.severity": "error", + "security-severity": "8.8" + } + }, + { + "id": "cpp/tainted-format-string", + "name": "cpp/tainted-format-string", + "shortDescription": { + "text": "Uncontrolled format string" + }, + "fullDescription": { + "text": "Using externally-controlled format strings in printf-style functions can lead to buffer overflows or data representation problems." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Uncontrolled format string\nThe 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.\n\nThe 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)\".\n\n\n## Recommendation\nUse constant expressions as the format strings. If you need to print a value from the user, use `printf(\"%s\", value_from_user)`.\n\n\n## Example\n\n```c\n#include \n\nvoid printWrapper(char *str) {\n\tprintf(str);\n}\n\nint main(int argc, char **argv) {\n\t// This should be avoided\n\tprintf(argv[1]);\n\n\t// This should be avoided too, because it has the same effect\n\tprintWrapper(argv[1]);\n\n\t// This is fine\n\tprintf(\"%s\", argv[1]);\n}\n```\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html).\n", + "markdown": "# Uncontrolled format string\nThe 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.\n\nThe 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)\".\n\n\n## Recommendation\nUse constant expressions as the format strings. If you need to print a value from the user, use `printf(\"%s\", value_from_user)`.\n\n\n## Example\n\n```c\n#include \n\nvoid printWrapper(char *str) {\n\tprintf(str);\n}\n\nint main(int argc, char **argv) {\n\t// This should be avoided\n\tprintf(argv[1]);\n\n\t// This should be avoided too, because it has the same effect\n\tprintWrapper(argv[1]);\n\n\t// This is fine\n\tprintf(\"%s\", argv[1]);\n}\n```\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-134](https://cwe.mitre.org/data/definitions/134.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-134" + ], + "description": "Using externally-controlled format strings in\n printf-style functions can lead to buffer overflows\n or data representation problems.", + "id": "cpp/tainted-format-string", + "kind": "path-problem", + "name": "Uncontrolled format string", + "precision": "high", + "problem.severity": "warning", + "security-severity": "9.3" + } + }, + { + "id": "cpp/use-of-string-after-lifetime-ends", + "name": "cpp/use-of-string-after-lifetime-ends", + "shortDescription": { + "text": "Use of string after lifetime ends" + }, + "fullDescription": { + "text": "If the value of a call to 'c_str' outlives the underlying object it may lead to unexpected behavior." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Use of string after lifetime ends\nCalling `c_str` on a `std::string` object returns a pointer to the underlying character array. When the `std::string` object is destroyed, the pointer returned by `c_str` is no longer valid. If the pointer is used after the `std::string` object is destroyed, then the behavior is undefined.\n\n\n## Recommendation\nEnsure that the pointer returned by `c_str` does not outlive the underlying `std::string` object.\n\n\n## Example\nThe following example concatenates two `std::string` objects, and then converts the resulting string to a C string using `c_str` so that it can be passed to the `work` function. However, the underlying `std::string` object that represents the concatenated string is destroyed as soon as the call to `c_str` returns. This means that `work` is given a pointer to invalid memory.\n\n\n```cpp\n#include \nvoid work(const char*);\n\n// BAD: the concatenated string is deallocated when `c_str` returns. So `work`\n// is given a pointer to invalid memory.\nvoid work_with_combined_string_bad(std::string s1, std::string s2) {\n const char* combined_string = (s1 + s2).c_str();\n work(combined_string);\n}\n```\nThe following example fixes the above code by ensuring that the pointer returned by the call to `c_str` does not outlive the underlying `std::string` objects. This ensures that the pointer passed to `work` points to valid memory.\n\n\n```cpp\n#include \nvoid work(const char*);\n\n// GOOD: the concatenated string outlives the call to `work`. So the pointer\n// obtainted from `c_str` is valid.\nvoid work_with_combined_string_good(std::string s1, std::string s2) {\n auto combined_string = s1 + s2;\n work(combined_string.c_str());\n}\n```\n\n## References\n* [MEM50-CPP. Do not access freed memory](https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM50-CPP.+Do+not+access+freed+memory).\n* Common Weakness Enumeration: [CWE-416](https://cwe.mitre.org/data/definitions/416.html).\n* Common Weakness Enumeration: [CWE-664](https://cwe.mitre.org/data/definitions/664.html).\n", + "markdown": "# Use of string after lifetime ends\nCalling `c_str` on a `std::string` object returns a pointer to the underlying character array. When the `std::string` object is destroyed, the pointer returned by `c_str` is no longer valid. If the pointer is used after the `std::string` object is destroyed, then the behavior is undefined.\n\n\n## Recommendation\nEnsure that the pointer returned by `c_str` does not outlive the underlying `std::string` object.\n\n\n## Example\nThe following example concatenates two `std::string` objects, and then converts the resulting string to a C string using `c_str` so that it can be passed to the `work` function. However, the underlying `std::string` object that represents the concatenated string is destroyed as soon as the call to `c_str` returns. This means that `work` is given a pointer to invalid memory.\n\n\n```cpp\n#include \nvoid work(const char*);\n\n// BAD: the concatenated string is deallocated when `c_str` returns. So `work`\n// is given a pointer to invalid memory.\nvoid work_with_combined_string_bad(std::string s1, std::string s2) {\n const char* combined_string = (s1 + s2).c_str();\n work(combined_string);\n}\n```\nThe following example fixes the above code by ensuring that the pointer returned by the call to `c_str` does not outlive the underlying `std::string` objects. This ensures that the pointer passed to `work` points to valid memory.\n\n\n```cpp\n#include \nvoid work(const char*);\n\n// GOOD: the concatenated string outlives the call to `work`. So the pointer\n// obtainted from `c_str` is valid.\nvoid work_with_combined_string_good(std::string s1, std::string s2) {\n auto combined_string = s1 + s2;\n work(combined_string.c_str());\n}\n```\n\n## References\n* [MEM50-CPP. Do not access freed memory](https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM50-CPP.+Do+not+access+freed+memory).\n* Common Weakness Enumeration: [CWE-416](https://cwe.mitre.org/data/definitions/416.html).\n* Common Weakness Enumeration: [CWE-664](https://cwe.mitre.org/data/definitions/664.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-416", + "external/cwe/cwe-664" + ], + "description": "If the value of a call to 'c_str' outlives the underlying object it may lead to unexpected behavior.", + "id": "cpp/use-of-string-after-lifetime-ends", + "kind": "problem", + "name": "Use of string after lifetime ends", + "precision": "high", + "problem.severity": "warning", + "security-severity": "8.8" + } + }, + { + "id": "cpp/use-of-unique-pointer-after-lifetime-ends", + "name": "cpp/use-of-unique-pointer-after-lifetime-ends", + "shortDescription": { + "text": "Use of unique pointer after lifetime ends" + }, + "fullDescription": { + "text": "Referencing the contents of a unique pointer after the underlying object has expired may lead to unexpected behavior." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Use of unique pointer after lifetime ends\nCalling `get` on a `std::unique_ptr` object returns a pointer to the underlying allocations. When the `std::unique_ptr` object is destroyed, the pointer returned by `get` is no longer valid. If the pointer is used after the `std::unique_ptr` object is destroyed, then the behavior is undefined.\n\n\n## Recommendation\nEnsure that the pointer returned by `get` does not outlive the underlying `std::unique_ptr` object.\n\n\n## Example\nThe following example gets a `std::unique_ptr` object, and then converts the resulting unique pointer to a pointer using `get` so that it can be passed to the `work` function. However, the `std::unique_ptr` object is destroyed as soon as the call to `get` returns. This means that `work` is given a pointer to invalid memory.\n\n\n```cpp\n#include \nstd::unique_ptr getUniquePointer();\nvoid work(const T*);\n\n// BAD: the unique pointer is deallocated when `get` returns. So `work`\n// is given a pointer to invalid memory.\nvoid work_with_unique_ptr_bad() {\n const T* combined_string = getUniquePointer().get();\n work(combined_string);\n}\n```\nThe following example fixes the above code by ensuring that the pointer returned by the call to `get` does not outlive the underlying `std::unique_ptr` objects. This ensures that the pointer passed to `work` points to valid memory.\n\n\n```cpp\n#include \nstd::unique_ptr getUniquePointer();\nvoid work(const T*);\n\n// GOOD: the unique pointer outlives the call to `work`. So the pointer\n// obtainted from `get` is valid.\nvoid work_with_unique_ptr_good() {\n auto combined_string = getUniquePointer();\n work(combined_string.get());\n}\n```\n\n## References\n* [MEM50-CPP. Do not access freed memory](https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM50-CPP.+Do+not+access+freed+memory).\n* Common Weakness Enumeration: [CWE-416](https://cwe.mitre.org/data/definitions/416.html).\n* Common Weakness Enumeration: [CWE-664](https://cwe.mitre.org/data/definitions/664.html).\n", + "markdown": "# Use of unique pointer after lifetime ends\nCalling `get` on a `std::unique_ptr` object returns a pointer to the underlying allocations. When the `std::unique_ptr` object is destroyed, the pointer returned by `get` is no longer valid. If the pointer is used after the `std::unique_ptr` object is destroyed, then the behavior is undefined.\n\n\n## Recommendation\nEnsure that the pointer returned by `get` does not outlive the underlying `std::unique_ptr` object.\n\n\n## Example\nThe following example gets a `std::unique_ptr` object, and then converts the resulting unique pointer to a pointer using `get` so that it can be passed to the `work` function. However, the `std::unique_ptr` object is destroyed as soon as the call to `get` returns. This means that `work` is given a pointer to invalid memory.\n\n\n```cpp\n#include \nstd::unique_ptr getUniquePointer();\nvoid work(const T*);\n\n// BAD: the unique pointer is deallocated when `get` returns. So `work`\n// is given a pointer to invalid memory.\nvoid work_with_unique_ptr_bad() {\n const T* combined_string = getUniquePointer().get();\n work(combined_string);\n}\n```\nThe following example fixes the above code by ensuring that the pointer returned by the call to `get` does not outlive the underlying `std::unique_ptr` objects. This ensures that the pointer passed to `work` points to valid memory.\n\n\n```cpp\n#include \nstd::unique_ptr getUniquePointer();\nvoid work(const T*);\n\n// GOOD: the unique pointer outlives the call to `work`. So the pointer\n// obtainted from `get` is valid.\nvoid work_with_unique_ptr_good() {\n auto combined_string = getUniquePointer();\n work(combined_string.get());\n}\n```\n\n## References\n* [MEM50-CPP. Do not access freed memory](https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM50-CPP.+Do+not+access+freed+memory).\n* Common Weakness Enumeration: [CWE-416](https://cwe.mitre.org/data/definitions/416.html).\n* Common Weakness Enumeration: [CWE-664](https://cwe.mitre.org/data/definitions/664.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-416", + "external/cwe/cwe-664" + ], + "description": "Referencing the contents of a unique pointer after the underlying object has expired may lead to unexpected behavior.", + "id": "cpp/use-of-unique-pointer-after-lifetime-ends", + "kind": "problem", + "name": "Use of unique pointer after lifetime ends", + "precision": "high", + "problem.severity": "warning", + "security-severity": "8.8" + } + }, + { + "id": "cpp/comparison-with-wider-type", + "name": "cpp/comparison-with-wider-type", + "shortDescription": { + "text": "Comparison of narrow type with wide type in loop condition" + }, + "fullDescription": { + "text": "Comparisons between types of different widths in a loop condition can cause the loop to behave unexpectedly." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Comparison of narrow type with wide type in loop condition\nIn 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.\n\n\n## Recommendation\nChange 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.\n\n\n## Example\nIn 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.\n\nThis problem is avoided in the 'GOOD' case because `bytes_received2` is an `int32_t`, which is as wide as the type of `max_get`.\n\n\n```c\nvoid main(int argc, char **argv) {\n\tuint32_t big_num = INT32_MAX;\n\tchar buf[big_num];\n\tint16_t bytes_received = 0;\n\tint max_get = INT16_MAX + 1;\n\n\t// BAD: 'bytes_received' is compared with a value of a wider type.\n\t// 'bytes_received' overflows before reaching 'max_get',\n\t// causing an infinite loop\n\twhile (bytes_received < max_get)\n\t\tbytes_received += get_from_input(buf, bytes_received);\n\t}\n\n\tuint32_t bytes_received = 0;\n\n\t// GOOD: 'bytes_received2' has a type at least as wide as 'max_get'\n\twhile (bytes_received < max_get) {\n\t\tbytes_received += get_from_input(buf, bytes_received);\n\t}\n\n}\n\n\nint getFromInput(char *buf, short pos) {\n\t// write to buf\n\t// ...\n\treturn 1;\n}\n\n```\n\n## References\n* [Data type ranges](https://docs.microsoft.com/en-us/cpp/cpp/data-type-ranges)\n* [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)\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html).\n* Common Weakness Enumeration: [CWE-835](https://cwe.mitre.org/data/definitions/835.html).\n", + "markdown": "# Comparison of narrow type with wide type in loop condition\nIn 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.\n\n\n## Recommendation\nChange 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.\n\n\n## Example\nIn 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.\n\nThis problem is avoided in the 'GOOD' case because `bytes_received2` is an `int32_t`, which is as wide as the type of `max_get`.\n\n\n```c\nvoid main(int argc, char **argv) {\n\tuint32_t big_num = INT32_MAX;\n\tchar buf[big_num];\n\tint16_t bytes_received = 0;\n\tint max_get = INT16_MAX + 1;\n\n\t// BAD: 'bytes_received' is compared with a value of a wider type.\n\t// 'bytes_received' overflows before reaching 'max_get',\n\t// causing an infinite loop\n\twhile (bytes_received < max_get)\n\t\tbytes_received += get_from_input(buf, bytes_received);\n\t}\n\n\tuint32_t bytes_received = 0;\n\n\t// GOOD: 'bytes_received2' has a type at least as wide as 'max_get'\n\twhile (bytes_received < max_get) {\n\t\tbytes_received += get_from_input(buf, bytes_received);\n\t}\n\n}\n\n\nint getFromInput(char *buf, short pos) {\n\t// write to buf\n\t// ...\n\treturn 1;\n}\n\n```\n\n## References\n* [Data type ranges](https://docs.microsoft.com/en-us/cpp/cpp/data-type-ranges)\n* [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)\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-197](https://cwe.mitre.org/data/definitions/197.html).\n* Common Weakness Enumeration: [CWE-835](https://cwe.mitre.org/data/definitions/835.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-190", + "external/cwe/cwe-197", + "external/cwe/cwe-835" + ], + "description": "Comparisons between types of different widths in a loop\n condition can cause the loop to behave unexpectedly.", + "id": "cpp/comparison-with-wider-type", + "kind": "problem", + "name": "Comparison of narrow type with wide type in loop condition", + "precision": "high", + "problem.severity": "warning", + "security-severity": "7.8" + } + }, + { + "id": "cpp/uncontrolled-arithmetic", + "name": "cpp/uncontrolled-arithmetic", + "shortDescription": { + "text": "Uncontrolled data in arithmetic expression" + }, + "fullDescription": { + "text": "Arithmetic operations on uncontrolled data that is not validated can cause overflows." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Uncontrolled data in arithmetic expression\nPerforming calculations on uncontrolled data can result in integer overflows unless the input is validated.\n\nIf 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.\n\n\n## Recommendation\nAlways guard against overflow in arithmetic operations on uncontrolled data by doing one of the following:\n\n* Validate the data.\n* 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`.\n* Use a wider type, so that larger input values do not cause overflow.\n\n## Example\nIn 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.\n\n\n```c\nint main(int argc, char** argv) {\n\tint i = rand();\n\t// BAD: potential overflow\n\tint j = i + 1000;\n\n\t// ...\n\n\tint n = rand();\n\tint k;\n\t// GOOD: use a guard to prevent overflow\n\tif (n < INT_MAX-1000)\n\t\tk = n + 1000;\n\telse\n\t\tk = INT_MAX;\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-191](https://cwe.mitre.org/data/definitions/191.html).\n", + "markdown": "# Uncontrolled data in arithmetic expression\nPerforming calculations on uncontrolled data can result in integer overflows unless the input is validated.\n\nIf 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.\n\n\n## Recommendation\nAlways guard against overflow in arithmetic operations on uncontrolled data by doing one of the following:\n\n* Validate the data.\n* 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`.\n* Use a wider type, so that larger input values do not cause overflow.\n\n## Example\nIn 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.\n\n\n```c\nint main(int argc, char** argv) {\n\tint i = rand();\n\t// BAD: potential overflow\n\tint j = i + 1000;\n\n\t// ...\n\n\tint n = rand();\n\tint k;\n\t// GOOD: use a guard to prevent overflow\n\tif (n < INT_MAX-1000)\n\t\tk = n + 1000;\n\telse\n\t\tk = INT_MAX;\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-191](https://cwe.mitre.org/data/definitions/191.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-190", + "external/cwe/cwe-191" + ], + "description": "Arithmetic operations on uncontrolled data that is not\n validated can cause overflows.", + "id": "cpp/uncontrolled-arithmetic", + "kind": "path-problem", + "name": "Uncontrolled data in arithmetic expression", + "precision": "high", + "problem.severity": "warning", + "security-severity": "8.6" + } + }, + { + "id": "cpp/weak-cryptographic-algorithm", + "name": "cpp/weak-cryptographic-algorithm", + "shortDescription": { + "text": "Use of a broken or risky cryptographic algorithm" + }, + "fullDescription": { + "text": "Using broken or weak cryptographic algorithms can allow an attacker to compromise security." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Use of a broken or risky cryptographic algorithm\nUsing broken or weak cryptographic algorithms can leave data vulnerable to being decrypted.\n\nMany 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.\n\n\n## Recommendation\nEnsure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048.\n\n\n## Example\nThe 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.\n\n\n```c\nvoid advapi() {\n HCRYPTPROV hCryptProv;\n HCRYPTKEY hKey;\n HCRYPTHASH hHash;\n // other preparation goes here\n\n // BAD: use 3DES for key\n CryptDeriveKey(hCryptProv, CALG_3DES, hHash, 0, &hKey);\n\n // GOOD: use AES\n CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey);\n}\n\n\n```\n\n## References\n* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf).\n* 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).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n", + "markdown": "# Use of a broken or risky cryptographic algorithm\nUsing broken or weak cryptographic algorithms can leave data vulnerable to being decrypted.\n\nMany 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.\n\n\n## Recommendation\nEnsure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048.\n\n\n## Example\nThe 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.\n\n\n```c\nvoid advapi() {\n HCRYPTPROV hCryptProv;\n HCRYPTKEY hKey;\n HCRYPTHASH hHash;\n // other preparation goes here\n\n // BAD: use 3DES for key\n CryptDeriveKey(hCryptProv, CALG_3DES, hHash, 0, &hKey);\n\n // GOOD: use AES\n CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey);\n}\n\n\n```\n\n## References\n* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf).\n* 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).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-327" + ], + "description": "Using broken or weak cryptographic algorithms can allow\n an attacker to compromise security.", + "id": "cpp/weak-cryptographic-algorithm", + "kind": "problem", + "name": "Use of a broken or risky cryptographic algorithm", + "precision": "high", + "problem.severity": "error", + "security-severity": "7.5" + } + }, + { + "id": "cpp/openssl-heartbleed", + "name": "cpp/openssl-heartbleed", + "shortDescription": { + "text": "Use of a version of OpenSSL with Heartbleed" + }, + "fullDescription": { + "text": "Using an old version of OpenSSL can allow remote attackers to retrieve portions of memory." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Use of a version of OpenSSL with Heartbleed\nEarlier 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\".\n\nSoftware 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.\n\n\n## Recommendation\nUpgrade to the latest version of OpenSSL. This problem was fixed in version 1.0.1g.\n\n\n## Example\nThe 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.\n\n\n```c\nint\ntls1_process_heartbeat(SSL *s)\n {\n unsigned char *p = &s->s3->rrec.data[0], *pl;\n unsigned short hbtype;\n unsigned int payload;\n \n /* ... */\n \n hbtype = *p++;\n n2s(p, payload);\n pl = p;\n \n /* ... */\n \n if (hbtype == TLS1_HB_REQUEST)\n {\n /* ... */\n memcpy(bp, pl, payload); // BAD: overflow here\n /* ... */\n }\n \n \n /* ... */\n \n }\n\n```\n\n## References\n* Common Vulnerabilities and Exposures: [CVE-2014-0160](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160).\n* OpenSSL News: [OpenSSL Security Advisory \\[07 Apr 2014\\]](https://www.openssl.org/news/secadv_20140407.txt).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n* Common Weakness Enumeration: [CWE-788](https://cwe.mitre.org/data/definitions/788.html).\n", + "markdown": "# Use of a version of OpenSSL with Heartbleed\nEarlier 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\".\n\nSoftware 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.\n\n\n## Recommendation\nUpgrade to the latest version of OpenSSL. This problem was fixed in version 1.0.1g.\n\n\n## Example\nThe 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.\n\n\n```c\nint\ntls1_process_heartbeat(SSL *s)\n {\n unsigned char *p = &s->s3->rrec.data[0], *pl;\n unsigned short hbtype;\n unsigned int payload;\n \n /* ... */\n \n hbtype = *p++;\n n2s(p, payload);\n pl = p;\n \n /* ... */\n \n if (hbtype == TLS1_HB_REQUEST)\n {\n /* ... */\n memcpy(bp, pl, payload); // BAD: overflow here\n /* ... */\n }\n \n \n /* ... */\n \n }\n\n```\n\n## References\n* Common Vulnerabilities and Exposures: [CVE-2014-0160](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160).\n* OpenSSL News: [OpenSSL Security Advisory \\[07 Apr 2014\\]](https://www.openssl.org/news/secadv_20140407.txt).\n* Common Weakness Enumeration: [CWE-327](https://cwe.mitre.org/data/definitions/327.html).\n* Common Weakness Enumeration: [CWE-788](https://cwe.mitre.org/data/definitions/788.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-327", + "external/cwe/cwe-788" + ], + "description": "Using an old version of OpenSSL can allow remote\n attackers to retrieve portions of memory.", + "id": "cpp/openssl-heartbleed", + "kind": "problem", + "name": "Use of a version of OpenSSL with Heartbleed", + "precision": "very-high", + "problem.severity": "error", + "security-severity": "7.5" + } + }, + { + "id": "cpp/toctou-race-condition", + "name": "cpp/toctou-race-condition", + "shortDescription": { + "text": "Time-of-check time-of-use filesystem race condition" + }, + "fullDescription": { + "text": "Separately checking the state of a file before operating on it may allow an attacker to modify the file between the two operations." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Time-of-check time-of-use filesystem race condition\nOften 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.\n\nHowever, 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.\n\n\n## Recommendation\nWherever possible, use functions that operate on file descriptors rather than file names (for example, `fchmod` rather than `chmod`).\n\nFor 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.\n\nIf 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.\n\n\n## Example\nThe 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.\n\n\n```c\nchar *file_name;\nFILE *f_ptr;\n \n/* Initialize file_name */\n \nf_ptr = fopen(file_name, \"w\");\nif (f_ptr == NULL) {\n /* Handle error */\n}\n \n/* ... */\n \nif (chmod(file_name, S_IRUSR) == -1) {\n /* Handle error */\n}\n```\nThis 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.\n\n\n```c\nchar *file_name;\nint fd;\n \n/* Initialize file_name */\n \nfd = open(\n file_name,\n O_WRONLY | O_CREAT | O_EXCL,\n S_IRWXU\n);\nif (fd == -1) {\n /* Handle error */\n}\n \n/* ... */\n \nif (fchmod(fd, S_IRUSR) == -1) {\n /* Handle error */\n}\n```\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-367](https://cwe.mitre.org/data/definitions/367.html).\n", + "markdown": "# Time-of-check time-of-use filesystem race condition\nOften 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.\n\nHowever, 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.\n\n\n## Recommendation\nWherever possible, use functions that operate on file descriptors rather than file names (for example, `fchmod` rather than `chmod`).\n\nFor 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.\n\nIf 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.\n\n\n## Example\nThe 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.\n\n\n```c\nchar *file_name;\nFILE *f_ptr;\n \n/* Initialize file_name */\n \nf_ptr = fopen(file_name, \"w\");\nif (f_ptr == NULL) {\n /* Handle error */\n}\n \n/* ... */\n \nif (chmod(file_name, S_IRUSR) == -1) {\n /* Handle error */\n}\n```\nThis 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.\n\n\n```c\nchar *file_name;\nint fd;\n \n/* Initialize file_name */\n \nfd = open(\n file_name,\n O_WRONLY | O_CREAT | O_EXCL,\n S_IRWXU\n);\nif (fd == -1) {\n /* Handle error */\n}\n \n/* ... */\n \nif (fchmod(fd, S_IRUSR) == -1) {\n /* Handle error */\n}\n```\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-367](https://cwe.mitre.org/data/definitions/367.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-367" + ], + "description": "Separately checking the state of a file before operating\n on it may allow an attacker to modify the file between\n the two operations.", + "id": "cpp/toctou-race-condition", + "kind": "problem", + "name": "Time-of-check time-of-use filesystem race condition", + "precision": "high", + "problem.severity": "warning", + "security-severity": "7.7" + } + }, + { + "id": "cpp/open-call-with-mode-argument", + "name": "cpp/open-call-with-mode-argument", + "shortDescription": { + "text": "File opened with O_CREAT flag but without mode argument" + }, + "fullDescription": { + "text": "Opening a file with the O_CREAT flag but without mode argument reads arbitrary bytes from the stack." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# File opened with O_CREAT flag but without mode argument\nWhen opening a file with the `O_CREAT` or `O_TMPFILE` flag, the `mode` must be supplied. If the `mode` argument is omitted, some arbitrary bytes from the stack will be used as the file mode. This leaks some bits from the stack into the permissions of the file.\n\n\n## Recommendation\nThe `mode` must be supplied when `O_CREAT` or `O_TMPFILE` is specified.\n\n\n## Example\nThe first example opens a file with the `O_CREAT` flag without supplying the `mode` argument. In this case arbitrary bytes from the stack will be used as `mode` argument. The second example correctly supplies the `mode` argument and creates a file that is user readable and writable.\n\n\n```c\nint open_file_bad() {\n\t// BAD - this uses arbitrary bytes from the stack as mode argument\n return open(FILE, O_CREAT)\n}\n\nint open_file_good() {\n\t// GOOD - the mode argument is supplied\n return open(FILE, O_CREAT, S_IRUSR | S_IWUSR)\n}\n\n```\n", + "markdown": "# File opened with O_CREAT flag but without mode argument\nWhen opening a file with the `O_CREAT` or `O_TMPFILE` flag, the `mode` must be supplied. If the `mode` argument is omitted, some arbitrary bytes from the stack will be used as the file mode. This leaks some bits from the stack into the permissions of the file.\n\n\n## Recommendation\nThe `mode` must be supplied when `O_CREAT` or `O_TMPFILE` is specified.\n\n\n## Example\nThe first example opens a file with the `O_CREAT` flag without supplying the `mode` argument. In this case arbitrary bytes from the stack will be used as `mode` argument. The second example correctly supplies the `mode` argument and creates a file that is user readable and writable.\n\n\n```c\nint open_file_bad() {\n\t// BAD - this uses arbitrary bytes from the stack as mode argument\n return open(FILE, O_CREAT)\n}\n\nint open_file_good() {\n\t// GOOD - the mode argument is supplied\n return open(FILE, O_CREAT, S_IRUSR | S_IWUSR)\n}\n\n```\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-732" + ], + "description": "Opening a file with the O_CREAT flag but without mode argument reads arbitrary bytes from the stack.", + "id": "cpp/open-call-with-mode-argument", + "kind": "problem", + "name": "File opened with O_CREAT flag but without mode argument", + "precision": "high", + "problem.severity": "error", + "security-severity": "7.8" + } + }, + { + "id": "cpp/unsafe-dacl-security-descriptor", + "name": "cpp/unsafe-dacl-security-descriptor", + "shortDescription": { + "text": "Setting a DACL to NULL in a SECURITY_DESCRIPTOR" + }, + "fullDescription": { + "text": "Setting a DACL to NULL in a SECURITY_DESCRIPTOR will result in an unprotected object. If the DACL that belongs to the security descriptor of an object is set to NULL, a null DACL is created. A null DACL grants full access to any user who requests it; normal security checking is not performed with respect to the object." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Setting a DACL to NULL in a SECURITY_DESCRIPTOR\nThis query indicates that a call is setting the DACL field in a `SECURITY_DESCRIPTOR` to null.\n\nWhen using `SetSecurityDescriptorDacl` to set a discretionary access control (DACL), setting the `bDaclPresent` argument to `TRUE` indicates the presence of a DACL in the security description in the argument `pDacl`.\n\nWhen 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.\n\nA `NULL DACL` grants full access to any user who requests it; normal security checking is not performed with respect to the object.\n\n\n## Recommendation\nYou should not use a `NULL DACL` with an object because any user can change the DACL and owner of the security descriptor.\n\n\n## Example\nIn the following example, the call to `SetSecurityDescriptorDacl` is setting an unsafe DACL (`NULL DACL`) to the security descriptor.\n\n\n```cpp\nSECURITY_DESCRIPTOR pSD;\nSECURITY_ATTRIBUTES SA;\n\nif (!InitializeSecurityDescriptor(&pSD, SECURITY_DESCRIPTOR_REVISION))\n{\n // error handling\n}\nif (!SetSecurityDescriptorDacl(&pSD,\n TRUE, // bDaclPresent - this value indicates the presence of a DACL in the security descriptor\n NULL, // pDacl - the pDacl parameter does not point to a DACL. All access will be allowed\n FALSE))\n{\n // error handling\n}\n\n```\nTo fix this issue, `pDacl` argument should be a pointer to an `ACL` structure that specifies the DACL for the security descriptor.\n\n\n## References\n* [SetSecurityDescriptorDacl function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-setsecuritydescriptordacl)\n* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html).\n", + "markdown": "# Setting a DACL to NULL in a SECURITY_DESCRIPTOR\nThis query indicates that a call is setting the DACL field in a `SECURITY_DESCRIPTOR` to null.\n\nWhen using `SetSecurityDescriptorDacl` to set a discretionary access control (DACL), setting the `bDaclPresent` argument to `TRUE` indicates the presence of a DACL in the security description in the argument `pDacl`.\n\nWhen 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.\n\nA `NULL DACL` grants full access to any user who requests it; normal security checking is not performed with respect to the object.\n\n\n## Recommendation\nYou should not use a `NULL DACL` with an object because any user can change the DACL and owner of the security descriptor.\n\n\n## Example\nIn the following example, the call to `SetSecurityDescriptorDacl` is setting an unsafe DACL (`NULL DACL`) to the security descriptor.\n\n\n```cpp\nSECURITY_DESCRIPTOR pSD;\nSECURITY_ATTRIBUTES SA;\n\nif (!InitializeSecurityDescriptor(&pSD, SECURITY_DESCRIPTOR_REVISION))\n{\n // error handling\n}\nif (!SetSecurityDescriptorDacl(&pSD,\n TRUE, // bDaclPresent - this value indicates the presence of a DACL in the security descriptor\n NULL, // pDacl - the pDacl parameter does not point to a DACL. All access will be allowed\n FALSE))\n{\n // error handling\n}\n\n```\nTo fix this issue, `pDacl` argument should be a pointer to an `ACL` structure that specifies the DACL for the security descriptor.\n\n\n## References\n* [SetSecurityDescriptorDacl function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-setsecuritydescriptordacl)\n* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-732" + ], + "description": "Setting a DACL to NULL in a SECURITY_DESCRIPTOR will result in an unprotected object.\n If the DACL that belongs to the security descriptor of an object is set to NULL, a null DACL is created.\n A null DACL grants full access to any user who requests it;\n normal security checking is not performed with respect to the object.", + "id": "cpp/unsafe-dacl-security-descriptor", + "kind": "problem", + "name": "Setting a DACL to NULL in a SECURITY_DESCRIPTOR", + "precision": "high", + "problem.severity": "error", + "security-severity": "7.8" + } + }, + { + "id": "cpp/dangerous-function-overflow", + "name": "cpp/dangerous-function-overflow", + "shortDescription": { + "text": "Use of dangerous function" + }, + "fullDescription": { + "text": "Use of a standard library function that does not guard against buffer overflow." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Use of dangerous function\nThis 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.\n\nThe `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.\n\n\n## Recommendation\nReplace calls to `gets` with `fgets`, specifying the maximum length to copy. This will prevent the buffer overflow.\n\n\n## Example\nThe following example gets a string from standard input in two ways:\n\n\n```c\n#define BUFFERSIZE (1024)\n\n// BAD: using gets\nvoid echo_bad() {\n char buffer[BUFFERSIZE];\n gets(buffer);\n printf(\"Input was: '%s'\\n\", buffer);\n}\n\n// GOOD: using fgets\nvoid echo_good() {\n char buffer[BUFFERSIZE];\n fgets(buffer, BUFFERSIZE, stdin);\n printf(\"Input was: '%s'\\n\", buffer);\n}\n\n```\nThe 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.\n\n\n## Related rules\nOther 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:\n\n* [CWE-120 Classic Buffer Overflow](https://cwe.mitre.org/data/definitions/120.html).\n* [CWE-131 Incorrect Calculation of Buffer Size](https://cwe.mitre.org/data/definitions/131.html).\n\n## References\n* Wikipedia: [Morris worm](http://en.wikipedia.org/wiki/Morris_worm).\n* E. Spafford. *The Internet Worm Program: An Analysis*. Purdue Technical Report CSD-TR-823, [(online)](http://www.textfiles.com/100/tr823.txt), 1988.\n* Common Weakness Enumeration: [CWE-242](https://cwe.mitre.org/data/definitions/242.html).\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n", + "markdown": "# Use of dangerous function\nThis 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.\n\nThe `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.\n\n\n## Recommendation\nReplace calls to `gets` with `fgets`, specifying the maximum length to copy. This will prevent the buffer overflow.\n\n\n## Example\nThe following example gets a string from standard input in two ways:\n\n\n```c\n#define BUFFERSIZE (1024)\n\n// BAD: using gets\nvoid echo_bad() {\n char buffer[BUFFERSIZE];\n gets(buffer);\n printf(\"Input was: '%s'\\n\", buffer);\n}\n\n// GOOD: using fgets\nvoid echo_good() {\n char buffer[BUFFERSIZE];\n fgets(buffer, BUFFERSIZE, stdin);\n printf(\"Input was: '%s'\\n\", buffer);\n}\n\n```\nThe 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.\n\n\n## Related rules\nOther 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:\n\n* [CWE-120 Classic Buffer Overflow](https://cwe.mitre.org/data/definitions/120.html).\n* [CWE-131 Incorrect Calculation of Buffer Size](https://cwe.mitre.org/data/definitions/131.html).\n\n## References\n* Wikipedia: [Morris worm](http://en.wikipedia.org/wiki/Morris_worm).\n* E. Spafford. *The Internet Worm Program: An Analysis*. Purdue Technical Report CSD-TR-823, [(online)](http://www.textfiles.com/100/tr823.txt), 1988.\n* Common Weakness Enumeration: [CWE-242](https://cwe.mitre.org/data/definitions/242.html).\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-242", + "external/cwe/cwe-676" + ], + "description": "Use of a standard library function that does not guard against buffer overflow.", + "id": "cpp/dangerous-function-overflow", + "kind": "problem", + "name": "Use of dangerous function", + "precision": "very-high", + "problem.severity": "error", + "security-severity": "10.0" + } + }, + { + "id": "cpp/dangerous-cin", + "name": "cpp/dangerous-cin", + "shortDescription": { + "text": "Dangerous use of 'cin'" + }, + "fullDescription": { + "text": "Using `cin` without specifying the length of the input may be dangerous." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Dangerous use of 'cin'\nThis 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.\n\n\n## Recommendation\nAlways specify the length of any input expected from `cin` by calling `cin.width` before consuming the input.\n\n\n## Example\nThe following example shows both a dangerous and a safe way to consume input from `cin`.\n\n\n```cpp\n#define BUFFER_SIZE 20\n\nvoid bad()\n{\n\tchar buffer[BUFFER_SIZE];\n\t// BAD: Use of 'cin' without specifying the length of the input.\n\tcin >> buffer;\n\tbuffer[BUFFER_SIZE-1] = '\\0';\n}\n\nvoid good()\n{\n\tchar buffer[BUFFER_SIZE];\n\t// GOOD: Specifying the length of the input before using 'cin'.\n\tcin.width(BUFFER_SIZE);\n\tcin >> buffer;\n\tbuffer[BUFFER_SIZE-1] = '\\0';\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n", + "markdown": "# Dangerous use of 'cin'\nThis 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.\n\n\n## Recommendation\nAlways specify the length of any input expected from `cin` by calling `cin.width` before consuming the input.\n\n\n## Example\nThe following example shows both a dangerous and a safe way to consume input from `cin`.\n\n\n```cpp\n#define BUFFER_SIZE 20\n\nvoid bad()\n{\n\tchar buffer[BUFFER_SIZE];\n\t// BAD: Use of 'cin' without specifying the length of the input.\n\tcin >> buffer;\n\tbuffer[BUFFER_SIZE-1] = '\\0';\n}\n\nvoid good()\n{\n\tchar buffer[BUFFER_SIZE];\n\t// GOOD: Specifying the length of the input before using 'cin'.\n\tcin.width(BUFFER_SIZE);\n\tcin >> buffer;\n\tbuffer[BUFFER_SIZE-1] = '\\0';\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-676" + ], + "description": "Using `cin` without specifying the length of the input\n may be dangerous.", + "id": "cpp/dangerous-cin", + "kind": "problem", + "name": "Dangerous use of 'cin'", + "precision": "high", + "problem.severity": "error", + "security-severity": "10.0" + } + }, + { + "id": "cpp/suspicious-add-sizeof", + "name": "cpp/suspicious-add-sizeof", + "shortDescription": { + "text": "Suspicious add with sizeof" + }, + "fullDescription": { + "text": "Explicitly scaled pointer arithmetic expressions can cause buffer overflow conditions if the offset is also implicitly scaled." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Suspicious add with sizeof\nPointer 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`.\n\nThis 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)`.\n\n\n## Recommendation\n1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`.\n1. 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.\n\n## Example\n\n```cpp\nint example1(int i) {\n int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n int *intPointer = intArray;\n // BAD: the offset is already automatically scaled by sizeof(int),\n // so this code will compute the wrong offset.\n return *(intPointer + (i * sizeof(int)));\n}\n\nint example2(int i) {\n int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n int *intPointer = intArray;\n // GOOD: the offset is automatically scaled by sizeof(int).\n return *(intPointer + i);\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html).\n", + "markdown": "# Suspicious add with sizeof\nPointer 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`.\n\nThis 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)`.\n\n\n## Recommendation\n1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`.\n1. 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.\n\n## Example\n\n```cpp\nint example1(int i) {\n int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n int *intPointer = intArray;\n // BAD: the offset is already automatically scaled by sizeof(int),\n // so this code will compute the wrong offset.\n return *(intPointer + (i * sizeof(int)));\n}\n\nint example2(int i) {\n int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n int *intPointer = intArray;\n // GOOD: the offset is automatically scaled by sizeof(int).\n return *(intPointer + i);\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-468" + ], + "description": "Explicitly scaled pointer arithmetic expressions\n can cause buffer overflow conditions if the offset is also\n implicitly scaled.", + "id": "cpp/suspicious-add-sizeof", + "kind": "problem", + "name": "Suspicious add with sizeof", + "precision": "high", + "problem.severity": "warning", + "security-severity": "8.8" + } + }, + { + "id": "cpp/cgi-xss", + "name": "cpp/cgi-xss", + "shortDescription": { + "text": "CGI script vulnerable to cross-site scripting" + }, + "fullDescription": { + "text": "Writing user input directly to a web page allows for a cross-site scripting vulnerability." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# CGI script vulnerable to cross-site scripting\nDirectly 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.\n\nFor web servers implemented with the Common Gateway Interface (CGI), HTTP parameters are supplied via the `QUERY_STRING` environment variable.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider escaping special characters before writing the HTTP parameter back to the page.\n\n\n## Example\nIn 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.\n\n\n```c\nvoid bad_server() {\n char* query = getenv(\"QUERY_STRING\");\n puts(\"

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

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

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

\\n\");\n puts(do_search(query));\n}\n\n```\n\n## References\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* IETF Tools: [The Common Gateway Specification (CGI)](http://tools.ietf.org/html/draft-robinson-www-interface-00).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n", + "markdown": "# CGI script vulnerable to cross-site scripting\nDirectly 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.\n\nFor web servers implemented with the Common Gateway Interface (CGI), HTTP parameters are supplied via the `QUERY_STRING` environment variable.\n\n\n## Recommendation\nTo guard against cross-site scripting, consider escaping special characters before writing the HTTP parameter back to the page.\n\n\n## Example\nIn 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.\n\n\n```c\nvoid bad_server() {\n char* query = getenv(\"QUERY_STRING\");\n puts(\"

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

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

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

\\n\");\n puts(do_search(query));\n}\n\n```\n\n## References\n* OWASP: [XSS (Cross Site Scripting) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html).\n* Wikipedia: [Cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting).\n* IETF Tools: [The Common Gateway Specification (CGI)](http://tools.ietf.org/html/draft-robinson-www-interface-00).\n* Common Weakness Enumeration: [CWE-79](https://cwe.mitre.org/data/definitions/79.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-079" + ], + "description": "Writing user input directly to a web page\n allows for a cross-site scripting vulnerability.", + "id": "cpp/cgi-xss", + "kind": "path-problem", + "name": "CGI script vulnerable to cross-site scripting", + "precision": "high", + "problem.severity": "error", + "security-severity": "6.1" + } + }, + { + "id": "cpp/external-entity-expansion", + "name": "cpp/external-entity-expansion", + "shortDescription": { + "text": "XML external entity expansion" + }, + "fullDescription": { + "text": "Parsing user-controlled XML documents and allowing expansion of external entity references may lead to disclosure of confidential data or denial of service." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# XML external entity expansion\nParsing 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.\n\n\n## Recommendation\nThe 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.\n\n\n## Example\nThe following example uses the `Xerces-C++` XML parser to parse a string `data`. If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since the parser is constructed in its default state with `setDisableDefaultEntityResolution` set to `false`:\n\n\n```cpp\n\nXercesDOMParser *parser = new XercesDOMParser();\n\nparser->parse(data); // BAD (parser is not correctly configured, may expand external entity references)\n\n```\nTo guard against XXE attacks, the `setDisableDefaultEntityResolution` option should be set to `true`.\n\n\n```cpp\n\nXercesDOMParser *parser = new XercesDOMParser();\n\nparser->setDisableDefaultEntityResolution(true);\nparser->parse(data);\n\n```\n\n## References\n* OWASP: [XML External Entity (XXE) Processing](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing).\n* OWASP: [XML External Entity Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html).\n* Timothy Morgen: [XML Schema, DTD, and Entity Attacks](https://research.nccgroup.com/2014/05/19/xml-schema-dtd-and-entity-attacks-a-compendium-of-known-techniques/).\n* Timur Yunusov, Alexey Osipov: [XML Out-Of-Band Data Retrieval](https://www.slideshare.net/qqlan/bh-ready-v4).\n* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html).\n", + "markdown": "# XML external entity expansion\nParsing 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.\n\n\n## Recommendation\nThe 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.\n\n\n## Example\nThe following example uses the `Xerces-C++` XML parser to parse a string `data`. If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since the parser is constructed in its default state with `setDisableDefaultEntityResolution` set to `false`:\n\n\n```cpp\n\nXercesDOMParser *parser = new XercesDOMParser();\n\nparser->parse(data); // BAD (parser is not correctly configured, may expand external entity references)\n\n```\nTo guard against XXE attacks, the `setDisableDefaultEntityResolution` option should be set to `true`.\n\n\n```cpp\n\nXercesDOMParser *parser = new XercesDOMParser();\n\nparser->setDisableDefaultEntityResolution(true);\nparser->parse(data);\n\n```\n\n## References\n* OWASP: [XML External Entity (XXE) Processing](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing).\n* OWASP: [XML External Entity Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html).\n* Timothy Morgen: [XML Schema, DTD, and Entity Attacks](https://research.nccgroup.com/2014/05/19/xml-schema-dtd-and-entity-attacks-a-compendium-of-known-techniques/).\n* Timur Yunusov, Alexey Osipov: [XML Out-Of-Band Data Retrieval](https://www.slideshare.net/qqlan/bh-ready-v4).\n* Common Weakness Enumeration: [CWE-611](https://cwe.mitre.org/data/definitions/611.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-611" + ], + "description": "Parsing user-controlled XML documents and allowing expansion of\n external entity references may lead to disclosure of\n confidential data or denial of service.", + "id": "cpp/external-entity-expansion", + "kind": "path-problem", + "name": "XML external entity expansion", + "precision": "high", + "problem.severity": "warning", + "security-severity": "9.1" + } + }, + { + "id": "cpp/insufficient-key-size", + "name": "cpp/insufficient-key-size", + "shortDescription": { + "text": "Use of a cryptographic algorithm with insufficient key size" + }, + "fullDescription": { + "text": "Using cryptographic algorithms with too small a key size can allow an attacker to compromise security." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Use of a cryptographic algorithm with insufficient key size\nUsing cryptographic algorithms with a small key size can leave data vulnerable to being decrypted.\n\nMany cryptographic algorithms provided by cryptography libraries can be configured with key sizes that are vulnerable to brute force attacks. Using such a key size means that an attacker may be able to easily decrypt the encrypted data.\n\n\n## Recommendation\nEnsure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048.\n\n\n## Example\nThe following code shows an example of using the `openssl` library to generate an RSA key. When creating a key, you must specify which key size to use. The first example uses 1024 bits, which is not considered sufficient. The second example uses 2048 bits, which is currently considered sufficient.\n\n\n```c\nvoid encrypt_with_openssl(EVP_PKEY_CTX *ctx) {\n\n // BAD: only 1024 bits for an RSA key\n EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 1024);\n\n // GOOD: 2048 bits for an RSA key\n EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048);\n}\n```\n\n## References\n* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf).\n* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf).\n* Common Weakness Enumeration: [CWE-326](https://cwe.mitre.org/data/definitions/326.html).\n", + "markdown": "# Use of a cryptographic algorithm with insufficient key size\nUsing cryptographic algorithms with a small key size can leave data vulnerable to being decrypted.\n\nMany cryptographic algorithms provided by cryptography libraries can be configured with key sizes that are vulnerable to brute force attacks. Using such a key size means that an attacker may be able to easily decrypt the encrypted data.\n\n\n## Recommendation\nEnsure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048.\n\n\n## Example\nThe following code shows an example of using the `openssl` library to generate an RSA key. When creating a key, you must specify which key size to use. The first example uses 1024 bits, which is not considered sufficient. The second example uses 2048 bits, which is currently considered sufficient.\n\n\n```c\nvoid encrypt_with_openssl(EVP_PKEY_CTX *ctx) {\n\n // BAD: only 1024 bits for an RSA key\n EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 1024);\n\n // GOOD: 2048 bits for an RSA key\n EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048);\n}\n```\n\n## References\n* NIST, FIPS 140 Annex a: [ Approved Security Functions](http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf).\n* NIST, SP 800-131A: [ Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf).\n* Common Weakness Enumeration: [CWE-326](https://cwe.mitre.org/data/definitions/326.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-326" + ], + "description": "Using cryptographic algorithms with too small a key size can\n allow an attacker to compromise security.", + "id": "cpp/insufficient-key-size", + "kind": "path-problem", + "name": "Use of a cryptographic algorithm with insufficient key size", + "precision": "high", + "problem.severity": "error", + "security-severity": "7.5" + } + }, + { + "id": "cpp/command-line-injection", + "name": "cpp/command-line-injection", + "shortDescription": { + "text": "Uncontrolled data used in OS command" + }, + "fullDescription": { + "text": "Using user-supplied data in an OS command, without neutralizing special elements, can make code vulnerable to command injection." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Uncontrolled data used in OS command\nThe code passes user input as part of a call to `system` or `popen` without escaping special elements. It generates a command line using `sprintf`, with the user-supplied data directly passed as a formatting argument. This leaves the code vulnerable to attack by command injection.\n\n\n## Recommendation\nUse a library routine to escape characters in the user-supplied string before passing it to a command shell.\n\n\n## Example\nThe following example runs an external command in two ways. The first way uses `sprintf` to build a command directly out of a user-supplied argument. As such, it is vulnerable to command injection. The second way quotes the user-provided value before embedding it in the command; assuming the `encodeShellString` utility is correct, this code should be safe against command injection.\n\n\n```c\nint main(int argc, char** argv) {\n char *userName = argv[2];\n \n {\n // BAD: a string from the user is injected directly into\n // a command line.\n char command1[1000] = {0};\n sprintf(command1, \"userinfo -v \\\"%s\\\"\", userName);\n system(command1);\n }\n\n {\n // GOOD: the user string is encoded by a library routine.\n char userNameQuoted[1000] = {0};\n encodeShellString(userNameQuoted, 1000, userName); \n char command2[1000] = {0};\n sprintf(command2, \"userinfo -v %s\", userNameQuoted);\n system(command2);\n }\n}\n\n```\n\n## References\n* CERT C Coding Standard: [STR02-C. Sanitize data passed to complex subsystems](https://www.securecoding.cert.org/confluence/display/c/STR02-C.+Sanitize+data+passed+to+complex+subsystems).\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n", + "markdown": "# Uncontrolled data used in OS command\nThe code passes user input as part of a call to `system` or `popen` without escaping special elements. It generates a command line using `sprintf`, with the user-supplied data directly passed as a formatting argument. This leaves the code vulnerable to attack by command injection.\n\n\n## Recommendation\nUse a library routine to escape characters in the user-supplied string before passing it to a command shell.\n\n\n## Example\nThe following example runs an external command in two ways. The first way uses `sprintf` to build a command directly out of a user-supplied argument. As such, it is vulnerable to command injection. The second way quotes the user-provided value before embedding it in the command; assuming the `encodeShellString` utility is correct, this code should be safe against command injection.\n\n\n```c\nint main(int argc, char** argv) {\n char *userName = argv[2];\n \n {\n // BAD: a string from the user is injected directly into\n // a command line.\n char command1[1000] = {0};\n sprintf(command1, \"userinfo -v \\\"%s\\\"\", userName);\n system(command1);\n }\n\n {\n // GOOD: the user string is encoded by a library routine.\n char userNameQuoted[1000] = {0};\n encodeShellString(userNameQuoted, 1000, userName); \n char command2[1000] = {0};\n sprintf(command2, \"userinfo -v %s\", userNameQuoted);\n system(command2);\n }\n}\n\n```\n\n## References\n* CERT C Coding Standard: [STR02-C. Sanitize data passed to complex subsystems](https://www.securecoding.cert.org/confluence/display/c/STR02-C.+Sanitize+data+passed+to+complex+subsystems).\n* OWASP: [Command Injection](https://www.owasp.org/index.php/Command_Injection).\n* Common Weakness Enumeration: [CWE-78](https://cwe.mitre.org/data/definitions/78.html).\n* Common Weakness Enumeration: [CWE-88](https://cwe.mitre.org/data/definitions/88.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-078", + "external/cwe/cwe-088" + ], + "description": "Using user-supplied data in an OS command, without\n neutralizing special elements, can make code vulnerable\n to command injection.", + "id": "cpp/command-line-injection", + "kind": "path-problem", + "name": "Uncontrolled data used in OS command", + "precision": "high", + "problem.severity": "error", + "security-severity": "9.8" + } + }, + { + "id": "cpp/new-free-mismatch", + "name": "cpp/new-free-mismatch", + "shortDescription": { + "text": "Mismatching new/free or malloc/delete" + }, + "fullDescription": { + "text": "An object that was allocated with 'malloc' or 'new' is being freed using a mismatching 'free' or 'delete'." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Mismatching new/free or malloc/delete\nThis 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.\n\n\n## Recommendation\nUse the `delete` operator when freeing memory allocated with `new`, and the `free` function when freeing memory allocated with `malloc`.\n\n\n## Example\n\n```cpp\nRecord *ptr = new Record(...);\n\n...\n\nfree(ptr); // BAD: ptr was created using 'new', but is being freed using 'free'\n\n```\n\n## References\n* 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)\"\n* 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++)*.\n* Common Weakness Enumeration: [CWE-401](https://cwe.mitre.org/data/definitions/401.html).\n", + "markdown": "# Mismatching new/free or malloc/delete\nThis 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.\n\n\n## Recommendation\nUse the `delete` operator when freeing memory allocated with `new`, and the `free` function when freeing memory allocated with `malloc`.\n\n\n## Example\n\n```cpp\nRecord *ptr = new Record(...);\n\n...\n\nfree(ptr); // BAD: ptr was created using 'new', but is being freed using 'free'\n\n```\n\n## References\n* 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)\"\n* 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++)*.\n* Common Weakness Enumeration: [CWE-401](https://cwe.mitre.org/data/definitions/401.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-401" + ], + "description": "An object that was allocated with 'malloc' or 'new' is being freed using a mismatching 'free' or 'delete'.", + "id": "cpp/new-free-mismatch", + "kind": "problem", + "name": "Mismatching new/free or malloc/delete", + "precision": "high", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/double-free", + "name": "cpp/double-free", + "shortDescription": { + "text": "Potential double free" + }, + "fullDescription": { + "text": "Freeing a resource more than once can lead to undefined behavior and cause memory corruption." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Potential double free\nDeallocating memory more than once can lead to a double-free vulnerability. This can be exploited to corrupt the allocator's internal data structures, which can lead to denial-of-service attacks by crashing the program, or security vulnerabilities, by allowing an attacker to overwrite arbitrary memory locations.\n\n\n## Recommendation\nEnsure that all execution paths deallocate the allocated memory at most once. If possible, reassign the pointer to a null value after deallocating it. This will prevent double-free vulnerabilities since most deallocation functions will perform a null-pointer check before attempting to deallocate the memory.\n\n\n## Example\n\n```cpp\nint* f() {\n\tint *buff = malloc(SIZE*sizeof(int));\n\tdo_stuff(buff);\n\tfree(buff);\n\tint *new_buffer = malloc(SIZE*sizeof(int));\n\tfree(buff); // BAD: If new_buffer is assigned the same address as buff,\n // the memory allocator will free the new buffer memory region,\n // leading to use-after-free problems and memory corruption.\n\treturn new_buffer;\n}\n\n```\n\n## References\n* OWASP: [Doubly freeing memory](https://owasp.org/www-community/vulnerabilities/Doubly_freeing_memory).\n* Common Weakness Enumeration: [CWE-415](https://cwe.mitre.org/data/definitions/415.html).\n", + "markdown": "# Potential double free\nDeallocating memory more than once can lead to a double-free vulnerability. This can be exploited to corrupt the allocator's internal data structures, which can lead to denial-of-service attacks by crashing the program, or security vulnerabilities, by allowing an attacker to overwrite arbitrary memory locations.\n\n\n## Recommendation\nEnsure that all execution paths deallocate the allocated memory at most once. If possible, reassign the pointer to a null value after deallocating it. This will prevent double-free vulnerabilities since most deallocation functions will perform a null-pointer check before attempting to deallocate the memory.\n\n\n## Example\n\n```cpp\nint* f() {\n\tint *buff = malloc(SIZE*sizeof(int));\n\tdo_stuff(buff);\n\tfree(buff);\n\tint *new_buffer = malloc(SIZE*sizeof(int));\n\tfree(buff); // BAD: If new_buffer is assigned the same address as buff,\n // the memory allocator will free the new buffer memory region,\n // leading to use-after-free problems and memory corruption.\n\treturn new_buffer;\n}\n\n```\n\n## References\n* OWASP: [Doubly freeing memory](https://owasp.org/www-community/vulnerabilities/Doubly_freeing_memory).\n* Common Weakness Enumeration: [CWE-415](https://cwe.mitre.org/data/definitions/415.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-415" + ], + "description": "Freeing a resource more than once can lead to undefined behavior and cause memory corruption.", + "id": "cpp/double-free", + "kind": "path-problem", + "name": "Potential double free", + "precision": "high", + "problem.severity": "warning", + "security-severity": "9.3" + } + }, + { + "id": "cpp/use-after-free", + "name": "cpp/use-after-free", + "shortDescription": { + "text": "Potential use after free" + }, + "fullDescription": { + "text": "An allocated memory block is used after it has been freed. Behavior in such cases is undefined and can cause memory corruption." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Potential use after free\nThis rule finds accesses through a pointer of a memory location that has already been freed (i.e. through a dangling pointer). Such memory blocks have already been released to the dynamic memory manager, and modifying them can lead to anything from a segfault to memory corruption that would cause subsequent calls to the dynamic memory manger to behave erratically, to a possible security vulnerability.\n\n> WARNING: This check is an approximation, so some results may not be actual defects in the program. It is not possible in general to compute the values of pointers without running the program with all input data.\n\n## Recommendation\nEnsure that all execution paths that access memory through a pointer never access that pointer after it is freed.\n\n\n## Example\n\n```cpp\nvoid f() {\n\tchar* buf = new char[SIZE];\n\t...\n\tif (error) {\n\t\tdelete buf; //error handling has freed the buffer\n\t}\n\t...\n\tlog_contents(buf); //but it is still used here for logging\n\t...\n}\n\n```\n\n## References\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-416](https://cwe.mitre.org/data/definitions/416.html).\n", + "markdown": "# Potential use after free\nThis rule finds accesses through a pointer of a memory location that has already been freed (i.e. through a dangling pointer). Such memory blocks have already been released to the dynamic memory manager, and modifying them can lead to anything from a segfault to memory corruption that would cause subsequent calls to the dynamic memory manger to behave erratically, to a possible security vulnerability.\n\n> WARNING: This check is an approximation, so some results may not be actual defects in the program. It is not possible in general to compute the values of pointers without running the program with all input data.\n\n## Recommendation\nEnsure that all execution paths that access memory through a pointer never access that pointer after it is freed.\n\n\n## Example\n\n```cpp\nvoid f() {\n\tchar* buf = new char[SIZE];\n\t...\n\tif (error) {\n\t\tdelete buf; //error handling has freed the buffer\n\t}\n\t...\n\tlog_contents(buf); //but it is still used here for logging\n\t...\n}\n\n```\n\n## References\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-416](https://cwe.mitre.org/data/definitions/416.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-416" + ], + "description": "An allocated memory block is used after it has been freed. Behavior in such cases is undefined and can cause memory corruption.", + "id": "cpp/use-after-free", + "kind": "path-problem", + "name": "Potential use after free", + "precision": "high", + "problem.severity": "warning", + "security-severity": "9.3" + } + }, + { + "id": "cpp/incorrectly-checked-scanf", + "name": "cpp/incorrectly-checked-scanf", + "shortDescription": { + "text": "Incorrect return-value check for a 'scanf'-like function" + }, + "fullDescription": { + "text": "Failing to account for EOF in a call to a scanf-like function can lead to undefined behavior." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Incorrect return-value check for a 'scanf'-like function\nThis query finds calls of `scanf`-like functions with improper return-value checking. Specifically, it flags uses of `scanf` where the return value is only checked against zero.\n\nFunctions in the `scanf` family return either `EOF` (a negative value) in case of IO failure, or the number of items successfully read from the input. Consequently, a simple check that the return value is nonzero is not enough.\n\n\n## Recommendation\nEnsure that all uses of `scanf` check the return value against the expected number of arguments rather than just against zero.\n\n\n## Example\nThe following examples show different ways of guarding a `scanf` output. In the BAD examples, the results are only checked against zero. In the GOOD examples, the results are checked against the expected number of matches instead.\n\n\n```cpp\n{\n int i, j;\n\n // BAD: The result is only checked against zero\n if (scanf(\"%d %d\", &i, &j)) { \n use(i);\n use(j);\n }\n\n // BAD: The result is only checked against zero\n if (scanf(\"%d %d\", &i, &j) == 0) { \n i = 0;\n j = 0;\n }\n use(i);\n use(j);\n\n if (scanf(\"%d %d\", &i, &j) == 2) { \n // GOOD: the result is checked against 2\n }\n\n // GOOD: the result is compared directly\n int r = scanf(\"%d %d\", &i, &j);\n if (r < 2) {\n return;\n }\n if (r == 1) { \n j = 0;\n }\n}\n\n```\n\n## References\n* SEI CERT C++ Coding Standard: [ERR62-CPP. Detect errors when converting a string to a number](https://wiki.sei.cmu.edu/confluence/display/cplusplus/ERR62-CPP.+Detect+errors+when+converting+a+string+to+a+number).\n* SEI CERT C Coding Standard: [ERR33-C. Detect and handle standard library errors](https://wiki.sei.cmu.edu/confluence/display/c/ERR33-C.+Detect+and+handle+standard+library+errors).\n* cppreference.com: [scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s](https://en.cppreference.com/w/c/io/fscanf).\n* Common Weakness Enumeration: [CWE-253](https://cwe.mitre.org/data/definitions/253.html).\n", + "markdown": "# Incorrect return-value check for a 'scanf'-like function\nThis query finds calls of `scanf`-like functions with improper return-value checking. Specifically, it flags uses of `scanf` where the return value is only checked against zero.\n\nFunctions in the `scanf` family return either `EOF` (a negative value) in case of IO failure, or the number of items successfully read from the input. Consequently, a simple check that the return value is nonzero is not enough.\n\n\n## Recommendation\nEnsure that all uses of `scanf` check the return value against the expected number of arguments rather than just against zero.\n\n\n## Example\nThe following examples show different ways of guarding a `scanf` output. In the BAD examples, the results are only checked against zero. In the GOOD examples, the results are checked against the expected number of matches instead.\n\n\n```cpp\n{\n int i, j;\n\n // BAD: The result is only checked against zero\n if (scanf(\"%d %d\", &i, &j)) { \n use(i);\n use(j);\n }\n\n // BAD: The result is only checked against zero\n if (scanf(\"%d %d\", &i, &j) == 0) { \n i = 0;\n j = 0;\n }\n use(i);\n use(j);\n\n if (scanf(\"%d %d\", &i, &j) == 2) { \n // GOOD: the result is checked against 2\n }\n\n // GOOD: the result is compared directly\n int r = scanf(\"%d %d\", &i, &j);\n if (r < 2) {\n return;\n }\n if (r == 1) { \n j = 0;\n }\n}\n\n```\n\n## References\n* SEI CERT C++ Coding Standard: [ERR62-CPP. Detect errors when converting a string to a number](https://wiki.sei.cmu.edu/confluence/display/cplusplus/ERR62-CPP.+Detect+errors+when+converting+a+string+to+a+number).\n* SEI CERT C Coding Standard: [ERR33-C. Detect and handle standard library errors](https://wiki.sei.cmu.edu/confluence/display/c/ERR33-C.+Detect+and+handle+standard+library+errors).\n* cppreference.com: [scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s](https://en.cppreference.com/w/c/io/fscanf).\n* Common Weakness Enumeration: [CWE-253](https://cwe.mitre.org/data/definitions/253.html).\n" + }, + "properties": { + "tags": [ + "security", + "correctness", + "external/cwe/cwe-253" + ], + "description": "Failing to account for EOF in a call to a scanf-like function can lead to\n undefined behavior.", + "id": "cpp/incorrectly-checked-scanf", + "kind": "problem", + "name": "Incorrect return-value check for a 'scanf'-like function", + "precision": "high", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/static-buffer-overflow", + "name": "cpp/static-buffer-overflow", + "shortDescription": { + "text": "Static array access may cause overflow" + }, + "fullDescription": { + "text": "Exceeding the size of a static array during write or access operations may result in a buffer overflow." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Static array access may cause overflow\nWhen 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.\n\n\n## Recommendation\nCheck the offsets and sizes used in the highlighted operations to ensure that a buffer overflow will not occur.\n\n\n## Example\n\n```cpp\n#define SIZE 30\n\nint f(char * s) {\n\tchar buf[20]; //buf not set to use SIZE macro\n\n\tstrncpy(buf, s, SIZE); //wrong: copy may exceed size of buf\n\n\tfor (int i = 0; i < SIZE; i++) { //wrong: upper limit that is higher than array size\n\t\tcout << array[i];\n\t}\n}\n\n```\n\n## References\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html).\n* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html).\n", + "markdown": "# Static array access may cause overflow\nWhen 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.\n\n\n## Recommendation\nCheck the offsets and sizes used in the highlighted operations to ensure that a buffer overflow will not occur.\n\n\n## Example\n\n```cpp\n#define SIZE 30\n\nint f(char * s) {\n\tchar buf[20]; //buf not set to use SIZE macro\n\n\tstrncpy(buf, s, SIZE); //wrong: copy may exceed size of buf\n\n\tfor (int i = 0; i < SIZE; i++) { //wrong: upper limit that is higher than array size\n\t\tcout << array[i];\n\t}\n}\n\n```\n\n## References\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html).\n* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-119", + "external/cwe/cwe-131" + ], + "description": "Exceeding the size of a static array during write or access operations\n may result in a buffer overflow.", + "id": "cpp/static-buffer-overflow", + "kind": "problem", + "name": "Static array access may cause overflow", + "precision": "high", + "problem.severity": "warning", + "security-severity": "9.3" + } + }, + { + "id": "cpp/unsafe-strncat", + "name": "cpp/unsafe-strncat", + "shortDescription": { + "text": "Potentially unsafe call to strncat" + }, + "fullDescription": { + "text": "Calling 'strncat' with an incorrect size argument may result in a buffer overflow." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Potentially unsafe call to strncat\nThe 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.\n\nCalls 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.\n\nSimilarly, calls of the form `strncat(dest, src, sizeof (dest) - strlen (dest))` allow one byte to be written outside the `dest` buffer.\n\nBuffer overflows can lead to anything from a segmentation fault to a security vulnerability.\n\n\n## Recommendation\nCheck 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.\n\n\n## Example\n\n```cpp\nstrncat(dest, src, strlen(dest)); //wrong: should use remaining size of dest\n\nstrncat(dest, src, sizeof(dest)); //wrong: should use remaining size of dest. \n //Also fails if dest is a pointer and not an array.\n \nstrncat(dest, source, sizeof(dest) - strlen(dest)); // wrong: writes a zero byte past the `dest` buffer.\n\nstrncat(dest, source, sizeof(dest) - strlen(dest) - 1); // correct: reserves space for the zero byte.\n\n```\n\n## References\n* cplusplus.com: [strncat](http://www.cplusplus.com/reference/clibrary/cstring/strncat/), [strncpy](http://www.cplusplus.com/reference/clibrary/cstring/strncpy/).\n* I. Gerg, *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4, 2005.\n* M. Donaldson, *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room, 2002.\n* CERT C Coding Standard: [STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator](https://wiki.sei.cmu.edu/confluence/display/c/STR31-C.+Guarantee+that+storage+for+strings+has+sufficient+space+for+character+data+and+the+null+terminator).\n* Common Weakness Enumeration: [CWE-788](https://cwe.mitre.org/data/definitions/788.html).\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html).\n* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html).\n", + "markdown": "# Potentially unsafe call to strncat\nThe 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.\n\nCalls 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.\n\nSimilarly, calls of the form `strncat(dest, src, sizeof (dest) - strlen (dest))` allow one byte to be written outside the `dest` buffer.\n\nBuffer overflows can lead to anything from a segmentation fault to a security vulnerability.\n\n\n## Recommendation\nCheck 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.\n\n\n## Example\n\n```cpp\nstrncat(dest, src, strlen(dest)); //wrong: should use remaining size of dest\n\nstrncat(dest, src, sizeof(dest)); //wrong: should use remaining size of dest. \n //Also fails if dest is a pointer and not an array.\n \nstrncat(dest, source, sizeof(dest) - strlen(dest)); // wrong: writes a zero byte past the `dest` buffer.\n\nstrncat(dest, source, sizeof(dest) - strlen(dest) - 1); // correct: reserves space for the zero byte.\n\n```\n\n## References\n* cplusplus.com: [strncat](http://www.cplusplus.com/reference/clibrary/cstring/strncat/), [strncpy](http://www.cplusplus.com/reference/clibrary/cstring/strncpy/).\n* I. Gerg, *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4, 2005.\n* M. Donaldson, *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room, 2002.\n* CERT C Coding Standard: [STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator](https://wiki.sei.cmu.edu/confluence/display/c/STR31-C.+Guarantee+that+storage+for+strings+has+sufficient+space+for+character+data+and+the+null+terminator).\n* Common Weakness Enumeration: [CWE-788](https://cwe.mitre.org/data/definitions/788.html).\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html).\n* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "correctness", + "security", + "external/cwe/cwe-788", + "external/cwe/cwe-676", + "external/cwe/cwe-119", + "external/cwe/cwe-251" + ], + "description": "Calling 'strncat' with an incorrect size argument may result in a buffer overflow.", + "id": "cpp/unsafe-strncat", + "kind": "problem", + "name": "Potentially unsafe call to strncat", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "9.3" + } + }, + { + "id": "cpp/bad-strncpy-size", + "name": "cpp/bad-strncpy-size", + "shortDescription": { + "text": "Possibly wrong buffer size in string copy" + }, + "fullDescription": { + "text": "Calling 'strncpy' with the size of the source buffer as the third argument may result in a buffer overflow." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Possibly wrong buffer size in string copy\nThe 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.\n\n\n## Recommendation\nCheck the highlighted function calls carefully, and ensure that the size parameter is derived from the size of the destination buffer, not the source buffer.\n\n\n## Example\n\n```cpp\nstrncpy(dest, src, sizeof(src)); //wrong: size of dest should be used\nstrncpy(dest, src, strlen(src)); //wrong: size of dest should be used\n\n```\n\n## References\n* cplusplus.com: [strncpy](http://www.cplusplus.com/reference/clibrary/cstring/strncpy/).\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html).\n* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html).\n", + "markdown": "# Possibly wrong buffer size in string copy\nThe 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.\n\n\n## Recommendation\nCheck the highlighted function calls carefully, and ensure that the size parameter is derived from the size of the destination buffer, not the source buffer.\n\n\n## Example\n\n```cpp\nstrncpy(dest, src, sizeof(src)); //wrong: size of dest should be used\nstrncpy(dest, src, strlen(src)); //wrong: size of dest should be used\n\n```\n\n## References\n* cplusplus.com: [strncpy](http://www.cplusplus.com/reference/clibrary/cstring/strncpy/).\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html).\n* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "correctness", + "security", + "external/cwe/cwe-676", + "external/cwe/cwe-119", + "external/cwe/cwe-251" + ], + "description": "Calling 'strncpy' with the size of the source buffer\n as the third argument may result in a buffer overflow.", + "id": "cpp/bad-strncpy-size", + "kind": "problem", + "name": "Possibly wrong buffer size in string copy", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "9.3" + } + }, + { + "id": "cpp/unsafe-strcat", + "name": "cpp/unsafe-strcat", + "shortDescription": { + "text": "Potentially unsafe use of strcat" + }, + "fullDescription": { + "text": "Using 'strcat' without checking the size of the source string may result in a buffer overflow" + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Potentially unsafe use of strcat\nThe 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.\n\n\n## Recommendation\nCheck 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.\n\n\n## Example\n\n```cpp\nvoid f(char *s) {\n\tchar buf[80];\n\tstrcpy(buf, \"s: \");\n\tstrcat(buf, s); // wrong: buffer not checked before strcat\n}\n\nvoid g(char *s) {\n\tchar buf[80];\n\tstrcpy(buf, \"s: \");\n\tif(strlen(s) < 77)\n\t\tstrcat(buf, s); // correct: buffer size checked before strcat\n}\n\n```\n\n## References\n* I. Gerg, *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7, no 4, 2005.\n* M. Donaldson, *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html).\n", + "markdown": "# Potentially unsafe use of strcat\nThe 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.\n\n\n## Recommendation\nCheck 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.\n\n\n## Example\n\n```cpp\nvoid f(char *s) {\n\tchar buf[80];\n\tstrcpy(buf, \"s: \");\n\tstrcat(buf, s); // wrong: buffer not checked before strcat\n}\n\nvoid g(char *s) {\n\tchar buf[80];\n\tstrcpy(buf, \"s: \");\n\tif(strlen(s) < 77)\n\t\tstrcat(buf, s); // correct: buffer size checked before strcat\n}\n\n```\n\n## References\n* I. Gerg, *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7, no 4, 2005.\n* M. Donaldson, *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-251](https://cwe.mitre.org/data/definitions/251.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "correctness", + "security", + "external/cwe/cwe-676", + "external/cwe/cwe-120", + "external/cwe/cwe-251" + ], + "description": "Using 'strcat' without checking the size of the source string\n may result in a buffer overflow", + "id": "cpp/unsafe-strcat", + "kind": "problem", + "name": "Potentially unsafe use of strcat", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "9.8" + } + }, + { + "id": "cpp/uninitialized-local", + "name": "cpp/uninitialized-local", + "shortDescription": { + "text": "Potentially uninitialized local variable" + }, + "fullDescription": { + "text": "Reading from a local variable that has not been assigned to will typically yield garbage." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Potentially uninitialized local variable\nA 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`.\n\n\n## Recommendation\nReview the code and consider whether the variable should have an initializer or whether some path through the program lacks an assignment to the variable.\n\n\n## Example\nThe 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.\n\n\n```cpp\nint absWrong(int i) {\n\tint j;\n\tif (i > 0) {\n\t\tj = i;\n\t} else if (i < 0) {\n\t\tj = -i;\n\t}\n\treturn j; // wrong: j may not be initialized before use\n}\n\nint absCorrect1(int i) {\n\tint j = 0;\n\tif (i > 0) {\n\t\tj = i;\n\t} else if (i < 0) {\n\t\tj = -i;\n\t}\n\treturn j; // correct: j always initialized before use\n}\n\nint absCorrect2(int i) {\n\tint j;\n\tif (i > 0) {\n\t\tj = i;\n\t} else if (i < 0) {\n\t\tj = -i;\n\t} else {\n\t\tj = 0;\n\t}\n\treturn j; // correct: j always initialized before use\n}\n```\n\n## References\n* ISO/IEC 9899:2011: [Programming languages - C (Section 6.3.2.1)](https://www.iso.org/standard/57853.html).\n* Common Weakness Enumeration: [CWE-665](https://cwe.mitre.org/data/definitions/665.html).\n* Common Weakness Enumeration: [CWE-457](https://cwe.mitre.org/data/definitions/457.html).\n", + "markdown": "# Potentially uninitialized local variable\nA 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`.\n\n\n## Recommendation\nReview the code and consider whether the variable should have an initializer or whether some path through the program lacks an assignment to the variable.\n\n\n## Example\nThe 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.\n\n\n```cpp\nint absWrong(int i) {\n\tint j;\n\tif (i > 0) {\n\t\tj = i;\n\t} else if (i < 0) {\n\t\tj = -i;\n\t}\n\treturn j; // wrong: j may not be initialized before use\n}\n\nint absCorrect1(int i) {\n\tint j = 0;\n\tif (i > 0) {\n\t\tj = i;\n\t} else if (i < 0) {\n\t\tj = -i;\n\t}\n\treturn j; // correct: j always initialized before use\n}\n\nint absCorrect2(int i) {\n\tint j;\n\tif (i > 0) {\n\t\tj = i;\n\t} else if (i < 0) {\n\t\tj = -i;\n\t} else {\n\t\tj = 0;\n\t}\n\treturn j; // correct: j always initialized before use\n}\n```\n\n## References\n* ISO/IEC 9899:2011: [Programming languages - C (Section 6.3.2.1)](https://www.iso.org/standard/57853.html).\n* Common Weakness Enumeration: [CWE-665](https://cwe.mitre.org/data/definitions/665.html).\n* Common Weakness Enumeration: [CWE-457](https://cwe.mitre.org/data/definitions/457.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-665", + "external/cwe/cwe-457" + ], + "description": "Reading from a local variable that has not been assigned to\n will typically yield garbage.", + "id": "cpp/uninitialized-local", + "kind": "problem", + "name": "Potentially uninitialized local variable", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "7.8" + } + }, + { + "id": "cpp/suspicious-sizeof", + "name": "cpp/suspicious-sizeof", + "shortDescription": { + "text": "Suspicious 'sizeof' use" + }, + "fullDescription": { + "text": "Taking 'sizeof' of an array parameter is often mistakenly thought to yield the size of the underlying array, but it always yields the machine pointer size." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Suspicious 'sizeof' use\nThis 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.\n\n\n## Recommendation\nModify the function to take an extra argument indicating the buffer size.\n\n\n## Example\n\n```cpp\nvoid f(char s[]) {\n\tint size = sizeof(s); //wrong: s is now a char*, not an array. \n\t //sizeof(s) will evaluate to sizeof(char *)\n}\n\n```\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-467](https://cwe.mitre.org/data/definitions/467.html).\n", + "markdown": "# Suspicious 'sizeof' use\nThis 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.\n\n\n## Recommendation\nModify the function to take an extra argument indicating the buffer size.\n\n\n## Example\n\n```cpp\nvoid f(char s[]) {\n\tint size = sizeof(s); //wrong: s is now a char*, not an array. \n\t //sizeof(s) will evaluate to sizeof(char *)\n}\n\n```\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-467](https://cwe.mitre.org/data/definitions/467.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "correctness", + "security", + "external/cwe/cwe-467" + ], + "description": "Taking 'sizeof' of an array parameter is often mistakenly thought\n to yield the size of the underlying array, but it always yields\n the machine pointer size.", + "id": "cpp/suspicious-sizeof", + "kind": "problem", + "name": "Suspicious 'sizeof' use", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "8.8" + } + }, + { + "id": "cpp/incorrect-not-operator-usage", + "name": "cpp/incorrect-not-operator-usage", + "shortDescription": { + "text": "Incorrect 'not' operator usage" + }, + "fullDescription": { + "text": "Usage of a logical-not (!) operator as an operand for a bit-wise operation. This commonly indicates the usage of an incorrect operator instead of the bit-wise not (~) operator, also known as ones' complement operator." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Incorrect 'not' operator usage\nThis rule finds logical-not operator usage as an operator for in a bit-wise operation.\n\nDue 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 operations. Violations are often indicative of a typo, using a logical-not (`!`) operator instead of the bit-wise not (`~`) operator.\n\nThis rule is restricted to analyze bit-wise and (`&`) and bit-wise or (`|`) operation in order to provide better precision.\n\nThis rule ignores instances where a double negation (`!!`) is explicitly used as the operator of the bitwise operation, as this is a commonly used as a mechanism to normalize an integer value to either 1 or 0.\n\nNOTE: It is not recommended to use this rule in kernel code or older C code as it will likely find several false positive instances.\n\n\n## Recommendation\nCarefully inspect the flagged expressions. Consider the intent in the code logic, and decide whether it is necessary to change the not operator.\n\n\n## Example\n\n```cpp\n#define FLAGS 0x4004\n\nvoid f_warning(int i)\n{\n // The usage of the logical not operator in this case is unlikely to be correct\n // as the output is being used as an operator for a bit-wise and operation\n if (i & !FLAGS) \n {\n // code\n }\n}\n\n\nvoid f_fixed(int i)\n{\n if (i & ~FLAGS) // Changing the logical not operator for the bit-wise not operator would fix this logic\n {\n // code\n }\n}\n```\n\n## References\n* [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)\n* Common Weakness Enumeration: [CWE-480](https://cwe.mitre.org/data/definitions/480.html).\n", + "markdown": "# Incorrect 'not' operator usage\nThis rule finds logical-not operator usage as an operator for in a bit-wise operation.\n\nDue 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 operations. Violations are often indicative of a typo, using a logical-not (`!`) operator instead of the bit-wise not (`~`) operator.\n\nThis rule is restricted to analyze bit-wise and (`&`) and bit-wise or (`|`) operation in order to provide better precision.\n\nThis rule ignores instances where a double negation (`!!`) is explicitly used as the operator of the bitwise operation, as this is a commonly used as a mechanism to normalize an integer value to either 1 or 0.\n\nNOTE: It is not recommended to use this rule in kernel code or older C code as it will likely find several false positive instances.\n\n\n## Recommendation\nCarefully inspect the flagged expressions. Consider the intent in the code logic, and decide whether it is necessary to change the not operator.\n\n\n## Example\n\n```cpp\n#define FLAGS 0x4004\n\nvoid f_warning(int i)\n{\n // The usage of the logical not operator in this case is unlikely to be correct\n // as the output is being used as an operator for a bit-wise and operation\n if (i & !FLAGS) \n {\n // code\n }\n}\n\n\nvoid f_fixed(int i)\n{\n if (i & ~FLAGS) // Changing the logical not operator for the bit-wise not operator would fix this logic\n {\n // code\n }\n}\n```\n\n## References\n* [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)\n* Common Weakness Enumeration: [CWE-480](https://cwe.mitre.org/data/definitions/480.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-480" + ], + "description": "Usage of a logical-not (!) operator as an operand for a bit-wise operation.\n This commonly indicates the usage of an incorrect operator instead of the bit-wise not (~) operator,\n also known as ones' complement operator.", + "id": "cpp/incorrect-not-operator-usage", + "kind": "problem", + "name": "Incorrect 'not' operator usage", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/offset-use-before-range-check", + "name": "cpp/offset-use-before-range-check", + "shortDescription": { + "text": "Array offset used before range check" + }, + "fullDescription": { + "text": "Accessing an array offset before checking the range means that the program may attempt to read beyond the end of a buffer" + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Array offset used before range check\nThe 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.\n\n\n## Recommendation\nUpdate 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.\n\n\n## Example\nThe `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).\n\n\n```c\nint find(int start, char *str, char goal)\n{\n int len = strlen(str);\n //Potential buffer overflow\n for (int i = start; str[i] != 0 && i < len; i++) { \n if (str[i] == goal)\n return i; \n }\n return -1;\n}\n\nint findRangeCheck(int start, char *str, char goal)\n{\n int len = strlen(str);\n //Range check protects against buffer overflow\n for (int i = start; i < len && str[i] != 0 ; i++) {\n if (str[i] == goal)\n return i; \n }\n return -1;\n}\n\n\n\n\n```\nUpdate the and-expression so that the range check precedes the array offset (for example, the `findRangeCheck` function).\n\n\n## References\n* cplusplus.com: [ C++: array](http://www.cplusplus.com/reference/array/array/).\n* Wikipedia: [ Bounds checking](http://en.wikipedia.org/wiki/Bounds_checking).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-125](https://cwe.mitre.org/data/definitions/125.html).\n", + "markdown": "# Array offset used before range check\nThe 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.\n\n\n## Recommendation\nUpdate 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.\n\n\n## Example\nThe `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).\n\n\n```c\nint find(int start, char *str, char goal)\n{\n int len = strlen(str);\n //Potential buffer overflow\n for (int i = start; str[i] != 0 && i < len; i++) { \n if (str[i] == goal)\n return i; \n }\n return -1;\n}\n\nint findRangeCheck(int start, char *str, char goal)\n{\n int len = strlen(str);\n //Range check protects against buffer overflow\n for (int i = start; i < len && str[i] != 0 ; i++) {\n if (str[i] == goal)\n return i; \n }\n return -1;\n}\n\n\n\n\n```\nUpdate the and-expression so that the range check precedes the array offset (for example, the `findRangeCheck` function).\n\n\n## References\n* cplusplus.com: [ C++: array](http://www.cplusplus.com/reference/array/array/).\n* Wikipedia: [ Bounds checking](http://en.wikipedia.org/wiki/Bounds_checking).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-125](https://cwe.mitre.org/data/definitions/125.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-120", + "external/cwe/cwe-125" + ], + "description": "Accessing an array offset before checking the range means that\n the program may attempt to read beyond the end of a buffer", + "id": "cpp/offset-use-before-range-check", + "kind": "problem", + "name": "Array offset used before range check", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "8.2" + } + }, + { + "id": "cpp/comma-before-misleading-indentation", + "name": "cpp/comma-before-misleading-indentation", + "shortDescription": { + "text": "Comma before misleading indentation" + }, + "fullDescription": { + "text": "If expressions before and after a comma operator use different indentation, it is easy to misread the purpose of the code." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Comma before misleading indentation\nIf the expression after the comma operator starts at an earlier column than the expression before the comma, then this suspicious indentation possibly indicates a logic error, caused by a typo that may escape visual inspection.\n\n> WARNING: This query has medium precision because CodeQL currently does not distinguish between tabs and spaces in whitespace. If a file contains mixed tabs and spaces, alerts may highlight code that is correctly indented for one value of tab size but not for other tab sizes.\n\n## Recommendation\nTo ensure that your code is easy to read and review, use standard indentation around the comma operator. Always begin the right-hand-side operand at the same level of indentation (column number) as the left-hand-side operand. This makes it easier for other developers to see the intended behavior of your code.\n\nUse whitespace consistently to communicate your coding intentions. Where possible, avoid mixing tabs and spaces within a file. If you need to mix them, use them consistently.\n\n\n## Example\nThis example shows three different ways of writing the same code. The first example contains a comma instead of a semicolon which means that the final line is part of the `if` statement, even though the indentation suggests that it is intended to be separate. The second example looks different but is functionally the same as the first example. It is more likely that the developer intended to write the third example.\n\n\n```cpp\n/*\n * In this example, the developer intended to use a semicolon but accidentally used a comma:\n */\n\nenum privileges entitlements = NONE;\n\nif (is_admin)\n entitlements = FULL, // BAD\n\nrestrict_privileges(entitlements);\n\n/*\n * The use of a comma means that the first example is equivalent to this second example:\n */\n\nenum privileges entitlements = NONE;\n\nif (is_admin) {\n entitlements = FULL;\n restrict_privileges(entitlements);\n}\n\n/*\n * The indentation of the first example suggests that the developer probably intended the following code:\n */\n\nenum privileges entitlements = NONE;\n\nif (is_admin)\n entitlements = FULL; // GOOD\n\nrestrict_privileges(entitlements);\n\n```\n\n## References\n* Wikipedia: [Comma operator](https://en.wikipedia.org/wiki/Comma_operator)\n* Wikipedia: [Indentation style — Tabs, spaces, and size of indentations](https://en.wikipedia.org/wiki/Indentation_style#Tabs,_spaces,_and_size_of_indentations)\n* Common Weakness Enumeration: [CWE-1078](https://cwe.mitre.org/data/definitions/1078.html).\n* Common Weakness Enumeration: [CWE-670](https://cwe.mitre.org/data/definitions/670.html).\n", + "markdown": "# Comma before misleading indentation\nIf the expression after the comma operator starts at an earlier column than the expression before the comma, then this suspicious indentation possibly indicates a logic error, caused by a typo that may escape visual inspection.\n\n> WARNING: This query has medium precision because CodeQL currently does not distinguish between tabs and spaces in whitespace. If a file contains mixed tabs and spaces, alerts may highlight code that is correctly indented for one value of tab size but not for other tab sizes.\n\n## Recommendation\nTo ensure that your code is easy to read and review, use standard indentation around the comma operator. Always begin the right-hand-side operand at the same level of indentation (column number) as the left-hand-side operand. This makes it easier for other developers to see the intended behavior of your code.\n\nUse whitespace consistently to communicate your coding intentions. Where possible, avoid mixing tabs and spaces within a file. If you need to mix them, use them consistently.\n\n\n## Example\nThis example shows three different ways of writing the same code. The first example contains a comma instead of a semicolon which means that the final line is part of the `if` statement, even though the indentation suggests that it is intended to be separate. The second example looks different but is functionally the same as the first example. It is more likely that the developer intended to write the third example.\n\n\n```cpp\n/*\n * In this example, the developer intended to use a semicolon but accidentally used a comma:\n */\n\nenum privileges entitlements = NONE;\n\nif (is_admin)\n entitlements = FULL, // BAD\n\nrestrict_privileges(entitlements);\n\n/*\n * The use of a comma means that the first example is equivalent to this second example:\n */\n\nenum privileges entitlements = NONE;\n\nif (is_admin) {\n entitlements = FULL;\n restrict_privileges(entitlements);\n}\n\n/*\n * The indentation of the first example suggests that the developer probably intended the following code:\n */\n\nenum privileges entitlements = NONE;\n\nif (is_admin)\n entitlements = FULL; // GOOD\n\nrestrict_privileges(entitlements);\n\n```\n\n## References\n* Wikipedia: [Comma operator](https://en.wikipedia.org/wiki/Comma_operator)\n* Wikipedia: [Indentation style — Tabs, spaces, and size of indentations](https://en.wikipedia.org/wiki/Indentation_style#Tabs,_spaces,_and_size_of_indentations)\n* Common Weakness Enumeration: [CWE-1078](https://cwe.mitre.org/data/definitions/1078.html).\n* Common Weakness Enumeration: [CWE-670](https://cwe.mitre.org/data/definitions/670.html).\n" + }, + "properties": { + "tags": [ + "maintainability", + "readability", + "security", + "external/cwe/cwe-1078", + "external/cwe/cwe-670" + ], + "description": "If expressions before and after a comma operator use different indentation, it is easy to misread the purpose of the code.", + "id": "cpp/comma-before-misleading-indentation", + "kind": "problem", + "name": "Comma before misleading indentation", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "7.8" + } + }, + { + "id": "cpp/incorrect-allocation-error-handling", + "name": "cpp/incorrect-allocation-error-handling", + "shortDescription": { + "text": "Incorrect allocation-error handling" + }, + "fullDescription": { + "text": "Mixing up the failure conditions of 'operator new' and 'operator new(std::nothrow)' can result in unexpected behavior." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Incorrect allocation-error handling\nDifferent overloads of the `new` operator handle allocation failures in different ways. If `new T` fails for some type `T`, it throws a `std::bad_alloc` exception, but `new(std::nothrow) T` returns a null pointer. If the programmer does not use the corresponding method of error handling, allocation failure may go unhandled and could cause the program to behave in unexpected ways.\n\n\n## Recommendation\nMake sure that exceptions are handled appropriately if `new T` is used. On the other hand, make sure to handle the possibility of null pointers if `new(std::nothrow) T` is used.\n\n\n## Example\n\n```cpp\n// BAD: the allocation will throw an unhandled exception\n// instead of returning a null pointer.\nvoid bad1(std::size_t length) noexcept {\n int* dest = new int[length];\n if(!dest) {\n return;\n }\n std::memset(dest, 0, length);\n // ...\n}\n\n// BAD: the allocation won't throw an exception, but\n// instead return a null pointer.\nvoid bad2(std::size_t length) noexcept {\n try {\n int* dest = new(std::nothrow) int[length];\n std::memset(dest, 0, length);\n // ...\n } catch(std::bad_alloc&) {\n // ...\n }\n}\n\n// GOOD: the allocation failure is handled appropriately.\nvoid good1(std::size_t length) noexcept {\n try {\n int* dest = new int[length];\n std::memset(dest, 0, length);\n // ...\n } catch(std::bad_alloc&) {\n // ...\n }\n}\n\n// GOOD: the allocation failure is handled appropriately.\nvoid good2(std::size_t length) noexcept {\n int* dest = new int[length];\n if(!dest) {\n return;\n }\n std::memset(dest, 0, length);\n // ...\n}\n\n```\n\n## References\n* CERT C++ Coding Standard: [MEM52-CPP. Detect and handle memory allocation errors](https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM52-CPP.+Detect+and+handle+memory+allocation+errors).\n* Common Weakness Enumeration: [CWE-570](https://cwe.mitre.org/data/definitions/570.html).\n* Common Weakness Enumeration: [CWE-252](https://cwe.mitre.org/data/definitions/252.html).\n* Common Weakness Enumeration: [CWE-755](https://cwe.mitre.org/data/definitions/755.html).\n", + "markdown": "# Incorrect allocation-error handling\nDifferent overloads of the `new` operator handle allocation failures in different ways. If `new T` fails for some type `T`, it throws a `std::bad_alloc` exception, but `new(std::nothrow) T` returns a null pointer. If the programmer does not use the corresponding method of error handling, allocation failure may go unhandled and could cause the program to behave in unexpected ways.\n\n\n## Recommendation\nMake sure that exceptions are handled appropriately if `new T` is used. On the other hand, make sure to handle the possibility of null pointers if `new(std::nothrow) T` is used.\n\n\n## Example\n\n```cpp\n// BAD: the allocation will throw an unhandled exception\n// instead of returning a null pointer.\nvoid bad1(std::size_t length) noexcept {\n int* dest = new int[length];\n if(!dest) {\n return;\n }\n std::memset(dest, 0, length);\n // ...\n}\n\n// BAD: the allocation won't throw an exception, but\n// instead return a null pointer.\nvoid bad2(std::size_t length) noexcept {\n try {\n int* dest = new(std::nothrow) int[length];\n std::memset(dest, 0, length);\n // ...\n } catch(std::bad_alloc&) {\n // ...\n }\n}\n\n// GOOD: the allocation failure is handled appropriately.\nvoid good1(std::size_t length) noexcept {\n try {\n int* dest = new int[length];\n std::memset(dest, 0, length);\n // ...\n } catch(std::bad_alloc&) {\n // ...\n }\n}\n\n// GOOD: the allocation failure is handled appropriately.\nvoid good2(std::size_t length) noexcept {\n int* dest = new int[length];\n if(!dest) {\n return;\n }\n std::memset(dest, 0, length);\n // ...\n}\n\n```\n\n## References\n* CERT C++ Coding Standard: [MEM52-CPP. Detect and handle memory allocation errors](https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM52-CPP.+Detect+and+handle+memory+allocation+errors).\n* Common Weakness Enumeration: [CWE-570](https://cwe.mitre.org/data/definitions/570.html).\n* Common Weakness Enumeration: [CWE-252](https://cwe.mitre.org/data/definitions/252.html).\n* Common Weakness Enumeration: [CWE-755](https://cwe.mitre.org/data/definitions/755.html).\n" + }, + "properties": { + "tags": [ + "correctness", + "security", + "external/cwe/cwe-570", + "external/cwe/cwe-252", + "external/cwe/cwe-755" + ], + "description": "Mixing up the failure conditions of 'operator new' and 'operator new(std::nothrow)' can result in unexpected behavior.", + "id": "cpp/incorrect-allocation-error-handling", + "kind": "problem", + "name": "Incorrect allocation-error handling", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/unsafe-create-process-call", + "name": "cpp/unsafe-create-process-call", + "shortDescription": { + "text": "NULL application name with an unquoted path in call to CreateProcess" + }, + "fullDescription": { + "text": "Calling a function of the CreateProcess* family of functions, where the path contains spaces, introduces a security vulnerability." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# NULL application name with an unquoted path in call to CreateProcess\nThis query indicates that there is a call to a function of the `CreateProcess*` family of functions, which introduces a security vulnerability.\n\n\n## Recommendation\nDo not use `NULL` for the `lpApplicationName` argument to the `CreateProcess*` function.\n\nIf you pass `NULL` for `lpApplicationName`, use quotation marks around the executable path in `lpCommandLine`.\n\n\n## Example\nIn 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.\n\nIf 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.\n\n\n```cpp\nSTARTUPINFOW si;\nPROCESS_INFORMATION pi;\n\n// ... \n\nCreateProcessW( // BUG\n NULL, // lpApplicationName\n (LPWSTR)L\"C:\\\\Program Files\\\\MyApp\", // lpCommandLine\n NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);\n\n// ...\n```\nTo fix this issue, specify a valid string for `lpApplicationName`, or quote the path for `lpCommandLine`. For example:\n\n`(LPWSTR)L\"\\\"C:\\\\Program Files\\\\MyApp\\\"\", // lpCommandLine`\n\n\n## References\n* [CreateProcessA function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessa)\n* [CreateProcessW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessw)\n* [CreateProcessAsUserA function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasusera)\n* [CreateProcessAsUserW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw)\n* [CreateProcessWithLogonW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createprocesswithlogonw)\n* [CreateProcessWithTokenW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createprocesswithtokenw)\n* Common Weakness Enumeration: [CWE-428](https://cwe.mitre.org/data/definitions/428.html).\n", + "markdown": "# NULL application name with an unquoted path in call to CreateProcess\nThis query indicates that there is a call to a function of the `CreateProcess*` family of functions, which introduces a security vulnerability.\n\n\n## Recommendation\nDo not use `NULL` for the `lpApplicationName` argument to the `CreateProcess*` function.\n\nIf you pass `NULL` for `lpApplicationName`, use quotation marks around the executable path in `lpCommandLine`.\n\n\n## Example\nIn 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.\n\nIf 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.\n\n\n```cpp\nSTARTUPINFOW si;\nPROCESS_INFORMATION pi;\n\n// ... \n\nCreateProcessW( // BUG\n NULL, // lpApplicationName\n (LPWSTR)L\"C:\\\\Program Files\\\\MyApp\", // lpCommandLine\n NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);\n\n// ...\n```\nTo fix this issue, specify a valid string for `lpApplicationName`, or quote the path for `lpCommandLine`. For example:\n\n`(LPWSTR)L\"\\\"C:\\\\Program Files\\\\MyApp\\\"\", // lpCommandLine`\n\n\n## References\n* [CreateProcessA function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessa)\n* [CreateProcessW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessw)\n* [CreateProcessAsUserA function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasusera)\n* [CreateProcessAsUserW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw)\n* [CreateProcessWithLogonW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createprocesswithlogonw)\n* [CreateProcessWithTokenW function (Microsoft documentation).](https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createprocesswithtokenw)\n* Common Weakness Enumeration: [CWE-428](https://cwe.mitre.org/data/definitions/428.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-428" + ], + "description": "Calling a function of the CreateProcess* family of functions, where the path contains spaces, introduces a security vulnerability.", + "id": "cpp/unsafe-create-process-call", + "kind": "problem", + "msrc.severity": "important", + "name": "NULL application name with an unquoted path in call to CreateProcess", + "precision": "medium", + "problem.severity": "error", + "security-severity": "7.8" + } + }, + { + "id": "cpp/overrunning-write", + "name": "cpp/overrunning-write", + "shortDescription": { + "text": "Potentially overrunning write" + }, + "fullDescription": { + "text": "Buffer write operations that do not control the length of data written may overflow." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Potentially overrunning write\nThe 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.\n\n\n## Recommendation\nAlways 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.\n\n\n## Example\n\n```c\nvoid sayHello(uint32_t userId)\n{\n\tchar buffer[18];\n\n\t// BAD: this message overflows the buffer if userId >= 10000\n\tsprintf(buffer, \"Hello, user %d!\", userId);\n\n\tMessageBox(hWnd, buffer, \"New Message\", MB_OK);\n}\n```\nIn this example, the call to `sprintf` writes a message of 14 characters (including the terminating null) plus the length of the string conversion of \\`userId\\` into a buffer with space for just 18 characters. As such, if \\`userId\\` is greater or equal to \\`10000\\`, the last characters overflow the buffer resulting in undefined behavior.\n\nTo fix this issue these changes should be made:\n\n* Control the size of the buffer by declaring it with a compile time constant.\n* Preferably, replace the call to `sprintf` with `snprintf`, using the defined constant size of the buffer or \\`sizeof(buffer)\\` as maximum length to write. This will prevent the buffer overflow.\n* Optionally, if \\`userId\\` is expected to be less than \\`10000\\`, then return or throw an error if \\`userId\\` is out of bounds.\n* Otherwise, consider increasing the buffer size to at least 25 characters, so that the message is displayed correctly regardless of the value of \\`userId\\`.\n\n## References\n* 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).\n* 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).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html).\n", + "markdown": "# Potentially overrunning write\nThe 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.\n\n\n## Recommendation\nAlways 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.\n\n\n## Example\n\n```c\nvoid sayHello(uint32_t userId)\n{\n\tchar buffer[18];\n\n\t// BAD: this message overflows the buffer if userId >= 10000\n\tsprintf(buffer, \"Hello, user %d!\", userId);\n\n\tMessageBox(hWnd, buffer, \"New Message\", MB_OK);\n}\n```\nIn this example, the call to `sprintf` writes a message of 14 characters (including the terminating null) plus the length of the string conversion of \\`userId\\` into a buffer with space for just 18 characters. As such, if \\`userId\\` is greater or equal to \\`10000\\`, the last characters overflow the buffer resulting in undefined behavior.\n\nTo fix this issue these changes should be made:\n\n* Control the size of the buffer by declaring it with a compile time constant.\n* Preferably, replace the call to `sprintf` with `snprintf`, using the defined constant size of the buffer or \\`sizeof(buffer)\\` as maximum length to write. This will prevent the buffer overflow.\n* Optionally, if \\`userId\\` is expected to be less than \\`10000\\`, then return or throw an error if \\`userId\\` is out of bounds.\n* Otherwise, consider increasing the buffer size to at least 25 characters, so that the message is displayed correctly regardless of the value of \\`userId\\`.\n\n## References\n* 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).\n* 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).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-120", + "external/cwe/cwe-787", + "external/cwe/cwe-805" + ], + "description": "Buffer write operations that do not control the length\n of data written may overflow.", + "id": "cpp/overrunning-write", + "kind": "problem", + "name": "Potentially overrunning write", + "precision": "medium", + "problem.severity": "error", + "security-severity": "9.3" + } + }, + { + "id": "cpp/unbounded-write", + "name": "cpp/unbounded-write", + "shortDescription": { + "text": "Unbounded write" + }, + "fullDescription": { + "text": "Buffer write operations that do not control the length of data written may overflow." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Unbounded write\nThe 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.\n\n\n## Recommendation\nAlways 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.\n\n\n## Example\n\n```c\nvoid congratulateUser(const char *userName)\n{\n\tchar buffer[80];\n\n\t// BAD: this could overflow the buffer if the UserName is long\n\tsprintf(buffer, \"Congratulations, %s!\", userName);\n\n\tMessageBox(hWnd, buffer, \"New Message\", MB_OK);\n}\n```\nIn 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.\n\nTo fix the problem the call to `sprintf` should be replaced with `snprintf`, specifying a maximum length of 80 characters.\n\n\n## References\n* 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).\n* 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).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html).\n", + "markdown": "# Unbounded write\nThe 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.\n\n\n## Recommendation\nAlways 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.\n\n\n## Example\n\n```c\nvoid congratulateUser(const char *userName)\n{\n\tchar buffer[80];\n\n\t// BAD: this could overflow the buffer if the UserName is long\n\tsprintf(buffer, \"Congratulations, %s!\", userName);\n\n\tMessageBox(hWnd, buffer, \"New Message\", MB_OK);\n}\n```\nIn 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.\n\nTo fix the problem the call to `sprintf` should be replaced with `snprintf`, specifying a maximum length of 80 characters.\n\n\n## References\n* 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).\n* 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).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-120", + "external/cwe/cwe-787", + "external/cwe/cwe-805" + ], + "description": "Buffer write operations that do not control the length\n of data written may overflow.", + "id": "cpp/unbounded-write", + "kind": "path-problem", + "name": "Unbounded write", + "precision": "medium", + "problem.severity": "error", + "security-severity": "9.3" + } + }, + { + "id": "cpp/overrunning-write-with-float", + "name": "cpp/overrunning-write-with-float", + "shortDescription": { + "text": "Potentially overrunning write with float to string conversion" + }, + "fullDescription": { + "text": "Buffer write operations that do not control the length of data written may overflow when floating point inputs take extreme values." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Potentially overrunning write with float to string conversion\nThe 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.\n\n\n## Recommendation\nAlways 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.\n\n\n## Example\n\n```c\nvoid displayValue(double value)\n{\n\tchar buffer[256];\n\n\t// BAD: extreme values may overflow the buffer\n\tsprintf(buffer, \"%f\", value);\n\n\tMessageBox(hWnd, buffer, \"A Number\", MB_OK);\n}\n```\nIn 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.\n\nTo fix this issue three changes should be made:\n\n* Control the size of the buffer using a preprocessor define.\n* Replace the call to `sprintf` with `snprintf`, specifying the define as the maximum length to copy. This will prevent the buffer overflow.\n* Consider using the `%g` format specifier instead of `%f`.\n\n## References\n* 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).\n* 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).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html).\n", + "markdown": "# Potentially overrunning write with float to string conversion\nThe 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.\n\n\n## Recommendation\nAlways 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.\n\n\n## Example\n\n```c\nvoid displayValue(double value)\n{\n\tchar buffer[256];\n\n\t// BAD: extreme values may overflow the buffer\n\tsprintf(buffer, \"%f\", value);\n\n\tMessageBox(hWnd, buffer, \"A Number\", MB_OK);\n}\n```\nIn 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.\n\nTo fix this issue three changes should be made:\n\n* Control the size of the buffer using a preprocessor define.\n* Replace the call to `sprintf` with `snprintf`, specifying the define as the maximum length to copy. This will prevent the buffer overflow.\n* Consider using the `%g` format specifier instead of `%f`.\n\n## References\n* 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).\n* 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).\n* Common Weakness Enumeration: [CWE-120](https://cwe.mitre.org/data/definitions/120.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n* Common Weakness Enumeration: [CWE-805](https://cwe.mitre.org/data/definitions/805.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-120", + "external/cwe/cwe-787", + "external/cwe/cwe-805" + ], + "description": "Buffer write operations that do not control the length\n of data written may overflow when floating point inputs\n take extreme values.", + "id": "cpp/overrunning-write-with-float", + "kind": "problem", + "name": "Potentially overrunning write with float to string conversion", + "precision": "medium", + "problem.severity": "error", + "security-severity": "9.3" + } + }, + { + "id": "cpp/potential-system-data-exposure", + "name": "cpp/potential-system-data-exposure", + "shortDescription": { + "text": "Potential exposure of sensitive system data to an unauthorized control sphere" + }, + "fullDescription": { + "text": "Exposing sensitive system data helps a malicious user learn about the system and form an attack plan." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Potential exposure of sensitive system data to an unauthorized control sphere\nExposing system data or debugging information may help a malicious user learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in the software.\n\nThis query finds locations where system configuration information that is particularly sensitive might be revealed to a user.\n\n\n## Recommendation\nDo not expose system configuration information to users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to a malicious user.\n\n\n## Example\nIn this example the value of the `PATH` environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to a malicious user who does not have legitimate access to that information.\n\n\n```cpp\nchar* key = getenv(\"APP_KEY\");\n\n//...\n\nfprintf(stderr, \"Key not recognized: %s\\n\", key);\n```\nThe message should be rephrased without this information, for example:\n\n\n```cpp\nchar* key = getenv(\"APP_KEY\");\n\n//...\n\nfprintf(stderr, \"Application key not recognized. Please ensure the key is correct or contact a system administrator.\\n\", key);\n```\n\n## References\n* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html).\n", + "markdown": "# Potential exposure of sensitive system data to an unauthorized control sphere\nExposing system data or debugging information may help a malicious user learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in the software.\n\nThis query finds locations where system configuration information that is particularly sensitive might be revealed to a user.\n\n\n## Recommendation\nDo not expose system configuration information to users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to a malicious user.\n\n\n## Example\nIn this example the value of the `PATH` environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to a malicious user who does not have legitimate access to that information.\n\n\n```cpp\nchar* key = getenv(\"APP_KEY\");\n\n//...\n\nfprintf(stderr, \"Key not recognized: %s\\n\", key);\n```\nThe message should be rephrased without this information, for example:\n\n\n```cpp\nchar* key = getenv(\"APP_KEY\");\n\n//...\n\nfprintf(stderr, \"Application key not recognized. Please ensure the key is correct or contact a system administrator.\\n\", key);\n```\n\n## References\n* Common Weakness Enumeration: [CWE-497](https://cwe.mitre.org/data/definitions/497.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-497" + ], + "description": "Exposing sensitive system data helps\n a malicious user learn about the system and form an\n attack plan.", + "id": "cpp/potential-system-data-exposure", + "kind": "path-problem", + "name": "Potential exposure of sensitive system data to an unauthorized control sphere", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "6.5" + } + }, + { + "id": "cpp/cleartext-storage-buffer", + "name": "cpp/cleartext-storage-buffer", + "shortDescription": { + "text": "Cleartext storage of sensitive information in buffer" + }, + "fullDescription": { + "text": "Storing sensitive information in cleartext can expose it to an attacker." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Cleartext storage of sensitive information in buffer\nSensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage.\n\n\n## Recommendation\nEnsure that sensitive information is always encrypted before being stored to a file or transmitted over the network. It may be wise to encrypt information before it is put into a buffer that may be readable in memory.\n\nIn general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.\n\n\n## Example\nThe 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.\n\n\n```c\nvoid writeCredentials() {\n char *password = \"cleartext password\";\n FILE* file = fopen(\"credentials.txt\", \"w\");\n \n // BAD: write password to disk in cleartext\n fputs(password, file);\n \n // GOOD: encrypt password first\n char *encrypted = encrypt(password);\n fputs(encrypted, file);\n}\n\n\n```\n\n## References\n* 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.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n", + "markdown": "# Cleartext storage of sensitive information in buffer\nSensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage.\n\n\n## Recommendation\nEnsure that sensitive information is always encrypted before being stored to a file or transmitted over the network. It may be wise to encrypt information before it is put into a buffer that may be readable in memory.\n\nIn general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.\n\n\n## Example\nThe 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.\n\n\n```c\nvoid writeCredentials() {\n char *password = \"cleartext password\";\n FILE* file = fopen(\"credentials.txt\", \"w\");\n \n // BAD: write password to disk in cleartext\n fputs(password, file);\n \n // GOOD: encrypt password first\n char *encrypted = encrypt(password);\n fputs(encrypted, file);\n}\n\n\n```\n\n## References\n* 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.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-312](https://cwe.mitre.org/data/definitions/312.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-312" + ], + "description": "Storing sensitive information in cleartext can expose it\n to an attacker.", + "id": "cpp/cleartext-storage-buffer", + "kind": "path-problem", + "name": "Cleartext storage of sensitive information in buffer", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/uncontrolled-process-operation", + "name": "cpp/uncontrolled-process-operation", + "shortDescription": { + "text": "Uncontrolled process operation" + }, + "fullDescription": { + "text": "Using externally controlled strings in a process operation can allow an attacker to execute malicious commands." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Uncontrolled process operation\nThe 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.\n\n\n## Recommendation\nIf 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.\n\nIf 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.\n\n\n## Example\n\n```c\nint main(int argc, char** argv) {\n char *lib = argv[2];\n \n // BAD: the user can cause arbitrary code to be loaded\n void* handle = dlopen(lib, RTLD_LAZY);\n \n // GOOD: only hard-coded libraries can be loaded\n void* handle2;\n\n if (!strcmp(lib, \"inmem\")) {\n handle2 = dlopen(\"/usr/share/dbwrap/inmem\", RTLD_LAZY);\n } else if (!strcmp(lib, \"mysql\")) {\n handle2 = dlopen(\"/usr/share/dbwrap/mysql\", RTLD_LAZY);\n } else {\n die(\"Invalid library specified\\n\");\n }\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-114](https://cwe.mitre.org/data/definitions/114.html).\n", + "markdown": "# Uncontrolled process operation\nThe 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.\n\n\n## Recommendation\nIf 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.\n\nIf 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.\n\n\n## Example\n\n```c\nint main(int argc, char** argv) {\n char *lib = argv[2];\n \n // BAD: the user can cause arbitrary code to be loaded\n void* handle = dlopen(lib, RTLD_LAZY);\n \n // GOOD: only hard-coded libraries can be loaded\n void* handle2;\n\n if (!strcmp(lib, \"inmem\")) {\n handle2 = dlopen(\"/usr/share/dbwrap/inmem\", RTLD_LAZY);\n } else if (!strcmp(lib, \"mysql\")) {\n handle2 = dlopen(\"/usr/share/dbwrap/mysql\", RTLD_LAZY);\n } else {\n die(\"Invalid library specified\\n\");\n }\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-114](https://cwe.mitre.org/data/definitions/114.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-114" + ], + "description": "Using externally controlled strings in a process\n operation can allow an attacker to execute malicious\n commands.", + "id": "cpp/uncontrolled-process-operation", + "kind": "path-problem", + "name": "Uncontrolled process operation", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "8.2" + } + }, + { + "id": "cpp/user-controlled-bypass", + "name": "cpp/user-controlled-bypass", + "shortDescription": { + "text": "Authentication bypass by spoofing" + }, + "fullDescription": { + "text": "Authentication by checking that the peer's address matches a known IP or web address is unsafe as it is vulnerable to spoofing attacks." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Authentication bypass by spoofing\nCode which relies on an IP address or domain name for authentication can be exploited by an attacker who spoofs their address.\n\n\n## Recommendation\nIP 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.\n\n\n## Example\nIn 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.\n\n\n```cpp\n\n#define BUFFER_SIZE (4 * 1024)\n\nvoid receiveData()\n{\n int sock;\n sockaddr_in addr, addr_from;\n char buffer[BUFFER_SIZE];\n int msg_size;\n socklen_t addr_from_len;\n\n // configure addr\n memset(&addr, 0, sizeof(addr));\n addr.sin_family = AF_INET;\n addr.sin_port = htons(1234);\n addr.sin_addr.s_addr = INADDR_ANY;\n\n // create and bind the socket\n sock = socket(AF_INET, SOCK_DGRAM, 0);\n bind(sock, (sockaddr *)&addr, sizeof(addr));\n\n // receive message\n addr_from_len = sizeof(addr_from);\n msg_size = recvfrom(sock, buffer, BUFFER_SIZE, 0, (sockaddr *)&addr_from, &addr_from_len);\n\n // BAD: the address is controllable by the user, so it\n // could be spoofed to bypass the security check below.\n if ((msg_size > 0) && (strcmp(\"127.0.0.1\", inet_ntoa(addr_from.sin_addr)) == 0))\n {\n // ...\n }\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html).\n", + "markdown": "# Authentication bypass by spoofing\nCode which relies on an IP address or domain name for authentication can be exploited by an attacker who spoofs their address.\n\n\n## Recommendation\nIP 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.\n\n\n## Example\nIn 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.\n\n\n```cpp\n\n#define BUFFER_SIZE (4 * 1024)\n\nvoid receiveData()\n{\n int sock;\n sockaddr_in addr, addr_from;\n char buffer[BUFFER_SIZE];\n int msg_size;\n socklen_t addr_from_len;\n\n // configure addr\n memset(&addr, 0, sizeof(addr));\n addr.sin_family = AF_INET;\n addr.sin_port = htons(1234);\n addr.sin_addr.s_addr = INADDR_ANY;\n\n // create and bind the socket\n sock = socket(AF_INET, SOCK_DGRAM, 0);\n bind(sock, (sockaddr *)&addr, sizeof(addr));\n\n // receive message\n addr_from_len = sizeof(addr_from);\n msg_size = recvfrom(sock, buffer, BUFFER_SIZE, 0, (sockaddr *)&addr_from, &addr_from_len);\n\n // BAD: the address is controllable by the user, so it\n // could be spoofed to bypass the security check below.\n if ((msg_size > 0) && (strcmp(\"127.0.0.1\", inet_ntoa(addr_from.sin_addr)) == 0))\n {\n // ...\n }\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-290](https://cwe.mitre.org/data/definitions/290.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-290" + ], + "description": "Authentication by checking that the peer's address\n matches a known IP or web address is unsafe as it is\n vulnerable to spoofing attacks.", + "id": "cpp/user-controlled-bypass", + "kind": "path-problem", + "name": "Authentication bypass by spoofing", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "8.1" + } + }, + { + "id": "cpp/path-injection", + "name": "cpp/path-injection", + "shortDescription": { + "text": "Uncontrolled data used in path expression" + }, + "fullDescription": { + "text": "Accessing paths influenced by users can allow an attacker to access unexpected resources." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Uncontrolled data used in path expression\nAccessing 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.\n\nPaths 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.\n\n\n## Recommendation\nValidate user input before using it to construct a filepath. Ideally, follow these rules:\n\n* Do not allow more than a single \".\" character.\n* Do not allow directory separators such as \"/\" or \"\\\\\" (depending on the filesystem).\n* Do not rely on simply replacing problematic sequences such as \"../\". For example, after applying this filter to \".../...//\" the resulting string would still be \"../\".\n* Ideally use a whitelist of known good patterns.\n\n## Example\nIn 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.\n\n\n```c\nint main(int argc, char** argv) {\n char *userAndFile = argv[2];\n \n {\n char fileBuffer[FILENAME_MAX] = \"/home/\";\n char *fileName = fileBuffer;\n size_t len = strlen(fileName);\n strncat(fileName+len, userAndFile, FILENAME_MAX-len-1);\n // BAD: a string from the user is used in a filename\n fopen(fileName, \"wb+\");\n }\n\n {\n char fileBuffer[FILENAME_MAX] = \"/home/\";\n char *fileName = fileBuffer;\n size_t len = strlen(fileName);\n // GOOD: use a fixed file\n char* fixed = \"jim/file.txt\";\n strncat(fileName+len, fixed, FILENAME_MAX-len-1);\n fopen(fileName, \"wb+\");\n }\n}\n\n```\n\n## References\n* OWASP: [Path Traversal](https://owasp.org/www-community/attacks/Path_Traversal).\n* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html).\n* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html).\n* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html).\n* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html).\n", + "markdown": "# Uncontrolled data used in path expression\nAccessing 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.\n\nPaths 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.\n\n\n## Recommendation\nValidate user input before using it to construct a filepath. Ideally, follow these rules:\n\n* Do not allow more than a single \".\" character.\n* Do not allow directory separators such as \"/\" or \"\\\\\" (depending on the filesystem).\n* Do not rely on simply replacing problematic sequences such as \"../\". For example, after applying this filter to \".../...//\" the resulting string would still be \"../\".\n* Ideally use a whitelist of known good patterns.\n\n## Example\nIn 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.\n\n\n```c\nint main(int argc, char** argv) {\n char *userAndFile = argv[2];\n \n {\n char fileBuffer[FILENAME_MAX] = \"/home/\";\n char *fileName = fileBuffer;\n size_t len = strlen(fileName);\n strncat(fileName+len, userAndFile, FILENAME_MAX-len-1);\n // BAD: a string from the user is used in a filename\n fopen(fileName, \"wb+\");\n }\n\n {\n char fileBuffer[FILENAME_MAX] = \"/home/\";\n char *fileName = fileBuffer;\n size_t len = strlen(fileName);\n // GOOD: use a fixed file\n char* fixed = \"jim/file.txt\";\n strncat(fileName+len, fixed, FILENAME_MAX-len-1);\n fopen(fileName, \"wb+\");\n }\n}\n\n```\n\n## References\n* OWASP: [Path Traversal](https://owasp.org/www-community/attacks/Path_Traversal).\n* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html).\n* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html).\n* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html).\n* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-022", + "external/cwe/cwe-023", + "external/cwe/cwe-036", + "external/cwe/cwe-073" + ], + "description": "Accessing paths influenced by users can allow an\n attacker to access unexpected resources.", + "id": "cpp/path-injection", + "kind": "path-problem", + "name": "Uncontrolled data used in path expression", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/uncontrolled-allocation-size", + "name": "cpp/uncontrolled-allocation-size", + "shortDescription": { + "text": "Overflow in uncontrolled allocation size" + }, + "fullDescription": { + "text": "Allocating memory with a size controlled by an external user can result in integer overflow." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Overflow in uncontrolled allocation size\nThis 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.\n\n\n## Recommendation\nGuard 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.\n\n\n## Example\n\n```c\nint factor = atoi(getenv(\"BRANCHING_FACTOR\"));\n\n// GOOD: Prevent overflow by checking the input\nif (factor < 0 || factor > 1000) {\n log(\"Factor out of range (%d)\\n\", factor);\n return -1;\n}\n\n// This line can allocate too little memory if factor\n// is very large.\nchar **root_node = (char **) malloc(factor * sizeof(char *));\n\n```\nThis 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.\n\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-789](https://cwe.mitre.org/data/definitions/789.html).\n", + "markdown": "# Overflow in uncontrolled allocation size\nThis 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.\n\n\n## Recommendation\nGuard 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.\n\n\n## Example\n\n```c\nint factor = atoi(getenv(\"BRANCHING_FACTOR\"));\n\n// GOOD: Prevent overflow by checking the input\nif (factor < 0 || factor > 1000) {\n log(\"Factor out of range (%d)\\n\", factor);\n return -1;\n}\n\n// This line can allocate too little memory if factor\n// is very large.\nchar **root_node = (char **) malloc(factor * sizeof(char *));\n\n```\nThis 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.\n\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-190](https://cwe.mitre.org/data/definitions/190.html).\n* Common Weakness Enumeration: [CWE-789](https://cwe.mitre.org/data/definitions/789.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-190", + "external/cwe/cwe-789" + ], + "description": "Allocating memory with a size controlled by an external\n user can result in integer overflow.", + "id": "cpp/uncontrolled-allocation-size", + "kind": "path-problem", + "name": "Overflow in uncontrolled allocation size", + "precision": "medium", + "problem.severity": "error", + "security-severity": "8.1" + } + }, + { + "id": "cpp/cleartext-storage-database", + "name": "cpp/cleartext-storage-database", + "shortDescription": { + "text": "Cleartext storage of sensitive information in an SQLite database" + }, + "fullDescription": { + "text": "Storing sensitive information in a non-encrypted database can expose it to an attacker." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Cleartext storage of sensitive information in an SQLite database\nSensitive information that is stored in an unencrypted SQLite database is accessible to an attacker who gains access to the database.\n\n\n## Recommendation\nEnsure that if sensitive information is stored in a database then the database is always encrypted.\n\n\n## Example\nThe 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.\n\n\n```c\n\nvoid bad(void) {\n char *password = \"cleartext password\";\n sqlite3 *credentialsDB;\n sqlite3_stmt *stmt;\n\n if (sqlite3_open(\"credentials.db\", &credentialsDB) == SQLITE_OK) {\n // BAD: database opened without encryption being enabled\n sqlite3_exec(credentialsDB, \"CREATE TABLE IF NOT EXISTS creds (password TEXT);\", NULL, NULL, NULL);\n if (sqlite3_prepare_v2(credentialsDB, \"INSERT INTO creds(password) VALUES(?)\", -1, &stmt, NULL) == SQLITE_OK) {\n sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT);\n sqlite3_step(stmt);\n sqlite3_finalize(stmt);\n sqlite3_close(credentialsDB);\n }\n }\n}\n\nvoid good(void) {\n char *password = \"cleartext password\";\n sqlite3 *credentialsDB;\n sqlite3_stmt *stmt;\n\n if (sqlite3_open(\"credentials.db\", &credentialsDB) == SQLITE_OK) {\n // GOOD: database encryption enabled:\n sqlite3_exec(credentialsDB, \"PRAGMA key = 'secretKey!'\", NULL, NULL, NULL);\n sqlite3_exec(credentialsDB, \"CREATE TABLE IF NOT EXISTS creds (password TEXT);\", NULL, NULL, NULL);\n if (sqlite3_prepare_v2(credentialsDB, \"INSERT INTO creds(password) VALUES(?)\", -1, &stmt, NULL) == SQLITE_OK) {\n sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT);\n sqlite3_step(stmt);\n sqlite3_finalize(stmt);\n sqlite3_close(credentialsDB);\n }\n }\n}\n\n\n```\n\n## References\n* 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.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html).\n", + "markdown": "# Cleartext storage of sensitive information in an SQLite database\nSensitive information that is stored in an unencrypted SQLite database is accessible to an attacker who gains access to the database.\n\n\n## Recommendation\nEnsure that if sensitive information is stored in a database then the database is always encrypted.\n\n\n## Example\nThe 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.\n\n\n```c\n\nvoid bad(void) {\n char *password = \"cleartext password\";\n sqlite3 *credentialsDB;\n sqlite3_stmt *stmt;\n\n if (sqlite3_open(\"credentials.db\", &credentialsDB) == SQLITE_OK) {\n // BAD: database opened without encryption being enabled\n sqlite3_exec(credentialsDB, \"CREATE TABLE IF NOT EXISTS creds (password TEXT);\", NULL, NULL, NULL);\n if (sqlite3_prepare_v2(credentialsDB, \"INSERT INTO creds(password) VALUES(?)\", -1, &stmt, NULL) == SQLITE_OK) {\n sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT);\n sqlite3_step(stmt);\n sqlite3_finalize(stmt);\n sqlite3_close(credentialsDB);\n }\n }\n}\n\nvoid good(void) {\n char *password = \"cleartext password\";\n sqlite3 *credentialsDB;\n sqlite3_stmt *stmt;\n\n if (sqlite3_open(\"credentials.db\", &credentialsDB) == SQLITE_OK) {\n // GOOD: database encryption enabled:\n sqlite3_exec(credentialsDB, \"PRAGMA key = 'secretKey!'\", NULL, NULL, NULL);\n sqlite3_exec(credentialsDB, \"CREATE TABLE IF NOT EXISTS creds (password TEXT);\", NULL, NULL, NULL);\n if (sqlite3_prepare_v2(credentialsDB, \"INSERT INTO creds(password) VALUES(?)\", -1, &stmt, NULL) == SQLITE_OK) {\n sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT);\n sqlite3_step(stmt);\n sqlite3_finalize(stmt);\n sqlite3_close(credentialsDB);\n }\n }\n}\n\n\n```\n\n## References\n* 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.\n* M. Howard and D. LeBlanc, *Writing Secure Code*, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.\n* Common Weakness Enumeration: [CWE-313](https://cwe.mitre.org/data/definitions/313.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-313" + ], + "description": "Storing sensitive information in a non-encrypted\n database can expose it to an attacker.", + "id": "cpp/cleartext-storage-database", + "kind": "path-problem", + "name": "Cleartext storage of sensitive information in an SQLite database", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/world-writable-file-creation", + "name": "cpp/world-writable-file-creation", + "shortDescription": { + "text": "File created without restricting permissions" + }, + "fullDescription": { + "text": "Creating a file that is world-writable can allow an attacker to write to the file." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# File created without restricting permissions\nWhen 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.\n\n\n## Recommendation\nFiles 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.\n\nOn 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.\n\n\n## Example\nThis 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.\n\nThe 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.\n\n\n```c\nvoid write_default_config_bad() {\n\t// BAD - this is world-writable so any user can overwrite the config\n\tint out = creat(OUTFILE, 0666);\n\tdprintf(out, DEFAULT_CONFIG);\n}\n\nvoid write_default_config_good() {\n\t// GOOD - this allows only the current user to modify the file\n\tint out = creat(OUTFILE, S_IWUSR | S_IRUSR);\n\tdprintf(out, DEFAULT_CONFIG);\n}\n\n```\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html).\n", + "markdown": "# File created without restricting permissions\nWhen 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.\n\n\n## Recommendation\nFiles 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.\n\nOn 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.\n\n\n## Example\nThis 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.\n\nThe 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.\n\n\n```c\nvoid write_default_config_bad() {\n\t// BAD - this is world-writable so any user can overwrite the config\n\tint out = creat(OUTFILE, 0666);\n\tdprintf(out, DEFAULT_CONFIG);\n}\n\nvoid write_default_config_good() {\n\t// GOOD - this allows only the current user to modify the file\n\tint out = creat(OUTFILE, S_IWUSR | S_IRUSR);\n\tdprintf(out, DEFAULT_CONFIG);\n}\n\n```\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-732](https://cwe.mitre.org/data/definitions/732.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-732" + ], + "description": "Creating a file that is world-writable can allow an attacker to write to the file.", + "id": "cpp/world-writable-file-creation", + "kind": "problem", + "name": "File created without restricting permissions", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "7.8" + } + }, + { + "id": "cpp/unterminated-variadic-call", + "name": "cpp/unterminated-variadic-call", + "shortDescription": { + "text": "Unterminated variadic call" + }, + "fullDescription": { + "text": "Calling a variadic function without a sentinel value may result in a buffer overflow if the function expects a specific value to terminate the argument list." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Unterminated variadic call\nThe 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.\n\n\n## Recommendation\nEach 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.\n\n\n## Example\n\n```cpp\n#include \n\nvoid pushStrings(char *firstString, ...)\n{\n\tva_list args;\n\tchar *arg;\n\n\tva_start(args, firstString);\n\n\t// process inputs, beginning with firstString, ending when NULL is reached\n\targ = firstString;\n\twhile (arg != NULL)\n\t{\n\t\t// push the string\n\t\tpushString(arg);\n\t\n\t\t// move on to the next input\n\t\targ = va_arg(args, char *);\n\t}\n\n\tva_end(args);\n}\n\nvoid badFunction()\n{\n\tpushStrings(\"hello\", \"world\", NULL); // OK\n\t\n\tpushStrings(\"apple\", \"pear\", \"banana\", NULL); // OK\n\n\tpushStrings(\"car\", \"bus\", \"train\"); // BAD, not terminated with the expected NULL\n}\n```\nIn 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.\n\n\n## References\n* Common Weakness Enumeration: [CWE-121](https://cwe.mitre.org/data/definitions/121.html).\n", + "markdown": "# Unterminated variadic call\nThe 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.\n\n\n## Recommendation\nEach 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.\n\n\n## Example\n\n```cpp\n#include \n\nvoid pushStrings(char *firstString, ...)\n{\n\tva_list args;\n\tchar *arg;\n\n\tva_start(args, firstString);\n\n\t// process inputs, beginning with firstString, ending when NULL is reached\n\targ = firstString;\n\twhile (arg != NULL)\n\t{\n\t\t// push the string\n\t\tpushString(arg);\n\t\n\t\t// move on to the next input\n\t\targ = va_arg(args, char *);\n\t}\n\n\tva_end(args);\n}\n\nvoid badFunction()\n{\n\tpushStrings(\"hello\", \"world\", NULL); // OK\n\t\n\tpushStrings(\"apple\", \"pear\", \"banana\", NULL); // OK\n\n\tpushStrings(\"car\", \"bus\", \"train\"); // BAD, not terminated with the expected NULL\n}\n```\nIn 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.\n\n\n## References\n* Common Weakness Enumeration: [CWE-121](https://cwe.mitre.org/data/definitions/121.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-121" + ], + "description": "Calling a variadic function without a sentinel value\n may result in a buffer overflow if the function expects\n a specific value to terminate the argument list.", + "id": "cpp/unterminated-variadic-call", + "kind": "problem", + "name": "Unterminated variadic call", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "8.8" + } + }, + { + "id": "cpp/potentially-dangerous-function", + "name": "cpp/potentially-dangerous-function", + "shortDescription": { + "text": "Use of potentially dangerous function" + }, + "fullDescription": { + "text": "Use of a standard library function that is not thread-safe." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Use of potentially dangerous function\nThis rule finds calls to functions that are dangerous to use. Currently, it checks for calls to `gmtime`, `localtime`, `ctime` and `asctime`.\n\nThe 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.\n\n\n## Recommendation\nReplace 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.\n\nSimilarly replace calls to `localtime` with `localtime_r`, calls to `ctime` with `ctime_r` and calls to `asctime` with `asctime_r` (if those functions exist on your platform).\n\n\n## Example\nThe following example checks the local time in two ways:\n\n\n```c\n// BAD: using gmtime\nint is_morning_bad() {\n const time_t now_seconds = time(NULL);\n struct tm *now = gmtime(&now_seconds);\n return (now->tm_hour < 12);\n}\n\n// GOOD: using gmtime_r\nint is_morning_good() {\n const time_t now_seconds = time(NULL);\n struct tm now;\n gmtime_r(&now_seconds, &now);\n return (now.tm_hour < 12);\n}\n\n```\nThe 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`.\n\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n", + "markdown": "# Use of potentially dangerous function\nThis rule finds calls to functions that are dangerous to use. Currently, it checks for calls to `gmtime`, `localtime`, `ctime` and `asctime`.\n\nThe 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.\n\n\n## Recommendation\nReplace 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.\n\nSimilarly replace calls to `localtime` with `localtime_r`, calls to `ctime` with `ctime_r` and calls to `asctime` with `asctime_r` (if those functions exist on your platform).\n\n\n## Example\nThe following example checks the local time in two ways:\n\n\n```c\n// BAD: using gmtime\nint is_morning_bad() {\n const time_t now_seconds = time(NULL);\n struct tm *now = gmtime(&now_seconds);\n return (now->tm_hour < 12);\n}\n\n// GOOD: using gmtime_r\nint is_morning_good() {\n const time_t now_seconds = time(NULL);\n struct tm now;\n gmtime_r(&now_seconds, &now);\n return (now.tm_hour < 12);\n}\n\n```\nThe 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`.\n\n\n## References\n* 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).\n* Common Weakness Enumeration: [CWE-676](https://cwe.mitre.org/data/definitions/676.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-676" + ], + "description": "Use of a standard library function that is not thread-safe.", + "id": "cpp/potentially-dangerous-function", + "kind": "problem", + "name": "Use of potentially dangerous function", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "10.0" + } + }, + { + "id": "cpp/suspicious-pointer-scaling", + "name": "cpp/suspicious-pointer-scaling", + "shortDescription": { + "text": "Suspicious pointer scaling" + }, + "fullDescription": { + "text": "Implicit scaling of pointer arithmetic expressions can cause buffer overflow conditions." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Suspicious pointer scaling\nPointer 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.\n\nThis query finds pointer arithmetic expressions where it appears likely that the programmer has forgotten that the offset is automatically scaled.\n\n\n## Recommendation\n1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`.\n1. 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.\n\n## Example\n\n```cpp\nint example1(int i) {\n int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n int *intPointer = intArray;\n // BAD: the offset is already automatically scaled by sizeof(int),\n // so this code will compute the wrong offset.\n return *(intPointer + (i * sizeof(int)));\n}\n\nint example2(int i) {\n int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n int *intPointer = intArray;\n // GOOD: the offset is automatically scaled by sizeof(int).\n return *(intPointer + i);\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html).\n", + "markdown": "# Suspicious pointer scaling\nPointer 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.\n\nThis query finds pointer arithmetic expressions where it appears likely that the programmer has forgotten that the offset is automatically scaled.\n\n\n## Recommendation\n1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`.\n1. 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.\n\n## Example\n\n```cpp\nint example1(int i) {\n int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n int *intPointer = intArray;\n // BAD: the offset is already automatically scaled by sizeof(int),\n // so this code will compute the wrong offset.\n return *(intPointer + (i * sizeof(int)));\n}\n\nint example2(int i) {\n int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n int *intPointer = intArray;\n // GOOD: the offset is automatically scaled by sizeof(int).\n return *(intPointer + i);\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-468" + ], + "description": "Implicit scaling of pointer arithmetic expressions\n can cause buffer overflow conditions.", + "id": "cpp/suspicious-pointer-scaling", + "kind": "problem", + "name": "Suspicious pointer scaling", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "8.8" + } + }, + { + "id": "cpp/suspicious-pointer-scaling-void", + "name": "cpp/suspicious-pointer-scaling-void", + "shortDescription": { + "text": "Suspicious pointer scaling to void" + }, + "fullDescription": { + "text": "Implicit scaling of pointer arithmetic expressions can cause buffer overflow conditions." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Suspicious pointer scaling to void\nCasting arbitrary pointers into `void*` and then accessing their contents should be done with care. The results may not be portable.\n\nThis query finds pointer arithmetic expressions where a pointer to `void` (or similar) is then cast to another type and dereferenced.\n\n\n## Recommendation\n1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`.\n1. 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.\n1. 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.\n\n## Example\n\n```cpp\nchar example1(int i) {\n int intArray[5] = { 1, 2, 3, 4, 5 };\n void *voidPointer = (void *)intArray;\n // BAD: the pointer arithmetic uses type void*, so the offset\n // is not scaled by sizeof(int).\n return *(voidPointer + i);\n}\n\nint example2(int i) {\n int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n int *intPointer = intArray;\n // GOOD: the offset is automatically scaled by sizeof(int).\n return *(intPointer + i);\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html).\n", + "markdown": "# Suspicious pointer scaling to void\nCasting arbitrary pointers into `void*` and then accessing their contents should be done with care. The results may not be portable.\n\nThis query finds pointer arithmetic expressions where a pointer to `void` (or similar) is then cast to another type and dereferenced.\n\n\n## Recommendation\n1. Whenever possible, use the array subscript operator rather than pointer arithmetic. For example, replace `*(p+k)` with `p[k]`.\n1. 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.\n1. 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.\n\n## Example\n\n```cpp\nchar example1(int i) {\n int intArray[5] = { 1, 2, 3, 4, 5 };\n void *voidPointer = (void *)intArray;\n // BAD: the pointer arithmetic uses type void*, so the offset\n // is not scaled by sizeof(int).\n return *(voidPointer + i);\n}\n\nint example2(int i) {\n int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n int *intPointer = intArray;\n // GOOD: the offset is automatically scaled by sizeof(int).\n return *(intPointer + i);\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-468](https://cwe.mitre.org/data/definitions/468.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-468" + ], + "description": "Implicit scaling of pointer arithmetic expressions\n can cause buffer overflow conditions.", + "id": "cpp/suspicious-pointer-scaling-void", + "kind": "problem", + "name": "Suspicious pointer scaling to void", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "8.8" + } + }, + { + "id": "cpp/unsigned-difference-expression-compared-zero", + "name": "cpp/unsigned-difference-expression-compared-zero", + "shortDescription": { + "text": "Unsigned difference expression compared to zero" + }, + "fullDescription": { + "text": "A subtraction with an unsigned result can never be negative. Using such an expression in a relational comparison with `0` is likely to be wrong." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Unsigned difference expression compared to zero\nThis rule finds relational comparisons between the result of an unsigned subtraction and the value `0`. Such comparisons are likely to be wrong as the value of an unsigned subtraction can never be negative. So the relational comparison ends up checking whether the result of the subtraction is equal to `0`. This is probably not what the programmer intended.\n\n\n## Recommendation\nIf a relational comparison is intended, consider casting the result of the subtraction to a signed type. If the intention was to test for equality, consider replacing the relational comparison with an equality test.\n\n\n## Example\n\n```c\nunsigned limit = get_limit();\nunsigned total = 0;\nwhile (limit - total > 0) { // wrong: if `total` is greater than `limit` this will underflow and continue executing the loop.\n total += get_data();\n}\n```\n\n## References\n* SEI CERT C Coding Standard: [INT02-C. Understand integer conversion rules](https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules).\n* Common Weakness Enumeration: [CWE-191](https://cwe.mitre.org/data/definitions/191.html).\n", + "markdown": "# Unsigned difference expression compared to zero\nThis rule finds relational comparisons between the result of an unsigned subtraction and the value `0`. Such comparisons are likely to be wrong as the value of an unsigned subtraction can never be negative. So the relational comparison ends up checking whether the result of the subtraction is equal to `0`. This is probably not what the programmer intended.\n\n\n## Recommendation\nIf a relational comparison is intended, consider casting the result of the subtraction to a signed type. If the intention was to test for equality, consider replacing the relational comparison with an equality test.\n\n\n## Example\n\n```c\nunsigned limit = get_limit();\nunsigned total = 0;\nwhile (limit - total > 0) { // wrong: if `total` is greater than `limit` this will underflow and continue executing the loop.\n total += get_data();\n}\n```\n\n## References\n* SEI CERT C Coding Standard: [INT02-C. Understand integer conversion rules](https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules).\n* Common Weakness Enumeration: [CWE-191](https://cwe.mitre.org/data/definitions/191.html).\n" + }, + "properties": { + "tags": [ + "security", + "correctness", + "external/cwe/cwe-191" + ], + "description": "A subtraction with an unsigned result can never be negative. Using such an expression in a relational comparison with `0` is likely to be wrong.", + "id": "cpp/unsigned-difference-expression-compared-zero", + "kind": "problem", + "name": "Unsigned difference expression compared to zero", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "9.8" + } + }, + { + "id": "cpp/invalid-pointer-deref", + "name": "cpp/invalid-pointer-deref", + "shortDescription": { + "text": "Invalid pointer dereference" + }, + "fullDescription": { + "text": "Dereferencing an out-of-bounds pointer is undefined behavior and may lead to security vulnerabilities." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Invalid pointer dereference\nThe program performs an out-of-bounds read or write operation, which can cause program instability. In addition, attackers may take advantage of the situation, and implement techniques to use this vulnerability to execute arbitrary code.\n\n\n## Recommendation\nEnsure that pointer dereferences are properly guarded to ensure that they cannot be used to read or write past the end of the allocation.\n\n\n## Example\nThe first example allocates a buffer of size `size` and creates a local variable that stores the location that is one byte past the end of the allocation. This local variable is then dereferenced, which results in an out-of-bounds write. The second example subtracts one from the `end` variable before dereferencing it. This subtraction ensures that the write correctly updates the final byte of the allocation.\n\n\n```cpp\nvoid *malloc(unsigned);\nunsigned get_size();\nvoid write_data(const unsigned char*, const unsigned char*);\n\nint main(int argc, char* argv[]) {\n unsigned size = get_size();\n \n {\n unsigned char *begin = (unsigned char*)malloc(size);\n if(!begin) return -1;\n\n unsigned char* end = begin + size;\n write_data(begin, end);\n *end = '\\0'; // BAD: Out-of-bounds write\n }\n\n {\n unsigned char *begin = (unsigned char*)malloc(size);\n if(!begin) return -1;\n\n unsigned char* end = begin + size;\n write_data(begin, end);\n *(end - 1) = '\\0'; // GOOD: writing to the last byte\n }\n\n}\n```\n\n## References\n* CERT C Coding Standard: [ARR30-C. Do not form or use out-of-bounds pointers or array subscripts](https://wiki.sei.cmu.edu/confluence/display/c/ARR30-C.+Do+not+form+or+use+out-of-bounds+pointers+or+array+subscripts).\n* OWASP: [Buffer Overflow](https://owasp.org/www-community/vulnerabilities/Buffer_Overflow).\n* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html).\n* Common Weakness Enumeration: [CWE-125](https://cwe.mitre.org/data/definitions/125.html).\n* Common Weakness Enumeration: [CWE-193](https://cwe.mitre.org/data/definitions/193.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n", + "markdown": "# Invalid pointer dereference\nThe program performs an out-of-bounds read or write operation, which can cause program instability. In addition, attackers may take advantage of the situation, and implement techniques to use this vulnerability to execute arbitrary code.\n\n\n## Recommendation\nEnsure that pointer dereferences are properly guarded to ensure that they cannot be used to read or write past the end of the allocation.\n\n\n## Example\nThe first example allocates a buffer of size `size` and creates a local variable that stores the location that is one byte past the end of the allocation. This local variable is then dereferenced, which results in an out-of-bounds write. The second example subtracts one from the `end` variable before dereferencing it. This subtraction ensures that the write correctly updates the final byte of the allocation.\n\n\n```cpp\nvoid *malloc(unsigned);\nunsigned get_size();\nvoid write_data(const unsigned char*, const unsigned char*);\n\nint main(int argc, char* argv[]) {\n unsigned size = get_size();\n \n {\n unsigned char *begin = (unsigned char*)malloc(size);\n if(!begin) return -1;\n\n unsigned char* end = begin + size;\n write_data(begin, end);\n *end = '\\0'; // BAD: Out-of-bounds write\n }\n\n {\n unsigned char *begin = (unsigned char*)malloc(size);\n if(!begin) return -1;\n\n unsigned char* end = begin + size;\n write_data(begin, end);\n *(end - 1) = '\\0'; // GOOD: writing to the last byte\n }\n\n}\n```\n\n## References\n* CERT C Coding Standard: [ARR30-C. Do not form or use out-of-bounds pointers or array subscripts](https://wiki.sei.cmu.edu/confluence/display/c/ARR30-C.+Do+not+form+or+use+out-of-bounds+pointers+or+array+subscripts).\n* OWASP: [Buffer Overflow](https://owasp.org/www-community/vulnerabilities/Buffer_Overflow).\n* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html).\n* Common Weakness Enumeration: [CWE-125](https://cwe.mitre.org/data/definitions/125.html).\n* Common Weakness Enumeration: [CWE-193](https://cwe.mitre.org/data/definitions/193.html).\n* Common Weakness Enumeration: [CWE-787](https://cwe.mitre.org/data/definitions/787.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-119", + "external/cwe/cwe-125", + "external/cwe/cwe-193", + "external/cwe/cwe-787" + ], + "description": "Dereferencing an out-of-bounds pointer is undefined behavior and may lead to security vulnerabilities.", + "id": "cpp/invalid-pointer-deref", + "kind": "path-problem", + "name": "Invalid pointer dereference", + "precision": "medium", + "problem.severity": "error", + "security-severity": "9.3" + } + }, + { + "id": "cpp/overrun-write", + "name": "cpp/overrun-write", + "shortDescription": { + "text": "Overrunning write" + }, + "fullDescription": { + "text": "Exceeding the size of a static array during write or access operations may result in a buffer overflow." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Overrunning write\nYou must ensure that you do not exceed the size of an allocation during write and read operations. If an operation attempts to write to or access an element that is outside the range of the allocation then this results in a buffer overflow. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability.\n\n\n## Recommendation\nCheck the offsets and sizes used in the highlighted operations to ensure that a buffer overflow will not occur.\n\n\n## Example\n\n```cpp\nint f(char * s, unsigned size) {\n\tchar* buf = (char*)malloc(size);\n\n\tstrncpy(buf, s, size + 1); // wrong: copy may exceed size of buf\n\n\tfor (int i = 0; i <= size; i++) { // wrong: upper limit that is higher than size of buf\n\t\tcout << buf[i];\n\t}\n}\n\n```\n\n## References\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html).\n* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html).\n", + "markdown": "# Overrunning write\nYou must ensure that you do not exceed the size of an allocation during write and read operations. If an operation attempts to write to or access an element that is outside the range of the allocation then this results in a buffer overflow. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability.\n\n\n## Recommendation\nCheck the offsets and sizes used in the highlighted operations to ensure that a buffer overflow will not occur.\n\n\n## Example\n\n```cpp\nint f(char * s, unsigned size) {\n\tchar* buf = (char*)malloc(size);\n\n\tstrncpy(buf, s, size + 1); // wrong: copy may exceed size of buf\n\n\tfor (int i = 0; i <= size; i++) { // wrong: upper limit that is higher than size of buf\n\t\tcout << buf[i];\n\t}\n}\n\n```\n\n## References\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-119](https://cwe.mitre.org/data/definitions/119.html).\n* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-119", + "external/cwe/cwe-131" + ], + "description": "Exceeding the size of a static array during write or access operations\n may result in a buffer overflow.", + "id": "cpp/overrun-write", + "kind": "path-problem", + "name": "Overrunning write", + "precision": "medium", + "problem.severity": "error", + "security-severity": "9.3" + } + }, + { + "id": "cpp/tainted-permissions-check", + "name": "cpp/tainted-permissions-check", + "shortDescription": { + "text": "Untrusted input for a condition" + }, + "fullDescription": { + "text": "Using untrusted inputs in a statement that makes a security decision makes code vulnerable to attack." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Untrusted input for a condition\nThis 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.\n\n\n## Recommendation\nIn 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.\n\nThis 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.\n\n\n## Example\nThe following example is included in CWE 807.\n\n\n```c\nstruct hostent *hp;struct in_addr myaddr;\nchar* tHost = \"trustme.example.com\";\nmyaddr.s_addr=inet_addr(ip_addr_string);\n\nhp = gethostbyaddr((char *) &myaddr, sizeof(struct in_addr), AF_INET);\nif (hp && !strncmp(hp->h_name, tHost, sizeof(tHost))) {\n trusted = true;\n} else {\n trusted = false;\n}\n\n```\nIn 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`.\n\nTo 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.\n\n\n## References\n* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html).\n", + "markdown": "# Untrusted input for a condition\nThis 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.\n\n\n## Recommendation\nIn 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.\n\nThis 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.\n\n\n## Example\nThe following example is included in CWE 807.\n\n\n```c\nstruct hostent *hp;struct in_addr myaddr;\nchar* tHost = \"trustme.example.com\";\nmyaddr.s_addr=inet_addr(ip_addr_string);\n\nhp = gethostbyaddr((char *) &myaddr, sizeof(struct in_addr), AF_INET);\nif (hp && !strncmp(hp->h_name, tHost, sizeof(tHost))) {\n trusted = true;\n} else {\n trusted = false;\n}\n\n```\nIn 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`.\n\nTo 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.\n\n\n## References\n* Common Weakness Enumeration: [CWE-807](https://cwe.mitre.org/data/definitions/807.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-807" + ], + "description": "Using untrusted inputs in a statement that makes a\n security decision makes code vulnerable to\n attack.", + "id": "cpp/tainted-permissions-check", + "kind": "path-problem", + "name": "Untrusted input for a condition", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/certificate-result-conflation", + "name": "cpp/certificate-result-conflation", + "shortDescription": { + "text": "Certificate result conflation" + }, + "fullDescription": { + "text": "Only accept SSL certificates that pass certificate verification." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Certificate result conflation\nWhen checking the result of SSL certificate verification, accepting any error code may allow an attacker to impersonate someone who is trusted.\n\n\n## Recommendation\nWhen checking an SSL certificate with `SSL_get_verify_result`, only `X509_V_OK` is a success code. If there is any other result the certificate should not be accepted.\n\n\n## Example\nIn this example the error code `X509_V_ERR_CERT_HAS_EXPIRED` is treated the same as an OK result. An expired certificate should not be accepted as it is more likely to be compromised than a valid certificate.\n\n\n```cpp\n// ...\n\nif (cert = SSL_get_peer_certificate(ssl))\n{\n\tresult = SSL_get_verify_result(ssl);\n\n\tif ((result == X509_V_OK) || (result == X509_V_ERR_CERT_HAS_EXPIRED)) // BAD (conflates OK and a non-OK codes)\n\t{\n\t\tdo_ok();\n\t} else {\n\t\tdo_error();\n\t}\n}\n\n```\nIn the corrected example, only a result of `X509_V_OK` is accepted.\n\n\n```cpp\n// ...\n\nif (cert = SSL_get_peer_certificate(ssl))\n{\n\tresult = SSL_get_verify_result(ssl);\n\n\tif (result == X509_V_OK) // GOOD\n\t{\n\t\tdo_ok();\n\t} else {\n\t\tdo_error();\n\t}\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html).\n", + "markdown": "# Certificate result conflation\nWhen checking the result of SSL certificate verification, accepting any error code may allow an attacker to impersonate someone who is trusted.\n\n\n## Recommendation\nWhen checking an SSL certificate with `SSL_get_verify_result`, only `X509_V_OK` is a success code. If there is any other result the certificate should not be accepted.\n\n\n## Example\nIn this example the error code `X509_V_ERR_CERT_HAS_EXPIRED` is treated the same as an OK result. An expired certificate should not be accepted as it is more likely to be compromised than a valid certificate.\n\n\n```cpp\n// ...\n\nif (cert = SSL_get_peer_certificate(ssl))\n{\n\tresult = SSL_get_verify_result(ssl);\n\n\tif ((result == X509_V_OK) || (result == X509_V_ERR_CERT_HAS_EXPIRED)) // BAD (conflates OK and a non-OK codes)\n\t{\n\t\tdo_ok();\n\t} else {\n\t\tdo_error();\n\t}\n}\n\n```\nIn the corrected example, only a result of `X509_V_OK` is accepted.\n\n\n```cpp\n// ...\n\nif (cert = SSL_get_peer_certificate(ssl))\n{\n\tresult = SSL_get_verify_result(ssl);\n\n\tif (result == X509_V_OK) // GOOD\n\t{\n\t\tdo_ok();\n\t} else {\n\t\tdo_error();\n\t}\n}\n\n```\n\n## References\n* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-295" + ], + "description": "Only accept SSL certificates that pass certificate verification.", + "id": "cpp/certificate-result-conflation", + "kind": "problem", + "name": "Certificate result conflation", + "precision": "medium", + "problem.severity": "error", + "security-severity": "7.5" + } + }, + { + "id": "cpp/certificate-not-checked", + "name": "cpp/certificate-not-checked", + "shortDescription": { + "text": "Certificate not checked" + }, + "fullDescription": { + "text": "Always check the result of certificate verification after fetching an SSL certificate." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Certificate not checked\nAfter fetching an SSL certificate, always check the result of certificate verification.\n\n\n## Recommendation\nAlways check the result of SSL certificate verification. A certificate that has been revoked may indicate that data is coming from an attacker, whereas a certificate that has expired or was self-signed may indicate an increased likelihood that the data is malicious.\n\n\n## Example\nIn this example, the `SSL_get_peer_certificate` function is used to get the certificate of a peer. However it is unsafe to use that information without checking if the certificate is valid.\n\n\n```cpp\n// ...\n\nX509 *cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is never called)\n\n// ...\n```\nIn the corrected example, we use `SSL_get_verify_result` to check that certificate verification was successful.\n\n\n```cpp\n// ...\n\nX509 *cert = SSL_get_peer_certificate(ssl); // GOOD\nif (cert)\n{\n\tresult = SSL_get_verify_result(ssl);\n\tif (result == X509_V_OK)\n\t{\n\t\t// ...\n```\n\n## References\n* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html).\n", + "markdown": "# Certificate not checked\nAfter fetching an SSL certificate, always check the result of certificate verification.\n\n\n## Recommendation\nAlways check the result of SSL certificate verification. A certificate that has been revoked may indicate that data is coming from an attacker, whereas a certificate that has expired or was self-signed may indicate an increased likelihood that the data is malicious.\n\n\n## Example\nIn this example, the `SSL_get_peer_certificate` function is used to get the certificate of a peer. However it is unsafe to use that information without checking if the certificate is valid.\n\n\n```cpp\n// ...\n\nX509 *cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is never called)\n\n// ...\n```\nIn the corrected example, we use `SSL_get_verify_result` to check that certificate verification was successful.\n\n\n```cpp\n// ...\n\nX509 *cert = SSL_get_peer_certificate(ssl); // GOOD\nif (cert)\n{\n\tresult = SSL_get_verify_result(ssl);\n\tif (result == X509_V_OK)\n\t{\n\t\t// ...\n```\n\n## References\n* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html).\n" + }, + "properties": { + "tags": [ + "security", + "external/cwe/cwe-295" + ], + "description": "Always check the result of certificate verification after fetching an SSL certificate.", + "id": "cpp/certificate-not-checked", + "kind": "problem", + "name": "Certificate not checked", + "precision": "medium", + "problem.severity": "error", + "security-severity": "7.5" + } + }, + { + "id": "cpp/missing-check-scanf", + "name": "cpp/missing-check-scanf", + "shortDescription": { + "text": "Missing return-value check for a 'scanf'-like function" + }, + "fullDescription": { + "text": "Failing to check that a call to 'scanf' actually writes to an output variable can lead to unexpected behavior at reading time." + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Missing return-value check for a 'scanf'-like function\nThis query finds calls of `scanf`-like functions with missing or improper return-value checking.\n\nSpecifically, the query flags uses of variables that may have been modified by `scanf` and subsequently are used without being guarded by a correct return-value check. A proper check is one that ensures that the corresponding `scanf` has returned (at least) a certain minimum constant.\n\nFunctions in the `scanf` family return either EOF (a negative value) in case of IO failure, or the number of items successfully read from the input. Consequently, a simple check that the return value is truthy (nonzero) is not enough.\n\n> WARNING: This query has medium precision because, in the current implementation, it takes a strict stance on unguarded uses of output variables, and flags them as problematic even if they have already been initialized.\n\n## Recommendation\nEnsure that all subsequent uses of `scanf` output arguments occur in a branch of an `if` statement (or similar), in which it is known that the corresponding `scanf` call has in fact read all possible items from its input. This can be done by comparing the return value to a numerical constant.\n\n\n## Example\nThis example shows different ways of guarding a `scanf` output:\n\n\n```cpp\n{\n int i, j, r;\n\n r = scanf(\"%d %d\", &i, &j);\n\n use(i); // BAD: i is not guarded\n\n if (r >= 1) {\n use(i); // GOOD: i is guarded correctly\n use(j); // BAD: j is guarded incorrectly\n }\n\n if (r != 2)\n return;\n\n use(j); // GOOD: j is guarded correctly\n}\n\n```\n\n## References\n* SEI CERT C++ Coding Standard: [ERR62-CPP. Detect errors when converting a string to a number](https://wiki.sei.cmu.edu/confluence/display/cplusplus/ERR62-CPP.+Detect+errors+when+converting+a+string+to+a+number).\n* SEI CERT C Coding Standard: [ERR33-C. Detect and handle standard library errors](https://wiki.sei.cmu.edu/confluence/display/c/ERR33-C.+Detect+and+handle+standard+library+errors).\n* cppreference.com: [scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s](https://en.cppreference.com/w/c/io/fscanf).\n* Common Weakness Enumeration: [CWE-252](https://cwe.mitre.org/data/definitions/252.html).\n* Common Weakness Enumeration: [CWE-253](https://cwe.mitre.org/data/definitions/253.html).\n", + "markdown": "# Missing return-value check for a 'scanf'-like function\nThis query finds calls of `scanf`-like functions with missing or improper return-value checking.\n\nSpecifically, the query flags uses of variables that may have been modified by `scanf` and subsequently are used without being guarded by a correct return-value check. A proper check is one that ensures that the corresponding `scanf` has returned (at least) a certain minimum constant.\n\nFunctions in the `scanf` family return either EOF (a negative value) in case of IO failure, or the number of items successfully read from the input. Consequently, a simple check that the return value is truthy (nonzero) is not enough.\n\n> WARNING: This query has medium precision because, in the current implementation, it takes a strict stance on unguarded uses of output variables, and flags them as problematic even if they have already been initialized.\n\n## Recommendation\nEnsure that all subsequent uses of `scanf` output arguments occur in a branch of an `if` statement (or similar), in which it is known that the corresponding `scanf` call has in fact read all possible items from its input. This can be done by comparing the return value to a numerical constant.\n\n\n## Example\nThis example shows different ways of guarding a `scanf` output:\n\n\n```cpp\n{\n int i, j, r;\n\n r = scanf(\"%d %d\", &i, &j);\n\n use(i); // BAD: i is not guarded\n\n if (r >= 1) {\n use(i); // GOOD: i is guarded correctly\n use(j); // BAD: j is guarded incorrectly\n }\n\n if (r != 2)\n return;\n\n use(j); // GOOD: j is guarded correctly\n}\n\n```\n\n## References\n* SEI CERT C++ Coding Standard: [ERR62-CPP. Detect errors when converting a string to a number](https://wiki.sei.cmu.edu/confluence/display/cplusplus/ERR62-CPP.+Detect+errors+when+converting+a+string+to+a+number).\n* SEI CERT C Coding Standard: [ERR33-C. Detect and handle standard library errors](https://wiki.sei.cmu.edu/confluence/display/c/ERR33-C.+Detect+and+handle+standard+library+errors).\n* cppreference.com: [scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s](https://en.cppreference.com/w/c/io/fscanf).\n* Common Weakness Enumeration: [CWE-252](https://cwe.mitre.org/data/definitions/252.html).\n* Common Weakness Enumeration: [CWE-253](https://cwe.mitre.org/data/definitions/253.html).\n" + }, + "properties": { + "tags": [ + "security", + "correctness", + "external/cwe/cwe-252", + "external/cwe/cwe-253" + ], + "description": "Failing to check that a call to 'scanf' actually writes to an\n output variable can lead to unexpected behavior at reading time.", + "id": "cpp/missing-check-scanf", + "kind": "problem", + "name": "Missing return-value check for a 'scanf'-like function", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "7.5" + } + }, + { + "id": "cpp/allocation-too-small", + "name": "cpp/allocation-too-small", + "shortDescription": { + "text": "Not enough memory allocated for pointer type" + }, + "fullDescription": { + "text": "Calling 'malloc', 'calloc' or 'realloc' without allocating enough memory to contain an instance of the type of the pointer may result in a buffer overflow" + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Not enough memory allocated for pointer type\nWhen 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.\n\n\n## Recommendation\nThe 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.\n\n\n## Example\n\n```cpp\n#define RECORD_SIZE 30 //incorrect or outdated size for record\ntypedef struct {\n\tchar name[30];\n\tint status;\n} Record;\n\nvoid f() {\n\tRecord* p = malloc(RECORD_SIZE); //not of sufficient size to hold a Record\n\t...\n}\n\n```\n\n## References\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html).\n* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html).\n", + "markdown": "# Not enough memory allocated for pointer type\nWhen 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.\n\n\n## Recommendation\nThe 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.\n\n\n## Example\n\n```cpp\n#define RECORD_SIZE 30 //incorrect or outdated size for record\ntypedef struct {\n\tchar name[30];\n\tint status;\n} Record;\n\nvoid f() {\n\tRecord* p = malloc(RECORD_SIZE); //not of sufficient size to hold a Record\n\t...\n}\n\n```\n\n## References\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html).\n* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-131", + "external/cwe/cwe-122" + ], + "description": "Calling 'malloc', 'calloc' or 'realloc' without allocating enough memory to contain\n an instance of the type of the pointer may result in a buffer overflow", + "id": "cpp/allocation-too-small", + "kind": "problem", + "name": "Not enough memory allocated for pointer type", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "8.1" + } + }, + { + "id": "cpp/suspicious-allocation-size", + "name": "cpp/suspicious-allocation-size", + "shortDescription": { + "text": "Not enough memory allocated for array of pointer type" + }, + "fullDescription": { + "text": "Calling 'malloc', 'calloc' or 'realloc' without allocating enough memory to contain multiple instances of the type of the pointer may result in a buffer overflow" + }, + "defaultConfiguration": { + "enabled": true, + "level": "warning" + }, + "help": { + "text": "# Not enough memory allocated for array of pointer type\nWhen 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.\n\n\n## Recommendation\nThe 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.\n\n\n## Example\n\n```cpp\n#define RECORD_SIZE 30 //incorrect or outdated size for record\ntypedef struct {\n\tchar name[30];\n\tint status;\n} Record;\n\nvoid f() {\n\tRecord* p = malloc(RECORD_SIZE * 4); //wrong: not a multiple of the size of Record\n\tp[3].status = 1; //will most likely segfault\n\t...\n}\n\n```\n\n## References\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html).\n* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html).\n", + "markdown": "# Not enough memory allocated for array of pointer type\nWhen 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.\n\n\n## Recommendation\nThe 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.\n\n\n## Example\n\n```cpp\n#define RECORD_SIZE 30 //incorrect or outdated size for record\ntypedef struct {\n\tchar name[30];\n\tint status;\n} Record;\n\nvoid f() {\n\tRecord* p = malloc(RECORD_SIZE * 4); //wrong: not a multiple of the size of Record\n\tp[3].status = 1; //will most likely segfault\n\t...\n}\n\n```\n\n## References\n* I. Gerg. *An Overview and Example of the Buffer-Overflow Exploit*. IANewsletter vol 7 no 4. 2005.\n* M. Donaldson. *Inside the Buffer Overflow Attack: Mechanism, Method & Prevention*. SANS Institute InfoSec Reading Room. 2002.\n* Common Weakness Enumeration: [CWE-131](https://cwe.mitre.org/data/definitions/131.html).\n* Common Weakness Enumeration: [CWE-122](https://cwe.mitre.org/data/definitions/122.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "security", + "external/cwe/cwe-131", + "external/cwe/cwe-122" + ], + "description": "Calling 'malloc', 'calloc' or 'realloc' without allocating enough memory to contain\n multiple instances of the type of the pointer may result in a buffer overflow", + "id": "cpp/suspicious-allocation-size", + "kind": "problem", + "name": "Not enough memory allocated for array of pointer type", + "precision": "medium", + "problem.severity": "warning", + "security-severity": "8.1" + } + }, + { + "id": "cpp/summary/lines-of-user-code", + "name": "cpp/summary/lines-of-user-code", + "shortDescription": { + "text": "Total lines of user written C/C++ code in the database" + }, + "fullDescription": { + "text": "The total number of lines of C/C++ code from the source code directory, excluding auto-generated files. This query counts the lines of code, excluding whitespace or comments. Note: If external libraries are included in the codebase either in a checked-in virtual environment or as vendored code, that will currently be counted as user written code." + }, + "defaultConfiguration": { + "enabled": true + }, + "properties": { + "tags": [ + "summary", + "lines-of-code" + ], + "description": "The total number of lines of C/C++ code from the source code directory, excluding auto-generated files. This query counts the lines of code, excluding whitespace or comments. Note: If external libraries are included in the codebase either in a checked-in virtual environment or as vendored code, that will currently be counted as user written code.", + "id": "cpp/summary/lines-of-user-code", + "kind": "metric", + "name": "Total lines of user written C/C++ code in the database" + } + }, + { + "id": "cpp/summary/lines-of-code", + "name": "cpp/summary/lines-of-code", + "shortDescription": { + "text": "Total lines of C/C++ code in the database" + }, + "fullDescription": { + "text": "The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments." + }, + "defaultConfiguration": { + "enabled": true + }, + "properties": { + "tags": [ + "summary", + "telemetry" + ], + "description": "The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.", + "id": "cpp/summary/lines-of-code", + "kind": "metric", + "name": "Total lines of C/C++ code in the database" + } + } + ], + "locations": [ + { + "uri": "file:///opt/hostedtoolcache/CodeQL/2.16.3/x64/codeql/qlpacks/codeql/cpp-queries/0.9.5/", + "description": { + "text": "The QL pack root directory." + } + }, + { + "uri": "file:///opt/hostedtoolcache/CodeQL/2.16.3/x64/codeql/qlpacks/codeql/cpp-queries/0.9.5/qlpack.yml", + "description": { + "text": "The QL pack definition file." + } + } + ] + } + ] + }, + "invocations": [ + { + "toolExecutionNotifications": [ + { + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/main.c", + "uriBaseId": "%SRCROOT%", + "index": 0 + } + } + } + ], + "message": { + "text": "File successfully extracted." + }, + "level": "none", + "descriptor": { + "id": "cpp/diagnostics/successfully-extracted-files", + "index": 2, + "toolComponent": { + "index": 0 + } + }, + "properties": { + "formattedMessage": { + "text": "File successfully extracted." + } + } + }, + { + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/core/geekmasher/wordcounter.c", + "uriBaseId": "%SRCROOT%", + "index": 1 + } + } + } + ], + "message": { + "text": "File successfully extracted." + }, + "level": "none", + "descriptor": { + "id": "cpp/diagnostics/successfully-extracted-files", + "index": 2, + "toolComponent": { + "index": 0 + } + }, + "properties": { + "formattedMessage": { + "text": "File successfully extracted." + } + } + }, + { + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/main.c", + "uriBaseId": "%SRCROOT%", + "index": 0 + } + } + } + ], + "message": { + "text": "" + }, + "level": "none", + "descriptor": { + "id": "cli/expected-extracted-files/c", + "index": 0 + }, + "properties": { + "formattedMessage": { + "text": "" + } + } + }, + { + "message": { + "text": "Internal telemetry for the C++ extractor.\n\nNo action needed.", + "markdown": "Internal telemetry for the C++ extractor.\n\nNo action needed." + }, + "level": "note", + "timeUtc": "2024-02-29T15:13:01.113+00:00", + "descriptor": { + "id": "cpp/extractor/summary", + "index": 1 + }, + "properties": { + "attributes": { + "cache-hits": 0, + "cache-misses": 1, + "extractor-failures": 0, + "extractor-successes": 1, + "trap-caching": "disabled" + }, + "visibility": { + "statusPage": false, + "telemetry": true + } + } + } + ], + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "src/main.c", + "uriBaseId": "%SRCROOT%", + "index": 0 + } + }, + { + "location": { + "uri": "src/core/geekmasher/wordcounter.c", + "uriBaseId": "%SRCROOT%", + "index": 1 + } + } + ], + "results": [ + { + "ruleId": "cpp/wrong-type-format-argument", + "rule": { + "id": "cpp/wrong-type-format-argument", + "index": 2, + "toolComponent": { + "index": 0 + } + }, + "message": { + "text": "This argument should be of type 'char *' but is of type '(unnamed class/struct/union)'." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/core/main.c", + "uriBaseId": "%SRCROOT%", + "index": 0 + }, + "region": { + "startLine": 22, + "startColumn": 45, + "endColumn": 47 + } + } + } + ], + "partialFingerprints": { + "primaryLocationLineHash": "b009cce36690efad:1", + "primaryLocationStartColumnFingerprint": "40" + } + } + ], + "automationDetails": { + "id": "/language:c-cpp/" + }, + "columnKind": "utf16CodeUnits", + "properties": { + "codeqlConfigSummary": { + "disableDefaultQueries": false, + "queries": [ + { + "type": "builtinSuite", + "uses": "security-extended" + } + ] + }, + "metricResults": [ + { + "rule": { + "id": "cpp/summary/lines-of-user-code", + "index": 82, + "toolComponent": { + "index": 0 + } + }, + "ruleId": "cpp/summary/lines-of-user-code", + "value": 46 + }, + { + "rule": { + "id": "cpp/summary/lines-of-code", + "index": 83, + "toolComponent": { + "index": 0 + } + }, + "ruleId": "cpp/summary/lines-of-code", + "value": 3014 + } + ], + "semmle.formatSpecifier": "sarif-latest" + } + } + ] +} diff --git a/sariftoolkit/plugins/subfolders.py b/sariftoolkit/plugins/subfolders.py index 5d48a14..97cc97d 100644 --- a/sariftoolkit/plugins/subfolders.py +++ b/sariftoolkit/plugins/subfolders.py @@ -74,7 +74,6 @@ def run(self, arguments, **kargvs): for sarif, sarif_file in self.loadSarif(self.sarif_path): - self.logger.info(f"sarif :: {sarif}") self.processSarif(config, sarif, sarif_file) def processSarif( From cca2f54302ffb8772c7d00a794149c258a0b8c53 Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Fri, 22 Mar 2024 17:33:21 +0100 Subject: [PATCH 4/5] Update subfolders.py --- sariftoolkit/plugins/subfolders.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sariftoolkit/plugins/subfolders.py b/sariftoolkit/plugins/subfolders.py index 97cc97d..ca2894b 100644 --- a/sariftoolkit/plugins/subfolders.py +++ b/sariftoolkit/plugins/subfolders.py @@ -132,10 +132,10 @@ def processSarif( new_location_uri ) - if not subfolder_sarifs[subfolder.name].get(result.ruleId): - subfolder_sarifs[subfolder.name][result.ruleId] = [] + if not subfolder_sarifs[subfolder['name']].get(result.ruleId): + subfolder_sarifs[subfolder['name']][result.ruleId] = [] - subfolder_sarifs[subfolder.name][result.ruleId].append( + subfolder_sarifs[subfolder['name']][result.ruleId].append( result ) From 716845bcbde3124178bf781c5eee9ab34f64064f Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Fri, 29 Mar 2024 18:09:39 +0100 Subject: [PATCH 5/5] Update subfolder configuration and publish SARIF files --- config.yml | 4 ++ examples/sarifs/cpp-testing-queries.sarif | 2 +- examples/sarifs/python-testing-queries.sarif | 66 ++++++++++++++++++++ sariftoolkit/plugins/subfolders.py | 26 +++++--- subfolders/README.md | 19 ++++++ 5 files changed, 107 insertions(+), 10 deletions(-) diff --git a/config.yml b/config.yml index 61276e7..0c980fb 100644 --- a/config.yml +++ b/config.yml @@ -2,7 +2,11 @@ url: https://github.com/ORG_REPO path: src/core token: github_pat_ + branch: main + commit: xxx - name: lib url: https://github.com/ORG_REPO@ path: src/lib token: github_pat_ + branch: main + commit: xxx diff --git a/examples/sarifs/cpp-testing-queries.sarif b/examples/sarifs/cpp-testing-queries.sarif index 0072d8a..d2d81c6 100644 --- a/examples/sarifs/cpp-testing-queries.sarif +++ b/examples/sarifs/cpp-testing-queries.sarif @@ -3049,4 +3049,4 @@ } } ] -} +} \ No newline at end of file diff --git a/examples/sarifs/python-testing-queries.sarif b/examples/sarifs/python-testing-queries.sarif index 27aa83a..0aecd86 100644 --- a/examples/sarifs/python-testing-queries.sarif +++ b/examples/sarifs/python-testing-queries.sarif @@ -706,6 +706,39 @@ "sub-severity": "high" } }, + { + "id": "cpp/wrong-type-format-argument", + "name": "cpp/wrong-type-format-argument", + "shortDescription": { + "text": "Wrong type of arguments to formatting function" + }, + "fullDescription": { + "text": "Calling a printf-like function with the wrong type of arguments causes unpredictable behavior." + }, + "defaultConfiguration": { + "enabled": true, + "level": "error" + }, + "help": { + "text": "# Wrong type of arguments to formatting function\nEach 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.\n\n\n## Recommendation\nReview 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.\n\n\n## Example\n\n```cpp\nint main() {\n printf(\"%s\\n\", 42); //printf will treat 42 as a char*, will most likely segfault\n return 0;\n}\n\n```\n\n## References\n* 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).\n* cplusplus.com: [C++ Functions](http://www.tutorialspoint.com/cplusplus/cpp_functions.htm).\n* CRT Alphabetical Function Reference: [printf, _printf_l, wprintf, _wprintf_l](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l).\n* Common Weakness Enumeration: [CWE-686](https://cwe.mitre.org/data/definitions/686.html).\n", + "markdown": "# Wrong type of arguments to formatting function\nEach 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.\n\n\n## Recommendation\nReview 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.\n\n\n## Example\n\n```cpp\nint main() {\n printf(\"%s\\n\", 42); //printf will treat 42 as a char*, will most likely segfault\n return 0;\n}\n\n```\n\n## References\n* 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).\n* cplusplus.com: [C++ Functions](http://www.tutorialspoint.com/cplusplus/cpp_functions.htm).\n* CRT Alphabetical Function Reference: [printf, _printf_l, wprintf, _wprintf_l](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l).\n* Common Weakness Enumeration: [CWE-686](https://cwe.mitre.org/data/definitions/686.html).\n" + }, + "properties": { + "tags": [ + "reliability", + "correctness", + "security", + "external/cwe/cwe-686" + ], + "description": "Calling a printf-like function with the wrong type of arguments causes unpredictable\n behavior.", + "id": "cpp/wrong-type-format-argument", + "kind": "problem", + "name": "Wrong type of arguments to formatting function", + "precision": "high", + "problem.severity": "error", + "security-severity": "7.5" + } + }, { "id": "py/request-without-cert-validation", "name": "py/request-without-cert-validation", @@ -1912,6 +1945,39 @@ } ], "results": [ + { + "ruleId": "cpp/wrong-type-format-argument", + "rule": { + "id": "cpp/wrong-type-format-argument", + "index": 2, + "toolComponent": { + "index": 0 + } + }, + "message": { + "text": "This argument should be of type 'char *' but is of type '(unnamed class/struct/union)'." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/core/main.c", + "uriBaseId": "%SRCROOT%", + "index": 0 + }, + "region": { + "startLine": 22, + "startColumn": 45, + "endColumn": 47 + } + } + } + ], + "partialFingerprints": { + "primaryLocationLineHash": "b009cce36690efad:1", + "primaryLocationStartColumnFingerprint": "40" + } + }, { "ruleId": "py/flask-debug", "ruleIndex": 11, diff --git a/sariftoolkit/plugins/subfolders.py b/sariftoolkit/plugins/subfolders.py index ca2894b..310da22 100644 --- a/sariftoolkit/plugins/subfolders.py +++ b/sariftoolkit/plugins/subfolders.py @@ -86,7 +86,7 @@ def processSarif( subfolder_sarifs = {} for sub in subfolder_structured: - subfolder_sarifs[sub["name"]] = {} + subfolder_sarifs[sub["name"]] = sub for run in sarif.runs: print("-----------SARIF -----------") @@ -168,7 +168,7 @@ def processSarif( submod_file = self.createsubfolderFileName(name, sarif_file) exportSarif(submod_file, subfolder_sarif) - self.publishSarifFile(subfolder, subfolder_sarif, sarif_file=submod_file) + self.publishSarifFile(subfolder_sarifs[sub["name"]], subfolder_sarif, sarif_file=submod_file) if self.cleanup: self.logger.info(f"Cleaning up SARIF file: {submod_file}") @@ -245,16 +245,20 @@ def publishSarifFile( sarif_file: str, instance: str = "https://github.com", ): - if not self.token: + self.logger.warning(f"Config: {subfolder}") + if not subfolder["token"]: self.logger.warning("Failed to find access token, skipping publishing...") return - self.logger.info(f"Publishing SARIF to subfolder: {subfolder.name}") + name = subfolder["name"] + self.logger.info(f"Publishing SARIF to subfolder: {name}") headers = { "Accept": "application/vnd.github.v3+json", - "Authorization": "token " + self.token, + "Authorization": "token " + subfolder["token"], } - owner, repo = subfolder.url.split("/") + url_split = subfolder["url"].split("/") + owner = url_split.pop(0) + repo = url_split.pop(1) if instance == "https://github.com": api_instance = "https://api.github.com" else: @@ -263,13 +267,17 @@ def publishSarifFile( url = f"{api_instance}/repos/{owner}/{repo}/code-scanning/sarifs" self.logger.debug(f"Publishing SARIF file to endpoint: {url}") + if not 'branch' in subfolder: + subfolder["branch"] = "main" + data = { - "commit_sha": subfolder.commit, - "ref": subfolder.branch, + "commit_sha": subfolder["url"], + "ref": subfolder["branch"], "sarif": self.packageSarif(sarif_file), "tool_name": sarif.runs[0].tool.driver.name, } res = requests.post(url, json=data, headers=headers) - + + self.logger.debug(f"Response: {res.status_code} - {res.text}") self.logger.info("Uploaded SARIF file to subfolder") diff --git a/subfolders/README.md b/subfolders/README.md index ac216ac..ebfb322 100644 --- a/subfolders/README.md +++ b/subfolders/README.md @@ -46,5 +46,24 @@ This Action needs to be placed in between the point of the SARIF file(s) being c # 'path': If any location is in the SARIF file # [optional]: Default: 'sink' mode: 'sink' + # Configuration file location + # configuration file is a YAML file that contains the configuration for the + # subfolders tool. + # Here is an example configuration file: + #  ```yaml + # - name: core + # url: https://github.com/ORG_REPO + # path: src/core + # token: github_pat_ + # branch: main + # commit: xxx + # - name: lib + # url: https://github.com/ORG_REPO@ + # path: src/lib + # token: github_pat_ + # branch: main + # commit: xxx   + # ``` + config-file: './config.yml' ```