Skip to content

Commit 94fd818

Browse files
committed
Merge branch 'fix/security-scan-remediations' into 'main'
fix: correct scanner suppression comments and add remaining fixes See merge request proserve/genaiid/reusable-assets/fullstack-agentcore-solution-template!43
2 parents 7ca5a30 + 32fbd0e commit 94fd818

5 files changed

Lines changed: 23 additions & 19 deletions

File tree

docker/Dockerfile.frontend.dev

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ COPY . .
1717
# Expose port
1818
EXPOSE 3000
1919

20+
# Run as non-root user (node user is built into node:20-alpine)
21+
USER node
22+
2023
# Healthcheck for container orchestration (dev server)
2124
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
2225
CMD wget -qO- http://localhost:3000/ || exit 1

infra-cdk/lambdas/zip-packager/index.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ def send_response(
6060
headers={"Content-Type": "application/json"},
6161
method="PUT",
6262
)
63-
urllib.request.urlopen(req) # nosec B310 B113 — URL is the CloudFormation pre-signed ResponseURL, not user-controlled
63+
urllib.request.urlopen( # nosemgrep: python.lang.security.audit.dynamic-urllib-use-detected.dynamic-urllib-use-detected # nosec B310 B113 — URL is the CloudFormation pre-signed ResponseURL, not user-controlled
64+
req
65+
)
6466

6567

6668
def download_wheels(requirements: list[str], download_dir: Path) -> None:

infra-cdk/lib/backend-stack.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ export class BackendStack extends cdk.NestedStack {
122122

123123
if (deploymentType === "zip") {
124124
// ZIP DEPLOYMENT: Use Lambda to package and upload to S3 (no Docker required)
125-
const repoRoot = path.resolve(__dirname, "..", "..")
126-
const patternDir = path.join(repoRoot, "patterns", pattern)
125+
const repoRoot = path.resolve(__dirname, "..", "..") // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
126+
const patternDir = path.join(repoRoot, "patterns", pattern) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
127127

128128
// Create S3 bucket for agent code
129129
const agentCodeBucket = new s3.Bucket(this, "AgentCodeBucket", {
@@ -137,7 +137,7 @@ export class BackendStack extends cdk.NestedStack {
137137
const packagerLambda = new lambda.Function(this, "ZipPackagerLambda", {
138138
runtime: lambda.Runtime.PYTHON_3_12,
139139
handler: "index.handler",
140-
code: lambda.Code.fromAsset(path.join(__dirname, "..", "lambdas", "zip-packager")),
140+
code: lambda.Code.fromAsset(path.join(__dirname, "..", "lambdas", "zip-packager")), // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
141141
timeout: cdk.Duration.minutes(10),
142142
memorySize: 1024,
143143
ephemeralStorageSize: cdk.Size.gibibytes(2),
@@ -151,21 +151,21 @@ export class BackendStack extends cdk.NestedStack {
151151
// Read pattern .py files
152152
for (const file of fs.readdirSync(patternDir)) {
153153
if (file.endsWith(".py")) {
154-
const content = fs.readFileSync(path.join(patternDir, file))
154+
const content = fs.readFileSync(path.join(patternDir, file)) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
155155
agentCode[file] = content.toString("base64")
156156
}
157157
}
158158

159159
// Read shared modules (gateway/, tools/)
160160
for (const module of ["gateway", "tools"]) {
161-
const moduleDir = path.join(repoRoot, module)
161+
const moduleDir = path.join(repoRoot, module) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
162162
if (fs.existsSync(moduleDir)) {
163163
this.readDirRecursive(moduleDir, module, agentCode)
164164
}
165165
}
166166

167167
// Read requirements
168-
const requirementsPath = path.join(patternDir, "requirements.txt")
168+
const requirementsPath = path.join(patternDir, "requirements.txt") // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
169169
const requirements = fs.readFileSync(requirementsPath, "utf-8")
170170
.split("\n")
171171
.map(line => line.trim())
@@ -209,7 +209,7 @@ export class BackendStack extends cdk.NestedStack {
209209
} else {
210210
// DOCKER DEPLOYMENT: Use container-based deployment
211211
agentRuntimeArtifact = agentcore.AgentRuntimeArtifact.fromAsset(
212-
path.resolve(__dirname, "..", ".."),
212+
path.resolve(__dirname, "..", ".."), // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
213213
{
214214
platform: ecr_assets.Platform.LINUX_ARM64,
215215
file: `patterns/${pattern}/Dockerfile`,
@@ -499,7 +499,7 @@ export class BackendStack extends cdk.NestedStack {
499499
functionName: `${config.stack_name_base}-feedback`,
500500
runtime: lambda.Runtime.PYTHON_3_13,
501501
architecture: lambda.Architecture.ARM_64,
502-
entry: path.join(__dirname, "..", "lambdas", "feedback"),
502+
entry: path.join(__dirname, "..", "lambdas", "feedback"), // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
503503
handler: "handler",
504504
environment: {
505505
TABLE_NAME: feedbackTable.tableName,
@@ -601,7 +601,7 @@ export class BackendStack extends cdk.NestedStack {
601601
const toolLambda = new lambda.Function(this, "SampleToolLambda", {
602602
runtime: lambda.Runtime.PYTHON_3_13,
603603
handler: "sample_tool_lambda.handler",
604-
code: lambda.Code.fromAsset(path.join(__dirname, "../../gateway/tools/sample_tool")),
604+
code: lambda.Code.fromAsset(path.join(__dirname, "../../gateway/tools/sample_tool")), // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
605605
timeout: cdk.Duration.seconds(30),
606606
logGroup: new logs.LogGroup(this, "SampleToolLambdaLogGroup", {
607607
logGroupName: `/aws/lambda/${config.stack_name_base}-sample-tool`,
@@ -663,7 +663,7 @@ export class BackendStack extends cdk.NestedStack {
663663
)
664664

665665
// Load tool specification from JSON file
666-
const toolSpecPath = path.join(__dirname, "../../gateway/tools/sample_tool/tool_spec.json")
666+
const toolSpecPath = path.join(__dirname, "../../gateway/tools/sample_tool/tool_spec.json") // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
667667
const apiSpec = JSON.parse(require("fs").readFileSync(toolSpecPath, "utf8"))
668668

669669
// Cognito OAuth2 configuration for gateway
@@ -678,7 +678,7 @@ export class BackendStack extends cdk.NestedStack {
678678
const oauth2ProviderLambda = new lambda.Function(this, "OAuth2ProviderLambda", {
679679
runtime: lambda.Runtime.PYTHON_3_13,
680680
handler: "index.handler",
681-
code: lambda.Code.fromAsset(path.join(__dirname, "..", "lambdas", "oauth2-provider")),
681+
code: lambda.Code.fromAsset(path.join(__dirname, "..", "lambdas", "oauth2-provider")), // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
682682
timeout: cdk.Duration.minutes(5),
683683
logGroup: new logs.LogGroup(this, "OAuth2ProviderLambdaLogGroup", {
684684
logGroupName: `/aws/lambda/${config.stack_name_base}-oauth2-provider`,
@@ -995,9 +995,8 @@ export class BackendStack extends cdk.NestedStack {
995995
*/
996996
private readDirRecursive(dirPath: string, prefix: string, output: Record<string, string>): void {
997997
for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
998-
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal — dirPath is derived from __dirname-relative CDK build paths, not user input
999-
const fullPath = path.join(dirPath, entry.name)
1000-
const relativePath = path.join(prefix, entry.name)
998+
const fullPath = path.join(dirPath, entry.name) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
999+
const relativePath = path.join(prefix, entry.name) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
10011000

10021001
if (entry.isDirectory()) {
10031002
// Skip __pycache__ directories

infra-cdk/lib/utils/config-manager.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ export class ConfigManager {
4747
}
4848

4949
private _loadConfig(configFile: string): AppConfig {
50-
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal — configFile is a hardcoded filename from the CDK app entry point, not user input
51-
const configPath = path.join(__dirname, "..", "..", configFile)
50+
const configPath = path.join(__dirname, "..", "..", configFile) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
5251

5352
if (!fs.existsSync(configPath)) {
5453
throw new Error(`Configuration file ${configPath} does not exist. Please create config.yaml file.`)
@@ -113,13 +112,13 @@ export class ConfigManager {
113112
return this.config
114113
}
115114

116-
// nosemgrep: javascript.lang.security.audit.prototype-pollution.prototype-pollution-loop.prototype-pollution-loop — iterates over a trusted local YAML config object, not user-controlled input
117115
public get(key: string, defaultValue?: any): any {
118116
const keys = key.split(".")
119117
let value: any = this.config
120118

121119
for (const k of keys) {
122120
if (typeof value === "object" && value !== null && k in value) {
121+
// nosemgrep: javascript.lang.security.audit.prototype-pollution.prototype-pollution-loop.prototype-pollution-loop — iterates over a trusted local YAML config object, not user-controlled input
123122
value = value[k]
124123
} else {
125124
return defaultValue

patterns/utils/auth.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@ def extract_user_id_from_context(context: RequestContext) -> str:
6060

6161
# Decode without signature verification — AgentCore Runtime already validated the token.
6262
# We use options to skip all verification since this is a trusted, pre-validated token.
63-
claims = jwt.decode( # nosec — signature verification intentionally skipped; AgentCore Runtime already validated the JWT
63+
claims = jwt.decode( # nosec B105
6464
jwt=token,
65+
# nosemgrep: python.jwt.security.unverified-jwt-decode.unverified-jwt-decode — signature verification intentionally skipped; AgentCore Runtime already validated the JWT
6566
options={"verify_signature": False},
6667
algorithms=["RS256"],
6768
)

0 commit comments

Comments
 (0)