# RailsGoat: an intentionally vulnerable Rails app for training

> RailsGoat is a deliberately insecure Ruby on Rails application that carries real OWASP Top 10 flaws on purpose, so developers and security staff can find, exploit and then fix them in a sandbox. The main branch runs Rails 8 on Ruby 3.4.1, and a training command turns the test suite into a list of open vulnerabilities.

**OWASP/railsgoat** — A vulnerable version of Rails that follows the OWASP Top 10

- Repository: https://github.com/OWASP/railsgoat
- Website: railsgoat.cktricky.com
- Stars: 929 · Forks: 846
- Language: HTML
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/owasp-railsgoat

## A target application, not a library

RailsGoat is a web application that is broken on purpose. The repository description calls it a vulnerable version of Rails that follows the OWASP Top 10, and the README is blunt about the intent: it demonstrates real-world security vulnerabilities from the OWASP Top 10 and serves as a hands-on training platform for developers and security professionals. The listed flaws include SQL injection, cross-site scripting, authentication issues and insecure direct object references, among others. The repository layout confirms this is a full Rails application rather than a library, with `app/`, `config/`, `db/`, `lib/`, `spec/`, `public/`, `vendor/`, a `Dockerfile`, a `docker-compose.yml`, a `Procfile` and a `Rakefile`. The audience is a training cohort or an individual who wants a legal, repeatable place to practise offensive thinking against a Rails stack, then read the code to understand why each flaw exists and how it should have been written.

## Training mode turns the specs into a checklist

The cleverest part of the project is how it uses its own test suite as the curriculum. In training mode a command runs the vulnerability specs, and each failing test marks a vulnerability that is present:

```bash
rails training
```

The output links to a wiki tutorial for each entry, and the README describes what those tutorials contain: how the vulnerability works, how to exploit it, and how to fix it. A single lesson can be isolated with the `SPEC` variable:

```bash
rails training SPEC=spec/vulnerabilities/sql_injection_spec.rb
```

That flips the usual relationship between tests and code. Instead of a green suite meaning the software is correct, a red suite means the lesson is armed. The alternative to training mode is maintainer mode, which inverts the expectation again and is used by the people who keep the application current:

```bash
RAILSGOAT_MAINTAINER="yes" bundle exec rspec
```

In maintainer mode the tests pass when the vulnerabilities are correctly implemented. The same specs are therefore a teaching instrument and a regression check, which is what keeps the deliberately broken code honest as the framework moves.

## Rails 8 on Ruby 3.4.1, with older branches kept alive

The current version line is stated plainly in the README, Rails 8.0 with Ruby 3.4.1, and the `main` branch runs Rails 8. The project has been carried through framework generations, with the history section stating it has been continuously updated through Rails versions 3, 4, 5, 6 and now 8, and that conversion to the OWASP Top Ten 2013 was completed in November 2013. Branches exist for the older stacks, which matters because a lesson that relies on a framework quirk only makes sense on the version where that quirk existed:

```bash
git checkout rails_3_2  # Rails 3.2
git checkout rails_4_2  # Rails 4.2
git checkout rails_5    # Rails 5.x
```

There is a caveat here. The tagged releases in the repository are all from March 2018, `rails.3`, `rails.4` and `rails.5.0.0`, while the last push was on 2026-09-08, so the current work is on branches rather than on tagged releases. The release tags therefore tell you about the legacy branches, not about what the main branch contains.

## Getting the app running on your own machine

The prerequisites are Ruby 3.4.1, Git and SQLite3, with MySQL optional but required for certain SQL injection demos. Readers new to Ruby are pointed at the GoRails setup guide for their operating system. The install sequence is four commands. Clone the repository and enter it:

```bash
git clone https://github.com/OWASP/railsgoat.git
cd railsgoat
```

Install bundler and the gems:

```bash
gem install bundler
bundle install
```

Create the database, then start the server:

```bash
rails db:setup
rails server
```

The application is then reachable at `http://localhost:3000`, where you create an account, log in, browse the features and try to reach other users' data. The README also points at MailCatcher for email testing, installed with `gem install mailcatcher` and started with `mailcatcher`, which serves the captured mail at `http://localhost:1080`. That matters for the lessons that depend on password reset and confirmation flows, since otherwise those emails would go nowhere during a local session.

## The Docker path and the pid file gotcha

