AWS Service Control Policy Misconfiguration: Cross-Account Permission Escalation
Théorie
Why This Matters
In 2019, a Capital One contractor exploited an overly permissive IAM role attached to a WAF instance to call ec2:DescribeInstances and s3:GetObject across an entire AWS Organization. A correctly configured Service Control Policy denying broad metadata and S3 read actions at the organizational unit level would have contained the blast radius to a single account rather than exposing over 100 million customer records. SCP misconfigurations are a force-multiplier vulnerability: one permissive policy silently widens the permission boundary of every IAM user, role, and group in every child account simultaneously — no individual account audit will detect the gap unless the SCP layer itself is reviewed.
Core Concept
AWS Organizations is the multi-account management service that groups AWS accounts into a hierarchy of Organizational Units (OUs). Service Control Policies (SCPs) are JSON permission documents attached to the root, to OUs, or to individual accounts. They act as a permission boundary — they never grant permissions, they only constrain what the maximum effective permission can be. Even if an IAM policy in a child account allows s3:*, an SCP that denies s3:DeleteBucket on the parent OU makes that action impossible for every principal in every child account.
SCPs follow an implicit deny at root model: if no SCP explicitly allows an action, it is denied. AWS provides a default FullAWSAccess SCP that allows all actions; organizations that rely solely on this policy have no SCP-level guardrails at all. A deny-list strategy keeps FullAWSAccess and adds explicit Deny statements; an allow-list strategy removes FullAWSAccess and grants only the actions required — the latter is harder to maintain but provides stronger containment.
The effective permission for any principal is the intersection of: the SCP allow set, the identity-based IAM policy, any resource-based policy, and any permission boundary. Attackers who gain access to a child account first enumerate SCPs to understand what actions are blocked before attempting privilege escalation — understanding that an SCP blocks iam:CreateUser shifts the attack toward Lambda execution roles or EC2 instance profiles instead.
Technical Deep-Dive
# List all SCPs in the organization (requires Organizations master account or delegated admin)
aws organizations list-policies --filter SERVICE_CONTROL_POLICY
--query 'Policies[*].{Id:Id,Name:Name,Description:Description}'
--output table
# Retrieve the full JSON of a specific SCP
aws organizations describe-policy --policy-id p-EXAMPLEPOLICYID
--query 'Policy.Content' --output text | python3 -m json.tool
# List all SCPs attached to a specific OU
aws organizations list-policies-for-target
--target-id ou-EXAMPLE-OUID
--filter SERVICE_CONTROL_POLICY
--query 'Policies[*].{Id:Id,Name:Name}'
--output table
# List all targets (OUs/accounts) that a specific SCP is attached to
aws organizations list-targets-for-policy --policy-id p-EXAMPLEPOLICYID
--query 'Targets[*].{Name:Name,TargetId:TargetId,Type:Type}'
--output table
# Simulate effective permissions for a principal in a child account
# (run from the child account after assuming the principal's role)
aws iam simulate-principal-policy
--policy-source-arn arn:aws:iam::123456789012:role/ExampleRole
--action-names s3:GetObject ec2:DescribeInstances iam:CreateUser
--query 'EvaluationResults[*].{Action:EvalActionName,Decision:EvalDecision}'
--output table
# Use Checkov to statically audit SCP JSON files saved locally
checkov -d ./scps/ --framework json_policy
--check CKV_AWS_132,CKV_AWS_192
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyLeaveOrganization",
"Effect": "Deny",
"Action": "organizations:LeaveOrganization",
"Resource": "*"
},
{
"Sid": "DenyRootUserActions",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalArn": "arn:aws:iam::*:root"
}
}
}
]
}
Security Assessment Methodology
- Enumerate the SCP hierarchy. From the management account, run
aws organizations list-policies --filter SERVICE_CONTROL_POLICYto obtain all SCP IDs, thenlist-targets-for-policyfor each. Build a map of which OUs and accounts are covered. - Identify accounts with only FullAWSAccess attached. If the only SCP is the AWS-managed
FullAWSAccess(policy IDp-FullAWSAccess), there are no organizational guardrails — every IAM permission in child accounts is fully effective. This is the highest-priority finding. - Parse each SCP for overly broad Allow statements. A statement of
"Effect": "Allow", "Action": "*", "Resource": "*"in a custom SCP is equivalent to FullAWSAccess — it adds nothing. Confirm that allow-list SCPs enumerate only required service namespaces. - Test effective permissions from inside a child account. Assume a role with known IAM permissions in a child account, then call
aws iam simulate-principal-policyagainst high-value actions (iam:CreateUser,sts:AssumeRole,s3:GetObject). Compare the decision to what the IAM policy alone would allow — any action the SCP should block that returnsallowedis a misconfiguration. - Audit for missing critical deny statements. Production SCPs should deny:
organizations:LeaveOrganization, root user actions, disabling CloudTrail, disabling GuardDuty, changing account contact information, and creating IAM users without MFA enforcement. - Remediate by adding targeted Deny statements to the OU-level SCP. Use
aws organizations update-policyor update via Terraformaws_organizations_policyresource. Re-run simulation to confirm the deny takes effect. Useaws organizations update-policy-contentcarefully — a malformed SCP that denies all actions on the root will lock every account in the organization.
Common Assessment Errors
- Assuming SCPs grant permissions. SCPs only constrain; they never grant. An SCP that allows
s3:*does nothing unless the IAM policy in the account also allows those actions. Assessors who read an SCP Allow as confirmation that a principal can perform the action will misreport findings. - Ignoring OU inheritance. SCPs are cumulative down the hierarchy — a child OU is constrained by both its own SCPs and all parent OU SCPs. Auditing only the directly attached SCP misses inherited restrictions or inherited gaps.
- Overlooking the management account exception. SCPs do not apply to the management (master) account itself. An attacker who escalates to the management account bypasses all SCP controls. This is a design constraint, not a misconfiguration, but assessors must document it clearly.
- Conflating SCPs with IAM permission boundaries. Permission boundaries are per-principal IAM constructs; SCPs are organizational. They interact but are configured differently. A finding about a missing permission boundary is not the same as a missing SCP.
- Modifying SCPs in production without simulation testing. An overly broad Deny SCP applied to the root OU can silently break workloads across hundreds of accounts. Always test with
simulate-principal-policyin a non-production OU before applying to production. - Missing delegated admin accounts. AWS allows a delegated administrator account for Organizations access. Enumerate with
aws organizations list-delegated-administrators— a compromised delegated admin account can read and potentially modify SCP configuration.
NICE Framework Alignment
| Code | Knowledge/Skill/Task Statement | How This Card Develops It |
|---|---|---|
| K0053 | Knowledge of security risk management processes | Evaluating SCP coverage gaps as organizational risk: a missing guardrail is a risk that spans every child account simultaneously |
| K0167 | Knowledge of system administration, network, and OS hardening techniques | Applying hardening principles to cloud organization structures: deny-list SCPs, root user restrictions, and CloudTrail protection |
| S0073 | Skill in conducting vulnerability scans and recognizing vulnerabilities | Using simulate-principal-policy and Checkov to detect SCP misconfigurations that widen effective permissions beyond intended boundaries |
| T0144 | Conduct penetration testing as required for new or updated applications | Enumerating SCP hierarchies from a child account to determine which escalation paths are blocked and which remain viable during a cloud penetration test |
| T0395 | Write code to address security vulnerabilities | Authoring correct SCP JSON with targeted Deny statements and condition keys to remediate identified permission boundary gaps |
Further Reading
- AWS Security Best Practices — Amazon Web Services, Service Control Policies chapter (AWS Documentation)
- Hacking the Cloud: AWS Organizations Attacks — Nick Frichette (hackingthe.cloud)
- Cloud Security Handbook — Eyal Estrin, Chapter 9: Multi-Account Governance (Packt Publishing)
Challenge Lab
Renforcez votre apprentissage avec un défi généré basé sur la compétence de cette carte.