aws-samples / aws-samples/sample-FAST-applications

🔒 ASH Security Scan - Monthly Report (2026-09-01)

Open
#183 0 comments 0 reactions 0 assignees View on GitHub
automated-scan security
Dominant language
No language data
Stars
32
Forks
13
Avg merge
4h 6m
Merged PRs (30d)
41

Description

# ASH Security Scan - Full Repository Report

**Scan Date:** 2026-09-01T02:26:21+00:00
**Trigger:** schedule
**Type:** Monthly scheduled scan

## Scanner Results Summary

| Scanner | S | C | H | M | L | I | Time | Action | Result | Thresh |
|---------|---|---|---|---|---|---|------|--------|--------|--------|
| bandit | 0 | 9 | 0 | 0 | 201 | 0 | 7.3s | 9 | FAILED | MED (g) |
| cdk-nag | 0 | 0 | 0 | 0 | 0 | 0 | 1m 2s | 0 | PASSED | MED (g) |
| cfn-nag | 0 | 0 | 0 | 0 | 0 | 0 | 40.8s | 0 | PASSED | MED (g) |
| checkov | 0 | 39 | 0 | 0 | 0 | 0 | 31.3s | 39 | FAILED | MED (g) |
| detect-s… | 0 | 18 | 0 | 0 | 0 | 0 | 53.2s | 18 | FAILED | MED (g) |
| grype | 0 | 57 | 0 | 36 | 7 | 0 | 1m 35s | 93 | FAILED | MED (g) |
| npm-audit | 0 | 0 | 0 | 0 | 0 | 0 | 16.9s | 0 | PASSED | MED (g) |
| opengrep | 40 | 64 | 0 | 0 | 0 | 0 | 58.4s | 64 | FAILED | MED (g) |
| semgrep | 0 | 0 | 0 | 0 | 0 | 0 | <1ms | 0 | MISSING | MED (g) |
| syft | 0 | 0 | 0 | 0 | 0 | 0 | 4.4s | 0 | PASSED | MED (g) |

**Status:** ⚠️ Security findings detected

## Detailed Findings

Detailed Findings

Show 223 actionable findings

### Finding 1: B310

- **Severity**: HIGH
- **Scanner**: bandit
- **Rule ID**: B310
- **Location**: samples/anycompany-bank/backend/api/auth.py:66-68

**Description**:
Audit url open for permitted schemes. Allowing use of file:/ or custom schemes is often unexpected.

**Code Snippet**:
```
# nosec B310 — the URL is built from our own pool ID, not user input.
with urlopen(url, timeout=5) as response:
import json
```

---

### Finding 2: B310

- **Severity**: HIGH
- **Scanner**: bandit
- **Rule ID**: B310
- **Location**: samples/anycompany-bank/scripts/deploy_frontend.py:105-107

**Description**:
Audit url open for permitted schemes. Allowing use of file:/ or custom schemes is often unexpected.

**Code Snippet**:
```
# nosec B310 — the URL is an AWS-issued presigned S3 URL.
with urllib.request.urlopen(request, timeout=300) as response:
if response.status not in (200, 204):
```

---

### Finding 3: B310

- **Severity**: HIGH
- **Scanner**: bandit
- **Rule ID**: B310
- **Location**: samples/anycompany-bank/scripts/discover_and_invoke_via_oauth.py:121-123

**Description**:
Audit url open for permitted schemes. Allowing use of file:/ or custom schemes is often unexpected.

**Code Snippet**:
```
try:
with urllib.request.urlopen(request, timeout=120) as resp:
return resp.status, resp.read().decode()
```

---

### Finding 4: B310

- **Severity**: HIGH
- **Scanner**: bandit
- **Rule ID**: B310
- **Location**: samples/anycompany-bank/scripts/discover_via_oauth_registry.py:79-81

**Description**:
Audit url open for permitted schemes. Allowing use of file:/ or custom schemes is often unexpected.

**Code Snippet**:
```
try:
with urllib.request.urlopen(request, timeout=60) as resp:
return resp.status, json.loads(resp.read().decode())
```

---

### Finding 5: B104

- **Severity**: HIGH
- **Scanner**: bandit
- **Rule ID**: B104
- **Location**: samples/aws-specialist-agent/gateway/tools/ltm_mcp_server/server.py:42-44

**Description**:
Possible binding to all interfaces.

**Code Snippet**:
```
mcp = FastMCP("ltm", host="0.0.0.0", stateless_http=True)
```

---

### Finding 6: B104

- **Severity**: HIGH
- **Scanner**: bandit
- **Rule ID**: B104
- **Location**: samples/aws-specialist-agent/gateway/tools/strands_mcp_server/server.py:35-37

**Description**:
Possible binding to all interfaces.

**Code Snippet**:
```
# AgentCore Runtime MCP contract.
mcp.settings.host = "0.0.0.0"
mcp.settings.port = 8000
```

---

### Finding 7: B104

- **Severity**: HIGH
- **Scanner**: bandit
- **Rule ID**: B104
- **Location**: samples/aws-specialist-agent/tests/unit/test_ltm_mcp_server.py:140-142

**Description**:
Possible binding to all interfaces.

**Code Snippet**:
```
_load_server_module()
assert captured["fastmcp_kwargs"] == {"host": "0.0.0.0", "stateless_http": True}
```

---

### Finding 8: B104

- **Severity**: HIGH
- **Scanner**: bandit
- **Rule ID**: B104
- **Location**: samples/aws-specialist-agent/tests/unit/test_strands_mcp_server.py:101-103

**Description**:
Possible binding to all interfaces.

**Code Snippet**:
```
mod = _load_server_module()
assert mod.mcp.settings.host == "0.0.0.0"
assert mod.mcp.settings.port == 8000
```

---

### Finding 9: B310

- **Severity**: HIGH
- **Scanner**: bandit
- **Rule ID**: B310
- **Location**: samples/llm-council/infra-cdk/lambdas/zip-packager/index.py:62-64

**Description**:
Audit url open for permitted schemes. Allowing use of file:/ or custom schemes is often unexpected.

**Code Snippet**:
```
)
urllib.request.urlopen(req)
```

---

### Finding 10: CKV_AWS_158

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_158
- **Location**: samples/anycompany-bank/infra/console_api.tf:57-60

**Description**:
Ensure that CloudWatch Log Group is encrypted by KMS

**Code Snippet**:
```
resource "aws_cloudwatch_log_group" "console_api" {
name = "/aws/lambda/${var.stack_name}-console-api"
retention_in_days = var.log_retention_days
}
```

---

### Finding 11: CKV_AWS_338

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_338
- **Location**: samples/anycompany-bank/infra/console_api.tf:57-60

**Description**:
Ensure CloudWatch log groups retains logs for at least 1 year

**Code Snippet**:
```
resource "aws_cloudwatch_log_group" "console_api" {
name = "/aws/lambda/${var.stack_name}-console-api"
retention_in_days = var.log_retention_days
}
```

---

### Finding 12: CKV_AWS_173

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_173
- **Location**: samples/anycompany-bank/infra/console_api.tf:149-200

**Description**:
Check encryption settings for Lambda environmental variable

**Code Snippet**:
```
resource "aws_lambda_function" "console_api" {
function_name = "${var.stack_name}-console-api"
role = aws_iam_role.console_api.arn
package_type = "Image"
image_uri = module.console_api_image.image_uri
architectures = ["arm64"]

# Must exceed the longest assessment; the Runtime call itself is capped at
# 600s by the boto3 read timeout in main.py.
timeout = 300
memory_size = 1024

environment {
variables = {
RUNTIME_ARN = aws_bedrockagentcore_agent_runtime.kyc.agent_runtime_arn
REGISTRY_ID = aws_bedrockagentcore_registry.fsi.registry_id
GATEWAY_ID = aws_bedrockagentcore_gateway.kyc.gateway_id
GATEWAY_URL = aws_bedrockagentcore_gateway.kyc.gateway_url
MEMORY_ID = aws_bedrockagentcore_memory.kyc.id
KYC_TOOLS_LAMBDA = aws_lambda_function.kyc_tools.function_name
USER_POOL_ID = aws_cognito_user_pool.console.id
USER_POOL_CLIENT_ID = aws_cognito_user_pool_client.console.id
CONSOLE_ORIGIN = "https://${aws_amplify_branch.console.branch_name}.${aws_amplify_app.console.id}.amplifyapp.com"

# Model-plane facts, mirrored from the runtime's own environment so
# /api/config can report which route and guardrail the deployment is
# configured for. The console API does not invoke models itself; these
# are descriptive only, which is why the same values are set in two
# places rather than read back from the runtime at request time.
INFERENCE_ROUTE = var.inference_route
GUARDRAIL_ID = aws_bedrock_guardrail.kyc.guardrail_id
GUARDRAIL_VERSION = aws_bedrock_guardrail_version.kyc.version
POLICY_ENGINE_ID = aws_bedrockagentcore_policy_engine.kyc.policy_engine_id
POLICY_MODE = var.policy_engine_mode

# AgentCore Harness — the managed agent loop, when deployed. one(...)
# yields null (→ empty env var) when enable_harness = false.
HARNESS_ID = one(aws_bedrockagentcore_harness.kyc[*].harness_id)
}
}

# No replace_triggered_by: the image is content-addressed, so image_uri
# changes on a code edit and Terraform issues an in-place
# update-function-code. Replacing the function instead would tear down the
# Function URL (whose hostname is regenerated) and its resource policy — the
# exact churn that broke the deployed frontend during the refactor.
depends_on = [
aws_iam_role_policy.console_api,
aws_cloudwatch_log_group.console_api,
module.console_api_image,
]
}
```

---

### Finding 13: CKV_AWS_116

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_116
- **Location**: samples/anycompany-bank/infra/console_api.tf:149-200

**Description**:
Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ)

**Code Snippet**:
```
resource "aws_lambda_function" "console_api" {
function_name = "${var.stack_name}-console-api"
role = aws_iam_role.console_api.arn
package_type = "Image"
image_uri = module.console_api_image.image_uri
architectures = ["arm64"]

# Must exceed the longest assessment; the Runtime call itself is capped at
# 600s by the boto3 read timeout in main.py.
timeout = 300
memory_size = 1024

environment {
variables = {
RUNTIME_ARN = aws_bedrockagentcore_agent_runtime.kyc.agent_runtime_arn
REGISTRY_ID = aws_bedrockagentcore_registry.fsi.registry_id
GATEWAY_ID = aws_bedrockagentcore_gateway.kyc.gateway_id
GATEWAY_URL = aws_bedrockagentcore_gateway.kyc.gateway_url
MEMORY_ID = aws_bedrockagentcore_memory.kyc.id
KYC_TOOLS_LAMBDA = aws_lambda_function.kyc_tools.function_name
USER_POOL_ID = aws_cognito_user_pool.console.id
USER_POOL_CLIENT_ID = aws_cognito_user_pool_client.console.id
CONSOLE_ORIGIN = "https://${aws_amplify_branch.console.branch_name}.${aws_amplify_app.console.id}.amplifyapp.com"

# Model-plane facts, mirrored from the runtime's own environment so
# /api/config can report which route and guardrail the deployment is
# configured for. The console API does not invoke models itself; these
# are descriptive only, which is why the same values are set in two
# places rather than read back from the runtime at request time.
INFERENCE_ROUTE = var.inference_route
GUARDRAIL_ID = aws_bedrock_guardrail.kyc.guardrail_id
GUARDRAIL_VERSION = aws_bedrock_guardrail_version.kyc.version
POLICY_ENGINE_ID = aws_bedrockagentcore_policy_engine.kyc.policy_engine_id
POLICY_MODE = var.policy_engine_mode

# AgentCore Harness — the managed agent loop, when deployed. one(...)
# yields null (→ empty env var) when enable_harness = false.
HARNESS_ID = one(aws_bedrockagentcore_harness.kyc[*].harness_id)
}
}

# No replace_triggered_by: the image is content-addressed, so image_uri
# changes on a code edit and Terraform issues an in-place
# update-function-code. Replacing the function instead would tear down the
# Function URL (whose hostname is regenerated) and its resource policy — the
# exact churn that broke the deployed frontend during the refactor.
depends_on = [
aws_iam_role_policy.console_api,
aws_cloudwatch_log_group.console_api,
module.console_api_image,
]
}
```

---

### Finding 14: CKV_AWS_272

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_272
- **Location**: samples/anycompany-bank/infra/console_api.tf:149-200

**Description**:
Ensure AWS Lambda function is configured to validate code-signing

