fix(aws-lambda): validate event S3 URIs against render bucket (F-004)#1213
Merged
vanceingalls merged 1 commit intoJun 6, 2026
Conversation
Collaborator
Author
Collaborator
miguel-heygen
left a comment
There was a problem hiding this comment.
Review: #1213 — validate event S3 URIs against render bucket
Clean, low-surface fix. Notes:
handler.ts
validateEventS3Uriscalled beforeprimeRuntimeEnv()— correct, fail-fast before any side effects. ✓- Graceful fallback when
HYPERFRAMES_RENDER_BUCKETis unset preserves backward compatibility for existing deployments. ✓ getEventS3Uriscovers all three event types and filters nullAudioS3Uri. ✓- Error name
S3_URI_NOT_ALLOWEDmatches the non-retryable lists in CDK. ✓
HyperframesRenderStack.ts
HYPERFRAMES_RENDER_BUCKETinjected into lambda env via CDK. ✓S3_URI_NOT_ALLOWEDadded to non-retryable lists for all three event types (plan, renderChunk, assemble). ✓
Tests
- Plan event with evil bucket rejected before any S3 ops (
s3.opslength check). ✓ - Assemble event with mixed chunk URIs rejected. ✓
prevBucketsave/restore pattern is clean.
One observation: validateEventS3Uris doesn't cover PlanOutputS3Prefix and ChunkOutputS3Prefix for the case where someone injects an output prefix pointing at a different bucket. Looking at getEventS3Uris, plan returns [ProjectS3Uri, PlanOutputS3Prefix] and renderChunk returns [PlanS3Uri, ChunkOutputS3Prefix] — those are included. ✓
No blocking issues. LGTM.
Merge activity
|
5a7b913 to
f9053c0
Compare
Lambda handler accepted S3 URIs in event fields without verifying they targeted the function's own render bucket, so an attacker who could inject a crafted event could route GetObject/PutObject calls to arbitrary S3 buckets in the same account. Add validateEventS3Uris(), called immediately after unwrapEvent() before any S3 I/O. If HYPERFRAMES_RENDER_BUCKET is set, every URI in the event must resolve to that bucket; mismatches throw S3_URI_NOT_ALLOWED (typed as non-retryable so Step Functions state machine doesn't retry). When the env var is unset validation is skipped so existing deployments without it keep working. CDK stack auto-wires the bucket name into the function environment so new deployments are protected without manual config. Add S3_URI_NOT_ALLOWED to all three NON_RETRYABLE_* lists in the Step Functions state machine definition. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
38d4151 to
7a0cb08
Compare
f9053c0 to
b5a30f4
Compare
The base branch was changed.
miguel-heygen
approved these changes
Jun 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
validateEventS3Uris(), called immediately afterunwrapEvent()in the Lambda handler before any S3 I/O.HYPERFRAMES_RENDER_BUCKETenv var is set, every S3 URI in the event (ProjectS3Uri,PlanOutputS3Prefix,PlanS3Uri,ChunkOutputS3Prefix,ChunkS3Uris,AudioS3Uri,OutputS3Uri) must resolve to that bucket. Mismatches throwS3_URI_NOT_ALLOWED.HyperframesRenderStack) auto-wiresHYPERFRAMES_RENDER_BUCKET: this.bucket.bucketNameso new deployments are protected without manual config.S3_URI_NOT_ALLOWEDadded to all threeNON_RETRYABLE_*lists in the Step Functions state machine so the state machine does not retry on this error.Security
F-004 MED — The Lambda handler accepted S3 URIs from the event payload without verifying they targeted the function's own render bucket. An attacker who could inject a crafted Step Functions execution input could route
GetObject/PutObjectcalls to arbitrary buckets in the same AWS account, potentially exfiltrating plan data or overwriting objects in unrelated buckets.Test plan
handlerrejects aplanevent whoseProjectS3Uritargets a different bucket —S3_URI_NOT_ALLOWEDthrown, zero S3 ops recordedhandlerrejects anassembleevent with one cross-bucket chunk URIHYPERFRAMES_RENDER_BUCKETis unset (no regression for existing callers)