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

Return actual secret strings for private keys when appear in same line #646

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
return secret strings for private keys
  • Loading branch information
arielkru committed Dec 7, 2022
commit b9e4229939b68c3f3316ec5135a19f50673452df
38 changes: 27 additions & 11 deletions detect_secrets/plugins/private_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
THE SOFTWARE.
"""
import re
from typing import Generator

from .base import RegexBasedDetector

Expand All @@ -39,16 +40,31 @@ class PrivateKeyDetector(RegexBasedDetector):

secret_type = 'Private Key'

begin_key_opening = r'(?P<begin_key>BEGIN'
key_types = r'(?: DSA | EC | OPENSSH | PGP | RSA | SSH2 ENCRYPTED | )'
begin_key_closing = r'PRIVATE KEY-*)'
begin_key = fr'{begin_key_opening}{key_types}{begin_key_closing}'
secret_key = r'(?P<secret_key>[A-Za-z0-9+\/\\\n]*={0,3})?'
end_key = r'(?P<end_key>\n*-*END)?'

denylist = [
re.compile(regexp)
for regexp in (
r'BEGIN DSA PRIVATE KEY',
r'BEGIN EC PRIVATE KEY',
r'BEGIN OPENSSH PRIVATE KEY',
r'BEGIN PGP PRIVATE KEY BLOCK',
r'BEGIN PRIVATE KEY',
r'BEGIN RSA PRIVATE KEY',
r'BEGIN SSH2 ENCRYPTED PRIVATE KEY',
r'PuTTY-User-Key-File-2',
)
re.compile(
r'{begin_key}{secret_key}{end_key}'.format(
begin_key=begin_key,
secret_key=secret_key,
end_key=end_key,
),
),
re.compile(r'PuTTY-User-Key-File-2'),
]

def analyze_string(self, string: str) -> Generator[str, None, None]:
for regex in self.denylist:
for match in regex.findall(string):
if isinstance(match, tuple):
begin_key, secret_key, end_key = match
if begin_key:
yield secret_key if secret_key else begin_key
else:
# only PuTTY-User-Key-File should not be a tuple
yield match
37 changes: 30 additions & 7 deletions tests/plugins/private_key_test.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,57 @@
import pytest
import json

from detect_secrets.core.secrets_collection import SecretsCollection
from detect_secrets.settings import transient_settings
from testing.mocks import mock_named_temporary_file


@pytest.mark.parametrize(
'file_content',
'file_content, secrets_amount, expected_secret',
[
(
'-----BEGIN RSA PRIVATE KEY-----\n'
'super secret private key here\n'
'-----END RSA PRIVATE KEY-----'
json.dumps(
'-----BEGIN RSA PRIVATE KEY-----\n'
'c3VwZXIgZHVwZXIgc2VjcmV0IHBhc3N3b3JkLCBzdXBlciBkdXBlciBzZ\n'
'WNyZXQgcGFzc3dvcmQhMTIzNCMkJQpzdXBlciBkdXBlciBzZWNyZXQgcGFzc3'
'dvcmQsIHN1cGVyIGR1cGVyIHNlY3JldCBwYXNzd29yZCExMjM0IyQlCgo=\n'
'-----END RSA PRIVATE KEY-----',
),
1,
'\\nc3VwZXIgZHVwZXIgc2VjcmV0IHBhc3N3b3JkLCBzdXBlciBkdXBlciBzZ\\n'
'WNyZXQgcGFzc3dvcmQhMTIzNCMkJQpzdXBlciBkdXB'
'lciBzZWNyZXQgcGFzc3dvcmQsIHN1cGVyIGR1cGVyIHNlY3JldCBwYXNzd29yZCExMjM0IyQlCgo=',
),
(
'some text here\n'
'-----BEGIN PRIVATE KEY-----\n'
'yabba dabba doo'
'c3VwZXIgZHVwZXIgc2VjcmV0IHBhc3N3b3JkLCBzdXBlciBkdXBlciBzZWNyZXQgcGFzc3'
'dvcmQhMTIzNCMkJQpzdXBlciBkdXBlciBzZWNyZXQgcGFzc3dvcmQsIHN1cGVyIGR1cGVy'
'IHNlY3JldCBwYXNzd29yZCExMjM0IyQlCgo=\n'
'-----END PRIVATE KEY-----',
1,
'BEGIN PRIVATE KEY-----',
),
(
'some text here\n'
'PuTTY-User-Key-File-2\n'
'secret key',
1,
'PuTTY-User-Key-File-2',
),
],
)
def test_basic(file_content):
def test_basic(file_content, secrets_amount, expected_secret):
with mock_named_temporary_file() as f:
f.write(file_content.encode())
f.seek(0)

secrets = SecretsCollection()
secrets.scan_file(f.name)

assert len(list(secrets)) == 1
temp_file = list(secrets.files)[0]
assert len(list(secrets)) == secrets_amount
assert list(secrets.data[temp_file])[0].secret_value == expected_secret


@pytest.fixture(autouse=True)
Expand Down