**Code Snippet**:
```
resource "aws_lambda_function" "console_api" {
function_name = "${var.stack_name}-console-api"
role = aws_iam_role.console_api.arn
package_type = "Image"
image_uri = module.console_api_image.image_uri
architectures = ["arm64"]

# Must exceed the longest assessment; the Runtime call itself is capped at
# 600s by the boto3 read timeout in main.py.
timeout = 300
memory_size = 1024

environment {
variables = {
RUNTIME_ARN = aws_bedrockagentcore_agent_runtime.kyc.agent_runtime_arn
REGISTRY_ID = aws_bedrockagentcore_registry.fsi.registry_id
GATEWAY_ID = aws_bedrockagentcore_gateway.kyc.gateway_id
GATEWAY_URL = aws_bedrockagentcore_gateway.kyc.gateway_url
MEMORY_ID = aws_bedrockagentcore_memory.kyc.id
KYC_TOOLS_LAMBDA = aws_lambda_function.kyc_tools.function_name
USER_POOL_ID = aws_cognito_user_pool.console.id
USER_POOL_CLIENT_ID = aws_cognito_user_pool_client.console.id
CONSOLE_ORIGIN = "https://${aws_amplify_branch.console.branch_name}.${aws_amplify_app.console.id}.amplifyapp.com"

# Model-plane facts, mirrored from the runtime's own environment so
# /api/config can report which route and guardrail the deployment is
# configured for. The console API does not invoke models itself; these
# are descriptive only, which is why the same values are set in two
# places rather than read back from the runtime at request time.
INFERENCE_ROUTE = var.inference_route
GUARDRAIL_ID = aws_bedrock_guardrail.kyc.guardrail_id
GUARDRAIL_VERSION = aws_bedrock_guardrail_version.kyc.version
POLICY_ENGINE_ID = aws_bedrockagentcore_policy_engine.kyc.policy_engine_id
POLICY_MODE = var.policy_engine_mode

# AgentCore Harness — the managed agent loop, when deployed. one(...)
# yields null (→ empty env var) when enable_harness = false.
HARNESS_ID = one(aws_bedrockagentcore_harness.kyc[*].harness_id)
}
}

# No replace_triggered_by: the image is content-addressed, so image_uri
# changes on a code edit and Terraform issues an in-place
# update-function-code. Replacing the function instead would tear down the
# Function URL (whose hostname is regenerated) and its resource policy — the
# exact churn that broke the deployed frontend during the refactor.
depends_on = [
aws_iam_role_policy.console_api,
aws_cloudwatch_log_group.console_api,
module.console_api_image,
]
}
```

---

### Finding 15: CKV_AWS_115

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_115
- **Location**: samples/anycompany-bank/infra/console_api.tf:149-200

**Description**:
Ensure that AWS Lambda function is configured for function-level concurrent execution limit

**Code Snippet**:
```
resource "aws_lambda_function" "console_api" {
function_name = "${var.stack_name}-console-api"
role = aws_iam_role.console_api.arn
package_type = "Image"
image_uri = module.console_api_image.image_uri
architectures = ["arm64"]

# Must exceed the longest assessment; the Runtime call itself is capped at
# 600s by the boto3 read timeout in main.py.
timeout = 300
memory_size = 1024

environment {
variables = {
RUNTIME_ARN = aws_bedrockagentcore_agent_runtime.kyc.agent_runtime_arn
REGISTRY_ID = aws_bedrockagentcore_registry.fsi.registry_id
GATEWAY_ID = aws_bedrockagentcore_gateway.kyc.gateway_id
GATEWAY_URL = aws_bedrockagentcore_gateway.kyc.gateway_url
MEMORY_ID = aws_bedrockagentcore_memory.kyc.id
KYC_TOOLS_LAMBDA = aws_lambda_function.kyc_tools.function_name
USER_POOL_ID = aws_cognito_user_pool.console.id
USER_POOL_CLIENT_ID = aws_cognito_user_pool_client.console.id
CONSOLE_ORIGIN = "https://${aws_amplify_branch.console.branch_name}.${aws_amplify_app.console.id}.amplifyapp.com"

# Model-plane facts, mirrored from the runtime's own environment so
# /api/config can report which route and guardrail the deployment is
# configured for. The console API does not invoke models itself; these
# are descriptive only, which is why the same values are set in two
# places rather than read back from the runtime at request time.
INFERENCE_ROUTE = var.inference_route
GUARDRAIL_ID = aws_bedrock_guardrail.kyc.guardrail_id
GUARDRAIL_VERSION = aws_bedrock_guardrail_version.kyc.version
POLICY_ENGINE_ID = aws_bedrockagentcore_policy_engine.kyc.policy_engine_id
POLICY_MODE = var.policy_engine_mode

# AgentCore Harness — the managed agent loop, when deployed. one(...)
# yields null (→ empty env var) when enable_harness = false.
HARNESS_ID = one(aws_bedrockagentcore_harness.kyc[*].harness_id)
}
}

# No replace_triggered_by: the image is content-addressed, so image_uri
# changes on a code edit and Terraform issues an in-place
# update-function-code. Replacing the function instead would tear down the
# Function URL (whose hostname is regenerated) and its resource policy — the
# exact churn that broke the deployed frontend during the refactor.
depends_on = [
aws_iam_role_policy.console_api,
aws_cloudwatch_log_group.console_api,
module.console_api_image,
]
}
```

