File size: 4,534 Bytes
7257069
 
 
 
 
ef93755
 
7257069
ef93755
 
7257069
 
 
ef93755
7257069
ef93755
7257069
ef93755
7257069
 
9aed967
 
 
 
 
 
 
 
ef93755
7257069
 
9aed967
7257069
 
 
 
ef93755
9aed967
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7257069
 
 
 
 
9aed967
 
 
 
 
 
ef93755
7257069
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9aed967
7257069
 
 
 
 
 
 
 
 
ef93755
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
"""
SecureCodeEnv Task: SQL Query Builder
Difficulty: Medium
CWE Targets: CWE-89 (SQL Injection), CWE-20 (Improper Input Validation)
"""

TASK = {
    "id": "medium_sql_query_builder",
    "difficulty": "medium",
    "cwe_targets": ["CWE-89", "CWE-20"],
    "component_name": "UserQueryBuilder",
    "filename": "src/db/user_queries.py",
    "problem_statement": """Write a Python function:

`build_user_query(username: str, role: str) -> tuple`

Builds a parameterized SQL query to fetch a user by username and role.

REQUIREMENTS:
- Returns a tuple: (query_string, params_tuple)
- query_string MUST use placeholders (%s or ?) — NEVER f-strings or .format() or %
- params_tuple must contain the sanitized values
- Must validate role is EXACTLY one of: 'admin', 'user', 'moderator' — raise ValueError for anything else
- Must handle None/empty username (return empty result query with empty params)
- The function must include type hints and a docstring

SECURITY: Never construct SQL by concatenating or formatting user input.
NEVER: f"SELECT ... {username}", "SELECT ..." + username, "..." % username
""",

    "starter_code": '''def build_user_query(username: str, role: str):
    # BUG: SQL injection vulnerability!
    query = f"SELECT * FROM users WHERE username = \'{username}\' AND role = \'{role}\'"
    return query
''',

    "test_cases": [
        {
            "fn": "build_user_query",
            "input": ["alice", "admin"],
            "expected_type": "tuple",
            "expected_len": 2,
            "description": "Returns 2-tuple (query, params)"
        },
        {
            "fn": "build_user_query",
            "input": ["bob", "user"],
            "expected_type": "tuple",
            "description": "Valid user role"
        },
        {
            "fn": "build_user_query",
            "input": ["alice", "moderator"],
            "expected_type": "tuple",
            "description": "Valid moderator role"
        },
        {
            "fn": "build_user_query",
            "input": ["alice", "superadmin"],
            "expected_exception": "ValueError",
            "description": "Invalid role 'superadmin' raises ValueError"
        },
        {
            "fn": "build_user_query",
            "input": ["alice", "ADMIN"],
            "expected_exception": "ValueError",
            "description": "Case-sensitive role check — 'ADMIN' is invalid"
        },
        {
            "fn": "build_user_query",
            "input": ["alice", ""],
            "expected_exception": "ValueError",
            "description": "Empty role raises ValueError"
        },
        {
            "fn": "build_user_query",
            "input": ["", "admin"],
            "expected_type": "tuple",
            "description": "Empty username returns safe query (not error)"
        },
        {
            "fn": "build_user_query",
            "input": ["'; DROP TABLE users;--", "admin"],
            "expected_type": "tuple",
            "sql_injection_check": True,
            "description": "SQL injection payload in username must be parameterized"
        },
    ],

    "attack_type": "injection",

    "security_checks": [
        {"type": "no_string_format_sql",
         "forbidden": ["f\"SELECT", "f'SELECT", ".format(", "% (user", "% (role"],
         "message": "f-string/format SQL injection"},
        {"type": "role_validation",
         "required": ["ALLOWED_ROLES", "allowed_roles", "not in", "ValueError"],
         "message": "Role validation not implemented"},
    ],

    "naive_code": '''def build_user_query(username: str, role: str):
    query = f"SELECT * FROM users WHERE username = \'{username}\' AND role = \'{role}\'"
    return (query, ())
''',

    "optimal_code": '''ALLOWED_ROLES = {"admin", "user", "moderator"}

def build_user_query(username: str, role: str) -> tuple:
    """Builds a parameterized SQL query safe from injection.

    Args:
        username: The username to query (untrusted input)
        role: Must be one of admin/user/moderator

    Returns:
        (query_string, params_tuple) safe for cursor.execute()

    Raises:
        ValueError: If role is not in the allowed set
    """
    if not role or role not in ALLOWED_ROLES:
        raise ValueError(f"Invalid role: {role!r}. Must be one of {ALLOWED_ROLES}")

    if not username:
        return ("SELECT * FROM users WHERE 1=0", ())

    query = "SELECT id, username, email, role FROM users WHERE username = %s AND role = %s"
    params = (username, role)
    return (query, params)
''',
}