Looks for SQL injection in the SQLalchemy library.
- Use of
text()
function to construct parameters on non-literal input - Use of the
.suffix_with()
and.prefix_with()
methods on a query object with unsafe input
Use of the SQLalchemy with a text()
fragment can expose the constructed query to SQL injection.
For example, this query should generate
part = f"age<{age}" # exploitable, can override the original filter.
_x = session.query(User).filter(User.username == user).filter(text(part)).all()
With an input of age = 224
:
SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname FROM users WHERE users.id = ? AND age < 224 OR 1=1
If the age
argument was 224 OR 1=1
, the query would bypass the filter:
SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname FROM users WHERE users.id = ? AND id<224 OR 1=1
Both the .suffix_with()
and .prefix_with()
methods are vulnerable to unsafe input.
suffix = " OR 1=1" # Example exploiting suffix to add/change WHERE clause
prefix = " *," # Example exploiting query to get all fields
stmt = select([users.c.name]).where(users.c.id == 1).suffix_with(suffix, dialect="sqlite")
conn.execute(stmt)
stmt2 = select([addresses]).prefix_with(prefix) # can be chained
conn.execute(stmt2)
Direct execution of vulnerable queries will be caught by SQL100:
connection.execute("SELECT email_address FROM addresses WHERE email_address = \'{}\'".format(unsafe_input))
Replace with native SQLalchemy queries using the API instead of creating direct SQL.