Skip to content

Build1 publisher3 min readPublished

Inspecting what reaches cursor.execute catches the f-string login four green tests cleared

Two Python login functions return the same 200s and 401s, and only the one keeping user values in a parameter tuple survives a test that reads what a fake cursor received. The placeholder it checks is SQLite's.

The Engineer · Build desk

What happened

  • Both login implementations passed the same two behavior cases, returning 200 for valid credentials and 401 for invalid ones, for a combined functional_total of 4/4 across four test executions.
  • The contract test substitutes a FakeDb whose execute method records the SQL and parameters on the instance instead of running the query, so assertions can read what the call received.
  • Against that fixture the f-string login reported params=None with alice and correct-password sitting inside the SQL text, while the parameterized version reported both values as a tuple.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint The published assertion looks for a literal question mark, so a team on psycopg or asyncpg that copies it gets a test that fails on correctly parameterized queries until the placeholder is edited.
  • decision Anyone adopting this has to choose what the test asserts against, because substring checks on usernames collide with the words in the query template and an approved query constant does not.
  • capability Checking the executor boundary needs no database in the test run, so the assertion can live in a unit suite with no fixture schema to maintain.
  • exposure Passing this test leaves password hashing, account lockout, rate limiting and session handling unexercised, so a login can clear the SQL boundary and still be the weakest part of an auth path.

The whole difference is the second positional argument to execute. One implementation hands the driver a finished string, built with an f-string that interpolates the username and the password into the WHERE clause [3]. The other hands it `SELECT id FROM users WHERE username = ? AND password = ?` plus a tuple of the two values [4]. The response is identical either way: 200 with `{"ok": True}` for valid credentials, 401 with `{"ok": False}` for invalid ones [5].

A reader on the author's earlier post put the fix in one line: "Assert that the query is parameterized before it reaches cursor.execute." [1] The post splits the problem into two boundaries, request parameters to response body and status, and request parameters to SQL string and parameters to cursor.execute [18]. Behavior tests cover the first, and here they covered it correctly [6].

FakeDb.execute takes `(self, sql, params=None)` and stores both on the instance; fetchone returns `(1,)` when the constructor's valid flag is set and None otherwise [7]. No SQL runs. The assertion reads `db.sql` and `db.params` after the call [8].

`assert_parameterized` makes four checks: a `?` somewhere in the SQL, params equal to the expected tuple, and the username and the password absent from the SQL text [8]. The last two are substring tests against a template made of English words. A user registered as `id`, `users` or `password` is a substring of `SELECT id FROM users WHERE username = ? AND password = ?`, so `assert username not in sql` fails on the implementation that is correct [17]. The experiment's fixture username is alice, which does not collide [9].

The `?` is SQLite's placeholder. psycopg commonly uses `%s` and asyncpg commonly uses `$1`, according to the post [10]. Lift the test into a psycopg codebase unchanged and `assert "?" in sql` fails on every parameterized query it inspects [16]. The post's own production advice is stricter than its demo: an approved query constant plus the expected parameter tuple "is usually stronger than checking for one character in the SQL string" [11].

The scanner run is the cheap half. code-audit-cli reported one finding on the unsafe file, severity high, pattern sql-concat, line 6, and zero findings on the safe one [12]. The post says that finding points to the f-string construction for human review, that it "does not prove that every possible exploit succeeds", and that it does not replace checking the input source, the execution path, authorization behavior, or the surrounding login logic [13].

What the contract test settles is one boundary, on two functions, with controlled values [9]. The post is explicit that this is a controlled demonstration and not a complete login-security review, and that it does not cover password hashing, account enumeration, rate limiting, account lockout, audit logging, session handling, or authorization [15].

What to watch

  • Whether the author publishes a version of assert_parameterized keyed to an approved query constant instead of a single-character SQL check.
  • Whether code-audit-cli's sql-concat pattern fires on concatenation spread across lines or built with .format(), not just a single f-string.
  • Whether the FakeDb approach holds in codebases where an ORM sits between application code and execute.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories