From c02231ff1c42261ac573f06e85e78042ecda9e66 Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Tue, 6 Dec 2022 13:39:51 +0100 Subject: [PATCH] Add Codex vuln detector The detector requires: - The user to use the flag `--codex` (meaning that codex is not ran by default) - `openai` must be installed, and `OPENAI_API_KEY` set The detector works at the contract level, and send the whole contract body to codex --- setup.py | 1 + slither/__main__.py | 4 ++ slither/detectors/all_detectors.py | 1 + slither/detectors/functions/codex.py | 80 ++++++++++++++++++++++++++++ slither/slither.py | 3 ++ 5 files changed, 89 insertions(+) create mode 100644 slither/detectors/functions/codex.py diff --git a/setup.py b/setup.py index 510efd0971..b29244713c 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ "deepdiff", "numpy", "solc-select>=v1.0.0b1", + "openai" ] }, license="AGPL-3.0", diff --git a/slither/__main__.py b/slither/__main__.py index 70357586e9..00ea308d2a 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -301,6 +301,10 @@ def parse_args( parser.add_argument("filename", help=argparse.SUPPRESS) + parser.add_argument( + "--codex", help="Enable codex (require an OpenAI API Key)", action="store_true", default=False + ) + cryticparser.init(parser) parser.add_argument( diff --git a/slither/detectors/all_detectors.py b/slither/detectors/all_detectors.py index 2c8d244281..e8c8334b72 100644 --- a/slither/detectors/all_detectors.py +++ b/slither/detectors/all_detectors.py @@ -85,3 +85,4 @@ from .statements.delegatecall_in_loop import DelegatecallInLoop from .functions.protected_variable import ProtectedVariables from .functions.permit_domain_signature_collision import DomainSeparatorCollision +from .functions.codex import Codex diff --git a/slither/detectors/functions/codex.py b/slither/detectors/functions/codex.py new file mode 100644 index 0000000000..daed064252 --- /dev/null +++ b/slither/detectors/functions/codex.py @@ -0,0 +1,80 @@ +import logging +import os +from typing import List + +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from slither.utils.output import Output + +logger = logging.getLogger("Slither") + + +class Codex(AbstractDetector): + """ + Use codex to detect vulnerability + """ + + ARGUMENT = "codex" + HELP = "Use Codex to find vulnerabilities." + IMPACT = DetectorClassification.HIGH + CONFIDENCE = DetectorClassification.LOW + + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#codex" + + WIKI_TITLE = "Codex" + WIKI_DESCRIPTION = "Use [codex](https://openai.com/blog/openai-codex/) to find vulnerabilities" + + # region wiki_exploit_scenario + WIKI_EXPLOIT_SCENARIO = """N/A""" + # endregion wiki_exploit_scenario + + WIKI_RECOMMENDATION = "Review codex's message." + + def _detect(self) -> List[Output]: + results: List[Output] = [] + + if not self.slither.codex_enabled: + return [] + + try: + # pylint: disable=import-outside-toplevel + import openai + except ImportError: + logging.info("OpenAI was not installed") + logging.info('run "pip install openai"') + return [] + + api_key = os.getenv("OPENAI_API_KEY") + if api_key is None: + logging.info( + "Please provide an Open API Key in OPENAI_API_KEY (https://beta.openai.com/account/api-keys)" + ) + return [] + openai.api_key = api_key + + for contract in self.compilation_unit.contracts: + prompt = "Is there a vulnerability in this solidity contracts?\n" + src_mapping = contract.source_mapping + content = contract.compilation_unit.core.source_code[src_mapping.filename.absolute] + start = src_mapping.start + end = src_mapping.start + src_mapping.length + prompt += content[start:end] + answer = openai.Completion.create( # type: ignore + model="text-davinci-003", prompt=prompt, temperature=0, max_tokens=200 + ) + + if "choices" in answer: + if answer["choices"]: + if "text" in answer["choices"][0]: + if "Yes," in answer["choices"][0]["text"]: + info = [ + "Codex detected a potential bug in ", + contract, + "\n", + answer["choices"][0]["text"], + "\n", + ] + + res = self.generate_result(info) + results.append(res) + + return results diff --git a/slither/slither.py b/slither/slither.py index dcfc0ad7e5..a61e8255ff 100644 --- a/slither/slither.py +++ b/slither/slither.py @@ -83,6 +83,9 @@ def __init__(self, target: Union[str, CryticCompile], **kwargs): self.line_prefix = kwargs.get("change_line_prefix", "#") + # Indicate if codex-related features should be used + self.codex_enabled = kwargs.get("codex", False) + self._parsers: List[SlitherCompilationUnitSolc] = [] try: if isinstance(target, CryticCompile):