Skip to content

feat: let the text attributes and URL parameters of a request object carry no NOSQL - #163

Merged
SizzleUnrlsd merged 2 commits into
mainfrom
feat/request-objects
Sep 26, 2026
Merged

SizzleUnrlsd merged 2 commits into
mainfrom
feat/request-objects

Conversation

@SizzleUnrlsd

Copy link
Copy Markdown
Contributor

Summary

Since #158, text input carries no NOSQL. Flask describes its request attribute by attribute. Django, REST framework, aiohttp and tornado's self.request taint the request object as a whole, so request.GET["name"] and every URL parameter carried NOSQL, like the body. A RequestObject(symbol, text=()) model now names the inputs that are request objects:

  • a view receives the request first (after self), then URL parameters, which are text;
  • reading one of the request's text attributes gives text, whether read directly (request.GET) or below a request source (self.request.GET);
  • the body, the files, REST framework's data and aiohttp's json() keep the request's kinds.

An attribute read counts only when every source of the value is a request object. Only NOSQL is affected: text keeps the other kinds.

Closes #162.

Declared request objects

Framework Inputs Text attributes
Django, REST framework annotated HttpRequest / WSGIRequest / ASGIRequest / DRF Request, class-based view bases, their self.request, view decorators, URL registrars GET, POST, COOKIES, META, headers, path, path_info, method, get_full_path, get_host, query_params, …
aiohttp annotated web.Request, RouteTableDef decorators, router and web.* registrations query, match_info, headers, cookies, path, url, rel_url, post, …
tornado self.request arguments, query_arguments, body_arguments, query, uri, path, headers, cookies, …

The aiohttp route symbols are gathered in _ROUTE_TABLES and _ROUTE_CALLS, so the entry points, the registrars and the request objects share one list. The models are the same.

Engine

  • parameter_sources: with a request object, the parameters after the request are text.
  • _TaintProblem.attribute: an attribute read of a value whose every source is a request object listing the attribute removes NOSQL.
  • _TaintProblem.covered: the source covering a symbol, narrowed by the request attribute read below it. Without it, self.request.GET got the full kinds back from the View.request source that covers its symbol. Both attribute reads and method calls use it.
  • _STRUCTURED (ALL without TEXT_KINDS, that is NOSQL) is what text loses, in the scalar parameters of Detection: a nosql-injection rule for structured attacker input #158 too.

Changed expectation

test_a_django_request_carries_nosql_as_a_whole documented the limit this PR lifts: request.GET["name"] was reported. It is replaced by tests where Django's text attributes and URL parameters are text and its body, read() and files stay payloads.

Remaining limit

A helper function the request is passed to reads it as a whole. Function summaries do not know where their parameters come from. test_a_helper_the_request_is_passed_to_reads_it_as_a_whole documents it.

Verification

  • Tests, one set per framework:
    • text attributes, URL parameters and payloads, for Django (registered and annotated views, class-based views), REST framework, aiohttp (route table and annotated) and tornado;
    • text attributes still carrying the other kinds (an xss from request.GET and a URL parameter);
    • the helper limit.
  • pytest: 1196 passed. pytest -m regression: 19 passed, unchanged. ruff check and mypy: clean.
  • The Enterprise plugins, including the pymongo table of CoreTrace-Entreprise/coretrace-python-analyzer-plugins#37: 255 passed on this branch.
  • End to end, with the Enterprise pymongo table, on a Django app with four views:
    • 0.12.0 reports five nosql-injection findings. Three are false: request.GET plus a URL parameter in search, and self.request.GET plus ObjectId(pk) in a class-based get, reported twice.
    • This branch reports the two true ones: json.loads(request.body) in login and json.loads(self.request.body) in post.

…carry no NOSQL

A RequestObject model names the inputs that are request objects: the URL parameters a view receives after the request are text, and so is an attribute of the request its model lists, read directly or below a request source such as self.request.
@SizzleUnrlsd SizzleUnrlsd added the enhancement New feature or request label Sep 26, 2026
@SizzleUnrlsd SizzleUnrlsd self-assigned this Sep 26, 2026
@SizzleUnrlsd
SizzleUnrlsd merged commit e695608 into main Sep 26, 2026
10 checks passed
@SizzleUnrlsd
SizzleUnrlsd deleted the feat/request-objects branch September 26, 2026 00:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Precision: the text attributes and URL parameters of a request object carry no NOSQL

1 participant