---

### Finding 16: CKV_AWS_117

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_117
- **Location**: samples/anycompany-bank/infra/console_api.tf:149-200

**Description**:
Ensure that AWS Lambda function is configured inside a VPC

**Code Snippet**:
```
resource "aws_lambda_function" "console_api" {
function_name = "${var.stack_name}-console-api"
role = aws_iam_role.console_api.arn
package_type = "Image"
image_uri = module.console_api_image.image_uri
architectures = ["arm64"]

# Must exceed the longest assessment; the Runtime call itself is capped at
# 600s by the boto3 read timeout in main.py.
timeout = 300
memory_size = 1024

environment {
variables = {
RUNTIME_ARN = aws_bedrockagentcore_agent_runtime.kyc.agent_runtime_arn
REGISTRY_ID = aws_bedrockagentcore_registry.fsi.registry_id
GATEWAY_ID = aws_bedrockagentcore_gateway.kyc.gateway_id
GATEWAY_URL = aws_bedrockagentcore_gateway.kyc.gateway_url
MEMORY_ID = aws_bedrockagentcore_memory.kyc.id
KYC_TOOLS_LAMBDA = aws_lambda_function.kyc_tools.function_name
USER_POOL_ID = aws_cognito_user_pool.console.id
USER_POOL_CLIENT_ID = aws_cognito_user_pool_client.console.id
CONSOLE_ORIGIN = "https://${aws_amplify_branch.console.branch_name}.${aws_amplify_app.console.id}.amplifyapp.com"

# Model-plane facts, mirrored from the runtime's own environment so
# /api/config can report which route and guardrail the deployment is
# configured for. The console API does not invoke models itself; these
# are descriptive only, which is why the same values are set in two
# places rather than read back from the runtime at request time.
INFERENCE_ROUTE = var.inference_route
GUARDRAIL_ID = aws_bedrock_guardrail.kyc.guardrail_id
GUARDRAIL_VERSION = aws_bedrock_guardrail_version.kyc.version
POLICY_ENGINE_ID = aws_bedrockagentcore_policy_engine.kyc.policy_engine_id
POLICY_MODE = var.policy_engine_mode

# AgentCore Harness — the managed agent loop, when deployed. one(...)
# yields null (→ empty env var) when enable_harness = false.
HARNESS_ID = one(aws_bedrockagentcore_harness.kyc[*].harness_id)
}
}

# No replace_triggered_by: the image is content-addressed, so image_uri
# changes on a code edit and Terraform issues an in-place
# update-function-code. Replacing the function instead would tear down the
# Function URL (whose hostname is regenerated) and its resource policy — the
# exact churn that broke the deployed frontend during the refactor.
depends_on = [
aws_iam_role_policy.console_api,
aws_cloudwatch_log_group.console_api,
module.console_api_image,
]
}
```

---

### Finding 17: CKV_AWS_50

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_50
- **Location**: samples/anycompany-bank/infra/console_api.tf:149-200

**Description**:
X-Ray tracing is enabled for Lambda

