How to Detect SQL Injection SELECT and XSS Input in Python

A SQL injection SELECT payload like 'UNION SELECT * FROM secrets' can dump an entire table through one unguarded input field. This project builds a Python CLI validator that runs input through two regex pattern sets - one for SQL injection markers, one for XSS - and prints SAFE or UNSAFE with a reason so obvious attacks get caught and logged at the edge.

Security Engineerpythoninput-validationsql-injection

What the validator catches

The goal is a small Python module, validator.py, that reads a string and prints SAFE or UNSAFE (with a reason). It runs as a CLI:

python3 validator.py "hello world"                  # SAFE
python3 validator.py "' UNION SELECT * FROM secrets --"   # UNSAFE: sql-injection
python3 validator.py "<script>alert(1)</script>"    # UNSAFE: xss

It must flag two attack classes. The SQL injection class covers the classic markers attackers append to a query: a UNION SELECT that stitches attacker rows onto a legitimate result set, a tautology like OR 1=1 that makes a WHERE clause always true, a stacked ; DROP TABLE, and comment terminators (--). The XSS class covers <script> tags, inline event handlers (onerror=, onload=), and javascript: URIs.

Why a SQL injection SELECT is dangerous

Consider a search endpoint that builds SQL by string concatenation:

query = "SELECT * FROM products WHERE name = '" + user_input + "'"

If a user submits ' UNION SELECT username, password FROM users --, the query becomes two SELECTs glued together, and the second one returns the credentials table. The trailing -- comments out whatever SQL followed. This is why UNION SELECT and OR 1=1 are the highest-signal tokens to detect - they are the building blocks of almost every hand-crafted injection.

Step 1 - write the two pattern sets

Compile one case-insensitive regex per attack class. The SQL pattern targets the injection markers directly; the XSS pattern targets the script-execution vectors:

import re, sys

SQLI = re.compile(
    r"('|\b)(or|and)\s+\d+=\d+|union\s+select|drop\s+table|insert\s+into"
    r"|--\s*$|;\s*--|\bexec\b|\bxp_",
    re.IGNORECASE
)
XSS = re.compile(
    r"<script|onerror\s*=|onload\s*=|javascript:|<img[^>]+on\w+\s*=",
    re.IGNORECASE
)

union\s+select matches UNION SELECT regardless of spacing or case; (or|and)\s+\d+=\d+ catches OR 1=1 and its variants; ;\s*-- and --\s*$ catch stacked queries and comment terminators.

Step 2 - flag and report

Check SQL first, then XSS, and return a reason so the caller can log which class fired:

def is_safe(text):
    if SQLI.search(text):
        return False, 'sql-injection'
    if XSS.search(text):
        return False, 'xss'
    return True, None

if __name__ == '__main__':
    text = ' '.join(sys.argv[1:])
    safe, reason = is_safe(text)
    print('SAFE' if safe else f'UNSAFE: {reason}')

Run it against normal input - names, emails, order descriptions - and confirm each prints SAFE. Order #12345 for Alice and john@example.com must pass through cleanly; a validator that flags everything is useless.

Where a regex validator fits (and where it does not)

A hand-rolled validator is a useful edge signal - it catches obvious attempts, surfaces them in logs, and stops trivial bots before they reach the app. But it is never the control. The real defenses are:

Regex validators are easy to bypass with obfuscation (encoding, comments inside keywords, unicode). Treat this as defense-in-depth and log signal, not a wall.

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

How do you detect a SQL injection SELECT attack?

Match the injection markers with a case-insensitive regex: UNION SELECT (which appends attacker rows to a result set), OR 1=1 (a tautology that makes any WHERE clause true), and comment terminators like a trailing double dash. These tokens appear in almost every hand-crafted injection, so flagging them catches obvious attempts at the edge.

What does UNION SELECT do in a SQL injection?

UNION SELECT stitches a second query onto a legitimate one so the response also returns rows the attacker chose - for example dumping a users table through a product search box. It only works when the input is concatenated into the SQL string; parameterized queries neutralize it because the value is sent separately from the query text.

Can a regex input validator stop SQL injection?

A regex validator catches obvious attempts and gives you log signal, but it is not a real defense - it is easy to bypass with encoding or obfuscation. The primary control is parameterized queries, which send input as data the database never parses as SQL. Use the validator as defense-in-depth at the edge.

How do I detect XSS input in Python?

Use a second case-insensitive regex targeting the script-execution vectors: script tags, inline event handlers such as onerror= and onload=, and javascript: URIs. Print an UNSAFE result with an xss reason so the attempt is logged, then rely on output escaping at render time as the actual fix.

Keep learning

Fix a Stored XSS With HTML EscapingSecurity projectPatch a SQL Injection QuerySecurity projectClose a SQL Injection in a Search EndpointSecurity projectSecurity roadmapStep by step to hiredSecurity interview questionsSTAR answersAll Security projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →