Exercise 2: A Real SQL Injection Attempt Against Search — Possible Solution ==================================================================== THE TEST ------------------------------ malicious = "x' OR '1'='1" GET /?q= # checked independently, directly against Note.search() itself: conn2 = sqlite3.connect(db_path) queries = [] conn2.set_trace_callback(lambda sql: queries.append(sql)) Note.search(conn2, malicious) VERIFIED, REAL RESULT ------------------------------ baseline, a real legitimate search ("Welcome"): 200 OK, the matching note present, the non-matching one absent the real injection attempt: 200 OK both real notes leaked despite the malicious input: False no notes matched (treated as a literal string): True the real SQL actually sent to SQLite: SELECT id, title, body, author_id FROM notes WHERE title LIKE '%x'' OR ''1''=''1%' ORDER BY id DESC WHY THIS WORKS ------------------------------ Note.search() builds its query with a `?` placeholder and passes the value as a bound parameter, exactly like Chapter 7's own find_author_safe(). SQLite's own driver is responsible for correctly escaping whatever the parameter's real value happens to contain before it's ever combined with the query text — the single quotes inside malicious are doubled ('' is SQL's own escaped single quote) in the real query sqlite3 traces, so the entire string, injected quotes and all, is treated as one literal value being searched for inside a title column, not as SQL syntax that could ever end the string early. WHY THIS WORKS AS AN ANSWER ------------------------------ It doesn't stop at "the response looked safe" — it goes one level deeper using sqlite3.set_trace_callback(), a real, built-in way to see the exact SQL text the database engine actually received, confirming directly that the malicious quotes were escaped by the driver rather than merely happening not to cause visible harm this one time. This mirrors Chapter 7's own discipline of checking the real, executed SQL rather than only checking the final result.