Compare commits

...

6 Commits

Author SHA1 Message Date
Hugo P.Brito 5ad2008ae5 docs(changelog): move #11222 entry to 5.28.0 2026-05-19 11:43:30 +01:00
Hugo P.Brito c6d2ef03e1 docs(changelog): move #11222 entry to 5.27.1 2026-05-19 11:39:37 +01:00
Hugo P.Brito c7792727ea docs(config): warn that secrets_ignore_files fully excludes files from secret scanning 2026-05-19 11:33:55 +01:00
Hugo P.Brito 08566aeaf7 test(awslambda): build deps.json fixture via mocked extractall instead of io.BytesIO
code_zip is typed Any in LambdaCode and the check only calls
extractall(dir), so a MagicMock side_effect that writes the fixture files
into the check's temp dir avoids constructing a real archive.
2026-05-19 11:30:49 +01:00
Hugo P.Brito 1d05990878 docs(changelog): add entry for #11222 lambda secrets_ignore_files 2026-05-19 11:22:42 +01:00
Hugo P.Brito 5eb5825bab feat(awslambda): add secrets_ignore_files to skip files by name in no-secrets-in-code check
awslambda_function_no_secrets_in_code scans every file inside the Lambda
deployment package. .NET deployments ship machine-generated *.deps.json
dependency manifests that reference AWS Secrets Manager, which detect-secrets
flags as Secret Keyword false positives. The only existing tuning knob,
secrets_ignore_patterns, matches secret content, not file names, so it cannot
target these files without risking masking real secrets.

Add a secrets_ignore_files audit-config option: a list of glob patterns of
file names inside the package to skip when scanning. Files matching any
pattern are excluded before detect-secrets runs.

