Skip to content

Commit 79c0ed6

Browse files
Add additional fastapi mheader write models
1 parent 5ced5c0 commit 79c0ed6

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

python/ql/lib/semmle/python/frameworks/FastApi.qll

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,5 +383,33 @@ module FastApi {
383383

384384
override predicate valueAllowsNewline() { none() }
385385
}
386+
387+
class HeaderSubscriptWrite extends Http::Server::ResponseHeaderWrite::Range {
388+
DataFlow::Node index;
389+
DataFlow::Node value;
390+
391+
HeaderSubscriptWrite() {
392+
exists(SubscriptNode subscript, DataFlow::AttrRead headerLookup |
393+
// To give `this` a value, we need to choose between either LHS or RHS,
394+
// and just go with the LHS
395+
this.asCfgNode() = subscript
396+
|
397+
headerLookup.accesses(instance(), "headers") and
398+
exists(DataFlow::Node subscriptObj | subscriptObj.asCfgNode() = subscript.getObject() |
399+
headerLookup.flowsTo(subscriptObj)
400+
) and
401+
value.asCfgNode() = subscript.(DefinitionNode).getValue() and
402+
index.asCfgNode() = subscript.getIndex()
403+
)
404+
}
405+
406+
override DataFlow::Node getNameArg() { result = index }
407+
408+
override DataFlow::Node getValueArg() { result = value }
409+
410+
override predicate nameAllowsNewline() { none() }
411+
412+
override predicate valueAllowsNewline() { none() }
413+
}
386414
}
387415
}

python/ql/test/library-tests/frameworks/fastapi/response_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ async def response_parameter(response: Response): # $ requestHandler
1313
response.set_cookie(key="key", value="value") # $ CookieWrite CookieName="key" CookieValue="value"
1414
response.headers.append("Set-Cookie", "key2=value2") # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2"
1515
response.headers.append(key="Set-Cookie", value="key2=value2") # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2"
16-
response.headers["X-MyHeader"] = "header-value" # $ MISSING: headerWriteName="X-MyHeader" headerWriteValue="header-value"
16+
response.headers["X-MyHeader"] = "header-value" # $ headerWriteName="X-MyHeader" headerWriteValue="header-value"
1717
response.status_code = 418
1818
return {"message": "response as parameter"} # $ HttpResponse mimetype=application/json responseBody=Dict
1919

@@ -45,7 +45,7 @@ async def response_parameter_custom_type(response: MyXmlResponse): # $ requestHa
4545
print(type(response))
4646
assert type(response) == fastapi.responses.Response
4747
response.set_cookie("key", "value") # $ CookieWrite CookieName="key" CookieValue="value"
48-
response.headers["Custom-Response-Type"] = "yes, but only after function has run" # $ MISSING: headerWriteName="Custom-Response-Typer" headerWriteValue="yes, but only after function has run"
48+
response.headers["Custom-Response-Type"] = "yes, but only after function has run" # $ headerWriteName="Custom-Response-Type" headerWriteValue="yes, but only after function has run"
4949
xml_data = "<foo>FOO</foo>"
5050
return xml_data # $ HttpResponse responseBody=xml_data mimetype=application/xml
5151

0 commit comments

Comments
 (0)