Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?


Failed to load latest commit information.
Latest commit message
Commit time

CloudGoat (☁️🐐)

Rhino PyPI GitHub license PRs Welcome

CloudGoat is Rhino Security Labs' "Vulnerable by Design" AWS deployment tool.

Quick reference

CloudGoat 2.0 is here!

CloudGoat is Rhino Security Labs' "Vulnerable by Design" AWS deployment tool. It allows you to hone your cloud cybersecurity skills by creating and completing several "capture-the-flag" style scenarios. Each scenario is composed of AWS resources arranged together to create a structured learning experience. Some scenarios are easy, some are hard, and many offer multiple paths to victory. As the attacker, it is your mission to explore the environment, identify vulnerabilities, and exploit your way to the scenario's goal(s).

Below are our main goals for CloudGoat:

  • Focused, Curated, High-Quality Learning Experiences - Each of CloudGoat’s scenarios should provide the opportunity for experimentation, exploration, and building hands-on cloud security skills.
  • Good Documentation - We've done our best to ensure that CloudGoat’s scenarios are well-documented and easy to understand and evaluate in terms of difficulty, content, structure, and skills-required.
  • Easy to Install and Use - We understand that CloudGoat is a means to an end - learning and practicing cloud security penetration testing. Therefore, we aim to keep things simple, straightforward, and reliable.
  • Modularity - Each scenario is a standalone learning environment with a clear goal (or set of goals), and CloudGoat is able to start up, reset, or shut down each scenario independently.
  • Expandability - CloudGoat’s core components (python app and scenarios) are designed to permit easy and independent expansion - by us or the community.

Before you proceed, please take note of these warnings!

Warning #1: CloudGoat creates intentionally vulnerable AWS resources into your account. DO NOT deploy CloudGoat in a production environment or alongside any sensitive AWS resources.

Warning #2: CloudGoat can only manage resources it creates. If you create any resources yourself in the course of a scenario, you should remove them manually before running the destroy command.


  • Linux or MacOS. Windows is not officially supported.
    • Argument tab-completion requires bash 4.2+ (Linux, or OSX with some difficulty).
  • Python3.6+ is required.
  • Terraform >= 0.14 installed and in your $PATH.
  • The AWS CLI installed and in your $PATH, and an AWS account with sufficient privileges to create and destroy resources.
  • jq

Quick Start

To install CloudGoat, make sure your system meets the requirements above, and then run the following commands:

git clone
cd cloudgoat
pip3 install -r ./requirements.txt
chmod +x

You may also want to run some quick configuration commands - it'll save you some time later:

$ ./ config profile
$ ./ config whitelist --auto

Now, at your command, CloudGoat can create an instance of a scenario in the cloud. When the environment is ready, a new folder will be created in the project base directory named after the scenario and with a unique scenario ID appended. Inside this folder will be a file called start.txt, which will contain all of the resources you'll need to begin the scenario, though these are also printed to your console when the create command completes. Sometimes an SSH keypair named cloudgoat/ will be created as well.

Note: Don't delete or modify the scenario instance folder or the files inside, as this could prevent CloudGoat from being able to manage your scenario's resources.

As you work through the scenario, feel free to refer to the scenario's readme if you need direction. If you get stuck, there are cheat sheets linked at the bottom of each route's walkthrough.

When you are finished with the scenario, delete any resources you created yourself (remember: CloudGoat can only manage resources it creates) and then run the destroy command. It's always a good idea to take a quick glance at your AWS web-console afterwards - just in case something didn't get deleted.

You can read the full documentation for CloudGoat's commands here in the Usage Guide section.

How to use CloudGoat's Docker image

Try in PWD

Option 1: Run with default entrypoint

$ docker run -it rhinosecuritylabs/cloudgoat:latest

Option 2: Run with AWS config and credentials

Warning: Running this command will mount your local AWS configuration files into the Docker container when it is launched. This means that any user with access to the container will have access to your host computer's AWS credentials.

$ docker run -it -v ~/.aws:/root/.aws/ rhinosecuritylabs/cloudgoat:latest

Scenarios Available

vulnerable_lambda (Small / Easy)

$ ./ create vulnerable_lambda

In this scenario, you start as the 'bilbo' user. You will assume a role with more privelages, discover a lambda function that applies policies to users, and exploit a vulnerability in the function to escalate the privelages of the bilbo user in order to search for secrets.

Visit Scenario Page.

iam_privesc_by_rollback (Small / Easy)

$ ./ create iam_privesc_by_rollback

Starting with a highly-limited IAM user, the attacker is able to review previous IAM policy versions and restore one which allows full admin privileges, resulting in a privilege escalation exploit.

Visit Scenario Page.

lambda_privesc (Small / Easy)

$ ./ create lambda_privesc

Starting as the IAM user Chris, the attacker discovers that they can assume a role that has full Lambda access and pass role permissions. The attacker can then perform privilege escalation using these new permissions to obtain full admin privileges.

Note: This scenario may require you to create some AWS resources, and because CloudGoat can only manage resources it creates, you should remove them manually before running ./cloudgoat destroy.