Closes #11148
2026-05-19 11:22:07 +01:00
4 changed files with 137 additions and 0 deletions
+8
View File
@@ -2,6 +2,14 @@
All notable changes to the **Prowler SDK** are documented in this file.
## [5.28.0] (Prowler v5.28.0)
### 🔄 Changed
- `awslambda_function_no_secrets_in_code` now supports a `secrets_ignore_files` audit-config option to skip files inside the deployment package by glob pattern (e.g. `*.deps.json`), suppressing .NET dependency-manifest false positives without masking real secrets [(#11222)](https://github.com/prowler-cloud/prowler/pull/11222)
---
## [5.27.0] (Prowler v5.27.0)
### 🚀 Added
+14
View File
@@ -390,6 +390,20 @@ aws:
# Patterns to ignore in the secrets checks
secrets_ignore_patterns: []
# aws.awslambda_function_no_secrets_in_code
# Glob patterns of file names inside the Lambda deployment package to skip
# when scanning for secrets. Useful to suppress known false positives such
# as .NET dependency manifests.
# Example:
# secrets_ignore_files:
# - "*.deps.json"
# WARNING: use at your own risk. Any file whose name matches one of these
# patterns is fully excluded from secret scanning, so a real secret placed
# in such a file will NOT be detected. Keep patterns as narrow and specific
# as possible; this is not recommended unless you have confirmed the matched
# files only ever contain false positives.
secrets_ignore_files: []
# AWS Secrets Manager Configuration
# aws.secretsmanager_secret_unused
# Maximum number of days a secret can be unused
@@ -1,3 +1,4 @@
import fnmatch
import os
import tempfile
@@ -13,6 +14,11 @@ class awslambda_function_no_secrets_in_code(Check):
secrets_ignore_patterns = awslambda_client.audit_config.get(
"secrets_ignore_patterns", []
)
# Glob patterns of file names inside the deployment package to skip
# when scanning for secrets (e.g. "*.deps.json" for .NET Lambdas).
secrets_ignore_files = awslambda_client.audit_config.get(
"secrets_ignore_files", []
)
for function, function_code in awslambda_client._get_function_code():
if function_code:
report = Check_Report_AWS(
@@ -29,6 +35,14 @@ class awslambda_function_no_secrets_in_code(Check):
files_in_zip = next(os.walk(tmp_dir_name))[2]
secrets_findings = []
for file in files_in_zip:
# Skip files whose name matches an ignore pattern
# so known false-positive files (e.g. .NET
# *.deps.json) do not raise spurious findings.
if any(
fnmatch.fnmatch(file, pattern)
for pattern in secrets_ignore_files
):
continue
detect_secrets_output = detect_secrets_scan(
file=f"{tmp_dir_name}/{file}",
excluded_secrets=secrets_ignore_patterns,
@@ -53,6 +53,43 @@ def get_lambda_code_with_secrets(code):
)
LAMBDA_DEPS_JSON_WITH_SECRET = """
{
"runtimeTarget": { "name": ".NETCoreApp,Version=v8.0" },
"libraries": {
"AWSSDK.SecretsManager/3.7.0": {
"type": "package",
"password": "test-deps-json-password"
}
}
}
"""
def get_lambda_code_from_files(files: dict) -> LambdaCode:
# The check only calls code_zip.extractall(dir); mock it to drop the
# given files into the temporary directory the check creates, so no
# real archive needs to be built.
code_zip = mock.MagicMock()
def _extractall(path):
for name, content in files.items():
with open(f"{path}/{name}", "w") as fd:
fd.write(content)
code_zip.extractall.side_effect = _extractall
return LambdaCode(location="", code_zip=code_zip)
def mock_get_function_code_with_deps_json_secret():
yield create_lambda_function(), get_lambda_code_from_files(
{
"lambda_function.py": LAMBDA_FUNCTION_CODE_WITHOUT_SECRETS,
"myapp.deps.json": LAMBDA_DEPS_JSON_WITH_SECRET,
}
)
def mock_get_function_codewith_secrets():
yield create_lambda_function(), get_lambda_code_with_secrets(
LAMBDA_FUNCTION_CODE_WITH_SECRETS
@@ -201,3 +238,67 @@ class Test_awslambda_function_no_secrets_in_code:
== f"No secrets found in Lambda function {LAMBDA_FUNCTION_NAME} code."
)
assert result[0].resource_tags == []
def test_function_code_deps_json_secret_not_ignored(self):
lambda_client = mock.MagicMock
lambda_client.functions = {LAMBDA_FUNCTION_ARN: create_lambda_function()}
lambda_client._get_function_code = mock_get_function_code_with_deps_json_secret
lambda_client.audit_config = {"secrets_ignore_patterns": []}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
),
mock.patch(
"prowler.providers.aws.services.awslambda.awslambda_function_no_secrets_in_code.awslambda_function_no_secrets_in_code.awslambda_client",
new=lambda_client,
),
):
from prowler.providers.aws.services.awslambda.awslambda_function_no_secrets_in_code.awslambda_function_no_secrets_in_code import (
awslambda_function_no_secrets_in_code,
)
check = awslambda_function_no_secrets_in_code()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert "myapp.deps.json" in result[0].status_extended
def test_function_code_deps_json_secret_ignored_by_file_pattern(self):
lambda_client = mock.MagicMock
lambda_client.functions = {LAMBDA_FUNCTION_ARN: create_lambda_function()}
lambda_client._get_function_code = mock_get_function_code_with_deps_json_secret
lambda_client.audit_config = {
"secrets_ignore_patterns": [],
"secrets_ignore_files": ["*.deps.json"],
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
),
mock.patch(
"prowler.providers.aws.services.awslambda.awslambda_function_no_secrets_in_code.awslambda_function_no_secrets_in_code.awslambda_client",
new=lambda_client,
),
):
from prowler.providers.aws.services.awslambda.awslambda_function_no_secrets_in_code.awslambda_function_no_secrets_in_code import (
awslambda_function_no_secrets_in_code,
)
check = awslambda_function_no_secrets_in_code()
result = check.execute()
assert len(result) == 1
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_id == LAMBDA_FUNCTION_NAME
assert result[0].resource_arn == LAMBDA_FUNCTION_ARN
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"No secrets found in Lambda function {LAMBDA_FUNCTION_NAME} code."
)
assert result[0].resource_tags == []