What's the worst someone could do with your HR system?
Pretend this is your company's HR portal. A developer wrote the login in twenty minutes and moved on. For the next five minutes, find out what that decision actually cost. Everything runs in your browser — no server, no stakes, no data leaves this page.
Parable HR Portal
LockedParable Industries
Employee Portal
Need a push? Reveal hints one at a time.
' in the username field. What happens to the SQL query?
AND and OR to combine conditions. What if you could make the WHERE clause always true?
' OR '1'='1' -- with any password. The -- comments out the rest of the query.
SELECT * on the login query returns 8 columns. To see the table structure, pull from SQLite's metadata table. Username: ' UNION SELECT name, sql, NULL, NULL, NULL, NULL, NULL, NULL FROM sqlite_master --. Any password. The schema panel on the right will unlock.
' UNION SELECT id, username, password, name, role, salary, pip, notes FROM employees --. Any password. You'll dump every salary, PIP flag, and private note.
Query Inspector
See exactly what the app executesTable schema
Schema hidden. Dump it with a UNION against sqlite_master (Hint 4) to unlock this panel.
TABLE employees id INTEGER PRIMARY KEY username TEXT NOT NULL password TEXT NOT NULL name TEXT NOT NULL role TEXT NOT NULL salary INTEGER NOT NULL pip INTEGER NOT NULL (default 0) notes TEXT
What just happened
The app built its SQL query by pasting your input directly into the query string using string concatenation. The template looks like this:
SELECT * FROM employees WHERE username='[INPUT]' AND password='[INPUT]'
What your input produced this time:
When the ' in your input closed the string early, the rest became code,
not data. OR '1'='1' made the WHERE clause always true; --
commented out the password check. The database returned everything it could see.
What this would actually cost you
You just pulled every salary in the company, plus medical-leave reasons and termination plans. If this happened for real, the GDPR fine would be the least of it. Every employee whose salary leaked is a potential EEOC complaint. The engineer whose rehab status is now public has a wrongful-disclosure case. And pay transparency, when it arrives by leak instead of policy, is a resignation event — plan for ten to twenty percent attrition in the quarter. One line of code above cost you all of that.
The fix is straightforward. Never build SQL by concatenation. Use parameterized queries so user input is always treated as data.
The fix: parameterized queries
Every modern database driver supports parameterized queries. Instead of pasting user input into the SQL
string, you send the query and the values separately. The driver treats values as data, not code, so
' OR '1'='1' -- becomes a literal username, not a logic operator.
Python (sqlite3 / psycopg2)
# Bad — string concatenation query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'" cursor.execute(query) # Good — parameterized cursor.execute( "SELECT * FROM users WHERE username=? AND password=?", (username, password) )
Node.js (pg, mysql2, better-sqlite3)
// Bad const rows = await db.query(`SELECT * FROM users WHERE username='${username}'`) // Good const rows = await db.query( 'SELECT * FROM users WHERE username = $1', [username] )
Parameterized queries are the minimum defense. Input validation, least-privilege database accounts, and a Web Application Firewall all add depth, but nothing substitutes for never concatenating user input into SQL in the first place.
Your own apps don't have this, right?
Knowing is different from hoping. A SignumCyber assessment checks your actual applications for this exact class of bug — and the 99 other ones we don't have labs for yet.
Talk to an advisorYour apps don't have this bug. Probably.