So this is a hard to accomplish exploit, and is really only accomplishable by first exploiting another exploit first,
or by an employee with some level of trusted access, though this employee might not normally have actual database
access. I do believe you should be aware of it, as it leaves open an avenue you may not be thinking of.

A sample application

So the first thing we need is an application that uses Flyway, let’s just use the
Spring Boot Flyway Sample. The example is semi contrived, I discovered the problem though trying to use flyway
to create admin users for PostgreSQL.

All we need to do is add a second, or modify the existing insert statement in V1__init.sql, to

Our code is working and we’re all set? right? Strings are quoted, so it’s secure? well that’ll make exploiting this
harder, but it should also be your first cue that this is vulnerable, injection secure code never has quotes like this.

Let’s modify one of our placeholders to contain something a bit more nefarious.

flyway.placeholders.adminfirst=', ''); DROP TABLE person; --

Now if you run the code you’ll notice the app fails to start during the person table being missing. Obviously you
could do something more subtle, like add a user to the database. I can already hear your protest though, you had to
modify a file to do this. To address that, unmodify the line back to Caleb, now before running the app set the
environment variable in your shell (or however you set environment variables)

exportFLYWAY_PLACEHOLDERS_ADMINFIRST="', ''); DROP TABLE person; --"

Run the application again, you’ll see the same error you had before, when it was in your properties file. Spring Boot
will override any defined property with an environment variable.

Why it’s important

Ok, so in order to do this you have to have access to the environment that Flyway runs on, while migrations are running.
That’ll never happen right? Take my AWSDocker Cloud, you can protect AWS with multifactor (2fa), and
api credentials seem pretty secure. What about Docker Cloud? To access that control panel, which gives you access to
start, stop and modify the environment variables of servers with a simple gui, all you need is a password. This
reinforces my opinion that Docker doesn’t care about your security. Yeah but they still need your password, sure
so how secure is that? do you use a different one for each site? if so how are you storing them? I mean with
LastPass’s recent zero days can you ever really be sure? What if they’re an employee that you thought was
adequately restricted because they only have access to the cloud control panel (25% of breaches are internal)?
What about your container build process? is that secure? Oh and let’s also consider that by default, PostgreSQL, its
container, Flyway, and Spring Boot, do not log the SQL executed by the connection; so how are you going to figure
out if someone did exploit the system?

Is this a practical attack? probably not, and if they have access to your environment variables there’s a good chance
you’re already owned worse than this. Seriously though, how hard is it to set an environment variable? have you seen
ShellShock? reality is, I don’t know how hard it would be to create this exploit in your system, or how many
employees you have that could. Maybe all the employees that could already have SQL access anyways.

A better way to provision PostgreSQL users in Docker

So my original StackOverflow question was trying to set up Postgres Users with flyway for my initial Docker
container configuration. I did find a better way to do this, instead of doing it with flyway, I’m doing it with
PostgreSQL itself. Now this is still and environment variable, and there’s a whole lot of security implications to be
had with putting security credentials into environment variables; it’s not really advised.

In order to do this you’ll need to extend the official PostgreSQL image, it will automatically run shell files in
/docker-entrypoint-initdb.d/, the -v in the below script sets a postgres variable.

So if you use :"var" you can quote an identifier, if you use :'var' you can quote a value. For more information on
this feature see your PostgreSQL Documentation.

TL;DR;

Beware of PropertySource’s and conscious of how their values are used. Don’t use Flyway’s
placeholders with Spring Boot, instead disable them by setting flyway.placeholderReplacement=false.
Also your application should never have access to your databases super user, not even when running changesets.