This project is a demo of SQL Injection vulnerabilities in a simple web application. It implements a deliberately vulnerable Flask web application to showcase various SQL injection attack vectors and their impacts.
sql-injection-demo/'
├── app.py
├── setup.sql
├── templates/
│ ├── login.html
│ ├── products.html
│ └── add_product.html
├── static/
│ └── css/
│ └── style.css
└── README.md
Login Bypass: Enter a sql statement to bypass the login form, logging in as a random user. INSERT Injection: Product creation form vulnerable to injection Delete Injection: Remove products via injection
Backend: Python 3 with Flask framework Database: MySQL with PyMySQL connector Frontend: HTML, CSS
The application uses string concatenation instead of parameterized queries:
query = f"SELECT * FROM users WHERE username = '{user}' AND password = '{pwd}';" cursor.execute(query) This allows attackers to inject malicious SQL by manipulating the username or password fields.
The MySQL connection is configured to allow multiple statements: pythondb = pymysql.connect(
host="localhost",
user="root", #REPLACE WITH USER
password="password", #REPLACE WITH YOUR MYSQL PASSWORD
database="injection_demo",
client_flag=pymysql.constants.CLIENT.MULTI_STATEMENTS
) This enables advanced attacks like dropping tables or inserting malicious data.
Login Form (/login)
Username and password fields both vulnerable Allows authentication bypass and data extraction
Add Product Form (/add_product)
Product name field vulnerable to injection Enables database manipulation through INSERT statements
In the login page enter the attack in the password field, and anything for the username.
Attack: ' OR '1'='1' #
SELECT * FROM users WHERE username = '' OR '1'='1' # ' AND password

In the password field, I entered the SQL injection statement, and logged in as a username that is gibberish, and not in the database.
In the products page, enter the attack.
Attack: x', 0); UPDATE products SET price = 0.01; #
Price: 0

In the products page, you can delete a product by name.
Attack: x', 0); DELETE FROM products WHERE name = 'Laptop'; #
Price: 0

Through the add products page, you can enter a statement to insert a user into the table.
Attack: Test', 0); INSERT INTO users (username, password) VALUES ('SQL', 'Injection'); #

Python 3.7 or higher MySQL Server 8.0 or higher pip
pip install flask pymysql
First, log into MySQL (using Local root user): enter in bash terminal: mysql -u root -p Go back to bash terminal. Then run the setup script: mysql -u root -p < database/schema.sql
This will create the injection_demo database, users, products, and logs tables, and also insert default data (admin/admin123, test/test123, shail/shail123)
YOU MUST UPDATE THESE LINES IN app.py TO MATCH YOUR MYSQL SETUP:
Open app.py and find this section (around line 6-13):
pythondb = pymysql.connect(
host="localhost", # ← Change if MySQL is on different host
user="root", # ← Change to YOUR MySQL username
password="Shail1234", # ← CHANGE THIS TO YOUR MYSQL PASSWORD
database="injection_demo",
autocommit=True,
client_flag=pymysql.constants.CLIENT.MULTI_STATEMENTS
)
Example configurations:
If your MySQL password is "password123":
pythondb = pymysql.connect(
host="localhost",
user="root",
password="password123", # ← Your actual password here
database="injection_demo",
autocommit=True,
client_flag=pymysql.constants.CLIENT.MULTI_STATEMENTS
)
If you created a different MySQL user:
pythondb = pymysql.connect(
host="localhost",
user="myusername", # ← Your MySQL username
password="mypassword", # ← Your MySQL password
database="injection_demo",
autocommit=True,
client_flag=pymysql.constants.CLIENT.MULTI_STATEMENTS
)
If MySQL is on a different port: pythondb = pymysql.connect(
host="localhost",
port=3307, # ← Add port if not default
user="root",
password="yourpassword",
database="injection_demo",
autocommit=True,
client_flag=pymysql.constants.CLIENT.MULTI_STATEMENTS
)
python app.py You should see output like:
- Serving Flask app 'app'
- Debug mode: on WARNING: This is a development server. Do not use it in production deployment.
- Running on http://127.0.0.1:5000
Open your web browser and navigate to: http://127.0.0.1:5000
I was originally using mysql-connector, but multi-statement executions were not being compiled correctly, so I switched to PyMySQL. PyMySQL allows functionality for multi-statements in SQL, this is important when trying to delete a product from the add product page, for example.
I was struggling to find ways to reset my database to the original schema I have in place through the web's frontend, but I found running the schema.sql file to be more convenient to use in a smaller demo like this. But because of this, when trying to test for dropping tables, you would need to run the schema again on MySQL.
When trying to delete products through the products page, I was inserting a product as well. The solution I found was to delete both the malicious entry and the product you want to delete. Attack: dummy', 0); DELETE FROM products WHERE name IN ('Laptop', 'dummy'); #