Skip to content

VNX-862: Missing Authorization on a destructive or administrative handler

A Python route, Django view or Graphene resolver deletes records or serves an /admin path with no authorization decorator, dependency, in-handler check or project-wide guard.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-862
Severity High
SARIF level error
Kind sast
Languages Python
CWE CWE-862
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:H/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H
Tags missing-authorization cwe-862 access-control
Source internal/sast/rules/vnx-862.rego

Overview

VNX-862 maps to CWE-862: Missing Authorization. It reports, on the def line, a Python request handler that deletes data or serves an /admin path with no authorization anywhere on its path.

Handlers understood: Flask/Quart/FastAPI/Sanic routes (@app.route, @bp.delete, @router.post …), Django function views in views/api modules (def view(request, ...)), and Graphene resolvers (def mutate(self, info, ...), def resolve_x(self, info, ...)). Sensitive means the body deletes records (ORM .delete(), db.session.delete(obj), delete_one/delete_many, SQL DELETE FROM/DROP TABLE/TRUNCATE) or the route path is under /admin.

Authorization that clears a handler: a decorator (login_required, roles_required, permission_required, jwt_required, user_passes_test, admin_required …), a FastAPI Depends/Security dependency that resolves a user, token, admin or permission, a check in the body (current_user, request.user, g.user, info.context.user, is_authenticated, has_perm, abort(403), PermissionDenied), a before_request hook that rejects unauthenticated requests anywhere in the project, a Django urls.py wrapping the view in login_required, LoginRequiredMiddleware, DRF DEFAULT_PERMISSION_CLASSES, or a Graphene auth middleware.

Not reported: routes on a FastAPI router or app built with dependencies=[Depends(...auth...)], or included with one by include_router; read-only handlers outside /admin, functions that are not handlers (model methods, CLI commands), test files, comments and strings. Authorization enforced by a reverse proxy, or by a decorator whose name does not say what it checks, is invisible to the rule.

Why This Matters

A delete endpoint without an authorization check lets anyone who can reach the URL destroy data: no stolen credential is needed, only the route. The same holds for admin pages and GraphQL mutations, which are often discovered through introspection.

What Gets Flagged

@app.route("/admin/users/<int:uid>/delete", methods=["POST"])
def delete_user(uid):                                  # FLAGGED
    User.query.filter_by(id=uid).delete()

@router.delete("/items/{item_id}")
async def delete_item(item_id: int, db: Session = Depends(get_db)):   # FLAGGED
    db.query(Item).filter(Item.id == item_id).delete()

class DeleteNote(graphene.Mutation):
    def mutate(self, info, id):                        # FLAGGED
        Note.query.filter_by(id=id).delete()

Not flagged: the same handler with @login_required, admin: User = Depends(get_current_admin), if post.author_id != current_user.id: abort(403), or a blueprint before_request that aborts with 403.

Remediation

  1. Put an authorization decorator or dependency on every handler that changes or deletes data.
  2. Check that the caller owns the record, or holds the required permission, before deleting it.
  3. Prefer a deny-by-default guard (a before_request hook, LoginRequiredMiddleware, DRF default permission classes) so a new route cannot be forgotten.

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-862
// nosec vnx-862

Or record an ignore rule: vulnetix ignore add --rule vnx-862 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-862.rego, cli/internal/sast/docs/vnx-862.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.