**Code Snippet**:
```
resource "aws_lambda_function" "console_api" {
function_name = "${var.stack_name}-console-api"
role = aws_iam_role.console_api.arn
package_type = "Image"
image_uri = module.console_api_image.image_uri
architectures = ["arm64"]

# Must exceed the longest assessment; the Runtime call itself is capped at
# 600s by the boto3 read timeout in main.py.
timeout = 300
memory_size = 1024

environment {
variables = {
RUNTIME_ARN = aws_bedrockagentcore_agent_runtime.kyc.agent_runtime_arn
REGISTRY_ID = aws_bedrockagentcore_registry.fsi.registry_id
GATEWAY_ID = aws_bedrockagentcore_gateway.kyc.gateway_id
GATEWAY_URL = aws_bedrockagentcore_gateway.kyc.gateway_url
MEMORY_ID = aws_bedrockagentcore_memory.kyc.id
KYC_TOOLS_LAMBDA = aws_lambda_function.kyc_tools.function_name
USER_POOL_ID = aws_cognito_user_pool.console.id
USER_POOL_CLIENT_ID = aws_cognito_user_pool_client.console.id
CONSOLE_ORIGIN = "https://${aws_amplify_branch.console.branch_name}.${aws_amplify_app.console.id}.amplifyapp.com"

# Model-plane facts, mirrored from the runtime's own environment so
# /api/config can report which route and guardrail the deployment is
# configured for. The console API does not invoke models itself; these
# are descriptive only, which is why the same values are set in two
# places rather than read back from the runtime at request time.
INFERENCE_ROUTE = var.inference_route
GUARDRAIL_ID = aws_bedrock_guardrail.kyc.guardrail_id
GUARDRAIL_VERSION = aws_bedrock_guardrail_version.kyc.version
POLICY_ENGINE_ID = aws_bedrockagentcore_policy_engine.kyc.policy_engine_id
POLICY_MODE = var.policy_engine_mode

# AgentCore Harness — the managed agent loop, when deployed. one(...)
# yields null (→ empty env var) when enable_harness = false.
HARNESS_ID = one(aws_bedrockagentcore_harness.kyc[*].harness_id)
}
}

# No replace_triggered_by: the image is content-addressed, so image_uri
# changes on a code edit and Terraform issues an in-place
# update-function-code. Replacing the function instead would tear down the
# Function URL (whose hostname is regenerated) and its resource policy — the
# exact churn that broke the deployed frontend during the refactor.
depends_on = [
aws_iam_role_policy.console_api,
aws_cloudwatch_log_group.console_api,
module.console_api_image,
]
}
```

---

### Finding 18: CKV_AWS_158

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_158
- **Location**: samples/anycompany-bank/infra/gateway.tf:16-19

**Description**:
Ensure that CloudWatch Log Group is encrypted by KMS

**Code Snippet**:
```
resource "aws_cloudwatch_log_group" "kyc_tools" {
name = "/aws/lambda/${var.stack_name}-kyc-tools"
retention_in_days = var.log_retention_days
}
```

---

### Finding 19: CKV_AWS_338

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_338
- **Location**: samples/anycompany-bank/infra/gateway.tf:16-19

**Description**:
Ensure CloudWatch log groups retains logs for at least 1 year

**Code Snippet**:
```
resource "aws_cloudwatch_log_group" "kyc_tools" {
name = "/aws/lambda/${var.stack_name}-kyc-tools"
retention_in_days = var.log_retention_days
}
```

---

### Finding 20: CKV_AWS_116

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_116
- **Location**: samples/anycompany-bank/infra/gateway.tf:75-91

**Description**:
Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ)

**Code Snippet**:
```
resource "aws_lambda_function" "kyc_tools" {
function_name = "${var.stack_name}-kyc-tools"
role = aws_iam_role.kyc_tools_lambda.arn
handler = "kyc_tools_lambda.handler"
runtime = "python3.13"
architectures = ["arm64"]
timeout = 30
memory_size = 256

filename = data.archive_file.kyc_tools.output_path
source_code_hash = data.archive_file.kyc_tools.output_base64sha256

depends_on = [
aws_cloudwatch_log_group.kyc_tools,
aws_iam_role_policy.kyc_tools_lambda,
]
}
```

---

### Finding 21: CKV_AWS_272

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_272
- **Location**: samples/anycompany-bank/infra/gateway.tf:75-91

**Description**:
Ensure AWS Lambda function is configured to validate code-signing

