diff --git a/detect_secrets/plugins/aws.py b/detect_secrets/plugins/aws.py index 0d1604174..23afd1610 100644 --- a/detect_secrets/plugins/aws.py +++ b/detect_secrets/plugins/aws.py @@ -24,6 +24,11 @@ class AWSKeyDetector(RegexBasedDetector): denylist = ( re.compile(r'AKIA[0-9A-Z]{16}'), + + # This examines the variable name to identify AWS secret tokens. + # The order is important since we want to prefer finding `AKIA`-based + # keys (since they can be verified), rather than the secret tokens. + re.compile(r'aws.{0,20}?[\'\"]([0-9a-zA-Z/+]{40})[\'\"]'), ) def verify( # type: ignore[override] # noqa: F821 @@ -31,6 +36,11 @@ def verify( # type: ignore[override] # noqa: F821 secret: str, context: CodeSnippet, ) -> VerifiedResult: + # As this verification process looks for multi-factor secrets, by assuming that + # the identified secret token is the key ID (then looking for the corresponding secret). + # we quit early if it fails our assumptions. + if not self.denylist[0].match(secret): + return VerifiedResult.UNVERIFIED secret_access_key_candidates = get_secret_access_keys(context) if not secret_access_key_candidates: return VerifiedResult.UNVERIFIED diff --git a/tests/plugins/aws_key_test.py b/tests/plugins/aws_key_test.py index 2c5f4f448..6174a857c 100644 --- a/tests/plugins/aws_key_test.py +++ b/tests/plugins/aws_key_test.py @@ -32,6 +32,18 @@ def setup(self): 'AKIAZZZ', False, ), + ( + 'aws_access_key = "{}"'.format(EXAMPLE_SECRET), + True, + ), + ( + 'aws_access_key = "{}"'.format(EXAMPLE_SECRET + 'a'), + False, + ), + ( + 'aws_access_key = "{}"'.format(EXAMPLE_SECRET[0:39]), + False, + ), ], ) def test_analyze(self, line, should_flag): @@ -48,6 +60,11 @@ def test_verify_no_secret(self): get_code_snippet([], 1), ) == VerifiedResult.UNVERIFIED + assert logic.verify( + EXAMPLE_SECRET, + get_code_snippet([], 1), + ) == VerifiedResult.UNVERIFIED + def test_verify_valid_secret(self): with mock.patch( 'detect_secrets.plugins.aws.verify_aws_secret_access_key',