Skip to content

VNX-425: Direct Request ('Forced Browsing')

Reports an administrative route (a path segment admin, administration, backoffice, superuser, sysadmin, staff or manage/management) registered with no authentication in front of it: Express/Koa/Fastify routes with no middleware, and Go handlers or gin/echo admin route groups with no middleware or in-handler check. The same defect on a Python route is VNX-306.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-425
Severity Medium
SARIF level warning
Kind sast
Languages JavaScript / TypeScript, Go
CWE CWE-425
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:M/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C
Tags direct-request forced-browsing missing-authorization cwe-425
Source internal/sast/rules/vnx-425.rego

Overview

VNX-425 maps to CWE-425: Direct Request (‘Forced Browsing’). An administrative page that is merely unlinked is not protected: anyone who guesses or reads its URL can request it directly. This rule reports admin routes that are registered without any authentication or authorisation check.

Reported:

  • JavaScript and TypeScript (Express-style): app/router .get/.post/.put/.patch/.delete/.all whose only argument after the path is the handler (the path may be on the line after an open call), unless an inline handler checks req.user/req.session or compares a role (role === ..., roles.includes(...), hasRole), only redirects, or the file mounts authentication middleware with .use() globally or on a prefix of the path.
  • Go: HandleFunc/Handle and gin/echo/chi GET/POST/… with a bare handler name, in a file with no .Use( middleware, when the handler is defined in the same file and does not check authentication in its first 15 lines.

What Gets Flagged

app.get('/admin/users', adminController.listUsers)   // FLAGGED
manageRouter.delete(                                     // FLAGGED: path on the next line
  '/administrator/cache', (req, res) => { purgeCache(); res.end(); });
http.HandleFunc("/admin/dashboard", adminDashboard)   // FLAGGED

What Is Not Flagged

  • Routes whose path is not administrative.
  • Routes with middleware (app.get('/admin', isLoggedIn, isAdmin, h)) or a check on the user inside the handler. Writing a role ({ role: 'admin' }) is not a check.
  • Files that mount auth middleware globally (router.use(passport.authenticate('jwt'))) or on the route’s prefix.
  • Go handlers wrapped in a call (requireAdmin(h)) or defined in another file.
  • NestJS controllers and Spring endpoints, whose guards usually live elsewhere.
  • Route calls inside string literals, test files and comments.

Reported by other rules, so one route is one finding:

  • An administrative Flask, FastAPI or Quart route with nothing in front of it is reported by VNX-306.
  • A Spring or JAX-RS handler that @PermitAll opens to everyone is reported by VNX-935.

Remediation

Put every administrative route behind a check that the caller is an authenticated administrator:

app.get('/admin/users', isLoggedIn, isAdmin, adminController.listUsers)

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

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

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