Zero Permissions on Secrets Manager. Full Access to Your Secrets. A CloudGoat walkthrough by VirajMathpati demonstrates a privilege escalation chain that bypasses permission-based scanners, allowing an IAM user with zero Secrets Manager permissions to retrieve a secret via a credential-value flow through SNS, API Gateway, and Lambda. The attack exploits the absence of resource policies and the data-flow of credentials, which is invisible to per-service policy checks. The Z3 prover in the stave project confirms the chain and identifies the missing policy checks. ✓ Human-authored analysis; AI used for formatting and proofreading. A 2025 CloudGoat walkthrough by VirajMathpati documents a privilege escalation that no permission-based scanner catches. The principal with a synthetic IAM user named cg-sns-user-cgidxi93qpes3g has zero permissions on Secrets Manager. Run their identity through IAM Access Analyzer; it confirms no access. Run it through PMapper; same answer. Run it through any policy-based review; the IAM user cannot read any secret in the account. The user retrieves a secret in seven API calls. The trick: the user's permissions don't connect to Secrets Manager directly. The connection is a credential-value flow through four services. SNS publishes an API key as a message payload. The user subscribes to the topic and receives the key in their inbox. The key authenticates to an API Gateway. The gateway's Lambda integration reads from Secrets Manager. The secret comes back as the HTTP response body. No policy connects SNS to Secrets Manager. The connection is the credential value itself. Every step is individually authorized. The compound chain is invisible to any tool that checks permissions service-by-service. 1 IAM user policy Allow: sns:Subscribe, sns:Receive, sns:ListTopics, …, apigateway:GET Resource: Deny: apigateway:GET on 7 specific paths 2 SNS topic Topic ARN: public-topic-cgidxi93qpes3g Topic policy: NONE defaults to IAM-only gate Publishes: a message containing an API Gateway key 3 API Gateway Auth: API key only no IAM, no Cognito, no Lambda authorizer Integration: Lambda 4 Lambda Reads: the target secret in Secrets Manager Each one is fine by per-service checklist criteria. The user's IAM policy is broad but doesn't grant Secrets Manager. The SNS topic has no resource policy — the standard "topic owner only" default. The API Gateway uses key-only auth, which is a documented authentication option. The Lambda accesses Secrets Manager via its execution role, the standard pattern. The bug is the connection. The Z3 prover in stave/examples/sns-secrets-compound-chain/z3prove/ runs four queries against the writeup configuration and four against a remediated version. The user's IAM policy admits sns:Subscribe on Resource: " " . The topic has no resource policy. In AWS, the IAM identity policy is the only gate when no topic policy is configured. The user wins. --- Finding 1: SNS topic subscribable, publishes credential --- subscribable + sensitive topics: 1 / 1 verdict: SAT — witness: arn:aws:sns:us-east-1:676206926638:public-topic-cgidxi93qpes3g publishes api key targeting arn:aws:apigateway:us-east-1::/restapis/x93anl9mj7 The data-flow annotation publishes credential type=api key on the topic asset makes this a security concern rather than a subscription pattern concern. Stave's existing broad-subscribe control checks the topic's resource policy. This issue lives in the IAM identity policy plus the absence of a topic policy plus the data-flow fact about what the topic publishes. The user's policy grants apigateway:GET on Resource: " " and denies seven specific patterns: { "Effect": "Deny", "Action": "apigateway:GET", "Resource": "/apikeys", "/apikeys/ ", "/restapis/ /resources/ /methods/GET", "/restapis/ /methods/GET", "/restapis/ /resources/ /integration", "/restapis/ /integration", "/restapis/ /resources/ /methods/ /integration" } Seven patterns. The author was thinking carefully. They identified specific high-sensitivity paths API keys, method bodies, integration internals and denied them. By any reasonable security review, this deny is well-considered. Z3 walks 24 known API Gateway management paths and finds 21 of them reachable: --- API Gateway Deny coverage analysis --- OPEN : /restapis OPEN : /restapis/{id} OPEN : /restapis/{id}/resources OPEN : /restapis/{id}/resources/{resource id} OPEN : /restapis/{id}/resources/{resource id}/methods/{method} BLOCKED : /restapis/{id}/resources/{resource id}/methods/{method}/integration OPEN : /restapis/{id}/stages OPEN : /restapis/{id}/stages/{stage} OPEN : /restapis/{id}/deployments OPEN : /restapis/{id}/deployments/{deployment id} OPEN : /restapis/{id}/models OPEN : /restapis/{id}/authorizers ... more The author blocked the API key endpoint. Reasonable. But the principal can enumerate the rest: /restapis lists every API ID. /restapis/{id}/stages lists each API's stages. /restapis/{id}/resources lists the resource paths. With those three calls, the attacker has the full URL. They don't need /methods/GET denied or /integration denied . They have the API key from Finding 1. They invoke the URL directly. The deny was correct for the things the author thought to protect . AWS API Gateway has more management endpoints than any individual reviewer holds in their head. The deny-list approach loses the race to the service surface area, just like the autoscaling iteration. The most novel modeling in this article. The Z3 program computes five booleans: hop 1: principal can subscribe to topic true hop 2: topic publishes credential true hop 3: API Gateway accepts credential, no IAM auth required true hop 4: API Gateway integrates with downstream function true hop 5: function reads Secrets Manager true Each hop is a fact read from a different service's observation. The conjunction is the data-flow chain. Z3's And of five booleans tells us the chain is satisfiable. This is the iteration's distinguishing feature. The five facts come from four different observation assets: the IAM user, the SNS topic, the API Gateway, the Lambda + one cross-asset claim "function reads Secrets Manager" . No single CEL predicate can express this. The composition is necessarily multi-asset. --- Finding 3: data-flow credential chain 5 hops --- hop 1 principal can subscribe to topic : true hop 2 topic publishes credential : true hop 3 API Gateway accepts credential, no IAM auth : true hop 4 API Gateway integrates with downstream function : true hop 5 function reads Secrets Manager : true verdict: SAT — full credential-flow chain is reachable zero direct Secrets Manager permissions; access via credential value flowing through SNS → API GW → Lambda F1 ∧ F2 ∧ F3. The complete escalation: sns:ListTopics → discover the topic sns:Subscribe → subscribe with attacker email receive SNS message → extract the API key apigateway:GET /restapis → enumerate API IDs apigateway:GET /restapis/.../stages → enumerate stages apigateway:GET /restapis/.../resources → enumerate paths curl https://