JanssenProject / JanssenProject/jans

fix(jans-auth-server): Agama flow pages are served with no framing protection

Open
#14,841 0 comments 0 reactions 1 assignee Claimed by @imran-ishaq View on GitHub
comp-jans-auth-server kind-bug
Dominant language
Java
Stars
647
Forks
173
Avg merge
1d 18h
Merged PRs (30d)
110

Description

## Description

Agama flow pages (login, MFA, passkey and any deployed Agama project) are served without
`X-Frame-Options` or `Content-Security-Policy: frame-ancestors`. Any site on the internet can
embed them in an iframe, which makes the affected flows vulnerable to clickjacking / UI redressing
— an attacker overlays their own UI on a real login frame and induces the user to complete an
authentication ceremony they didn't intend.

## Why the existing protection doesn't cover Agama

`jans-auth-server/server/src/main/java/io/jans/as/server/filter/HeadersFilter.java:46`

```java
if (requestURI.contains(".htm") || hasAny) {
httpResponse.addHeader(X_FRAME_OPTIONS_HEADER, appConfiguration.getXframeOptionsHeaderValue().getValue());
}
```

The header is emitted only when the request URI contains `.htm`, or matches
`applyXFrameOptionsHeaderIfUriContainsAny` — which defaults to an **empty list**
(`AppConfiguration.java:2152`).

Agama pages are served by `ExecutionServlet` under `/fl/` with a `.fls` suffix
(`ExecutionServlet.java:20-27`). `.fls` does not contain `.htm`, so no `X-Frame-Options` is
emitted. There is also no `Content-Security-Policy` set anywhere in the auth server (grep for
`Content-Security-Policy` across `jans-auth-server`: zero hits).

Net effect: JSF-based pages get `SAMEORIGIN`, Agama-based pages get nothing.

## Reproduction

1. Deploy any Agama flow (e.g. the agama-passkey project).
2. `curl -I https:///jans-auth/fl/.fls` — observe no `X-Frame-Options` and no
`Content-Security-Policy` in the response.
3. Serve a page on an unrelated origin containing
`` — it renders.

## Mitigation available today

Admins can set a CSP through Agama's existing response-header map
(`BaseServlet.java:142` applies `engineConf.getDefaultResponseHeaders()` to every flow page):

```json
"agamaConfiguration": {
"defaultResponseHeaders": {
"Cache-Control": "max-age=0, no-store",
"Content-Security-Policy": "frame-ancestors 'self'"
}
}
```

This is opt-in and undocumented, so no existing deployment has it.

## Proposed fix

1. Ship `frame-ancestors 'self'` as the **default** for Agama flow pages, so deployments are safe
without configuration.
2. Alternatively/additionally, include `.fls` in the default
`applyXFrameOptionsHeaderIfUriContainsAny` so the existing `X-Frame-Options` path covers Agama.
3. Document `defaultResponseHeaders` as the supported way to relax this for deployments that
intentionally embed flows.

Note that a per-client `frame-ancestors` allowlist (derived from the client's registered origins)
is a separate enhancement — it's what an embedded/iframe authentication flow would need, and is
tracked under GluuFederation/agama-passkey#13. This issue is only about closing the default-open
state.

## Impact

- Affects: all Agama flows, all versions shipping the Agama engine
- Severity: medium — requires user interaction and a convincing overlay, but the target is an
authentication ceremony
- Not exploitable for credential theft directly; the risk is inducing unintended authentication
or consent

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.