aws-ssm-instance-exposes-role-via-imds

A managed instance exposes its instance-profile role credentials to any code running on it via the IMDS endpoint.

derived aws emits ExposesCredential

match

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

{'instance': None} ExecutesAs {'role': None}

where

node_type(?instance) == VirtualMachine ?instance.ssm_ping_status == 'Online' # instance is SSM-reachable, making this fact actionable

emit

source typeVirtualMachine
target typeRole
source?instance
target?role
state logicACTIVE — the IMDS credential endpoint at 169.254.169.254 is always present on EC2 instances and delivers the instance-profile credentials. Any code executing on the instance (via SSM, SSH, application RCE, or any other vector) can call IMDS and obtain the role's temporary credentials. The edge is ACTIVE whenever the instance is SSM-Online (making it reachable for command injection); it does not become ACTIVE or BLOCKED independently — its exploitation is gated by the contributing CanExecuteCommand edge.

Narrative

{instance.name} exposes its instance-profile role {role.name} credentials to any code executing on it via the EC2 IMDS endpoint (169.254.169.254); ssm:SendCommand or ssm:StartSession delivers that code.

Raw rule rules/derived/aws/ssm.yaml

id: aws-ssm-instance-exposes-role-via-imds
emits: ExposesCredential
description: A managed instance exposes its instance-profile role credentials to any code running on it
  via the IMDS endpoint.
match:
- - instance: null
  - ExecutesAs
  - role: null
where:
- node_type(?instance) == VirtualMachine
- '?instance.ssm_ping_status == ''Online''  # instance is SSM-reachable, making this fact actionable'
emit:
  source_type: VirtualMachine
  target_type: Role
  source: ?instance
  target: ?role
  permissions: []
  conditions: []
  state_logic: "ACTIVE \u2014 the IMDS credential endpoint at 169.254.169.254 is always present on EC2\
    \ instances and delivers the instance-profile credentials. Any code executing on the instance (via\
    \ SSM, SSH, application RCE, or any other vector) can call IMDS and obtain the role's temporary credentials.\
    \ The edge is ACTIVE whenever the instance is SSM-Online (making it reachable for command injection);\
    \ it does not become ACTIVE or BLOCKED independently \u2014 its exploitation is gated by the contributing\
    \ CanExecuteCommand edge."
  confidence: 0.98
  derived_from:
  - ?instance ExecutesAs ?role
  false_positive_note: "Not an escalation by itself \u2014 it states that code execution on the instance\
    \ equals holding the instance-profile role's credentials. Path value comes from a contributing CanExecuteCommand\
    \ edge. IMDSv2 (instance metadata service version 2, requiring a PUT token exchange) limits some SSRF-based\
    \ credential theft but does NOT protect against command execution via SSM \u2014 the commands run\
    \ as OS processes that can call IMDS normally. Only if IMDSv2 hop-limit is 1 AND the instance has\
    \ http-put-response-hop-limit=1 does SSRF from an application NOT reach IMDS; direct OS command execution\
    \ still does."
  narrative: '{instance.name} exposes its instance-profile role {role.name} credentials to any code executing
    on it via the EC2 IMDS endpoint (169.254.169.254); ssm:SendCommand or ssm:StartSession delivers that
    code.'
move · open · esc close