aws-secretsmanager-credentials-for-escalation
Reading a secret that is credentials for a strictly-more-privileged identity is escalation.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'principal': None}
CanReadSecret {'secret': None}
{'secret': None} CredentialsFor {'identity': None}
where
node_class(?secret) ==
Secret
node_class(?identity) == Identity
privilege(?identity) > privilege(?principal)
emit
| source type | Identity |
|---|---|
| target type | Identity |
| source | ?principal |
| target | ?identity |
| permissions | secretsmanager:GetSecretValue |
| conditions | iam_permission resource_policy key_permission |
| state logic | inherit_weakest(CanReadSecret, CredentialsFor): a CONDITIONAL(key_permission) read (CMK not yet decryptable) yields CONDITIONAL(key_permission); BLOCKED if the read is BLOCKED; else ACTIVE. This is a service-local convenience roll-up; the canonical path is read-secret-yields-identity -> impersonate-is-escalation in credential-chains.yaml. Deduplicate against that collapsed edge. |
Narrative
{principal.name} can read {secret.name}, which holds credentials for the more-privileged {identity.name}; reading it lets {principal.name} escalate to {identity.name}.
Raw rule rules/derived/aws/secretsmanager.yaml
id: aws-secretsmanager-credentials-for-escalation
emits: CanEscalateTo
description: Reading a secret that is credentials for a strictly-more-privileged identity is escalation.
match:
- - principal: null
- CanReadSecret
- secret: null
- - secret: null
- CredentialsFor
- identity: null
where:
- node_class(?secret) == Secret
- node_class(?identity) == Identity
- privilege(?identity) > privilege(?principal)
emit:
source_type: Identity
target_type: Identity
source: ?principal
target: ?identity
permissions:
- secretsmanager:GetSecretValue
conditions:
- iam_permission
- resource_policy
- key_permission
state_logic: 'inherit_weakest(CanReadSecret, CredentialsFor): a CONDITIONAL(key_permission) read (CMK
not yet decryptable) yields CONDITIONAL(key_permission); BLOCKED if the read is BLOCKED; else ACTIVE.
This is a service-local convenience roll-up; the canonical path is read-secret-yields-identity ->
impersonate-is-escalation in credential-chains.yaml. Deduplicate against that collapsed edge.'
confidence: min(contributing_confidences)
derived_from:
- <CanReadSecret edge_id>
- <CredentialsFor edge_id>
false_positive_note: "Emit ONLY when ?identity is STRICTLY more privileged than ?principal; a lateral\
\ same-privilege credential is access, not escalation. CredentialsFor must be an evidenced link (managed\
\ DB secret, IAM key material, bound client secret), not a secret the identity merely owns. Honor\
\ the key_permission gate \u2014 do not report ACTIVE escalation off a CMK-gated read until decrypt\
\ is proven. DEDUP: this is a service-local convenience roll-up of the canonical read-secret-yields-identity\
\ -> impersonate-is-escalation collapse in credential-chains.yaml; both emit CanEscalateTo(?principal\
\ -> ?identity). The evaluator MUST dedup by (type,source,target,scope) so the same escalation edge\
\ is materialized once (RULE-FORMAT monotonic+deduped). If the canonical collapse already produced\
\ the edge, this rule is a no-op re-derivation."
narrative: '{principal.name} can read {secret.name}, which holds credentials for the more-privileged
{identity.name}; reading it lets {principal.name} escalate to {identity.name}.'