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.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
pfsense-api-fleet-jwt — pfSense Plus MIM API toolkit b4acd7ca - High - Remote - IDOR - one controller JWT is a fleet token | Kitploit
Tools/GitHubGitHub/abraxas/pfsense-api-fleet-jwt
Authentication & AuthorizationVulnerability AnalysisExploitationWeb Application ExploitationInformation GatheringPenetration TestingAPI SecurityLabs & Practice
GitHubabraxas/pfsense-api-fleet-jwt

pfsense-api-fleet-jwt

pfSense Plus MIM API toolkit b4acd7ca - High - Remote - IDOR - one controller JWT is a fleet token

1 day 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
View Repository

Abraxas Labs - pfsense-api-fleet-jwt

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  pfsense-api-fleet-jwt

pfsense-api-fleet-jwt

Class: IDOR Reach: Remote

pfSense Plus MIM API (Netgate) pin b4acd7ca - github.com/Netgate/pfsense-api

One POST /login Bearer is reused for every enrolled device_id. Official examples copy that token onto /api/device/pfsense/{device_id}/api for every id from GET /mim/devices. LoginResponse fields are only token, user, version, and alerts. LDAP MIM roles are global. They are not bound to a device. A controller login that can list devices talks to firewall B with a token issued for a user who was meant for firewall A.

This is one customer tenancy, not a SaaS cross-tenant leftover. Unauthenticated calls stay 401. Plus RBAC was not executed. Series hub: pfsense-api-nexus-mim (this is leftover 6). Stolen JWT from leftover 9 (verify_ssl=False samples) is this fleet token.

IDno CVE yet
ClassIDOR
ReachRemote (authenticated controller JWT)
CWECWE-639
CVSSHigh: 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N
ProductNetgate/pfsense-api (pfSense Plus Nexus Multi-instance Management controller OpenAPI + generated client)
Affectedpin b4acd7ca21dbca739a530403a1f62a7440f7726f (2026-05-25). No tags. Server is Plus-only (paid). Not the CE REST package.
Authcontroller JWT from POST /login. Guessing device_id is not required if GET /mim/devices is allowed.
LicenseGNU Affero GPL v3.0
Lab127.0.0.1:19161 only. Python mock of the published client contract. No Plus image.

I pinned github.com/Netgate/pfsense-api main b4acd7ca21dbca739a530403a1f62a7440f7726f (2026-05-25, Add Snort-3 API definitions). This is not jaredhendrickson/pfsense-api / pfrest.org.

What an attacker can do

A controller login that can list devices talks to every enrolled instance with the same JWT. CSRF is not in play (Bearer API). PHP / shell / export-key on every box is intended admin power once the proxy accepts the fleet token. The leftover is the missing per-device bind, not Diagnostics: Command.

PrivilegeMethod / pathLab-proven or inferred
List every enrolled device_id (name, address, state)GET /mim/devices with the login BearerRecon (lab-proven). Mock returned both site-a and site-b. Unauth is 401.
Read system status of firewall A and firewall B with one tokenGET /api/device/pfsense/{device_id}/api/systemRecon (lab-proven). device-a=200, device-b=200. Witness only on B.
POST the diagnostics PHP wrapper on both idsPOST /api/device/pfsense/{device_id}/api/diag/cmd/phpIntegrity (lab on mock only). Both 200. Plus RBAC was not executed, so a live role gate is unproven.
Run PHP / shell / file edit on every enrolled box if the login includes console or systemPOST /diag/cmd/php, POST /diag/cmd/shell, GET/POST /diag/editfile, download/uploadIntegrity (inferred from OAS + examples). Intended admin power once the proxy accepts the fleet token. Typical pfSense PHP-FPM is root.
Export CA / leaf private keys and PKCS12 on every listed instanceGET /system/certificates/{refid}/export-key, GET /system/certauth/{refid}/export-key, GET /system/certificates/{refid}/export-p12Recon (inferred). Same JWT, same schema as leftover 4. Plus RBAC not executed.
Dump ACME account and issued keys on every listed instanceGET /services/acme and related account/cert GETsRecon (inferred). Same JWT, leftover 5 schema.
Change aliases, firewall, interfaces, VPN, services on every listed instancesame per-device prefix, remaining 700+ opsIntegrity (inferred). Same JWT, same schema as the local instance.
Reboot / halt / restore config on every listed instancePOST /diag/control, POST /diag/backup/restoreAvailability + integrity (inferred). Same proxy. Not exercised.
Cross-customer SaaS IDORn/aClosed. One customer tenancy. Netgate runs the controller in that tenancy.
Unauthenticated Internet-to-:8443GET /mim/devices with no BearerClosed in this lab. 401. Wrong Bearer is also 401.
Offline devicessamples skip state != onlineClosed by samples. Not an auth boundary.
Blind numeric walk of device_idGET /api/device/pfsense/1/api/systemClosed as a guess requirement. Ids are long strings (ED25519-shaped). Listing removes the guess.

Requires: a controller login that is allowed onto the device proxy. Network path to the MIM controller (:8443 in product, loopback :19161 in this lab). Not unauth. Not CSRF.

Adjacent surface that stays closed

SurfaceWhy
Unauth listing / php / shellMock 401 without Bearer and with a wrong Bearer. Spec silence on securitySchemes is not a server 200.
SaaS cross-tenantOne customer tenancy. Tenancy clusters were still planned on the marketing page.
mim_user / no Nexus groupDocumented as closed if the login gate holds.
Functional mim_* role namesThey exist (view, logs, usermgmt, services, firewall, interfaces, devices, system, superuser). They are global, not per device_id. Live Plus checks were not executed (plus-rbac=not-executed).
Enrollment SSH JSON interpolationLeftover 1. Different pack.
Enrollment AutoAddPolicyLeftover 2. Different pack.
Device unix socket without JWTLeftover 3. Local, different pack.
CE REST packagejaredhendrickson/pfsense-api is a different server.
CE WebGUI QinQ / OpenVPN wizard / CARP / limiter / IPsec bannerAlready mailed as CE leftovers. Field names in this OAS are the same sinks, not new CVEs.
Intended admins / mim_superuser fleet consoleProduct model for the controller owner. The leftover is the missing object ACL for everyone else.

How I found it

I pinned b4acd7ca and read the official examples against the OpenAPI. Every sample that talks to managed firewalls does this:

devApi = AuthenticatedClient(
    base_url=CONTROLLER_URL+"/api/device/pfsense/{}/api".format(device.device_id),
    verify_ssl=False,
    headers={"Content-Type": "application/json"},
    cookies=cookies,
    token=token,
)
Download Tool