CVE-2026-94455 Overview
CVE-2026-94455 is a missing authentication vulnerability [CWE-306] in the Postiz application's enterprise provisioning HTTP endpoint. The authentication middleware is bound to an explicit controller list, and the enterprise controller is excluded. The endpoint only validates that the request body contains a token signed by the instance secret, without checking token purpose, audience, or expiry. Any authenticated user's login token satisfies the check. An attacker submitting their own session token can provision a new organization at the highest subscription tier, flagged as lifetime with an inflated channel allowance, and receive a valid API key for the public API.
Critical Impact
A low-privileged user can mint lifetime enterprise-tier organizations and obtain fully functional API keys, undermining subscription integrity and billing controls.
Affected Products
- Postiz App (gitroomhq/postiz-app) prior to v2.24.0
- Enterprise controller route /create-user and related provisioning endpoints
- Self-hosted and managed Postiz deployments using the vulnerable controller
Discovery Timeline
- 2026-09-22 - CVE-2026-94455 published to the National Vulnerability Database (NVD)
- 2026-09-22 - Fix committed to gitroomhq/postiz-app in commit 9259cf2
- 2026-09-22 - Postiz release v2.24.0 published with the patch
- 2026-09-22 - Last updated in NVD database
Technical Details for CVE-2026-94455
Vulnerability Analysis
The enterprise controller exposes provisioning routes that bypass the global authentication middleware. The middleware is registered against an explicit list of controllers, and the enterprise controller is not included. As a result, requests to these routes reach the handler without any session validation.
The handler's sole gatekeeper is a JSON Web Token (JWT) signature check via AuthService.verifyJWT. Because the same instance secret signs all token types, including user login tokens, password reset tokens, and team invite tokens, the signature check succeeds for any valid JWT the server has ever issued. The handler does not inspect the purpose, aud, or exp claims.
Once a valid token is presented, the endpoint creates a new organization at the highest subscription tier, marks it as lifetime, sets a channel allowance exceeding any sold plan, provisions an owner account, and returns a working API key in the response.
Root Cause
The root cause is twofold: incomplete authentication middleware coverage and token confusion. The middleware registration model requires explicit opt-in per controller, so omissions silently produce unauthenticated routes. Compounding this, JWTs are signed with a shared secret and lack claims that would distinguish issuance purpose, allowing token type substitution [CWE-306].
Attack Vector
An attacker with a low-privileged Postiz account extracts their own session JWT from the browser or client. They then send an HTTP POST request to the enterprise provisioning endpoint with the token in the request body's params field. The server accepts the token, creates a lifetime enterprise organization, and returns the API key.
// Patch from apps/backend/src/api/routes/enterprise.controller.ts
private _postsService: PostsService
) {}
+ private verifyEnterpriseToken<T extends object>(params: string): T {
+ const payload = AuthService.verifyJWT(params) as any;
+ if (
+ !payload ||
+ typeof payload !== 'object' ||
+ 'providerName' in payload || // login token (full User row)
+ 'orgId' in payload || // team invite token
+ 'expires' in payload // password reset token
+ ) {
+ throw new Error('Invalid enterprise token');
+ }
+
+ return payload as T;
+ }
+
@Post('/create-user')
async createUser(@Body('params') params: string) {
try {
- const { id, name, saasName, email } = AuthService.verifyJWT(params) as {
+ const { id, name, saasName, email } = this.verifyEnterpriseToken<{
id: string;
name: string;
email: string;
saasName: string;
- };
+ }>(params);
Source: GitHub Postiz App Commit 9259cf2. The patch adds a verifyEnterpriseToken helper that rejects tokens carrying claims specific to login, invite, or reset flows.
Detect Identity Attacks the Moment Authentication Fails
Singularity™ Identity surfaces credential misuse, lateral movement, and privilege escalation in real time, so you can contain the breach before it spreads.
Stop Identity AttacksDetection Methods for CVE-2026-94455
Indicators of Compromise
- Unexpected POST requests to enterprise controller routes such as /create-user from user-owned IP addresses
- New organization records with lifetime flags, top-tier subscription, or channel allowances beyond any sold plan
- API keys issued to organizations that were never onboarded through the billing or sales workflow
- Organization owner accounts created outside of normal signup or invite flows
Detection Strategies
- Audit database records for organizations with lifetime = true combined with recent creation timestamps and no billing transactions
- Review reverse proxy or application logs for requests to enterprise provisioning paths bearing session-shaped JWTs
- Correlate new API key issuance events with the accounts that triggered them and flag mismatches
Monitoring Recommendations
- Alert on any HTTP request to the enterprise controller until v2.24.0 or later is deployed
- Track subscription tier changes and channel allowance modifications in real time
- Monitor for API keys used against the public API that lack corresponding provisioning records in the billing system
How to Mitigate CVE-2026-94455
Immediate Actions Required
- Upgrade Postiz to v2.24.0 or later, which includes commit 9259cf2 restricting enterprise token acceptance
- Enumerate all organizations created since deployment and revoke any that were not legitimately provisioned
- Rotate API keys issued to unauthorized organizations and invalidate outstanding session JWTs if abuse is suspected
Patch Information
The fix is in GitHub Postiz App Release v2.24.0 via commit 9259cf2. The patch introduces verifyEnterpriseToken, which rejects any JWT containing providerName, orgId, or expires claims that indicate login, invite, or reset origin. See the Gadvisory Security Advisory PSA-2026-P8W1J0 for the full disclosure.
Workarounds
- Block external access to enterprise controller routes at the reverse proxy or web application firewall until the upgrade is applied
- Restrict the enterprise endpoint to trusted management IP ranges via network access control lists
- Rotate the instance JWT secret after patching to invalidate any tokens attackers may have captured
# Example nginx rule to block enterprise provisioning routes
location ~ ^/api/enterprise/(create-user|.*) {
allow 10.0.0.0/8; # internal management network
deny all;
return 403;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

