Skip to content

Commit 608b46c

Browse files
committed
Block SQL queries that fail tokenization
Our SQL injection detection tokenizes queries to check them. If the tokenizer can't parse a query, we skip it and the query goes through. Some databases still execute partially valid queries though: ClickHouse ignores junk after ; and SQLite runs everything before an unclosed /*. Now when user input shows up in a query we can't tokenize, we treat it as an attack. On by default, opt out with AIKIDO_BLOCK_INVALID_SQL=false.
1 parent bf3acdb commit 608b46c

3 files changed

Lines changed: 41 additions & 10 deletions

File tree

aikido_zen/vulnerabilities/sql_injection/__init__.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def detect_sql_injection(query, user_input, dialect):
1818
query_l = query.lower()
1919
userinput_l = user_input.lower()
2020
if should_return_early(query_l, userinput_l):
21-
return False
21+
return 0
2222

2323
internals_lib = ctypes.CDLL(get_binary_path())
2424
internals_lib.detect_sql_injection.argtypes = [
@@ -52,17 +52,12 @@ def detect_sql_injection(query, user_input, dialect):
5252
logger.debug(
5353
"Unable to check for SQL Injection, an error occurred in the library"
5454
)
55-
return False
55+
return 0
5656

57-
# This means that the library failed to tokenize the SQL query
58-
if c_int_res == 3:
59-
logger.debug("Unable to check for SQL Injection, SQL tokenization failed")
60-
return False
61-
62-
return c_int_res == 1
57+
return c_int_res
6358
except Exception as e:
6459
logger.debug("Exception in SQL algo: %s", e)
65-
return False
60+
return 0
6661

6762

6863
def should_return_early(query, user_input):

aikido_zen/vulnerabilities/sql_injection/context_contains_sql_injection.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,19 @@
22
This will check the context of the request for SQL Injections
33
"""
44

5+
import os
6+
57
from aikido_zen.helpers.extract_strings_from_context import extract_strings_from_context
68
from aikido_zen.vulnerabilities.sql_injection import detect_sql_injection
79

810

11+
def should_block_invalid_sql_queries():
12+
env_val = os.environ.get("AIKIDO_BLOCK_INVALID_SQL")
13+
if env_val is None:
14+
return True
15+
return env_val.lower() in ["true", "1"]
16+
17+
918
def context_contains_sql_injection(sql, operation, context, dialect):
1019
"""
1120
This will check the context of the request for SQL Injections
@@ -14,7 +23,22 @@ def context_contains_sql_injection(sql, operation, context, dialect):
1423
# Only supports SQL queries that are strings, return otherwise.
1524
return {}
1625
for user_input, path, source in extract_strings_from_context(context):
17-
if detect_sql_injection(sql, user_input, dialect):
26+
result = detect_sql_injection(sql, user_input, dialect)
27+
28+
if result == 1:
29+
return {
30+
"operation": operation,
31+
"kind": "sql_injection",
32+
"source": source,
33+
"pathToPayload": path,
34+
"metadata": {
35+
"sql": sql,
36+
"dialect": dialect,
37+
},
38+
"payload": user_input,
39+
}
40+
41+
if result == 3 and should_block_invalid_sql_queries():
1842
return {
1943
"operation": operation,
2044
"kind": "sql_injection",
@@ -23,6 +47,7 @@ def context_contains_sql_injection(sql, operation, context, dialect):
2347
"metadata": {
2448
"sql": sql,
2549
"dialect": dialect,
50+
"failedToTokenize": "true",
2651
},
2752
"payload": user_input,
2853
}

docs/invalid-sql-queries.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Blocking invalid SQL queries
2+
3+
Zen blocks SQL queries that it can't tokenize when they contain user input. This prevents attackers from bypassing SQL injection detection with malformed queries. For example, ClickHouse ignores invalid SQL after `;`, and SQLite runs queries before an unclosed `/*` comment.
4+
5+
This is on by default. In blocking mode, these queries are blocked. In detection-only mode, they are reported but still executed.
6+
7+
If you see false positives (legitimate queries being blocked), disable it with:
8+
9+
```
10+
AIKIDO_BLOCK_INVALID_SQL=false python app.py
11+
```

0 commit comments

Comments
 (0)