Android Security: SQL injection with the Room Persistence Library

During Google I/O 2017 the Room Persistence Library was announced. Room provides an abstraction layer over SQLite in a similar way to Retrofit with network requests.

SQL injection attacks are well documented on the web, indeed, OWASP rank injection as their number 1 security concern in 2017. SQLite built into Android is also susceptible to client-side SQL injection attacks, putting any data you store locally at risk.

As such, I thought it would be interesting to look at Room to see if it is possible to perform SQL injection attacks when using it. Surprisingly it is, so read on to find out more.

SQL injection on Android

Standard use of Room

public interface UserDao {
@Query("SELECT * FROM user WHERE first_name LIKE :first")
User findByFirstname(String first);


And Room generates the following code for you:

public User findByFirstname(String first) {
final String _sql = "SELECT * FROM user WHERE first_name LIKE ?";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
int _argIndex = 1;
if (first == null) {
} else {
_statement.bindString(_argIndex, first);
final Cursor _cursor = __db.query(_statement);

You can see how the query string from the annotation has been turned into a parameterised query with ? in place of :first. Similarly, if your query uses an array then Room dynamically builds a parameterised query based on the size of the array. The bindXXXX methods insert the value into the query string and perform automatic escaping at execution time.

i.e. Room is NOT prone to SQL injection with standard use.

Misuse of Room

@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();

This inheritance exposes a few methods, including public Cursor query(String sql, String[] selectionArgs). In regular use, you would provide a parameterised query to the sql parameter and the parameters in selectionArgs. SQL injection is then possible as sql is an easily malformed raw string.

For instance, String sql = "select * from user where first_name = '" + first + "'"; would be prone as you perform the substitution yourself.

It seems a shame that Room as of v1.0.0-alpha1 requires your database class to be an abstract class and not an interface to hide the internals. You want to write @AppDatabase public interface AppDatabase, with the annotation processor outputting public class AppDatabase_Impl extends RoomDatabase implements AppDatabase.



Matt Dolan has been eating doughnuts and developing with Android since the dark days of v1.6.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store