Visit Scenario Page.

cloud_breach_s3 (Small / Moderate)

$ ./ create cloud_breach_s3

Starting as an anonymous outsider with no access or privileges, exploit a misconfigured reverse-proxy server to query the EC2 metadata service and acquire instance profile keys. Then, use those keys to discover, access, and exfiltrate sensitive data from an S3 bucket.

Visit Scenario Page.

iam_privesc_by_attachment (Medium / Moderate)

$ ./ create iam_privesc_by_attachment

Starting with a very limited set of permissions, the attacker is able to leverage the instance-profile-attachment permissions to create a new EC2 instance with significantly greater privileges than their own. With access to this new EC2 instance, the attacker gains full administrative powers within the target account and is able to accomplish the scenario's goal - deleting the cg-super-critical-security-server and paving the way for further nefarious actions.

Note: This scenario may require you to create some AWS resources, and because CloudGoat can only manage resources it creates, you should remove them manually before running ./cloudgoat destroy.

Visit Scenario Page.

ec2_ssrf (Medium / Moderate)

$ ./ create ec2_ssrf

Starting as the IAM user Solus, the attacker discovers they have ReadOnly permissions to a Lambda function, where hardcoded secrets lead them to an EC2 instance running a web application that is vulnerable to server-side request forgery (SSRF). After exploiting the vulnerable app and acquiring keys from the EC2 metadata service, the attacker gains access to a private S3 bucket with a set of keys that allow them to invoke the Lambda function and complete the scenario.

Visit Scenario Page.

ecs_takeover (Medium / Moderate)

$ ./ create ecs_takeover

Starting with access to the external website, the attacker needs to find a remote code execution vulnerability. By using RCE the attacker can get access to resources available to the website container. Abusing several ECS misconfigurations the attacker gains access to IAM permissions that allow them to force ECS into rescheduling the target container to a compromised instance.

Visit Scenario Page.

rce_web_app (Medium / Hard)

$ ./ create rce_web_app

Starting as the IAM user Lara, the attacker explores a Load Balancer and S3 bucket for clues to vulnerabilities, leading to an RCE exploit on a vulnerable web app which exposes confidential files and culminates in access to the scenario’s goal: a highly-secured RDS database instance.

Alternatively, the attacker may start as the IAM user McDuck and enumerate S3 buckets, eventually leading to SSH keys which grant direct access to the EC2 server and the database beyond.

Visit Scenario Page.

codebuild_secrets (Large / Hard)

$ ./ create codebuild_secrets

Starting as the IAM user Solo, the attacker first enumerates and explores CodeBuild projects, finding unsecured IAM keys for the IAM user Calrissian therein. Then operating as Calrissian, the attacker discovers an RDS database. Unable to access the database's contents directly, the attacker can make clever use of the RDS snapshot functionality to acquire the scenario's goal: a pair of secret strings.

Alternatively, the attacker may explore SSM parameters and find SSH keys to an EC2 instance. Using the metadata service, the attacker can acquire the EC2 instance-profile's keys and push deeper into the target environment, eventually gaining access to the original database and the scenario goal inside (a pair of secret strings) by a more circuitous route.

Note: This scenario may require you to create some AWS resources, and because CloudGoat can only manage resources it creates, you should remove them manually before running ./cloudgoat destroy.

Visit Scenario Page.

cicd (Medium / Moderate)

$ ./ create cicd

FooCorp is a company exposing a public-facing API. Customers of FooCorp submit sensitive data to the API every minute. The API is implemented as a Lambda function, exposed through an API Gateway. Because FooCorp implements DevOps, it has a continuous deployment pipeline automatically deploying new versions of their Lambda function from source code to production in under a few minutes.

Your goal: steal the sensitive data submitted by FooCorp customers!

Contributed by Datadog.

Visit Scenario Page.

detection_evasion (Medium / Hard)

$ ./ create detection_evasion

The goal of this scenario is to read out the values for both secrets without being detected. The secrets are both stored in Secrets Manager, and their values have the following format (cg-secret-XXXXXX-XXXXXX).

This scenario is significantly different from other CloudGoat scenarios. In detection_evasion, your goals will be outlined for you more clearly, and the challenge is to complete them without triggering alarms. There is more setup involved in this scenario, and it will take longer to play (you might want/need to play it multiple times).

Visit Scenario Page.

ecs_efs_attack (Large / Hard)

$ ./ create ecs_efs_attack

Starting with access the "ruse" EC2 the user leverages the instace profile to backdoor the running ECS container. Using the backdoored container the attacker can retireve credentials from the container metadata API. These credentials allow the attacker to start a session on any EC2 with the proper tags set. The attacker uses their permissions to change the tags on the Admin EC2 and starts a session. Once in the Admin EC2 the attacker will port scan the subnet for an open EFS to mount. Once mounted the attacker can retrieve the flag from the elastic file system.

Visit Scenario Page.

Usage Guide

The basic anatomy of a CloudGoat command is as follows:

