Skip to content

SimulateCustomPolicy does not report MissingContextValues for condition keys in OrderedOrganizationPolicyInputList #10525

Description

@amrutp24

Describe the bug

SimulateCustomPolicy reports unsupplied condition keys in MissingContextValues when
the key appears in PolicyInputList, but not when the same key appears in a policy
passed via OrderedOrganizationPolicyInputList.

The SCP condition is still evaluated, against absent context, so the call returns a
confident decision with an empty MissingContextValues. Supplying the key changes the
decision. Nothing in the response distinguishes the two situations.

This matters because evaluating SCP conditions is the capability added on 2026-07-30.
Condition-based SCPs such as region locks and tag enforcement are the main reason to
simulate an SCP at all, and the simulator currently returns the wrong answer for one
without signalling that anything is missing.

Regression Issue

  • Select this option if this issue appears to be a regression.

Expected Behavior

A condition key referenced by a policy in OrderedOrganizationPolicyInputList and not
supplied in ContextEntries should appear in MissingContextValues, exactly as it does
for a key referenced in PolicyInputList.

Current Behavior

MissingContextValues is empty and the decision is presented as authoritative.

Running the three cases in the reproduction below:

A implicitDeny ['aws:PrincipalTag/team']
B explicitDeny []
C allowed []

A and B reference the same condition key, aws:PrincipalTag/team. A is in an identity
policy and is reported. B is in an SCP and is not. B and C differ only by the presence
of ContextEntries, and the decision flips from explicitDeny to allowed.

No exception or error is raised. The failure is a silently incorrect result.

Reproduction Steps

import botocore.session, json

s = botocore.session.get_session()
iam = s.create_client("iam", region_name="us-east-1")

full = json.dumps({"Version": "2012-10-17", "Statement": [
{"Effect": "Allow", "Action": "", "Resource": ""}]})

ident_conditional = json.dumps({"Version": "2012-10-17", "Statement": [
{"Effect": "Allow", "Action": "s3:CreateBucket", "Resource": "",
"Condition": {"StringEquals": {"aws:PrincipalTag/team": "platform"}}}]})
ident_plain = json.dumps({"Version": "2012-10-17", "Statement": [
{"Effect": "Allow", "Action": "s3:CreateBucket", "Resource": "
"}]})
scp_conditional = json.dumps({"Version": "2012-10-17", "Statement": [
{"Effect": "Deny", "Action": "", "Resource": "",
"Condition": {"StringNotEquals": {"aws:PrincipalTag/team": "platform"}}}]})

A: condition key in the identity policy, not supplied

r = iam.simulate_custom_policy(
PolicyInputList=[ident_conditional], ActionNames=["s3:CreateBucket"],
OrderedOrganizationPolicyInputList=[{"ServiceControlPolicyInputList": [full]}])
print("A", r["EvaluationResults"][0]["EvalDecision"],
r["EvaluationResults"][0]["MissingContextValues"])

B: same condition key in the SCP, not supplied

r = iam.simulate_custom_policy(
PolicyInputList=[ident_plain], ActionNames=["s3:CreateBucket"],
OrderedOrganizationPolicyInputList=[
{"ServiceControlPolicyInputList": [full]},
{"ServiceControlPolicyInputList": [full, scp_conditional]}])
print("B", r["EvaluationResults"][0]["EvalDecision"],
r["EvaluationResults"][0]["MissingContextValues"])

C: same as B, key supplied

r = iam.simulate_custom_policy(
PolicyInputList=[ident_plain], ActionNames=["s3:CreateBucket"],
OrderedOrganizationPolicyInputList=[
{"ServiceControlPolicyInputList": [full]},
{"ServiceControlPolicyInputList": [full, scp_conditional]}],
ContextEntries=[{"ContextKeyName": "aws:PrincipalTag/team",
"ContextKeyType": "string", "ContextKeyValues": ["platform"]}])
print("C", r["EvaluationResults"][0]["EvalDecision"],
r["EvaluationResults"][0]["MissingContextValues"])

Possible Solution

Populate MissingContextValues for condition keys referenced by policies in
OrderedOrganizationPolicyInputList, matching the existing behaviour for
PolicyInputList.

Alternatively, accept OrderedOrganizationPolicyInputList on
GetContextKeysForCustomPolicy so callers can determine the required keys themselves.
It currently accepts only PolicyInputList:

GetContextKeysForCustomPolicy -> ['PolicyInputList']
GetContextKeysForPrincipalPolicy -> ['PolicyInputList', 'PolicySourceArn']

Today there is no API-side way to detect the situation.

Additional Information/Context

Both the SimulateCustomPolicy and SimulatePrincipalPolicy reference pages state that
the simulator "evaluates statements in identity-based policies, service control
policies (SCPs) including their condition keys and resource scoping". Neither says
that MissingContextValues covers only the identity-based half. If the behaviour is
intended rather than a defect, documenting it would be enough.

Practical impact: a platform engineer testing a tag guardrail sees explicitDeny,
concludes the guardrail works, and attaches it. In production the principal carries
the tag and the guardrail does not fire.

CLI version used

aws-cli/2.24.24 Python/3.12.9 Windows/11 exe/AMD64 This CLI version predates the parameter and cannot reproduce the issue. The reproduction runs against botocore 1.43.62 directly.

Environment details (OS name and version, etc.)

Windows 11, version 10.0.26200.8875 Python 3.13.2 botocore 1.43.62 IAM endpoint us-east-1 Caller: IAM user in an AWS Organizations member account with no Organizations permissions Date tested: 2026-08-01

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis issue is a bug.needs-triageThis issue or PR still needs to be triaged.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions