T09 · Insecure Skill Coding Practices
Warning
- Location
- phase4/query_engine.py:42
- Finding
- SPARQL Injection Through Unsafe Template Substitution<![CDATA[ ## Vulnerability Details **File Location**: `phase4/query_engine.py:42-48`, `phase4/query_engine.py:253-287`, `phase4/query_engine.py:299-323`; related interpolation in `phase5/hybrid_query.py:197-214` and analogous query templates **Vulnerability Type**: SPARQL injection **Risk Level**: Medium ### Vulnerable Code ```python @dataclass class QueryTemplate: """A pre-built SPARQL query template with parameter substitution.""" name: str description: str sparql_template: str parameters: List[str] = field(default_factory=list) category: str = "general" def render(self, **kwargs) -> str: """Render the template with parameter values.""" result = self.sparql_template for param in self.parameters: if param in kwargs: result = result.replace(f"${{{param}}}", str(kwargs[param])) return result ``` Example vulnerable template: ```python QueryTemplate( name="find_entity_by_name", description="Find entities by name (partial match)", sparql_template=""" PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX dk-class: <https://domain-kit.midea.com/ontology/class/> SELECT ?entity ?type ?name ?description WHERE { ?entity rdf:type ?type . ?entity rdfs:label ?name . OPTIONAL { ?entity rdfs:comment ?description } FILTER(CONTAINS(LCASE(?name), LCASE("${name}"))) } LIMIT ${limit} """, parameters=["name", "limit"], category="entity", ) ``` Execution sink: ```python def execute(self, sparql: str) -> QueryResult: start = time.time() self._query_count += 1 try: results = self.graph.query(sparql) elapsed = (time.time() - start) * 1000 self._total_time_ms += elapsed bindings = [] if results.vars: var_names = [str(v) for v in results.vars] ...[truncated 3024 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace textual substitution with RDFLib prepared queries and `initBindings` for all data values. 2. Convert search text into `rdflib.Literal` values rather than embedding it in query source. 3. Allowlist entity types and validate identifiers against a restrictive syntax before using them in prefixed names. 4. Parse `limit` as an integer and enforce a safe range, such as `1` through `100`. 5. Reject `SERVICE`, graph update operations, and unexpected query forms when executing generated or predefined queries. 6. If arbitrary direct SPARQL is required, expose it only to trusted callers and enforce query timeouts and result limits. 7. Add regression tests containing quotes, braces, comments, prefixed-name delimiters, malformed limits, and `SERVICE` clauses. ]]>
