Debugging UI events, parameterized SQL and shell paths — DedSec Project
Debugging UI events, parameterized SQL and shell paths JavaScript: lost event listener Broken example — DO NOT USE Fixed example Why it fails and the repair works Replacing markup removes…
JavaScript: lost event listener
Broken example — DO NOT USE
container.innerHTML = `<button id="save">Save</button>`;
// old save button listener was attached before innerHTML changed
Fixed example
container.innerHTML = `<button id="save">Save</button>`;
container.querySelector("#save").addEventListener("click", save);
Why it fails and the repair works
Replacing markup removes listeners on replaced nodes.
Root cause and precise failure
An event listener attaches to a particular DOM node. Replacing a parent through innerHTML creates new nodes whose appearance may be identical but whose old listeners are gone.
Repeatable regression exercise
Attach a listener to a button in a disposable page, replace its parent markup, and compare click behavior. Repair using a stable ancestor with delegated events or explicit reattachment after rendering.
SQL: unsafe string building
Broken example — DO NOT USE
query = "SELECT * FROM users WHERE name = '" + user + "'"
Fixed example
cursor.execute("SELECT * FROM users WHERE name = ?", (user,))
Why it fails and the repair works
Parameter binding stops user text being treated as SQL commands.
Executable SQLite exercise
SQL assembled from untrusted text can change query meaning. Binding parameters keeps data values separate from SQL syntax. Use an in-memory database so the exercise never touches production data.
import sqlite3
db = sqlite3.connect(":memory:")
db.execute("CREATE TABLE people (name TEXT PRIMARY KEY)")
db.executemany("INSERT INTO people VALUES (?)", [("Ada",), ("Grace",)])
def find(name):
return db.execute("SELECT name FROM people WHERE name = ?", (name,)).fetchall()
assert find("Ada") == [("Ada",)]
assert find("Ada'") == []
assert db.execute("SELECT COUNT(*) FROM people").fetchone() == (2,)
db.close()
Save as query_lab.py and run python3 query_lab.py. The quote inside the second search must be handled as data, not as part of the SQL statement. The trailing comma in (name,) creates a one-item tuple. SQLite uses ? placeholders; other drivers may use different syntax. Parameter binding does not work for identifiers such as table names or sort directions: choose those from a fixed allowlist.
Bash: unquoted path
Broken example — DO NOT USE
cd $PROJECT_ROOT
Fixed example
cd -- "$PROJECT_ROOT"
Why it fails and the repair works
Quoting protects paths containing spaces or wildcard characters.
Reproducible Bash path test
Without quotes, parameter expansion can undergo word splitting and wildcard expansion. A directory containing spaces is passed as several arguments. Quoting preserves a single argument; -- stops option parsing in commands that support it.
#!/usr/bin/env bash
set -euo pipefail
tmp=$(mktemp -d)
PROJECT_ROOT="$tmp/project alpha"
mkdir -- "$PROJECT_ROOT"
trap 'rmdir -- "$PROJECT_ROOT"; rmdir -- "$tmp"' EXIT
set -- $PROJECT_ROOT
[[ $# -gt 1 ]] # The broken expansion split into words.
set -- "$PROJECT_ROOT"
[[ $# -eq 1 ]] # Correct: one argument.
cd -- "$PROJECT_ROOT"
[[ $PWD == "$PROJECT_ROOT" ]]
printf 'Quoted path works: %s\n' "$PWD"
Run bash path_lab.sh. Only the argument demonstration is intentionally unquoted; the filesystem operations use the repaired form. For passing all script arguments onward, use "$@", not "$*". Quotes do not validate a path or make destructive operations safe; validate target directories independently.