Skip to content

VNX-694: Two route handlers registered under the same identifier

Reports a Flask/FastAPI route decorator or a Django path()/re_path()/url() entry that repeats a route already registered in the same file, so only one of the two handlers is ever dispatched.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-694
Severity Low
SARIF level note
Kind sast
Languages Python
CWE CWE-694
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 duplicate-identifier routing cwe-694
Source internal/sast/rules/vnx-694.rego

Overview

VNX-694 maps to CWE-694: Use of Multiple Resources with Duplicate Identifier. A URL route is the identifier a web framework uses to pick a handler. When two handlers are registered under the same route, the dispatcher reaches only one of them; the other is dead code. The dangerous version is a second handler that adds an authorisation check and is never called.

The rule reports, at the second and later registration in a Python file:

  • a Flask/FastAPI/Starlette route decorator (@app.route, @bp.route, @router.get/post/put/patch/delete/head/options, @app.api_route, @app.websocket) on the same receiver with the same arguments (path, methods and options, with quote style and spacing normalised) as an earlier one;
  • a Django path(), re_path() or url() entry with the same route string as an earlier entry.

Not reported: the same path with different methods, the same path on different routers or blueprints, repeated include() prefixes, registrations in different files, test files, docstrings, comments and string literals. Decorators broken over several lines are not compared.

What Gets Flagged

@app.route("/admin/users")
def list_users():
    return render_users()

@app.route("/admin/users")          # FLAGGED: never dispatched
def list_users_checked():
    if not session.get("is_admin"):
        abort(403)
    return render_users()

urlpatterns = [
    path("orders/<int:pk>/", views.order_detail),
    path("orders/<int:pk>/", views.order_detail_secure),   # FLAGGED
]

What Is Not Flagged

@app.route("/login", methods=["GET"])
def login_form(): ...

@app.route("/login", methods=["POST"])
def login_submit(): ...

urlpatterns = [
    path("api/", include("billing.urls")),
    path("api/", include("accounts.urls")),
]

Remediation

  1. Delete the handler that is not meant to serve the route, or give each a distinct path or method.
  2. Keep authorisation in a decorator or middleware so a duplicate cannot silently drop it.

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

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

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