$ ./ [ command ] [ sub-command ] [ --arg-name ] [ arg-value ]

The five main commands in CloudGoat are summarized below:


create [ scenario-name ] deploys a scenario to the AWS account of your choosing. You can also run create against an existing scenario if you wish - CloudGoat will simply destroy and recreate the scenario named.

Tip: you can use /scenarios in the name, which allows for bash's native tab-completion.

Note that the --profile is required for safety reasons - we don't want anyone accidentally deploying CloudGoat scenarios to a production environment - and CloudGoat will not use the system's "default" AWS CLI profiles or profiles specified as defaults via environment variables. You can, however, set this via config profile to avoid having to provide it every time.


list shows some information about all, undeployed, or deployed scenarios, or even a lot of information about a [ scenario-name ] that's already deployed.


destroy shuts down and deletes a [ scenario-name ]'s cloud resources, and then moves the scenario instance folder to ./trash - just in case you need to recover the Terraform state file or other scenario files. You can also specify all instead of a scenario name to destroy all active scenarios.

Tip: CloudGoat can only manage resources it creates. If you create any resources yourself in the course of a scenario, you should remove them manually before running the destroy command.


config allows you to manage various aspects of your CloudGoat installation, specially the IP whitelist, your default AWS profile, and tab-completion via argcomplete. It's worth briefly describing what each of these sub-commands do.


CloudGoat needs to know what IP addresses should be whitelisted when potentially-vulnerable resources are deployed in the cloud, and these IPs are tracked in a ./whitelist.txt file in the base project directory. The IP address you provide for whitelisting doesn't have to be in CIDR format, but CloudGoat will add a /32 to any naked IPs you provide. Optionally, you can add the --auto argument, and CloudGoat will automatically make a network request, using curl to to find your IP address, and then create the whitelist file with the result.


While CloudGoat will not ever use the system's "default" AWS CLI profiles or profiles specified as defaults via environment variables, you can instruct CloudGoat to use a particular AWS profile by name using the config profile command. This will prompt for and save your profile's name in a config.yml file in the base project directory. As long as that file is present CloudGoat will use the profile name listed inside for create and destroy commands, rather than requiring the --profile flag. You can run the config profile command at any time to view the name of your CloudGoat-default profile and validate the format of the config.yml. You can also create config.yml manually, if you wish, provided that you use the correct format.


We really wanted to have native tab-completion in CloudGoat, but as it turns out that was somewhat difficult to do outside of a REPL. It should work reasonably well for Linux users, and those OSX users brave enough to figure out a way to upgrade their bash version to 4.2+. CloudGoat does include and support the python library "argcomplete". A brief summary of how to install argcomplete is provided below, though for more detailed steps you should refer to the official documentation at the library's github page.

  1. Install the argcomplete Python package using CloudGoat's requirements.txt file: $ pip3 install -r core/python/requirements.txt
  2. In bash, run the global Python argument completion script provided by the argcomplete package: $ activate-global-python-argcomplete
  3. Source the completion script at the location printed by the previous activation command, or restart your shell session: $ source [ /path/to/the/completion/script ]

For those who cannot or do not wish to configure argcomplete, CloudGoat also supports the use of directory paths as scenario names, which means tab-completion will work for scenario names. Just use /scenario/[ scenario-name ] or ./[ scenarioinstance-name ] and your shell should do the rest.


help provides contextual help about commands. help can come before or after the command in question, so it's always there when you need it. Below are some examples:

  • $ ./ create help
  • $ ./ destroy help
  • $ ./ list help
  • $ ./ config help

One other use of note: $ ./ [ scenario-name ] help can be used to print to the console a brief summary of the scenario, as defined by the scenario's author.

Feature Requests and Bug Reports

If you have a feature request or a bug to report, please submit them here.

For bugs, please make sure to include a description sufficient to reproduce the bug you found, including tracebacks and reproduction steps, and check for other reports of your bug before filing a new bug report.

For features, much the same applies! Be specific in your request, and make sure someone else hasn't already requested the same feature.

Contribution Guidelines

Contributions to CloudGoat are greatly appreciated. If you'd like to help make the project better, read on.

  1. Python code in CloudGoat should generally follow Python's style conventions, favoring readability and maintainability above all.
  2. Follow good git practices: use pull requests, prefer feature branches, always write clear commit messages.
  3. CloudGoat uses black and flake8 - Python syntax and style linters - If you're going to commit code for CloudGoat, ensure that first flake8, and then black are both run on all Python files in core/python/ and on black's decisions take priority over flake8's. Both of these are commented out in the core/python/requirements.txt file since normal users don't need them.
  4. CloudGoat code should always use the BSD 3-clause license.

And lastly, thank you for contributing!


  • 6/24/19: CloudGoat 2.0 is released!


CloudGoat is software that comes with absolutely no warranties whatsoever. By using CloudGoat, you take full responsibility for any and all outcomes that result.


CloudGoat is Rhino Security Labs' "Vulnerable by Design" AWS deployment tool







No releases published


No packages published