**Code Snippet**:
```
resource "aws_lambda_function" "kyc_tools" {
function_name = "${var.stack_name}-kyc-tools"
role = aws_iam_role.kyc_tools_lambda.arn
handler = "kyc_tools_lambda.handler"
runtime = "python3.13"
architectures = ["arm64"]
timeout = 30
memory_size = 256

filename = data.archive_file.kyc_tools.output_path
source_code_hash = data.archive_file.kyc_tools.output_base64sha256

depends_on = [
aws_cloudwatch_log_group.kyc_tools,
aws_iam_role_policy.kyc_tools_lambda,
]
}
```

---

### Finding 22: CKV_AWS_115

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_115
- **Location**: samples/anycompany-bank/infra/gateway.tf:75-91

**Description**:
Ensure that AWS Lambda function is configured for function-level concurrent execution limit

**Code Snippet**:
```
resource "aws_lambda_function" "kyc_tools" {
function_name = "${var.stack_name}-kyc-tools"
role = aws_iam_role.kyc_tools_lambda.arn
handler = "kyc_tools_lambda.handler"
runtime = "python3.13"
architectures = ["arm64"]
timeout = 30
memory_size = 256

filename = data.archive_file.kyc_tools.output_path
source_code_hash = data.archive_file.kyc_tools.output_base64sha256

depends_on = [
aws_cloudwatch_log_group.kyc_tools,
aws_iam_role_policy.kyc_tools_lambda,
]
}
```

---

### Finding 23: CKV_AWS_117

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_117
- **Location**: samples/anycompany-bank/infra/gateway.tf:75-91

**Description**:
Ensure that AWS Lambda function is configured inside a VPC

**Code Snippet**:
```
resource "aws_lambda_function" "kyc_tools" {
function_name = "${var.stack_name}-kyc-tools"
role = aws_iam_role.kyc_tools_lambda.arn
handler = "kyc_tools_lambda.handler"
runtime = "python3.13"
architectures = ["arm64"]
timeout = 30
memory_size = 256

filename = data.archive_file.kyc_tools.output_path
source_code_hash = data.archive_file.kyc_tools.output_base64sha256

depends_on = [
aws_cloudwatch_log_group.kyc_tools,
aws_iam_role_policy.kyc_tools_lambda,
]
}
```

---

### Finding 24: CKV_AWS_50

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_50
- **Location**: samples/anycompany-bank/infra/gateway.tf:75-91

**Description**:
X-Ray tracing is enabled for Lambda

**Code Snippet**:
```
resource "aws_lambda_function" "kyc_tools" {
function_name = "${var.stack_name}-kyc-tools"
role = aws_iam_role.kyc_tools_lambda.arn
handler = "kyc_tools_lambda.handler"
runtime = "python3.13"
architectures = ["arm64"]
timeout = 30
memory_size = 256

filename = data.archive_file.kyc_tools.output_path
source_code_hash = data.archive_file.kyc_tools.output_base64sha256

depends_on = [
aws_cloudwatch_log_group.kyc_tools,
aws_iam_role_policy.kyc_tools_lambda,
]
}
```

---

### Finding 25: CKV_AWS_107

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_107
- **Location**: samples/anycompany-bank/infra/harness.tf:123-260

**Description**:
Ensure IAM policies does not allow credentials exposure

**Code Snippet**:
```
data "aws_iam_policy_document" "harness" {
count = var.enable_harness ? 1 : 0

# Model invocation — the harness calls Bedrock for the agent loop.
statement {
sid = "BedrockModelInvocation"
effect = "Allow"
actions = [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream",
]
resources = [
"arn:aws:bedrock:*::foundation-model/*",
"arn:aws:bedrock:${local.region}:${local.account_id}:inference-profile/*",
]
}

# The managed harness image is pulled from ECR Public on the public network.
statement {
sid = "EcrPublicTokenAccess"
effect = "Allow"
actions = ["ecr-public:GetAuthorizationToken"]
resources = ["*"]
}
statement {
sid = "StsForEcrPublicPull"
effect = "Allow"
actions = ["sts:GetServiceBearerToken"]
resources = ["*"]
}

# Observability — traces to X-Ray, logs and metrics to CloudWatch. Same shape
# as the Runtime role so both agents land in the unified trace view.
statement {
sid = "Observability"
effect = "Allow"
actions = [
"xray:PutTraceSegments",
"xray:PutTelemetryRecords",
"xray:GetSamplingRules",
"xray:GetSamplingTargets",
]
resources = ["*"]
}
statement {
sid = "CloudWatchLogs"
effect = "Allow"
actions = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams",
]
resources = ["arn:aws:logs:${local.region}:${local.account_id}:log-group:/aws/bedrock-agentcore/runtimes/*"]
}
statement {
sid = "CloudWatchLogsDescribeGroups"
effect = "Allow"
actions = ["logs:DescribeLogGroups"]
resources = ["arn:aws:logs:${local.region}:${local.account_id}:log-group:*"]
}
statement {
sid = "CloudWatchLogsResourcePolicy"
effect = "Allow"
actions = ["logs:PutResourcePolicy"]
resources = ["*"]
}
statement {
sid = "CloudWatchMetrics"
effect = "Allow"
actions = ["cloudwatch:PutMetricData"]
resources = ["*"]
condition {
test = "StringEquals"
variable = "cloudwatch:namespace"
values = ["bedrock-agentcore"]
}
}

# Workload identity for the managed loop.
statement {
sid = "WorkloadIdentity"
effect = "Allow"
actions = [
"bedrock-agentcore:GetWorkloadAccessToken",
"bedrock-agentcore:GetWorkloadAccessTokenForJWT",
]
resources = [
"arn:aws:bedrock-agentcore:${local.region}:${local.account_id}:workload-identity-directory/default",
"arn:aws:bedrock-agentcore:${local.region}:${local.account_id}:workload-identity-directory/default/workload-identity/*",
]
}

# This harness's wiring: reach the shared Gateway (its KYC tools) under the
# same ARN the Runtime role grants.
statement {
sid = "InvokeGateway"
effect = "Allow"
actions = ["bedrock-agentcore:InvokeGateway"]
resources = [aws_bedrockagentcore_gateway.kyc.gateway_arn]
}

# Fetch the S3 skill bundle at session start. The docs require both GetObject
# (read the SKILL.md) and ListBucket (enumerate the skill prefix).
statement {
sid = "SkillBucketRead"
effect = "Allow"
actions = ["s3:GetObject"]
resources = ["${aws_s3_bucket.harness_skills[0].arn}/*"]
}
statement {
sid = "SkillBucketList"
effect = "Allow"
actions = ["s3:ListBucket"]
resources = [aws_s3_bucket.harness_skills[0].arn]
}
# The harness provisions its OWN managed short/long-term memory (the
# managedMemoryConfiguration the service creates by default) — a resource
# distinct from the Runtime's shared KYC memory, and named after the harness
# (`-`). Its id is not known at plan time,
# so scope to the harness-name prefix. Without this the loop fails mid-run on
# `ListEvents` against that managed memory.
statement {
sid = "ManagedMemoryAccess"
effect = "Allow"
actions = [
"bedrock-agentcore:CreateEvent",
"bedrock-agentcore:GetEvent",
"bedrock-agentcore:ListEvents",
"bedrock-agentcore:ListSessions",
"bedrock-agentcore:RetrieveMemoryRecords",
"bedrock-agentcore:ListMemoryRecords",
]
resources = [
"arn:aws:bedrock-agentcore:${local.region}:${local.account_id}:memory/${local.harness_name}-*",
]
}
}
```

---

### Finding 26: CKV_AWS_136

- **Severity**: HIGH
- **Scanner**: checkov
- **Rule ID**: CKV_AWS_136
- **Location**: samples/anycompany-bank/infra/modules/ecr-image/main.tf:30-43

**Description**:
Ensure that ECR repositories are encrypted using KMS

**Code Snippet**:
```
resource "aws_ecr_repository" "this" {
name = var.repository_name
image_tag_mutability = "MUTABLE"
# Demo stack: allow `terraform destroy` to remove the repo with images in it.
force_delete = true

image_scanning_configuration {
scan_on_push = true
}

---
*This issue was automatically created by the monthly security scan workflow.*

Contributor guide

Open the contributing guide

Research direction

Start with the listed findings in samples/anycompany-bank and samples/aws-specialist-agent, especially the referenced Python and Terraform files, and review the ASH scan output by rule and location. Done means the actionable findings are addressed or explicitly accepted with rationale and a subsequent scheduled scan no longer reports unresolved blockers.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, python, terraform
Domain
cloud, infrastructure, security
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
15/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.