aws-msk-connect-can-modify-code
kafkaconnect:UpdateConnector with a new custom plugin revision replaces the connector's executable code, enabling arbitrary code execution as its service execution role.
match (effective permission)
{
"action": "kafkaconnect:UpdateConnector",
"resource_type": "AWS::MSKConnect::Connector"
}
where
connector uses a CUSTOM plugin (customPlugin config present, not a built-in Confluent/community connector)
emit
| source type | Identity |
|---|---|
| target type | GenericCompute |
| source | <principal> |
| target | <MSK Connect Connector (GenericCompute)> |
| permissions | kafkaconnect:UpdateConnector |
| conditions | iam_permission service_state |
| state logic | ACTIVE when the principal has effective kafkaconnect:UpdateConnector on the connector scope AND the connector uses a custom plugin (the UpdateConnector API accepts customPlugin.revision to switch to a new plugin version). When the connector uses only built-in connectors (no custom plugin), UpdateConnector only changes configuration parameters (task count, settings) — emit CanModifyConfiguration (B3) instead, not CanModifyCode. BLOCKED if SCP or permission boundary denies kafkaconnect:UpdateConnector. Note that deploying a new custom plugin version also requires kafkaconnect:CreateCustomPlugin to upload the JAR/ZIP; the combined capability (CreateCustomPlugin + UpdateConnector) is the full code-replacement path. |
Narrative
{principal.name} can call kafkaconnect:UpdateConnector on {connector.name} with a new custom plugin revision, replacing the connector's executable code (JAR/ZIP); the running connector tasks are restarted with the attacker-supplied code, which executes as {role.name} (the connector's service execution role).
Raw rule rules/derived/aws/msk.yaml
id: aws-msk-connect-can-modify-code
emits: CanModifyCode
description: kafkaconnect:UpdateConnector with a new custom plugin revision replaces the connector's executable
code, enabling arbitrary code execution as its service execution role.
match_effective_permission:
action: kafkaconnect:UpdateConnector
resource_type: AWS::MSKConnect::Connector
where:
- connector uses a CUSTOM plugin (customPlugin config present, not a built-in Confluent/community connector)
emit:
source_type: Identity
target_type: GenericCompute
source: <principal>
target: <MSK Connect Connector (GenericCompute)>
permissions:
- kafkaconnect:UpdateConnector
conditions:
- iam_permission
- service_state
state_logic: "ACTIVE when the principal has effective kafkaconnect:UpdateConnector on the connector\
\ scope AND the connector uses a custom plugin (the UpdateConnector API accepts customPlugin.revision\
\ to switch to a new plugin version). When the connector uses only built-in connectors (no custom\
\ plugin), UpdateConnector only changes configuration parameters (task count, settings) \u2014 emit\
\ CanModifyConfiguration (B3) instead, not CanModifyCode. BLOCKED if SCP or permission boundary denies\
\ kafkaconnect:UpdateConnector. Note that deploying a new custom plugin version also requires kafkaconnect:CreateCustomPlugin\
\ to upload the JAR/ZIP; the combined capability (CreateCustomPlugin + UpdateConnector) is the full\
\ code-replacement path."
derived_from:
- effective kafkaconnect:UpdateConnector on connector scope
- connector.customPlugin config present
false_positive_note: "Only emit CanModifyCode (vs. CanModifyConfiguration) when the connector is confirmed\
\ to use a custom plugin ARN. Built-in connectors (Debezium, Confluent S3 sink, etc. deployed without\
\ a custom plugin ARN in the kafkaconnect API response) are not code-modifiable via UpdateConnector\
\ alone \u2014 the plugin binary is managed by AWS. When the custom plugin status is UNKNOWN, emit\
\ CanModifyConfiguration conservatively (B3). The can-execute-as linchpin execute-as-via-code-modify\
\ consumes this CanModifyCode edge plus the ExecutesAs(connector \u2192 role) fact (B1) to derive\
\ CanExecuteAs \u2014 cite, do not re-derive."
narrative: '{principal.name} can call kafkaconnect:UpdateConnector on {connector.name} with a new custom
plugin revision, replacing the connector''s executable code (JAR/ZIP); the running connector tasks
are restarted with the attacker-supplied code, which executes as {role.name} (the connector''s service
execution role).'