Summary
The /search-leases endpoint in routes/api.py concatenates user input directly into a SQLAlchemy .like() clause without escaping SQL wildcard characters (% and _).
Location
• web/shellcast-web-nc/routes/api.py ~line 382
• web/shellcast-web-fl/routes/api.py ~line 368
• web/shellcast-web-sc/routes/api.py ~line 410
Current code
Lease.lease_id.like("%%" + search_term + "%%")
Problem
A user can submit % or _ characters in the search term to manipulate the LIKE pattern. For example, sending % as the search term returns all leases. While this isn’t full SQL injection (SQLAlchemy parameterizes the value), it bypasses intended search behavior and could expose data the user shouldn’t browse.
Suggested fix
Escape wildcard characters before passing to .like():
import re
escaped = re.sub(r"([%_])", r"\\\1",
search_term)
Lease.lease_id.like(f"%%{escaped}%%")
Or use SQLAlchemy’s built-in Lease.lease_id.contains(search_term) which handles escaping automatically.
Affected states: NC, SC, FL (all three copies of api.py)
Summary
The /search-leases endpoint in routes/api.py concatenates user input directly into a SQLAlchemy .like() clause without escaping SQL wildcard characters (% and _).
Location
Current code
Lease.lease_id.like("%%" + search_term + "%%")Problem
A user can submit % or _ characters in the search term to manipulate the LIKE pattern. For example, sending % as the search term returns all leases. While this isn’t full SQL injection (SQLAlchemy parameterizes the value), it bypasses intended search behavior and could expose data the user shouldn’t browse.
Suggested fix
Escape wildcard characters before passing to .like():
Or use SQLAlchemy’s built-in Lease.lease_id.contains(search_term) which handles escaping automatically.
Affected states: NC, SC, FL (all three copies of api.py)