A containerised route exists for teams that would rather not manage a Ruby toolchain locally. The requirements are Docker and Docker Compose 1.6.0 or newer, and on Mac with Apple Silicon, Rosetta must be installed. The sequence is short:

```bash
docker-compose build
docker-compose run web rails db:setup
docker-compose up
```

The application is then served on `http://localhost:3000`. The compose file shows how the container is put together, with a `web` service built from the repository, port 3000 mapped to the host, the working tree mounted into the container and the server bound to all interfaces:

```yaml
version: '2'
services:
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
```

Note the `rm -f tmp/pids/server.pid` in that command. It exists because of the failure mode the README calls out: if the container exits with a message that a server is already running, you delete `tmp/pids/server.pid` from the working directory and try again. A stale pid file from an earlier run is the most common reason the container refuses to start.

## MySQL lessons need a different environment

Some of the SQL injection lessons do not work on SQLite, so the project documents a MySQL path that switches the whole application over with a `RAILS_ENV` value:

```bash
RAILS_ENV=mysql rails db:create
RAILS_ENV=mysql rails db:migrate
RAILS_ENV=mysql rails server
```

The `mysql` environment is a separate configuration in `config/`, not a runtime toggle on the same database, which is why the create and migrate steps are repeated for it. If a learner starts with the default SQLite setup and finds that a specific injection lesson behaves differently from the wiki tutorial, the environment is the first thing to check rather than the lesson itself. This is also the clearest illustration of how RailsGoat is built: the application has to behave like a real Rails app, including environment-specific configuration, precisely so that the flaws being taught are the ones a real deployment would contain.

## What RailsGoat is not, and the licence behind it

Two limits should be stated before anyone deploys this. The first is the one the README puts in bold: the application contains serious security vulnerabilities and must never be deployed on a public server or network, only in isolated training environments. A host on a shared network, a cloud instance with a public address or a shared training VPS all qualify as unsafe. The second is scope. RailsGoat teaches the OWASP Top 10 categories of flaw as they appear in Rails, and the wiki is where the detailed per-vulnerability instructions live; the README itself lists only the vulnerability classes and points to the wiki for the tutorials, so the depth of coverage is bounded by what the wiki contains. On licensing, the README links the MIT License, with the licence file at the root of the repository, which matters for trainers who want to deploy the app inside a private curriculum. The project also carries a `docs/bonus_encrypted_secrets.md` file covering encrypted secrets and credentials in Rails 5.1 and later, which is the one topic in the repository that steps outside the deliberately broken pattern.

## Conclusion

RailsGoat fits teams training developers on the OWASP Top 10 who want a runnable target with per-vulnerability specs and wiki tutorials, and who can run it on a laptop or an isolated network segment. It does not fit anyone who needs a hardened deployment target, and it should never be exposed on a public server, which the README states plainly. Before starting, confirm you have Ruby 3.4.1 with Git and SQLite3, install MySQL if you intend to work through the SQL injection lessons, and decide whether you want training mode or RAILSGOAT_MAINTAINER mode, since the two expect opposite test results.

## FAQ

### How do I run RailsGoat locally?

You need Ruby 3.4.1, Git and SQLite3. Clone the repository, run gem install bundler and bundle install, then rails db:setup and rails server, and open http://localhost:3000.

### What does the rails training command do?

It runs the vulnerability test suite, and each failing test marks a vulnerability that exists in the app. The output links to a wiki tutorial explaining how the flaw works, how to exploit it and how to fix it.

### Can I run RailsGoat with Docker?

Yes. With Docker and Docker Compose 1.6.0 or newer, run docker-compose build, then docker-compose run web rails db:setup and docker-compose up. The app is served on http://localhost:3000, and if the container exits saying a server is already running, delete tmp/pids/server.pid.

### Do I need MySQL to work through the SQL injection lessons?

Some SQL injection vulnerabilities require MySQL. The README documents a separate mysql environment, created with RAILS_ENV=mysql rails db:create and RAILS_ENV=mysql rails db:migrate, then started with RAILS_ENV=mysql rails server.

## Sources

- [Issues](https://github.com/OWASP/railsgoat/issues)
- [License: MIT](https://github.com/OWASP/railsgoat/blob/main/LICENSE)
- [OWASP/railsgoat on GitHub](https://github.com/OWASP/railsgoat)
- [README](https://github.com/OWASP/railsgoat/blob/main/README.md)
- [Releases](https://github.com/OWASP/railsgoat/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/owasp-railsgoat
