Summary
The SES processing chain invokes ingestion for incoming mail even when verification fails, creating a low-cost resource exhaustion path (Lambda invocations + DB connection churn) from unauthenticated email traffic.
Evidence
1) Receipt rule action chain is non-blocking for filter
cdk/lib/newswires.ts receipt rule:
- Actions include:
new Lambda({ function: emailFilterLambda, invocationType: LambdaInvocationType.EVENT })
new S3({ bucket: emailBucket, ... })
new Lambda({ function: ingestionLambda, invocationType: LambdaInvocationType.EVENT })
Because the filter lambda is EVENT (async), it cannot block subsequent actions.
2) Filter lambda is observational only
email-filter-lambda/src/handler.ts:
- Calls
findVerificationFailures(...).
- On failure, logs and
continues; no mechanism to stop SES pipeline actions.
3) Ingestion does expensive setup before failing email verification
ingestion-lambda/src/handler.ts:
main calls initialiseDbConnection() before per-record verification.
- For SES records,
processSESRecord may fail verification and return failure, but DB connection has already been created and Lambda invocation already consumed.
Impact
- Any sender reaching this SES recipient can force ingestion-lambda invocations, DB connection initialization attempts, and log churn even when messages are rejected by verification.
- Enables cost/availability degradation via unauthenticated email flood.
- In high-volume abuse, can contribute to queue/processing delays for legitimate traffic.
Recommended fix
- Move verification gate earlier so unverified emails do not invoke ingestion path.
- Options:
- Use SES recipient/rule-level controls to pre-filter.
- Make filter action synchronous/blocking where supported by architecture.
- Avoid early DB connection init in ingestion handler:
- Initialize DB lazily only when a record has passed verification and requires DB write.
- Rate-limit / throttle email-triggered ingestion path and add abuse alarms.
- Consider separating SES ingestion from queue-based ingestion handlers to reduce shared blast radius.
Severity
Medium (availability/cost abuse; easy to trigger relative to impact).
Summary
The SES processing chain invokes ingestion for incoming mail even when verification fails, creating a low-cost resource exhaustion path (Lambda invocations + DB connection churn) from unauthenticated email traffic.
Evidence
1) Receipt rule action chain is non-blocking for filter
cdk/lib/newswires.tsreceipt rule:new Lambda({ function: emailFilterLambda, invocationType: LambdaInvocationType.EVENT })new S3({ bucket: emailBucket, ... })new Lambda({ function: ingestionLambda, invocationType: LambdaInvocationType.EVENT })Because the filter lambda is
EVENT(async), it cannot block subsequent actions.2) Filter lambda is observational only
email-filter-lambda/src/handler.ts:findVerificationFailures(...).continues; no mechanism to stop SES pipeline actions.3) Ingestion does expensive setup before failing email verification
ingestion-lambda/src/handler.ts:maincallsinitialiseDbConnection()before per-record verification.processSESRecordmay fail verification and return failure, but DB connection has already been created and Lambda invocation already consumed.Impact
Recommended fix
Severity
Medium (availability/cost abuse; easy to trigger relative to impact).