CVE-2026-94455 (GCVE-0-2026-94455)
Vulnerability from cvelistv5 – Published: 2026-09-22 16:17 – Updated: 2026-09-22 18:14
VLAI
EPSS
VEX
Title
Unauthenticated /enterprise/create-user mints lifetime top-tier organizations and discloses their API key
Summary
An HTTP endpoint intended for provisioning enterprise and reseller organisations is reachable without any session. The authentication middleware is bound only to an explicit list of controllers, and the enterprise controller is not on that list, so no authentication runs for these routes.
The endpoint's only check is that the request body carries a token bearing a valid signature from the instance secret. It does not check what that token was issued for. Login tokens are signed with the same secret and carry no purpose, audience or expiry claim, so an ordinary user's own session token satisfies the check.
Presented with such a token, the endpoint creates a new organisation holding the highest subscription tier, flagged as lifetime and with a channel allowance far above any sold plan, creates an organisation-owner account alongside it, and returns the new organisation's API key in the response body. That key is immediately valid against the public API.
Severity
7.1 (High)
SSVC
Exploitation: none
Automatable: no
Technical Impact: partial
CISA Coordinator · CISA-ADP (v2.0.3)
Decision recorded 2026-09-22 18:13 UTC
Assigner
References
4 references
| URL | Tags |
|---|---|
| https://github.com/gitroomhq/postiz-app | product |
| https://github.com/gitroomhq/postiz-app/releases/… | release-notes |
| https://github.com/gitroomhq/postiz-app/commit/92… | patch |
| https://gadvisory.org/advisories/PSA-2026-P8W1J0 | vendor-advisory |
Impacted products
1 product
| Vendor | Product | Version | CPE status | |
|---|---|---|---|---|
| GitroomHQ | postiz-app |
Affected:
0 , < 2.4.0
(semver)
|
guessed |
Date Public
2026-09-22 14:36
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-94455",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-09-22T18:13:58.426768Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-09-22T18:14:13.947Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"packageName": "postiz-app",
"product": "postiz-app",
"repo": "https://github.com/gitroomhq/postiz-app",
"vendor": "GitroomHQ",
"versions": [
{
"lessThan": "2.4.0",
"status": "affected",
"version": "0",
"versionType": "semver"
}
]
}
],
"configurations": [
{
"lang": "en",
"value": "You are affected if your deployment has billing enabled, that is if STRIPE_PUBLISHABLE_KEY or STRIPE_SECRET_KEY is set. This covers the hosted Postiz service and any self-hoster running Postiz commercially."
},
{
"lang": "en",
"value": "You are not meaningfully affected if you run a default self-hosted instance with no Stripe configuration. In that mode Postiz does not enforce subscription entitlements at all, so an organisation created through this endpoint holds no privileges your users do not already have."
},
{
"lang": "en",
"value": "Exposure is wider if self-registration is open, that is if DISABLE_REGISTRATION is unset or not set to \u0027true\u0027, because anyone on the internet can then obtain the account needed. With registration closed, the issue is reachable only by people who already hold an account on your instance."
}
],
"credits": [
{
"lang": "en",
"type": "reporter",
"value": "Santosh Kumar Puppala"
},
{
"lang": "en",
"type": "coordinator",
"value": "Enno Gelhaus"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Nevo David"
}
],
"datePublic": "2026-09-22T14:36:13.452Z",
"descriptions": [
{
"lang": "en",
"value": "An HTTP endpoint intended for provisioning enterprise and reseller organisations is reachable without any session. The authentication middleware is bound only to an explicit list of controllers, and the enterprise controller is not on that list, so no authentication runs for these routes.\n\nThe endpoint\u0027s only check is that the request body carries a token bearing a valid signature from the instance secret. It does not check what that token was issued for. Login tokens are signed with the same secret and carry no purpose, audience or expiry claim, so an ordinary user\u0027s own session token satisfies the check.\n\nPresented with such a token, the endpoint creates a new organisation holding the highest subscription tier, flagged as lifetime and with a channel allowance far above any sold plan, creates an organisation-owner account alongside it, and returns the new organisation\u0027s API key in the response body. That key is immediately valid against the public API."
}
],
"exploits": [
{
"lang": "en",
"value": "1. Register an ordinary account on the target instance and capture that account\u0027s own login JWT."
},
{
"lang": "en",
"value": "2. POST /api/enterprise/create-user with body {\"params\": \"\u003cthat login JWT, verbatim\u003e\"}."
},
{
"lang": "en",
"value": "3. The response is 200 with {\"id\": \"\u003cnew organisation id\u003e\", \"apiKey\": \"\u003ckey\u003e\"}."
},
{
"lang": "en",
"value": "4. Confirm the new organisation carries subscriptionTier=ULTIMATE, isLifetime=true and totalChannels=1000000, and that it is distinct from the caller\u0027s own registration organisation."
},
{
"lang": "en",
"value": "5. Send the returned apiKey as the Authorization header against a public API endpoint and confirm 200, versus 401 for an invalid key."
},
{
"lang": "en",
"value": "Controls: an absent token, a malformed token, and a token with a valid-looking payload but a wrong signature all fail with no organisation created, confirming signature verification is the only gate."
}
],
"impacts": [
{
"descriptions": [
{
"lang": "en",
"value": "Billing-integrity bypass. Any registered user can provision an organisation at the highest subscription tier, flagged as lifetime, with a channel allowance of 1,000,000 against the 100 provisioned for a genuine paying customer at that same tier."
}
]
},
{
"descriptions": [
{
"lang": "en",
"value": "Recurring unmetered resource consumption. The per-organisation AI allowance (500 image generations, 60 video generations, 600 clipping minutes) refills on a rolling monthly window, and the lifetime flag exempts the organisation from subscription reconciliation, so each provisioned organisation is an indefinite draw on the operator\u0027s model and GPU budget rather than a one-off."
}
]
},
{
"descriptions": [
{
"lang": "en",
"value": "Disclosure of a usable organisation API key in the response body, valid immediately against the public API without an interactive session."
}
]
},
{
"descriptions": [
{
"lang": "en",
"value": "No confidentiality impact on existing tenants. The provisioned organisation is empty; no other organisation\u0027s channels, posts, media or account data become reachable."
}
]
}
],
"metrics": [
{
"cvssV3_1": {
"baseScore": 7.1,
"baseSeverity": "HIGH",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L",
"version": "3.1"
},
"format": "CVSS"
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-306",
"description": "CWE-306",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-1390",
"description": "CWE-1390",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-345",
"description": "CWE-345",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-770",
"description": "CWE-770",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-09-22T16:17:00.413Z",
"orgId": "4cdc9741-f887-419a-a2fd-acbbd2729276",
"shortName": "postiz"
},
"references": [
{
"name": "Postiz",
"tags": [
"product"
],
"url": "https://github.com/gitroomhq/postiz-app"
},
{
"name": "v2.24.0",
"tags": [
"release-notes"
],
"url": "https://github.com/gitroomhq/postiz-app/releases/tag/v2.24.0"
},
{
"name": "9259cf2",
"tags": [
"patch"
],
"url": "https://github.com/gitroomhq/postiz-app/commit/9259cf2429e8cc0c88414e88d5e6c783d7ffba63"
},
{
"name": "GAdvisory",
"tags": [
"vendor-advisory"
],
"url": "https://gadvisory.org/advisories/PSA-2026-P8W1J0"
}
],
"timeline": [
{
"lang": "en",
"time": "2026-09-21T13:34:00.000Z",
"value": "Postiz has received and acknowledged the report."
},
{
"lang": "en",
"time": "2026-09-21T20:15:00.000Z",
"value": "Postiz has verified the report."
},
{
"lang": "en",
"time": "2026-09-22T04:32:00.000Z",
"value": "Postiz has developed and verified the patch."
},
{
"lang": "en",
"time": "2026-09-22T14:17:00.000Z",
"value": "Postiz has released the patch notes and published the advisory."
}
],
"title": "Unauthenticated /enterprise/create-user mints lifetime top-tier organizations and discloses their API key",
"workarounds": [
{
"lang": "en",
"value": "Block POST /enterprise/create-user, and preferably all of /enterprise/*, at your reverse proxy, ingress or WAF. If you do not use Postiz\u0027s enterprise or reseller provisioning integration, nothing legitimate calls these routes, so blocking them has no user-visible effect."
},
{
"lang": "en",
"value": "Set DISABLE_REGISTRATION=true. The caller needs an ordinary account on your instance to obtain a usable token, so closing self-registration limits exposure to people who already have one. This reduces reach, it does not close the issue."
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4cdc9741-f887-419a-a2fd-acbbd2729276",
"assignerShortName": "postiz",
"cveId": "CVE-2026-94455",
"datePublished": "2026-09-22T16:17:00.413Z",
"dateReserved": "2026-09-21T17:10:50.156Z",
"dateUpdated": "2026-09-22T18:14:13.947Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2",
"vulnerability-lookup:meta": {
"epss": {
"cve": "CVE-2026-94455",
"date": "2026-09-23",
"epss": "0.00263",
"percentile": "0.18437"
},
"nvd": {
"cve": {
"affected": [
{
"affectedData": [
{
"defaultStatus": "unaffected",
"packageName": "postiz-app",
"product": "postiz-app",
"repo": "https://github.com/gitroomhq/postiz-app",
"vendor": "GitroomHQ",
"versions": [
{
"lessThan": "2.4.0",
"status": "affected",
"version": "0",
"versionType": "semver"
}
]
}
],
"source": "4cdc9741-f887-419a-a2fd-acbbd2729276"
}
],
"cveTags": [],
"descriptions": [
{
"lang": "en",
"value": "An HTTP endpoint intended for provisioning enterprise and reseller organisations is reachable without any session. The authentication middleware is bound only to an explicit list of controllers, and the enterprise controller is not on that list, so no authentication runs for these routes.\n\nThe endpoint\u0027s only check is that the request body carries a token bearing a valid signature from the instance secret. It does not check what that token was issued for. Login tokens are signed with the same secret and carry no purpose, audience or expiry claim, so an ordinary user\u0027s own session token satisfies the check.\n\nPresented with such a token, the endpoint creates a new organisation holding the highest subscription tier, flagged as lifetime and with a channel allowance far above any sold plan, creates an organisation-owner account alongside it, and returns the new organisation\u0027s API key in the response body. That key is immediately valid against the public API."
}
],
"id": "CVE-2026-94455",
"lastModified": "2026-09-22T19:37:36.747",
"metrics": {
"cvssMetricV31": [
{
"cvssData": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "LOW",
"baseScore": 7.1,
"baseSeverity": "HIGH",
"confidentialityImpact": "NONE",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L",
"version": "3.1"
},
"exploitabilityScore": 2.8,
"impactScore": 4.2,
"source": "4cdc9741-f887-419a-a2fd-acbbd2729276",
"type": "Secondary"
}
],
"ssvcV203": [
{
"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"ssvcData": {
"id": "CVE-2026-94455",
"options": [
{
"exploitation": "none"
},
{
"automatable": "no"
},
{
"technicalImpact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-09-22T18:13:58.426768Z",
"version": "2.0.3"
}
}
]
},
"published": "2026-09-22T17:17:31.497",
"references": [
{
"source": "4cdc9741-f887-419a-a2fd-acbbd2729276",
"url": "https://gadvisory.org/advisories/PSA-2026-P8W1J0"
},
{
"source": "4cdc9741-f887-419a-a2fd-acbbd2729276",
"url": "https://github.com/gitroomhq/postiz-app"
},
{
"source": "4cdc9741-f887-419a-a2fd-acbbd2729276",
"url": "https://github.com/gitroomhq/postiz-app/commit/9259cf2429e8cc0c88414e88d5e6c783d7ffba63"
},
{
"source": "4cdc9741-f887-419a-a2fd-acbbd2729276",
"url": "https://github.com/gitroomhq/postiz-app/releases/tag/v2.24.0"
}
],
"sourceIdentifier": "4cdc9741-f887-419a-a2fd-acbbd2729276",
"vulnStatus": "Awaiting Analysis",
"weaknesses": [
{
"description": [
{
"lang": "en",
"value": "CWE-306"
},
{
"lang": "en",
"value": "CWE-345"
},
{
"lang": "en",
"value": "CWE-770"
},
{
"lang": "en",
"value": "CWE-1390"
}
],
"source": "4cdc9741-f887-419a-a2fd-acbbd2729276",
"type": "Secondary"
}
]
}
},
"vulnrichment": {
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-94455",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-09-22T18:13:58.426768Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-09-22T18:14:10.761Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"packageName": "postiz-app",
"product": "postiz-app",
"repo": "https://github.com/gitroomhq/postiz-app",
"vendor": "GitroomHQ",
"versions": [
{
"lessThan": "2.4.0",
"status": "affected",
"version": "0",
"versionType": "semver"
}
]
}
],
"configurations": [
{
"lang": "en",
"value": "You are affected if your deployment has billing enabled, that is if STRIPE_PUBLISHABLE_KEY or STRIPE_SECRET_KEY is set. This covers the hosted Postiz service and any self-hoster running Postiz commercially."
},
{
"lang": "en",
"value": "You are not meaningfully affected if you run a default self-hosted instance with no Stripe configuration. In that mode Postiz does not enforce subscription entitlements at all, so an organisation created through this endpoint holds no privileges your users do not already have."
},
{
"lang": "en",
"value": "Exposure is wider if self-registration is open, that is if DISABLE_REGISTRATION is unset or not set to \u0027true\u0027, because anyone on the internet can then obtain the account needed. With registration closed, the issue is reachable only by people who already hold an account on your instance."
}
],
"credits": [
{
"lang": "en",
"type": "reporter",
"value": "Santosh Kumar Puppala"
},
{
"lang": "en",
"type": "coordinator",
"value": "Enno Gelhaus"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Nevo David"
}
],
"datePublic": "2026-09-22T14:36:13.452Z",
"descriptions": [
{
"lang": "en",
"value": "An HTTP endpoint intended for provisioning enterprise and reseller organisations is reachable without any session. The authentication middleware is bound only to an explicit list of controllers, and the enterprise controller is not on that list, so no authentication runs for these routes.\n\nThe endpoint\u0027s only check is that the request body carries a token bearing a valid signature from the instance secret. It does not check what that token was issued for. Login tokens are signed with the same secret and carry no purpose, audience or expiry claim, so an ordinary user\u0027s own session token satisfies the check.\n\nPresented with such a token, the endpoint creates a new organisation holding the highest subscription tier, flagged as lifetime and with a channel allowance far above any sold plan, creates an organisation-owner account alongside it, and returns the new organisation\u0027s API key in the response body. That key is immediately valid against the public API."
}
],
"exploits": [
{
"lang": "en",
"value": "1. Register an ordinary account on the target instance and capture that account\u0027s own login JWT."
},
{
"lang": "en",
"value": "2. POST /api/enterprise/create-user with body {\"params\": \"\u003cthat login JWT, verbatim\u003e\"}."
},
{
"lang": "en",
"value": "3. The response is 200 with {\"id\": \"\u003cnew organisation id\u003e\", \"apiKey\": \"\u003ckey\u003e\"}."
},
{
"lang": "en",
"value": "4. Confirm the new organisation carries subscriptionTier=ULTIMATE, isLifetime=true and totalChannels=1000000, and that it is distinct from the caller\u0027s own registration organisation."
},
{
"lang": "en",
"value": "5. Send the returned apiKey as the Authorization header against a public API endpoint and confirm 200, versus 401 for an invalid key."
},
{
"lang": "en",
"value": "Controls: an absent token, a malformed token, and a token with a valid-looking payload but a wrong signature all fail with no organisation created, confirming signature verification is the only gate."
}
],
"impacts": [
{
"descriptions": [
{
"lang": "en",
"value": "Billing-integrity bypass. Any registered user can provision an organisation at the highest subscription tier, flagged as lifetime, with a channel allowance of 1,000,000 against the 100 provisioned for a genuine paying customer at that same tier."
}
]
},
{
"descriptions": [
{
"lang": "en",
"value": "Recurring unmetered resource consumption. The per-organisation AI allowance (500 image generations, 60 video generations, 600 clipping minutes) refills on a rolling monthly window, and the lifetime flag exempts the organisation from subscription reconciliation, so each provisioned organisation is an indefinite draw on the operator\u0027s model and GPU budget rather than a one-off."
}
]
},
{
"descriptions": [
{
"lang": "en",
"value": "Disclosure of a usable organisation API key in the response body, valid immediately against the public API without an interactive session."
}
]
},
{
"descriptions": [
{
"lang": "en",
"value": "No confidentiality impact on existing tenants. The provisioned organisation is empty; no other organisation\u0027s channels, posts, media or account data become reachable."
}
]
}
],
"metrics": [
{
"cvssV3_1": {
"baseScore": 7.1,
"baseSeverity": "HIGH",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L",
"version": "3.1"
},
"format": "CVSS"
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-306",
"description": "CWE-306",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-1390",
"description": "CWE-1390",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-345",
"description": "CWE-345",
"lang": "en",
"type": "CWE"
},
{
"cweId": "CWE-770",
"description": "CWE-770",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-09-22T16:17:00.413Z",
"orgId": "4cdc9741-f887-419a-a2fd-acbbd2729276",
"shortName": "postiz"
},
"references": [
{
"name": "Postiz",
"tags": [
"product"
],
"url": "https://github.com/gitroomhq/postiz-app"
},
{
"name": "v2.24.0",
"tags": [
"release-notes"
],
"url": "https://github.com/gitroomhq/postiz-app/releases/tag/v2.24.0"
},
{
"name": "9259cf2",
"tags": [
"patch"
],
"url": "https://github.com/gitroomhq/postiz-app/commit/9259cf2429e8cc0c88414e88d5e6c783d7ffba63"
},
{
"name": "GAdvisory",
"tags": [
"vendor-advisory"
],
"url": "https://gadvisory.org/advisories/PSA-2026-P8W1J0"
}
],
"timeline": [
{
"lang": "en",
"time": "2026-09-21T13:34:00.000Z",
"value": "Postiz has received and acknowledged the report."
},
{
"lang": "en",
"time": "2026-09-21T20:15:00.000Z",
"value": "Postiz has verified the report."
},
{
"lang": "en",
"time": "2026-09-22T04:32:00.000Z",
"value": "Postiz has developed and verified the patch."
},
{
"lang": "en",
"time": "2026-09-22T14:17:00.000Z",
"value": "Postiz has released the patch notes and published the advisory."
}
],
"title": "Unauthenticated /enterprise/create-user mints lifetime top-tier organizations and discloses their API key",
"workarounds": [
{
"lang": "en",
"value": "Block POST /enterprise/create-user, and preferably all of /enterprise/*, at your reverse proxy, ingress or WAF. If you do not use Postiz\u0027s enterprise or reseller provisioning integration, nothing legitimate calls these routes, so blocking them has no user-visible effect."
},
{
"lang": "en",
"value": "Set DISABLE_REGISTRATION=true. The caller needs an ordinary account on your instance to obtain a usable token, so closing self-registration limits exposure to people who already have one. This reduces reach, it does not close the issue."
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4cdc9741-f887-419a-a2fd-acbbd2729276",
"assignerShortName": "postiz",
"cveId": "CVE-2026-94455",
"datePublished": "2026-09-22T16:17:00.413Z",
"dateReserved": "2026-09-21T17:10:50.156Z",
"dateUpdated": "2026-09-22T18:14:13.947Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
}
}
Loading…
Loading…
Experimental. This forecast is provided for visualization only and may change without notice. Do not use it for operational decisions.
Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Loading…
Loading…
The MITRE ATT&CK techniques below are AI-generated suggestions, inferred from the description of the
vulnerability by the CIRCL/vulnerability-attack-technique-classification-roberta-base
model, served locally by ML-Gateway.
They have not been verified by an analyst and are provided for guidance only.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Loading…
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.
Loading…