NotAction Plus Allow: IAM's Silent Escalation Path
An IAM policy pairing Effect: Allow with NotAction grants every action AWS has not explicitly listed, not just the excluded services. The bound role can call sts:AssumeRole, lambda:UpdateFunctionCode, and ec2:RunInstances to escalate privileges, and the exposed surface silently grows as AWS ships new API actions each quarter.
Operational summary
At a glance
- Symptom
- Role assumes broad allow permissions covering every current and future AWS action not named in the exclusion list
- Likely cause
- IAM policy statement using Effect: Allow combined with NotAction instead of an explicit Action list
- Impact
- Account-wide privilege escalation via AssumeRole, PassRole, and compute pivots, worsening automatically as AWS adds new API actions
- Verification signal
- Re-run the detection test and a controlled negative-path test.
- Safe correction
- Restrict NotAction to Effect: Deny only; replace Allow statements with explicit Action lists generated from Access Analyzer policy generation
- Rollback or recovery
- Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.
The Trap
Writing an IAM permission statement with "Effect": "Allow" and NotAction instead of a curated Action list. The pattern usually appears when someone tries to write a “grant everything except administration” policy for a contractor, CI runner, or third-party integration role.
The Default State
A typical offender looks like this: {"Effect": "Allow", "NotAction": ["iam:*", "organizations:*"], "Resource": "*"}. The author reads this as “allow everything except IAM and Organizations actions.” That reading is wrong. NotAction paired with Allow actually means “allow every action that AWS has not named in this list,” including every action that exists today under s3, ec2, lambda, sts, kms, and every action AWS ships tomorrow under services that don’t yet exist. Terraform modules copied from internal wikis and AWS console policy templates propagate this shape because it looks compact and self-documenting.
The Blast Radius
The role granted this policy can call sts:AssumeRole to pivot into other roles in the account, lambda:UpdateFunctionCode to inject payloads into privileged functions, and ec2:RunInstances with an attached instance profile carrying broader permissions than the original role itself. None of this requires a policy change on the attacker’s part — it is already permitted. Worse, AWS adds dozens of new API actions per quarter. A NotAction/Allow policy that passed a security review six months ago now covers a materially larger action surface without anyone touching the policy document. An access review signed off in Q1 is silently wrong by Q3, and nothing in CloudTrail or IAM’s policy JSON flags the drift.
The Lead Mechanic Fix
Never combine NotAction with Effect: Allow. If an exclusion pattern is genuinely required, use NotAction only under Effect: Deny, layered as a permissions boundary or Service Control Policy, never as the primary grant. Replace the allow-list with an explicit Action array generated from real usage: run aws accessanalyzer start-policy-generation against 90 days of CloudTrail data for the role, then attach the resulting least-privilege policy. Enforce this account-wide by requiring every role creation to set iam:PermissionsBoundary to a boundary policy that itself uses Effect: Deny with NotAction covering the approved service set, so any Allow statement attached later is capped regardless of how it is written.
Apply the safer control
Before you change production
Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.
Fix commands and configuration
NotActionEffect: AllowEffect: DenyVerify, roll back or escalate
Verify
Re-run the detection test and a controlled negative-path test. Confirm the unsafe behaviour is blocked while approved traffic still succeeds.
Rollback
Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.