Skip to content
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

Use different regexes in KeywordDetector to improve accuracy #86

Merged
merged 19 commits into from
Jan 3, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
b9c80f9
Use different regexes in KeywordDetector to improve accuracy
KevinHock Oct 22, 2018
c4e7676
Trim regexes down, include secret 'foo'; as well.
KevinHock Oct 22, 2018
fce2837
Do not alert if whitespace is in secret
KevinHock Oct 22, 2018
3167cb1
[Keyword Plugin] Add 3 re's and their secret groups in dict
KevinHock Oct 31, 2018
b6dc9cc
Merge branch 'master' into upgrade_keyword_detector
KevinHock Oct 31, 2018
b89209f
Add a few more Keyword negative test-cases
KevinHock Oct 31, 2018
431ad12
Added a variety of accuracy improvements to Keyword Plugin (see tests)
KevinHock Nov 1, 2018
a27659a
:telescope:[Keyword Plugin] Filter false-positives
KevinHock Dec 14, 2018
a4c0432
Merge branch 'master' into upgrade_keyword_detector
KevinHock Dec 14, 2018
d8f4e29
:snake: Make tests pass
KevinHock Dec 14, 2018
ed6a374
:snake: Improve test coverage
KevinHock Dec 14, 2018
3fd9e87
:telescope:[Keyword Plugin] Precision improvements
KevinHock Dec 14, 2018
f15366e
:zap: Remove unnecessary wrapping parens
KevinHock Dec 21, 2018
e01d818
:telescope:[Keyword Plugin] Precision improvements
KevinHock Dec 28, 2018
4581aa8
:mortar_board: Eg. -> E.g.
KevinHock Dec 28, 2018
b7e48ab
:telescope:[Keyword Plugin] Handle dict['keyword']
KevinHock Dec 28, 2018
a37a9c9
:arrows_counterclockwise: Merge branch 'master' into upgrade_keyword_…
KevinHock Dec 28, 2018
d314550
:snake:[consistency] 2 spaces before pragma comment
KevinHock Dec 29, 2018
a29108b
:telescope:[Keyword Plugin] Precision improvements
KevinHock Jan 3, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion detect_secrets/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION = '0.10.3'
VERSION = '0.10.4'
3 changes: 3 additions & 0 deletions detect_secrets/plugins/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ def secret_generator(self, string):

:type string: str
:param string: the secret to scan

:rtype: iter
:returns: Of all the identifiers found
"""
raise NotImplementedError

Expand Down
53 changes: 43 additions & 10 deletions detect_secrets/plugins/keyword.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,55 @@
"""
from __future__ import absolute_import

import re

from .base import BasePlugin
from detect_secrets.core.potential_secret import PotentialSecret
from detect_secrets.plugins.core.constants import WHITELIST_REGEX


# Note: All values here should be lowercase
BLACKLIST = (
# NOTE all values here should be lowercase,
# otherwise _secret_generator can fail to match them
'pass =',
'apikey',
'api_key',
'pass',
'password',
'passwd',
'pwd',
'private_key',
'secret',
'secrete',
'token',
)
# Uses lazy quantifiers
BLACKLIST_REGEX = re.compile(
KevinHock marked this conversation as resolved.
Show resolved Hide resolved
# Followed by double-quotes and a semi-colon
# e.g. private_key "something";
# e.g. private_key 'something';
r'|'.join(
'{}(.*?)("|\')(\\S*?)(\'|");'.format(
KevinHock marked this conversation as resolved.
Show resolved Hide resolved
value,
)
for value in BLACKLIST
) + '|' +
# Followed by a :
# e.g. token:
r'|'.join(
'{}:'.format(
KevinHock marked this conversation as resolved.
Show resolved Hide resolved
value,
)
for value in BLACKLIST
) + '|' +
# Follwed by an = sign
# e.g. my_password =
r'|'.join(
'{}(.*?)='.format(
KevinHock marked this conversation as resolved.
Show resolved Hide resolved
value,
)
for value in BLACKLIST
) +
# For `pwd` it has to start with pwd after whitespace, it is too common
'|\\spwd(.*?)=',
KevinHock marked this conversation as resolved.
Show resolved Hide resolved
)


class KeywordDetector(BasePlugin):
Expand All @@ -68,10 +101,10 @@ def analyze_string(self, string, line_num, filename):

return output

def _secret_generator(self, lowercase_string):
for line in BLACKLIST:
if line in lowercase_string:
yield line

def secret_generator(self, string):
return self._secret_generator(string.lower())
match = BLACKLIST_REGEX.search(
string.lower(),
)
if not match:
return []
return [match.group()]
68 changes: 62 additions & 6 deletions tests/plugins/keyword_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,79 @@ class TestKeywordDetector(object):
'file_content',
[
(
KevinHock marked this conversation as resolved.
Show resolved Hide resolved
'login_somewhere --http-password hopenobodyfindsthisone\n'
'apikey "something";'
),
(
'token = "noentropy"'
'token "something";'
),
(
'private_key \'"something\';' # Single-quotes not double-quotes
),
(
'apikey:'
),
(
'the_token:'
),
(
'my_password ='
),
(
'some_token_for_something ='
),
(
'PASSWORD = "verysimple"'
' pwd = foo'
),
(
'private_key "something";'
),

(
'passwordone=foo\n'
),
(
'API_KEY=hopenobodyfindsthisone\n'
),
(
'token = "noentropy"'
),
],
)
def test_analyze(self, file_content):
def test_analyze_positives(self, file_content):
logic = KeywordDetector()

f = mock_file_object(file_content)
output = logic.analyze(f, 'mock_filename')
assert len(output) == 1
for potential_secret in output:
assert 'mock_filename' == potential_secret.filename
generated = list(logic.secret_generator(file_content))
assert len(generated) == len(output)

@pytest.mark.parametrize(
'file_content',
[
(
'private_key \'"no spaces\';' # Has whitespace in-between
KevinHock marked this conversation as resolved.
Show resolved Hide resolved
),
(
'passwordonefoo\n' # No = or anything
),
(
'api_keyhopenobodyfindsthisone:\n' # Has char's in between api_key and :
),
(
'my_pwd =' # Does not start with pwd
),
(
'token "noentropy;' # No 2nd double-quote
),
(
'token noentropy;' # No quotes
),
],
)
def test_analyze_negatives(self, file_content):
logic = KeywordDetector()

f = mock_file_object(file_content)
output = logic.analyze(f, 'mock_filename')
assert len(output) == 0