VNX-1083: Data Access from Outside Expected Data Manager Component
A Python views, routes, controllers or handlers module that opens a raw database connection or cursor, or runs raw SQL, instead of going through the data layer.
| Field | Value |
|---|---|
| Rule ID | VNX-1083 |
| Severity | Low |
| SARIF level | note |
| Kind | sast |
| Languages | Python |
| CWE | CWE-1083 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:L/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:L/DI:H/EX:L/EC:N/P:L |
| Tags | data-access-outside-data-layer raw-sql cwe-1083 |
| Source | internal/sast/rules/vnx-1083.rego |
Overview
VNX-1083 maps to CWE-1083: Data Access from Outside Expected Data Manager Component. A Python views, routes, controllers or handlers module that opens a raw database connection or cursor, or runs raw SQL, instead of going through the data layer.
Why This Matters
Raw SQL scattered across request handlers is where unparameterised queries and missing authorisation checks hide, because nothing central reviews it. When every query goes through a repository or model layer, that layer is the one place to check parameterisation, tenancy filters and access control.
What Gets Flagged
In views.py, viewsets.py, routes.py, routers.py, controllers.py, handlers.py, endpoints.py, or any file under views/, viewsets/, routes/, routers/, controllers/, handlers/ or endpoints/:
def order_totals(request):
with connection.cursor() as cur: # FLAGGED
cur.execute("SELECT customer_id, SUM(total) FROM orders GROUP BY customer_id")
@bp.route("/reports/daily")
def daily():
db = sqlite3.connect("app.db") # FLAGGED
def search(self, request):
return User.objects.raw("SELECT * FROM users WHERE name LIKE %s", [term]) # FLAGGED
Also reported: psycopg2.connect, pymysql.connect, MySQLdb.connect, mysql.connector.connect, cx_Oracle.connect, oracledb.connect, pyodbc.connect (also through an import ... as alias or from sqlite3 import connect), connections["alias"].cursor(), Django .objects.extra(...) and RawSQL(...), and SQLAlchemy db.session.execute(...), db.engine.execute(...) and Post.query.filter(text("...")).
What Does Not Get Flagged
- The same calls in a repository, model,
db.pyor service module: that is the expected data manager. - ORM queries in a view (
Product.objects.filter(...)). - The calls named in comments or string literals.
- Test files.
- In a project that has a data manager module (a
models,repositories,dao,db,database,persistence,store,crudorqueriesmodule or directory): a handler’s driverconnect(),cursor(),objects.raw()anddb.session.execute()/db.engine.execute()of SQL text. Those lines are reported by VNX-1057, which says the same thing for the same reason; this rule still reports them in a project with no such module, and always reportsobjects.extra(),RawSQL()andtext()fragments.
Which module is the data manager is a project convention; the rule infers it from the file path only.
Remediation
- Move the query into a repository, manager or model method and call that from the view.
- Keep queries parameterised in that one place, and apply tenancy and permission filters there.
- For a deliberate exception, add
# vulnetix-ignore: VNX-1083on the line.
References
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-1083
// nosec vnx-1083
Or record an ignore rule: vulnetix ignore add --rule vnx-1083 --reason "...". See Suppressing findings.