aws-appflow-create-flow-exfil

Creating a new AppFlow flow that references an existing connector profile and points to an attacker-controlled destination exfiltrates SaaS data without modifying any existing flow.

derived aws emits CanExfiltrate

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} CanCreate {'scope': None}

where

?principal has effective appflow:CreateFlow (resource scope: *) ?principal has effective appflow:UseConnectorProfile on at least one connector profile with SaaS credentials ?principal can also trigger the new flow: appflow:StartFlow on the newly created flow ARN, OR the new flow is configured with a schedule/event trigger

emit

source typeIdentity
target typeData
source?principal
target<data accessible via the referenced connector profile's SaaS connection>
permissionsappflow:CreateFlow appflow:UseConnectorProfile appflow:StartFlow?
conditionsiam_permission resource_policy
state logicCONDITIONAL(resource_policy) unless the attacker-controlled destination S3 bucket already has an appflow.amazonaws.com write grant — without that grant the flow run fails at the S3 write step. Upgrade toward ACTIVE when the principal also controls the destination bucket policy (s3:PutBucketPolicy on the target bucket). Also CONDITIONAL(trigger_exists) if the principal cannot call appflow:StartFlow on the newly created flow — but a flow created with a schedule trigger fires automatically, so for scheduled new flows this condition is met at creation time. Inherit weakest from contributing CanCreate.

Narrative

{principal.name} can create a new AppFlow flow (appflow:CreateFlow) referencing an existing connector profile (appflow:UseConnectorProfile), configuring the destination as an attacker-controlled S3 bucket; when started or scheduled, the new flow exfiltrates SaaS data from the referenced connector without modifying any existing flow.

Raw rule rules/derived/aws/appflow.yaml

id: aws-appflow-create-flow-exfil
emits: CanExfiltrate
description: Creating a new AppFlow flow that references an existing connector profile and points to an
  attacker-controlled destination exfiltrates SaaS data without modifying any existing flow.
applies_to:
- aws
match:
- - principal: null
  - CanCreate
  - scope: null
where:
- '?principal has effective appflow:CreateFlow (resource scope: *)'
- ?principal has effective appflow:UseConnectorProfile on at least one connector profile with SaaS credentials
- '?principal can also trigger the new flow: appflow:StartFlow on the newly created flow ARN, OR the new
  flow is configured with a schedule/event trigger'
emit:
  source_type: Identity
  target_type: Data
  source: ?principal
  target: <data accessible via the referenced connector profile's SaaS connection>
  permissions:
  - appflow:CreateFlow
  - appflow:UseConnectorProfile
  - appflow:StartFlow?
  conditions:
  - iam_permission
  - resource_policy
  state_logic: "CONDITIONAL(resource_policy) unless the attacker-controlled destination S3 bucket already\
    \ has an appflow.amazonaws.com write grant \u2014 without that grant the flow run fails at the S3\
    \ write step. Upgrade toward ACTIVE when the principal also controls the destination bucket policy\
    \ (s3:PutBucketPolicy on the target bucket). Also CONDITIONAL(trigger_exists) if the principal cannot\
    \ call appflow:StartFlow on the newly created flow \u2014 but a flow created with a schedule trigger\
    \ fires automatically, so for scheduled new flows this condition is met at creation time. Inherit\
    \ weakest from contributing CanCreate."
  confidence: min(contributing_confidences) * 0.80
  derived_from:
  - ?principal CanCreate ?scope (appflow:CreateFlow + appflow:UseConnectorProfile)
  - 'messaging-chains.yaml (cited: data-plane exfil via new messaging path creation)'
  false_positive_note: "appflow:UseConnectorProfile is a REQUIRED gate \u2014 confirm the principal holds\
    \ it on at least one connector profile ARN before emitting. Without it, CreateFlow rejects any flow\
    \ that references a connector profile (which is every meaningful exfil flow). Also: CreateFlow requires\
    \ Resource:* in the IAM policy (no ARN pre-exists); honor that: a policy with appflow:CreateFlow scoped\
    \ to a specific flow ARN does NOT satisfy CreateFlow. Scope the CanCreate emit to the account/ region\
    \ scope, not a specific flow node. The destination bucket policy gate is the same as in aws-appflow-update-flow-exfil:\
    \ emit CONDITIONAL(resource_policy) when unconfirmed."
  narrative: '{principal.name} can create a new AppFlow flow (appflow:CreateFlow) referencing an existing
    connector profile (appflow:UseConnectorProfile), configuring the destination as an attacker-controlled
    S3 bucket; when started or scheduled, the new flow exfiltrates SaaS data from the referenced connector
    without modifying any existing flow.'
move · open · esc close