Skip to content

fix(aws-lambda): validate event S3 URIs against render bucket (F-004)#1213

Merged
vanceingalls merged 1 commit into
mainfrom
06-04-fix_aws-lambda_validate_event_s3_uris_against_render_bucket_f-004_
Jun 6, 2026
Merged

fix(aws-lambda): validate event S3 URIs against render bucket (F-004)#1213
vanceingalls merged 1 commit into
mainfrom
06-04-fix_aws-lambda_validate_event_s3_uris_against_render_bucket_f-004_

Conversation

@vanceingalls
Copy link
Copy Markdown
Collaborator

@vanceingalls vanceingalls commented Jun 5, 2026

Summary

  • Adds validateEventS3Uris(), called immediately after unwrapEvent() in the Lambda handler before any S3 I/O.
  • If HYPERFRAMES_RENDER_BUCKET env var is set, every S3 URI in the event (ProjectS3Uri, PlanOutputS3Prefix, PlanS3Uri, ChunkOutputS3Prefix, ChunkS3Uris, AudioS3Uri, OutputS3Uri) must resolve to that bucket. Mismatches throw S3_URI_NOT_ALLOWED.
  • Env var unset → validation skips (backwards-compatible; existing deployments without the var continue to work).
  • CDK stack (HyperframesRenderStack) auto-wires HYPERFRAMES_RENDER_BUCKET: this.bucket.bucketName so new deployments are protected without manual config.
  • S3_URI_NOT_ALLOWED added to all three NON_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 / PutObject calls to arbitrary buckets in the same AWS account, potentially exfiltrating plan data or overwriting objects in unrelated buckets.

Test plan

  • handler rejects a plan event whose ProjectS3Uri targets a different bucket — S3_URI_NOT_ALLOWED thrown, zero S3 ops recorded
  • handler rejects an assemble event with one cross-bucket chunk URI
  • Validation is skipped when HYPERFRAMES_RENDER_BUCKET is unset (no regression for existing callers)
  • All 12 handler unit tests pass

Copy link
Copy Markdown
Collaborator Author

vanceingalls commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

@miguel-heygen miguel-heygen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: #1213 — validate event S3 URIs against render bucket

Clean, low-surface fix. Notes:

handler.ts

  • validateEventS3Uris called before primeRuntimeEnv() — correct, fail-fast before any side effects. ✓
  • Graceful fallback when HYPERFRAMES_RENDER_BUCKET is unset preserves backward compatibility for existing deployments. ✓
  • getEventS3Uris covers all three event types and filters null AudioS3Uri. ✓
  • Error name S3_URI_NOT_ALLOWED matches the non-retryable lists in CDK. ✓

HyperframesRenderStack.ts

  • HYPERFRAMES_RENDER_BUCKET injected into lambda env via CDK. ✓
  • S3_URI_NOT_ALLOWED added to non-retryable lists for all three event types (plan, renderChunk, assemble). ✓

Tests

  • Plan event with evil bucket rejected before any S3 ops (s3.ops length check). ✓
  • Assemble event with mixed chunk URIs rejected. ✓
  • prevBucket save/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.

Copy link
Copy Markdown
Collaborator

@miguel-heygen miguel-heygen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

miguel-heygen
miguel-heygen previously approved these changes Jun 5, 2026
Copy link
Copy Markdown
Collaborator

@miguel-heygen miguel-heygen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@vanceingalls vanceingalls changed the base branch from 06-04-fix_cli_re-validate_ssrf_denylist_on_redirects_harden_isprivateurl to graphite-base/1213 June 5, 2026 21:06
@graphite-app
Copy link
Copy Markdown

graphite-app Bot commented Jun 6, 2026

Merge activity

  • Jun 6, 12:01 AM UTC: This pull request can not be added to the Graphite merge queue. Please try rebasing and resubmitting to merge when ready.
  • Jun 6, 12:01 AM UTC: Graphite disabled "merge when ready" on this PR due to: a merge conflict with the target branch; resolve the conflict and try again..
  • Jun 6, 12:45 AM UTC: Graphite rebased this pull request, because this pull request is set to merge when ready.
  • Jun 6, 12:52 AM UTC: @vanceingalls merged this pull request with Graphite.

@vanceingalls vanceingalls force-pushed the 06-04-fix_aws-lambda_validate_event_s3_uris_against_render_bucket_f-004_ branch from 5a7b913 to f9053c0 Compare June 6, 2026 00:44
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>
@vanceingalls vanceingalls force-pushed the 06-04-fix_aws-lambda_validate_event_s3_uris_against_render_bucket_f-004_ branch from f9053c0 to b5a30f4 Compare June 6, 2026 00:44
@graphite-app graphite-app Bot changed the base branch from graphite-base/1213 to main June 6, 2026 00:45
@graphite-app graphite-app Bot dismissed miguel-heygen’s stale review June 6, 2026 00:45

The base branch was changed.

@vanceingalls vanceingalls merged commit 6588884 into main Jun 6, 2026
38 of 44 checks passed
@vanceingalls vanceingalls deleted the 06-04-fix_aws-lambda_validate_event_s3_uris_against_render_bucket_f-004_ branch June 6, 2026 00:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants