-
Notifications
You must be signed in to change notification settings - Fork 448
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Keyword Plugin] Various accuracy improvements #229
Changes from all commits
646c1e0
85f0c74
04c6d34
2f2ccb0
a53d12e
5de43e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,8 +66,9 @@ | |
"'this", | ||
'(nsstring', | ||
'-default}', | ||
'/etc/passwd:ro', | ||
'::', | ||
'<%=', | ||
'<?php', | ||
'<a', | ||
'<aws_secret_access_key>', | ||
'<input', | ||
|
@@ -80,53 +81,81 @@ | |
"\\k.*'", | ||
'`cat', | ||
'`grep', | ||
'`sudo', | ||
'account_password', | ||
'api_key', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this in both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this is for the case wherein silly code does
|
||
'disable', | ||
'dummy_secret', | ||
'dummy_value', | ||
'false', | ||
'false):', | ||
'false,', | ||
'false;', | ||
'login_password', | ||
'none', | ||
'none,', | ||
'none}', | ||
'not', | ||
'not_real_key', | ||
'null', | ||
'null,', | ||
'null.*"', | ||
"null.*'", | ||
'null;', | ||
'pass', | ||
'pass)', | ||
'password', | ||
'password)', | ||
'password))', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to clarify, does this mean a word that contains There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The short-answer is, only if it The |
||
'password,', | ||
'password},', | ||
'prompt', | ||
'redacted', | ||
'secret', | ||
'some_key', | ||
'str', | ||
'str_to_sign', | ||
'string', | ||
'string)', | ||
'string,', | ||
'string;', | ||
'string?', | ||
'string?)', | ||
'string}', | ||
'string}}', | ||
'test', | ||
'test-access-key', | ||
'thisisnottherealsecret', | ||
'todo', | ||
'true', | ||
'true):', | ||
'true,', | ||
'true;', | ||
'undef', | ||
'undef,', | ||
'{', | ||
'{{', | ||
} | ||
QUOTE = r'[\'"]' | ||
# includes ], ', " as closing | ||
# Includes ], ', " as closing | ||
CLOSING = r'[]\'"]{0,2}' | ||
# non-greedy match | ||
DENYLIST_REGEX = r'|'.join(DENYLIST) | ||
# Non-greedy match | ||
OPTIONAL_WHITESPACE = r'\s*?' | ||
OPTIONAL_NON_WHITESPACE = r'[^\s]*?' | ||
QUOTE = r'[\'"]' | ||
SECRET = r'[^\s]+' | ||
DENYLIST_REGEX = r'|'.join(DENYLIST) | ||
SQUARE_BRACKETS = r'(\[\])' | ||
|
||
FOLLOWED_BY_COLON_EQUAL_SIGNS_REGEX = re.compile( | ||
# e.g. my_password := "bar" or my_password := bar | ||
r'({denylist})({closing})?{whitespace}:=?{whitespace}({quote}?)({secret})(\3)'.format( | ||
denylist=DENYLIST_REGEX, | ||
closing=CLOSING, | ||
quote=QUOTE, | ||
whitespace=OPTIONAL_WHITESPACE, | ||
secret=SECRET, | ||
), | ||
) | ||
FOLLOWED_BY_COLON_REGEX = re.compile( | ||
# e.g. api_key: foo | ||
r'({denylist})({closing})?:{whitespace}({quote}?)({secret})(\3)'.format( | ||
|
@@ -147,6 +176,17 @@ | |
secret=SECRET, | ||
), | ||
) | ||
FOLLOWED_BY_EQUAL_SIGNS_OPTIONAL_BRACKETS_OPTIONAL_AT_SIGN_QUOTES_REQUIRED_REGEX = re.compile( | ||
# e.g. my_password = "bar" | ||
# e.g. my_password = @"bar" | ||
# e.g. my_password[] = "bar"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Based on below this is Objective-C. What does this actually do in Objective-C? (I couldn't Google it) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Something I do not handle yet, but can ticket, are strings like the following
Prior to this PR, we'd capture e.g. |
||
r'({denylist})({square_brackets})?{optional_whitespace}={optional_whitespace}(@)?(")({secret})(\5)'.format( # noqa: E501 | ||
denylist=DENYLIST_REGEX, | ||
square_brackets=SQUARE_BRACKETS, | ||
optional_whitespace=OPTIONAL_WHITESPACE, | ||
secret=SECRET, | ||
), | ||
) | ||
FOLLOWED_BY_EQUAL_SIGNS_REGEX = re.compile( | ||
# e.g. my_password = bar | ||
r'({denylist})({closing})?{whitespace}={whitespace}({quote}?)({secret})(\3)'.format( | ||
|
@@ -178,35 +218,31 @@ | |
secret=SECRET, | ||
), | ||
) | ||
FOLLOWED_BY_COLON_EQUAL_SIGNS_REGEX = re.compile( | ||
# e.g. my_password := "bar" or my_password := bar | ||
r'({denylist})({closing})?{whitespace}:=?{whitespace}({quote}?)({secret})(\3)'.format( | ||
denylist=DENYLIST_REGEX, | ||
closing=CLOSING, | ||
quote=QUOTE, | ||
whitespace=OPTIONAL_WHITESPACE, | ||
secret=SECRET, | ||
), | ||
) | ||
DENYLIST_REGEX_TO_GROUP = { | ||
FOLLOWED_BY_COLON_REGEX: 4, | ||
FOLLOWED_BY_EQUAL_SIGNS_REGEX: 4, | ||
FOLLOWED_BY_QUOTES_AND_SEMICOLON_REGEX: 3, | ||
} | ||
GOLANG_DENYLIST_REGEX_TO_GROUP = { | ||
FOLLOWED_BY_COLON_EQUAL_SIGNS_REGEX: 4, | ||
FOLLOWED_BY_EQUAL_SIGNS_REGEX: 4, | ||
FOLLOWED_BY_QUOTES_AND_SEMICOLON_REGEX: 3, | ||
} | ||
OBJECTIVE_C_DENYLIST_REGEX_TO_GROUP = { | ||
FOLLOWED_BY_EQUAL_SIGNS_OPTIONAL_BRACKETS_OPTIONAL_AT_SIGN_QUOTES_REQUIRED_REGEX: 6, | ||
} | ||
QUOTES_REQUIRED_DENYLIST_REGEX_TO_GROUP = { | ||
FOLLOWED_BY_COLON_QUOTES_REQUIRED_REGEX: 5, | ||
FOLLOWED_BY_EQUAL_SIGNS_QUOTES_REQUIRED_REGEX: 4, | ||
FOLLOWED_BY_QUOTES_AND_SEMICOLON_REGEX: 3, | ||
} | ||
GOLANG_DENYLIST_REGEX_TO_GROUP = { | ||
FOLLOWED_BY_EQUAL_SIGNS_REGEX: 4, | ||
FOLLOWED_BY_QUOTES_AND_SEMICOLON_REGEX: 3, | ||
FOLLOWED_BY_COLON_EQUAL_SIGNS_REGEX: 4, | ||
} | ||
QUOTES_REQUIRED_FILETYPES = { | ||
FileType.CLS, | ||
FileType.JAVA, | ||
FileType.JAVASCRIPT, | ||
FileType.PYTHON, | ||
FileType.SWIFT, | ||
FileType.TERRAFORM, | ||
} | ||
|
||
|
||
|
@@ -257,6 +293,8 @@ def secret_generator(self, string, filetype): | |
denylist_regex_to_group = QUOTES_REQUIRED_DENYLIST_REGEX_TO_GROUP | ||
elif filetype == FileType.GO: | ||
denylist_regex_to_group = GOLANG_DENYLIST_REGEX_TO_GROUP | ||
elif filetype == FileType.OBJECTIVE_C: | ||
denylist_regex_to_group = OBJECTIVE_C_DENYLIST_REGEX_TO_GROUP | ||
else: | ||
denylist_regex_to_group = DENYLIST_REGEX_TO_GROUP | ||
|
||
|
@@ -275,24 +313,27 @@ def secret_generator(self, string, filetype): | |
|
||
def probably_false_positive(lowered_secret, filetype): | ||
if ( | ||
'fake' in lowered_secret | ||
or 'forgot' in lowered_secret | ||
or lowered_secret in FALSE_POSITIVES | ||
or ( | ||
filetype == FileType.JAVASCRIPT | ||
and ( | ||
lowered_secret.startswith('this.') | ||
or lowered_secret.startswith('fs.read') | ||
or lowered_secret.startswith('options.') | ||
or lowered_secret == 'new' | ||
any( | ||
false_positive in lowered_secret | ||
for false_positive in ( | ||
'/etc/', | ||
'fake', | ||
'forgot', | ||
) | ||
) or lowered_secret in FALSE_POSITIVES | ||
# For e.g. private_key "some/dir/that/is/not/a/secret"; | ||
or lowered_secret.count('/') >= 3 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, added comment in 5de43e2 |
||
# For e.g. "secret": "{secret}" | ||
or ( | ||
lowered_secret[0] == '{' | ||
and lowered_secret[-1] == '}' | ||
) or ( | ||
filetype == FileType.PHP | ||
filetype not in QUOTES_REQUIRED_FILETYPES | ||
and lowered_secret[0] == '$' | ||
) or ( | ||
filetype == FileType.YAML | ||
and lowered_secret.startswith('{{') | ||
and lowered_secret.endswith('}}') | ||
filetype == FileType.EXAMPLE | ||
and lowered_secret[0] == '<' | ||
and lowered_secret[-1] == '>' | ||
) | ||
): | ||
return True | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this handle
my.weird.filename
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, and does this work with no file extension?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh it does, the
get
call in the next line has a defaultThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For posterity, it'll be
''
and then get set toFileType.OTHER
(I had an internal π€ about
setdefault
vs. the.get
fallback but π€·ββ I kinda liked the way it looked.)