Context
Found while dogfooding the new secreview skill (#12951) against PR #12950.
Both findings were reported on that PR
(#12950 (comment)) but it
merged as d48146e11 without them addressed, so they are now live on
Dev_new_gui. Filing so they are not dropped.
Both are in _package_router_files in
autobot-backend/api/codebase_analytics/api_endpoint_scanner.py, and both are
the same defect class #12945 set out to fix: a submodule mapped to a prefix it
is not actually served under, which produces phantom endpoints that later
resurface as false "orphaned" findings.
1. rglob descends into nested subpackages, but only the top-level package prefix is applied
for py_file in sorted(package.rglob("*.py"))
if not py_file.name.startswith("__")
rglob walks the entire tree while the __-prefix filter removes the nested
__init__.py that carries that subpackage's own prefix. So a nested router
subpackage's modules are mapped to the parent package's served_prefix, and
the only file that could correct them is excluded:
rglob: ['__init__.py', 'a.py', 'sub/__init__.py', 'sub/b.py']
filtered (not startswith __): ['a.py', 'sub/b.py']
sub/b.py is emitted with the parent's prefix. If a registry-mounted package
ever nests a router subpackage, this invents endpoints under the wrong path.
Fix: use glob("*.py") for the flat case, or recurse through
_package_router_files per nested __init__.py so every level contributes its
own prefix.
2. Docstring overclaims the include_router check
The docstring states:
Submodules are included only when the package actually mounts them via include_router
The code only checks that the package mounts something:
if not _INCLUDE_ROUTER_RE.search(init_content):
return {}
and then includes every submodule declaring an APIRouter(prefix=...),
mounted or not. A module that declares a router the package never mounts still
contributes routes — the same phantom-endpoint problem, narrower in scope.
Fix: match the mounted router names, or soften the docstring to what the
code actually guarantees. Code and comment disagreeing is its own hazard here,
since the docstring is the stated rationale for the design.
Not a finding
joinpath(*module_path.split(".")) would let a .. segment escape
backend_dir, but the router registry is code-controlled rather than user
input. Recorded only so it is not re-raised as a security issue later.
Acceptance criteria
Context
Found while dogfooding the new
secreviewskill (#12951) against PR #12950.Both findings were reported on that PR
(#12950 (comment)) but it
merged as
d48146e11without them addressed, so they are now live onDev_new_gui. Filing so they are not dropped.Both are in
_package_router_filesinautobot-backend/api/codebase_analytics/api_endpoint_scanner.py, and both arethe same defect class #12945 set out to fix: a submodule mapped to a prefix it
is not actually served under, which produces phantom endpoints that later
resurface as false "orphaned" findings.
1.
rglobdescends into nested subpackages, but only the top-level package prefix is appliedrglobwalks the entire tree while the__-prefix filter removes the nested__init__.pythat carries that subpackage's own prefix. So a nested routersubpackage's modules are mapped to the parent package's
served_prefix, andthe only file that could correct them is excluded:
sub/b.pyis emitted with the parent's prefix. If a registry-mounted packageever nests a router subpackage, this invents endpoints under the wrong path.
Fix: use
glob("*.py")for the flat case, or recurse through_package_router_filesper nested__init__.pyso every level contributes itsown prefix.
2. Docstring overclaims the
include_routercheckThe docstring states:
The code only checks that the package mounts something:
and then includes every submodule declaring an
APIRouter(prefix=...),mounted or not. A module that declares a router the package never mounts still
contributes routes — the same phantom-endpoint problem, narrower in scope.
Fix: match the mounted router names, or soften the docstring to what the
code actually guarantees. Code and comment disagreeing is its own hazard here,
since the docstring is the stated rationale for the design.
Not a finding
joinpath(*module_path.split("."))would let a..segment escapebackend_dir, but the router registry is code-controlled rather than userinput. Recorded only so it is not re-raised as a security issue later.
Acceptance criteria
include_routerbehaviour agree — either the check is tightened or the claim is narrowed