Skip to main content

📝 Latest Blog Post

SQL Injection Explained: How to Secure Your Python Code (Stop Using f-strings in SQL)

SQL Injection Explained: How to Secure Your Python Code

SQL Injection Explained: How to Secure Your Python Code

It is the oldest trick in the book, yet it still destroys companies in 2026. If you are using f-strings to build your database queries, you are holding the door open for hackers.

We all love Python's f-strings. They are clean, readable, and fast. `f"Hello {name}"` is much nicer than the old `.format()` method. But when it comes to Database Queries (SQL), f-strings are deadly.

This vulnerability is called SQL Injection (SQLi). It happens when untrusted user input is treated as code instead of data. If an attacker knows you are doing this, they can trick your database into revealing passwords, deleting tables, or granting them admin access.

The Golden Rule: Never, ever concatenate strings into a SQL command. Not with `+`, and definitely not with `f-strings`.

The Vulnerability: Anatomy of a Hack

Imagine you have a simple login script. You take a `username` from a form and check if it exists.

# ❌ VULNERABLE CODE (Do not use) query = f"SELECT * FROM users WHERE username = '{user_input}'" cursor.execute(query)

If the user enters `John`, the query becomes:
SELECT * FROM users WHERE username = 'John'
This works fine.

But what if the user enters this as their username?
admin' --

The query now becomes:
SELECT * FROM users WHERE username = 'admin' --'

In SQL, -- means "Comment." It tells the database to ignore everything that comes after it. The attacker just tricked your database into running a query for the admin user without needing a password. They are logged in as Admin.

The Fix: Parameterized Queries

The solution is not to "clean" or "sanitize" the input yourself (you will miss something). The solution is to use Parameterized Queries.

This technique sends the SQL logic and the user data separately. The database compiles the SQL command first, and then inserts the user data safely. Even if the data contains malicious SQL commands, the database treats it as just a harmless text string.

How to do it in Python (SQLite/PostgreSQL)

Instead of f-strings, use placeholders like `?` (for SQLite) or `%s` (for PostgreSQL/MySQL).

# ✅ SECURE CODE (Do this) # Notice the comma? We pass the data as a separate tuple (second argument) query = "SELECT * FROM users WHERE username = ?" cursor.execute(query, (user_input,))

Now, if the user types `admin' --`, the database searches for a user whose literal username is "admin' --". It finds nothing. The hack fails.

Comparison: Vulnerable vs. Secure

Feature F-Strings (Vulnerable) Parameterized (Secure)
Execution Logic Compiles data AND code together Compiles code first, then adds data
Hacking Risk High (Easy to exploit) Near Zero (Architecture prevents it)
Performance Slower (Re-compiles every query) Faster (Caches the query plan)
Syntax f"SELECT {var}" "SELECT ?", (var,)
Pro Tip: Most ORMs (like SQLAlchemy or Django ORM) handle this for you automatically. This is why using an ORM is generally safer for beginners than writing raw SQL.

Conclusion

Security is not an "advanced" topic; it is a fundamental responsibility. Writing secure code is just as important as writing working code.

Go check your codebase right now. Ctrl + F for `f"SELECT` or `f"INSERT`. If you find any, fix them immediately.

Download January Skills: Python Security Checklist

Comments

🔗 Related Blog Post

🌟 Popular Blog Post