Skip to content

Commit 2c21c50

Browse files
committed
Add OSSA-2026-037 security advisory for Keystone
Document the inconsistent scope enforcement for delegated tokens in Keystone (Launchpad bugs #2153453 and #2158538, CVE ids pending). Tokens derived from EC2 credentials and OAuth1 access tokens could create trusts, application credentials and OAuth1 access tokens that outlive the original credential and carry roles the delegation never had, and application credential and EC2 tokens could be rescoped to other projects through the token authentication method. Every deployment is affected. No fixed Keystone release exists upstream yet; OSISM ships the proposed upstream patches for 2025.1, 2025.2 and 2026.1 via container-images-kolla PR #776, which also carries the ec2credential token ban from master. Community-curated backports for 2024.1 and 2024.2 are in preparation. Overriding keystone_tag is sufficient. Assisted-by: Claude:claude-fable-5 Signed-off-by: Christian Berendt <berendt@osism.tech>
1 parent e449768 commit 2c21c50

2 files changed

Lines changed: 298 additions & 0 deletions

File tree

docs/appendix/security/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ handling of security-related information.
3434
| [OSSA-2026-022](ossa-2026-022.md) | Scheduler hint injection bypasses Placement claims | OpenStack Nova |
3535
| [OSSA-2026-032](ossa-2026-032.md) | Cross-project subnet mutation via subnetpool onboard | OpenStack Neutron |
3636
| [OSSA-2026-034](ossa-2026-034.md) | Cross-tenant DNS zone overlap and mDNS DoS | OpenStack Designate |
37+
| [OSSA-2026-037](ossa-2026-037.md) | Inconsistent scope enforcement for delegated tokens | OpenStack Keystone |
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
---
2+
sidebar_label: OSSA-2026-037
3+
---
4+
5+
# OSSA-2026-037: Inconsistent scope enforcement for delegated tokens in Keystone
6+
7+
| Property | Value |
8+
|:-----------------|:---------------------------------------------------|
9+
| Date | 2026-08-25 |
10+
| CVE | CVE pending (two ids requested from MITRE) |
11+
| Severity | High |
12+
| Affected Project | Keystone |
13+
| Reporter | Grzegorz Grasza (Red Hat), Tim Shephard (roiai.ca) |
14+
15+
## Summary
16+
17+
Two related vulnerabilities were discovered in OpenStack Keystone concerning tokens obtained through
18+
delegated credentials — application credentials, EC2 credentials, and OAuth1 access tokens.
19+
20+
Grzegorz Grasza of Red Hat reported that Keystone did not consistently block delegated tokens from
21+
creating new long-lived credentials or authorizing new delegations (Bug #2153453). A token derived
22+
from an EC2 credential or an OAuth1 access token could create, list, read, and delete trusts, and an
23+
EC2-derived token could create application credentials and authorize OAuth1 request tokens. Each of
24+
these operations mints a new, independent grant that persists after the original credential is
25+
revoked. Because trust creation validates the requested roles against the trustor's full role
26+
assignments rather than against the roles of the delegated token, a narrowly scoped OAuth1 or EC2
27+
token could additionally delegate roles it was never authorized for.
28+
29+
Tim Shephard of roiai.ca separately reported that delegated tokens could be submitted to the token
30+
authentication method of `POST /v3/auth/tokens` to escape their project scope (Bug #2158538). An
31+
application credential token presented without an explicit scope was rescoped to the credential
32+
owner's default project instead of the project the credential was issued for, and an EC2-derived
33+
token could be rescoped to any project the underlying user holds a role in.
34+
35+
**Every OSISM deployment running an unpatched Keystone version is affected.** Application
36+
credentials, EC2 credentials, trusts, and the token authentication method are available in every
37+
Keystone deployment, `[token] allow_rescope_scoped_token` is enabled by default, and there is no
38+
configuration that makes a deployment immune. Exploitation requires possession of a delegated
39+
credential, for example a leaked application credential or EC2 key pair.
40+
41+
Upstream has not published a CVSS score for this issue, and the two CVE ids requested from MITRE are
42+
still pending. The severity rating above is OSISM's assessment: an attacker holding a delegated
43+
credential can turn it into persistent access that survives revocation of that credential, obtain
44+
roles beyond the delegation, and reach other projects of the credential owner.
45+
46+
## Affected Versions
47+
48+
The upstream advisory states the affected ranges as `>=13.0.0 <27.0.3`, `>=28.0.0 <28.0.3` and
49+
`>=29.0.0 <29.0.3`, so the fixes are expected in Keystone 27.0.3 (Epoxy), 28.0.3 (Flamingo) and
50+
29.0.3 (Gazpacho).
51+
52+
**At the time of this advisory there is no fixed Keystone release available upstream for any
53+
series.** The upstream fixes are still under review on OpenDev and have not merged yet.
54+
55+
| OpenStack Release | Upstream Status | Fix in OSISM Images |
56+
|:-----------------------|:---------------------------------------------------|:---------------------------------------------------------------------------------------------------------------|
57+
| Caracal (2024.1) | Unmaintained, no upstream fix | Community-curated backport in preparation |
58+
| Dalmatian (2024.2) | End of life since 2026-04-29, no fix | Community-curated backport in preparation |
59+
| Epoxy (2025.1) | Vulnerable — fix proposed (27.0.3), not yet merged | Proposed upstream patch ([PR #776](https://github.com/osism/container-images-kolla/pull/776)) |
60+
| Flamingo (2025.2) | Vulnerable — fix proposed (28.0.3), not yet merged | Proposed upstream patch ([PR #776](https://github.com/osism/container-images-kolla/pull/776)) |
61+
| Gazpacho (2026.1) | Vulnerable — fix proposed (29.0.3), not yet merged | Patch included ([PR #776](https://github.com/osism/container-images-kolla/pull/776)), images not published yet |
62+
| Hibiscus (2026.2, dev) | Fix proposed on master, not yet merged | Not shipped by OSISM yet |
63+
64+
Caracal (2024.1) is unmaintained and Dalmatian (2024.2) reached end of life on 2026-04-29 upstream;
65+
neither will receive an official fixed release. For these two releases OSISM is preparing the fix as
66+
community-curated backports, shipped as downstream patches in the Keystone container images. This
67+
advisory will be updated as soon as the patched images are available.
68+
69+
For Epoxy (2025.1) and Flamingo (2025.2) OSISM already ships container images that carry the
70+
proposed upstream patches ahead of their official upstream release. The same patches are included
71+
for Gazpacho (2026.1), whose images will be published with the upcoming OSISM 11 release.
72+
73+
## Impact on OSISM
74+
75+
Keystone is a core service of every OSISM deployment, and all delegation mechanisms involved are
76+
available by default:
77+
78+
- **Application credentials** can be created by every user for their own projects. They are the
79+
recommended way to give automation access to the cloud and are widely used.
80+
- **EC2 credentials** are used to access the S3 API of Ceph RGW or Swift with Keystone identities.
81+
Every user can create them.
82+
- **OAuth1** is part of Keystone's default `[auth] methods`
83+
(`external,password,token,oauth1,mapped,application_credential`), which OSISM does not change.
84+
Kolla only replaces the list when Keystone federation is enabled
85+
(`password,token,openid,application_credential`), which removes OAuth1 but leaves the other
86+
paths open.
87+
- **Trusts** are created on behalf of users by services such as Heat and Magnum, and every user can
88+
create them.
89+
- The token authentication method and `[token] allow_rescope_scoped_token = True` are Keystone
90+
defaults that OSISM does not change.
91+
92+
Exploitation requires an attacker to hold a delegated credential of a victim — a leaked application
93+
credential, an EC2 access/secret key pair, or an OAuth1 access token — or a user to deliberately
94+
abuse their own narrow delegation. In both cases the attacker gains more than the delegation was
95+
meant to grant: persistent credentials that survive revocation of the original one, trusts carrying
96+
roles the delegation never had, and tokens for other projects of the credential owner.
97+
98+
### How to Check if You Are Affected
99+
100+
#### Check the Running Keystone Version
101+
102+
```bash
103+
docker exec keystone pip show keystone | grep ^Version
104+
```
105+
106+
Because no fixed Keystone release exists upstream yet, your deployment is **affected** unless you
107+
have deployed an OSISM container image that includes the patches (see Remediation).
108+
109+
#### Check Whether the Patched Image Is Deployed
110+
111+
The fix introduces the module `keystone.api._shared.delegation`, which only exists in patched
112+
images:
113+
114+
```bash
115+
docker exec keystone /var/lib/kolla/venv/bin/python3 -c "import keystone.api._shared.delegation" \
116+
2>/dev/null && echo patched || echo vulnerable
117+
```
118+
119+
`vulnerable` means the running image does not contain the fix.
120+
121+
## Vulnerability Details
122+
123+
Keystone distinguishes *primary* authentication methods, which authenticate a user directly
124+
(`password`, `token`, `totp`, `mapped`, `saml2`, `openid`, `external`, `kerberos`, `x509`), from
125+
*delegated* credentials, which are deliberately narrow grants derived from a user
126+
(`application_credential`, `ec2credential`, `oauth1`, and trust-scoped tokens). API endpoints that
127+
mint a new, independent grant must reject delegated tokens, otherwise a narrow grant can bootstrap a
128+
broader or longer-lived one. Before the fix these guards were implemented separately per endpoint,
129+
and each of them recognized only some of the delegated methods.
130+
131+
### Bug #2153453 — Delegated tokens can create persistent delegations
132+
133+
- `_check_application_credential()` in `keystone/api/trusts.py` only blocked tokens whose methods
134+
included `application_credential`. Tokens derived from an OAuth1 access token or an EC2 credential
135+
could create, list, read, and delete trusts. Since trust creation validates the requested roles
136+
against the trustor's full role assignments rather than against the roles of the requesting
137+
token, such a token could also delegate roles the delegation was never scoped to.
138+
- `_block_delegated_token_app_creds()` in `keystone/api/users.py` only checked for a `trust_id` or
139+
an OAuth1 `access_token_id` on the token, so an EC2-derived token — which carries neither — could
140+
create and manage application credentials and access rules.
141+
- `PUT /v3/OS-OAUTH1/authorize/{request_token_id}` in `keystone/api/os_oauth1.py` only rejected
142+
trust-scoped, OAuth1-scoped, and application credential tokens, so an EC2-derived token could
143+
authorize OAuth1 request tokens and thereby mint new OAuth1 access tokens.
144+
145+
All three grants outlive the credential used to create them: revoking a leaked EC2 key pair or
146+
OAuth1 access token does not remove the trusts, application credentials, or access tokens it
147+
bootstrapped.
148+
149+
The fix introduces `keystone/api/_shared/delegation.py` with a deny-by-default allowlist of primary
150+
authentication methods. `is_delegated_method()` treats every token whose methods are not entirely
151+
primary — including an empty method list, which occurs for `ec2credential` tokens after a fernet
152+
round-trip — as delegated, and all three endpoints now use this shared check. Application credential
153+
tokens keep their documented behavior (the opt-in `[security_compliance]
154+
allow_insecure_application_credential_trust_escalation` for trust management and the
155+
unrestricted/restricted distinction for creating further application credentials); OAuth1 and EC2
156+
credentials are blocked unconditionally.
157+
158+
### Bug #2158538 — Delegated tokens escape their project scope via token reauthentication
159+
160+
`token_authenticate()` in `keystone/auth/plugins/token.py` implements the token authentication
161+
method, i.e. exchanging an existing token for a new one. Trust-scoped and OAuth1-scoped tokens were
162+
rejected unconditionally, but application credential tokens were only rejected when an explicit
163+
scope was requested: with the scope omitted, the request fell through to Keystone's default-project
164+
scoping and returned a token for the credential owner's default project — a different project than
165+
the one the application credential was bound to. EC2-derived tokens matched none of the checks and,
166+
with the default `[token] allow_rescope_scoped_token = True`, could be rescoped to any project the
167+
underlying user has a role in.
168+
169+
The fix rejects every delegated token from the token authentication method using the same shared
170+
classification and returns HTTP 403.
171+
172+
### Prerequisite Changes
173+
174+
The upstream fix consists of two changes that are interdependent and must be applied together; OSISM
175+
ships both in the patched images:
176+
177+
1. **trusts, oauth1, app-creds: reject delegated tokens across all endpoints**
178+
([Bug #2153453](https://bugs.launchpad.net/keystone/+bug/2153453)) — introduces the shared
179+
delegation classification and the new `[auth] additional_primary_auth_methods` option and applies
180+
the check to trusts, application credentials, and OAuth1 authorization.
181+
2. **auth: reject delegated tokens from token-method reauthentication**
182+
([Bug #2158538](https://bugs.launchpad.net/keystone/+bug/2158538)) — applies the classification
183+
to the token authentication method and depends on the first change.
184+
185+
:::warning
186+
187+
Behavior changes after the fix:
188+
189+
- Any authentication method that is not built into Keystone is treated as a delegated credential and
190+
rejected from managing trusts, application credentials, and OAuth1 access tokens, and from token
191+
reauthentication. Deployments running a custom or third-party authentication plugin must list its
192+
method name in `[auth] additional_primary_auth_methods`, otherwise these workflows fail for users
193+
authenticated through it.
194+
- Exchanging an application credential token or an EC2-derived token for a new token via the token
195+
authentication method is rejected with HTTP 403. Clients must authenticate with the application
196+
credential directly instead.
197+
198+
:::
199+
200+
### Additional Hardening in the OSISM Images
201+
202+
Besides the two upstream patches, the patched OSISM images for 2025.1, 2025.2, and 2026.1 contain
203+
the upstream change *Ban ec2credential tokens from Keystone API*, which is merged on master but not
204+
backported to the stable branches upstream. It rejects tokens derived from EC2 credentials for every
205+
Keystone API call except token validation and re-authentication, closing the whole class of EC2
206+
token issues at the API boundary. The behavior is controlled by the new option `[auth]
207+
ban_ec2credential_tokens` (default `True`). Deployments that use EC2-derived tokens directly against
208+
the Keystone API must set it to `False`.
209+
210+
## Remediation
211+
212+
### For OSISM Releases
213+
214+
Because no fixed Keystone release is available upstream, OSISM provides the fix as downstream
215+
patches for the Keystone container images via the following change:
216+
217+
- [container-images-kolla commit 01ae42c](https://github.com/osism/container-images-kolla/commit/01ae42cdce2dc6c86927116fcce10c90a930122b)
218+
([PR #776](https://github.com/osism/container-images-kolla/pull/776))
219+
220+
This change adds the patches for 2025.1 (Epoxy), 2025.2 (Flamingo), and 2026.1 (Gazpacho). The
221+
community-curated backports for 2024.1 (Caracal) and 2024.2 (Dalmatian) are in preparation and will
222+
be announced in an update of this advisory.
223+
224+
A fix will be included in upcoming OSISM releases that ship the patched Keystone container images.
225+
Consult the [OSISM Release Notes](../../release-notes/) for version information and availability.
226+
227+
The affected code runs in the Keystone API service (`keystone` container). Using rolling tags,
228+
override the Keystone container images in `environments/kolla/images.yml`. With a stable OSISM
229+
release the Kolla images are pulled from the `kolla/release/<openstack_version>` namespace with
230+
pinned version tags (`docker_namespace` in `environments/kolla/configuration.yml`), whereas the
231+
rolling images live in the `kolla` namespace. The image parameters therefore have to be overridden
232+
together with the tag; the tag override alone would point at an image that does not exist:
233+
234+
```yaml title="environments/kolla/images.yml"
235+
keystone_tag: "2025.1" # or "2025.2", depending on your OpenStack release
236+
keystone_image: "registry.osism.tech/kolla/keystone"
237+
keystone_fernet_image: "registry.osism.tech/kolla/keystone-fernet"
238+
keystone_ssh_image: "registry.osism.tech/kolla/keystone-ssh"
239+
```
240+
241+
Replace `registry.osism.tech` if you pull the images from a mirror. From 2025.2 on the Keystone
242+
role additionally runs an `httpd` container (`keystone_httpd_image`, `keystone_httpd_tag`) that
243+
contains no Keystone code; its tag follows `keystone_tag` by default, so pin `keystone_httpd_tag`
244+
to the currently deployed tag when overriding `keystone_tag`.
245+
246+
### Mitigation
247+
248+
Because all deployments are affected and the vulnerabilities require only a delegated credential,
249+
applying the patched container image is the only complete remediation. Until the fix is deployed —
250+
in particular on 2024.1 and 2024.2 — consider the following measures:
251+
252+
1. Disabling the rescoping of scoped tokens closes the token reauthentication path (Bug #2158538).
253+
Add the following to the configuration repository and redeploy Keystone:
254+
255+
```ini title="environments/kolla/files/overlays/keystone.conf"
256+
[token]
257+
allow_rescope_scoped_token = False
258+
```
259+
260+
This also prevents legitimate clients from exchanging a scoped token for another scoped token;
261+
authenticating with an unscoped token or with credentials directly is not affected. It does not
262+
mitigate Bug #2153453.
263+
2. Auditing existing delegations. Trusts, application credentials, EC2 credentials, and OAuth1
264+
access tokens that were created through a delegated token before the fix remain valid after it is
265+
applied and have to be revoked manually:
266+
267+
```bash
268+
openstack --os-cloud admin trust list
269+
openstack --os-cloud admin credential list --type ec2
270+
openstack --os-cloud admin consumer list
271+
openstack --os-cloud admin application credential list --user <user>
272+
```
273+
274+
Application credentials can only be listed per user. Trusts whose trustee is not a service user,
275+
and credentials or consumers nobody can account for, are candidates for removal.
276+
3. Rotating EC2 credentials and OAuth1 access tokens that may have leaked, since revoking them does
277+
not remove grants they may already have bootstrapped.
278+
4. Monitoring the Keystone API logs for `POST /v3/OS-TRUST/trusts`,
279+
`POST /v3/users/{user_id}/application_credentials`, and `PUT /v3/OS-OAUTH1/authorize` requests
280+
from unexpected sources.
281+
282+
## References
283+
284+
- [OSSA-2026-037 Advisory](https://security.openstack.org/ossa/OSSA-2026-037.html)
285+
- [OSISM Fix (container-images-kolla commit 01ae42c)](https://github.com/osism/container-images-kolla/commit/01ae42cdce2dc6c86927116fcce10c90a930122b)
286+
- [OSISM Fix (container-images-kolla PR #776)](https://github.com/osism/container-images-kolla/pull/776)
287+
- [OpenDev Review (Proposed Fix 1/2 - Hibiscus)](https://review.opendev.org/1002301)
288+
- [OpenDev Review (Proposed Fix 2/2 - Hibiscus)](https://review.opendev.org/1002302)
289+
- [OpenDev Review (Proposed Fix 1/2 - Gazpacho)](https://review.opendev.org/1002303)
290+
- [OpenDev Review (Proposed Fix 2/2 - Gazpacho)](https://review.opendev.org/1002304)
291+
- [OpenDev Review (Proposed Fix 1/2 - Flamingo)](https://review.opendev.org/1002305)
292+
- [OpenDev Review (Proposed Fix 2/2 - Flamingo)](https://review.opendev.org/1002306)
293+
- [OpenDev Review (Proposed Fix 1/2 - Epoxy)](https://review.opendev.org/1002307)
294+
- [OpenDev Review (Proposed Fix 2/2 - Epoxy)](https://review.opendev.org/1002308)
295+
- [OpenDev Review (Ban ec2credential tokens from Keystone API)](https://review.opendev.org/997369)
296+
- [Launchpad Bug #2153453](https://bugs.launchpad.net/keystone/+bug/2153453)
297+
- [Launchpad Bug #2158538](https://bugs.launchpad.net/keystone/+bug/2158538)

0 commit comments

Comments
 (0)