PST-086: OpenID Connect discovery, token and userinfo requests bypass the guarded client and its destination policy #815

Closed
opened 2026-10-10 10:56:53 +00:00 by tiagoagueda · 1 comment
Owner

Found in the security audit of 2026-10-10 (SECURITY-AUDIT-2026-10-10.md), run against main at c30851b from 8 to 10 October 2026, as PST-086. Severity: Informational.

The text below is the audit's entry, unchanged apart from links to the other issues it names. The finding was produced by automated review and checked by a second automated pass; re-check it before acting on it.


  • Severity: Informational
  • Category: outbound-bypass / operator-controlled
  • Location: src/postulo/config/settings/base.py (302-334)
  • Found by: SSRF and outbound traffic

Who can do it, and what they need. Nobody today: POSTULO_OIDC_SERVER_URL comes only from the environment, which the threat model places with the operator. Recorded because rule 5 of the threat model says every outbound request goes through postulo.plugins.http.client(), and these do not.

How it works.

  1. allauth's openid_connect provider fetches <server_url>/.well-known/openid-configuration, the token endpoint and the userinfo endpoint through allauth.socialaccount.adapter.get_requests_session() (the requests library), with allauth's own timeouts, redirect following and no address policy.
  2. The provider's discovery document names the token/userinfo/jwks URLs, so a misbehaving or compromised provider can direct the server to arbitrary addresses (including private ones) on every sign-in.
  3. No code in Postulo pins, re-checks or bounds these requests.

Impact. None with a trustworthy provider; the operator chose it. If the discovery document is ever read from a less trusted source, or if a future change lets an administrator set the server URL from the Server settings page (as the mail host moved there in #149), the request path would have no guard.

Verification (verdict: confirmed; severity after verification: Informational). Attacker model: none under the threat model (operator environment variable and operator-chosen provider). A hardening option is a SocialAccountAdapter.get_requests_session override that applies the destination policy and honours POSTULO_CONNECTIONS_ALLOW_PRIVATE, or a documented exception in the threat model for the identity provider.

Suggested remediation. Document the exception in docs/THREAT-MODEL.md and the Hardening page (it already lists where the server dials); if the server URL ever becomes page-configurable, validate it with check_destination and consider overriding allauth's adapter get_requests_session/the OIDC client to route through the guarded client.

Found in the security audit of 2026-10-10 (`SECURITY-AUDIT-2026-10-10.md`), run against `main` at `c30851b` from 8 to 10 October 2026, as **PST-086**. Severity: **Informational**. The text below is the audit's entry, unchanged apart from links to the other issues it names. The finding was produced by automated review and checked by a second automated pass; re-check it before acting on it. --- - **Severity:** Informational - **Category:** outbound-bypass / operator-controlled - **Location:** `src/postulo/config/settings/base.py` (302-334) - **Found by:** SSRF and outbound traffic **Who can do it, and what they need.** Nobody today: POSTULO_OIDC_SERVER_URL comes only from the environment, which the threat model places with the operator. Recorded because rule 5 of the threat model says every outbound request goes through postulo.plugins.http.client(), and these do not. **How it works.** 1. allauth's openid_connect provider fetches `<server_url>/.well-known/openid-configuration`, the token endpoint and the userinfo endpoint through `allauth.socialaccount.adapter.get_requests_session()` (the `requests` library), with allauth's own timeouts, redirect following and no address policy. 2. The provider's discovery document names the token/userinfo/jwks URLs, so a misbehaving or compromised provider can direct the server to arbitrary addresses (including private ones) on every sign-in. 3. No code in Postulo pins, re-checks or bounds these requests. **Impact.** None with a trustworthy provider; the operator chose it. If the discovery document is ever read from a less trusted source, or if a future change lets an administrator set the server URL from the Server settings page (as the mail host moved there in #149), the request path would have no guard. **Verification** (verdict: confirmed; severity after verification: Informational). Attacker model: none under the threat model (operator environment variable and operator-chosen provider). A hardening option is a SocialAccountAdapter.get_requests_session override that applies the destination policy and honours POSTULO_CONNECTIONS_ALLOW_PRIVATE, or a documented exception in the threat model for the identity provider. **Suggested remediation.** Document the exception in docs/THREAT-MODEL.md and the Hardening page (it already lists where the server dials); if the server URL ever becomes page-configurable, validate it with `check_destination` and consider overriding allauth's adapter `get_requests_session`/the OIDC client to route through the guarded client.
tiagoagueda added this to the 1.0.0 milestone 2026-10-10 10:58:16 +00:00
Author
Owner

Fixed in 91f995a94 on main.

Fixed in 91f995a94 on main.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#815
No description provided.