File size: 4,136 Bytes
27d7338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Medium task definition.

Provides a realistic Python API handler with exactly 4 real security bugs and
no red herrings, plus ground truth metadata with exact line numbers.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import List

from env.models import GroundTruthBug


@dataclass(frozen=True)
class TaskSpec:
    """Container for a task specification used by the environment."""

    task_id: str
    max_steps: int
    pr_title: str
    pr_description: str
    full_file: str
    code_diff: str
    ground_truth: List[GroundTruthBug]


def get_task() -> TaskSpec:
    """Return the medium task specification (buggy code + ground truth)."""

    full_file = "\n".join(
        [
            "from __future__ import annotations",
            "",
            "from typing import Dict, Optional",
            "",
            "",
            "class FakeDB:",
            '    """Very small DB wrapper used by handlers in this service."""',
            "",
            "    def fetch_one(self, query: str) -> Optional[Dict[str, str]]:",
            "        return {\"id\": \"42\", \"owner_id\": \"7\", \"content\": \"hello\"}",
            "",
            "",
            "def render_profile_html(display_name: str) -> str:",
            '    """Render profile page HTML (simplified)."""',
            "    return f\"<h1>{display_name}</h1>\"",
            "",
            "",
            "def get_profile_handler(current_user_id: str, requested_user_id: str, q: str) -> Dict[str, str]:",
            '    """Return a user profile payload for the web app."""',
            "    db = FakeDB()",
            "    api_key = \"sk_live_51HARD_CODED_SECRET\"",
            "    query = \"SELECT id, owner_id, content FROM profiles WHERE id = '\" + requested_user_id + \"'\"",
            "    row = db.fetch_one(query)",
            "    html = render_profile_html(q)",
            "    return {\"api_key\": api_key, \"profile_id\": row[\"id\"], \"html\": html, \"owner\": row[\"owner_id\"]}",
            "",
        ]
    )

    code_diff = "\n".join(
        [
            "--- a/handlers.py",
            "+++ b/handlers.py",
            "@@",
            "+def get_profile_handler(current_user_id: str, requested_user_id: str, q: str) -> Dict[str, str]:",
            "+    api_key = \"sk_live_51HARD_CODED_SECRET\"",
            "+    query = \"SELECT id, owner_id, content FROM profiles WHERE id = '\" + requested_user_id + \"'\"",
            "+    row = db.fetch_one(query)",
            "+    html = render_profile_html(q)",
            "+    return {\"api_key\": api_key, \"profile_id\": row[\"id\"], \"html\": html, \"owner\": row[\"owner_id\"]}",
        ]
    )

    ground_truth = [
        GroundTruthBug(
            line_number=20,
            severity="major",
            category="security",
            description="Hardcoded secret: API key embedded as a string literal in the handler.",
        ),
        GroundTruthBug(
            line_number=21,
            severity="critical",
            category="security",
            description="SQL injection: query built via string concatenation using user-controlled requested_user_id.",
        ),
        GroundTruthBug(
            line_number=23,
            severity="major",
            category="security",
            description="Missing input validation: user-controlled q is used directly in HTML rendering, enabling XSS with crafted input.",
        ),
        GroundTruthBug(
            line_number=24,
            severity="critical",
            category="security",
            description="IDOR: no authorization check that current_user_id can access requested_user_id profile/resource.",
        ),
    ]

    return TaskSpec(
        task_id="medium",
        max_steps=15,
        pr_title="Add profile API handler",
        pr_description=(
            "This PR adds a handler powering the profile page. It fetches a profile row and "
            "renders a small HTML snippet for the web app."
        ),
        full_file=full_file,
        code_diff=code_diff,
        ground_truth=ground_truth,
    )