Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-46645-Analysis-Lab — Docker-based lab for reproducing CVE-2026-46645, an authorization bypass in SQLAdmin's ajax_lookup endpoint. Includes vulnerable and patched targets, PoC script, and manual curl reproduction steps for security research and education. | Kitploit
Tools/GitHubGitHub/rootdirective-sec/cve-2026-46645-analysis-lab
Vulnerability AnalysisWeb Application ExploitationAPI Security TestingPenetration TestingLearning & EducationLabs & Practice
GitHubrootdirective-sec/cve-2026-46645-analysis-lab

CVE-2026-46645-Analysis-Lab

Docker-based lab for reproducing CVE-2026-46645, an authorization bypass in SQLAdmin's ajax_lookup endpoint. Includes vulnerable and patched targets, PoC script, and manual curl reproduction steps for security research and education.

View Repository
183 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-46645 - SQLAdmin ajax_lookup Authorization Bypass

Executive Summary

This repository contains a local Docker lab for reproducing CVE-2026-46645, an authorization bypass vulnerability affecting SQLAdmin's ajax_lookup endpoint.

SQLAdmin is an admin interface for SQLAlchemy models in Starlette and FastAPI applications. The vulnerable behavior occurs when an application restricts a ModelView with is_accessible(request), but SQLAdmin's ajax_lookup route does not enforce the same access-control decision before returning lookup results.

This lab compares two SQLAdmin versions:

ServiceSQLAdmin versionPurposeURL
vuln0.25.0Vulnerable targethttp://127.0.0.1:8001
patched0.25.1Patched comparison targethttp://127.0.0.1:8002

The demonstrated vulnerability chain is:

Authenticated low-privileged user
→ restricted SQLAdmin ModelView
→ ModelView.is_accessible(request) returns False
→ user directly requests the ajax_lookup endpoint
→ SQLAdmin 0.25.0 returns relationship lookup data
→ SQLAdmin 0.25.1 blocks the same request with HTTP 403

The lab intentionally uses a simple Report / SecretProject data model to make the authorization bypass easy to understand. These model names are not the root cause of the vulnerability. They are only used to create a controlled reproduction condition.

This lab is designed for controlled local research, source-level understanding, and portfolio demonstration only.

Verified Facts

ClaimEvidenceHow to verify in this lab
SQLAdmin's ajax_lookup endpoint is the affected component.Public advisory describes the affected endpoint format as GET /{identity}/ajax/lookup?name=<field>&term=<query>.Run the PoC and observe requests to /admin/report/ajax/lookup?name=project&term=Secret.
SQLAdmin 0.25.0 is used as the vulnerable comparison target.The lab installs sqladmin==0.25.0 in the vuln container.Run docker compose exec -T vuln python -m pip show sqladmin.
SQLAdmin 0.25.1 is used as the patched comparison target.Public advisory and release notes identify 0.25.1 as the fixed version.Run docker compose exec -T patched python -m pip show sqladmin.
The root cause is in SQLAdmin's upstream Admin.ajax_lookup() route.The patch adds missing authentication and is_accessible(request) enforcement to ajax_lookup().Inspect Admin.ajax_lookup() inside both containers with the commands in this README.
The lab creates a restricted ModelView.ReportAdmin.is_accessible(request) intentionally returns False.Inspect app/main.py.
The PoC uses an authenticated session.The PoC first logs in to /admin/login, keeps the session cookie, then requests ajax_lookup.Run python3 poc/poc.py --base-url http://127.0.0.1:8001.
The vulnerable signal is data exposure.SQLAdmin 0.25.0 returns HTTP 200 and JSON lookup results from a restricted view.The vulnerable target should return Secret Project Alpha and Secret Project Beta.
The patched signal is access denial.SQLAdmin 0.25.1 returns HTTP 403 for the same authenticated request.The patched target should return 403 Forbidden.

Assumptions and Unknowns

This lab uses sqladmin==0.25.0 as the vulnerable baseline and sqladmin==0.25.1 as the patched baseline.

The lab focuses on the authorization bypass condition where:

A user is authenticated,
the target ModelView is not accessible,
but ajax_lookup is requested directly.

The lab does not attempt to reproduce every possible SQLAdmin deployment pattern. It intentionally creates a small Starlette application with one restricted admin view so the behavior difference between vulnerable and patched versions is easy to verify.

The Report and SecretProject models are lab-only objects. They are not part of SQLAdmin itself.

The PoC does not attempt privilege escalation, data modification, session theft, external callbacks, persistence, or attacks against non-lab systems.

Root Cause Summary

The root cause is in SQLAdmin's upstream Admin.ajax_lookup() route, not in this lab's application code.

SQLAdmin allows developers to restrict access to admin views by overriding:

ModelView.is_accessible(request)

Other admin routes are expected to enforce this access-control decision before allowing the request to continue. For example, routes such as list, create, details, delete, edit, and export check whether the current request is allowed to access the target ModelView.

The vulnerable ajax_lookup route did not enforce the same access-control decision.

The ajax_lookup endpoint is used by SQLAdmin's form_ajax_refs feature to dynamically load relationship values. Its endpoint format is:

/admin/<identity>/ajax/lookup?name=<field>&term=<query>

In the vulnerable version, ajax_lookup() resolves the target ModelView, reads the lookup field name and search term from the query string, then calls the AJAX loader and returns JSON results. The missing security step is that it does not first verify whether the current request is allowed to access that ModelView.

The security impact is that an authenticated user may be blocked from accessing a restricted admin view through normal UI routes, but can still directly request the AJAX lookup endpoint for that view and receive relationship lookup data.

SQLAdmin 0.25.1 fixes this by enforcing access control inside ajax_lookup(). The patched route checks model_view.is_accessible(request) and returns HTTP 403 when the target view is not accessible.

This lab defines ReportAdmin.is_accessible(request) to return False only to reproduce the vulnerable condition. The lab code is not the root cause. It is a controlled test harness that proves whether SQLAdmin's upstream ajax_lookup() route respects the access-control decision.

Expected behavior difference:

sqladmin 0.25.0 -> HTTP 200 with JSON lookup results
sqladmin 0.25.1 -> HTTP 403 Forbidden

Source Patch Summary

The meaningful upstream patch is the addition of authentication and authorization enforcement to Admin.ajax_lookup().

The patched behavior is equivalent to:

@login_required
async def ajax_lookup(self, request):
    identity = request.path_params["identity"]
    model_view = self._find_model_view(identity)

    if not model_view.is_accessible(request):
        raise HTTPException(status_code=403)

    name = request.query_params.get("name")
    term = request.query_params.get("term")
    ...

The key authorization check is:

Download Tool