Skip to content

Security Conformance

iderex edited this page Jul 20, 2026 · 4 revisions

Security conformance self-assessment (ASVS 5.0 · RFC 9700)

A single published mapping of the plugin's authentication surface to OWASP ASVS 5.0 (May 2025) and the OAuth 2.0 Security Best Current Practice (RFC 9700, Jan 2025). This is a maintainer self-assessment, not a certification or an audit result; it exists so the RC gate's "zero open security findings" is checkable against a named baseline with honestly-recorded residuals. It complements the Security Model (the control narratives) and the Review Gate (how they are verified).

Scope. The plugin is an OIDC/SAML relying party: it delegates authentication to the operator's IdP, exchanges the authorization code for an id_token / consumes a signed SAML assertion, and mints a Jellyfin session. It is not an authorization server and does not issue or downstream OAuth access tokens — several server-side ASVS/RFC requirements are therefore N/A by role.

Assessment date: 2026-07. Re-assess when a control changes; each row cites the implementing source so a drift is caught by the Review Gate.

OWASP ASVS 5.0 (applicable chapters)

Area (ASVS chapter) Requirement, as it applies here Status Where
V1 Encoding / output Server-rendered pages auto-escape; the intermediate auth page and error pages carry a per-response nonce CSP, X-Frame-Options: DENY, nosniff; IdP-supplied text is sanitized at the log call Met Api/Shared/FlowResponses.cs, Api/Shared/AuthPageCsp.cs, Api/Shared/BrowserErrorPage.cs; Security Model § Response hardening
V6 Authentication Identity bound to the stable sub / SAML NameID, never a mutable username; issuer-bound account links (TOFU); fail-closed on any missing signature/binding Met Api/Linking/CanonicalLinkService.cs (issuer binding #186), Api/Identity/VerifiedIdentity.cs; Security Model § Identity binding
V6 Authentication — id_token id_token signature validated against discovery JWKS; iss, aud/azp, exp/nbf (clock-skew) all checked; asymmetric-only algorithm allow-list; alg:none and RS→HS confusion rejected Met Api/Oidc/OidcIdTokenValidator.cs; Security Model § OpenID id_token validation
V6 Authentication — SAML XML-DSig verified before use; exactly one same-document reference covering the consumed assertion; enveloped-signature + position-bound XPath (XSW-resistant); SHA-256+ algorithm/canonicalization/transform allow-list; audience (strict AND), recipient, time-window, bearer-confirmation; replay cache; DTD/XXE prohibited Met Api/Saml/SamlResponse.cs, SamlAssertionValidator.cs, SamlSignatureAlgorithms.cs, SamlReplayCache.cs; Security Model § SAML response validation
V7 Session management CSRF/replay-resistant login: state + nonce, one-time authorize-state redemption, one-time login-outcome token, capped+swept state store; browser-binding cookie on both flows (forced-login defense) Met Api/Oidc/OidcStateStore.cs, Api/Saml/SamlRequestCache.cs, the authorize-state binding; Security Model § Login browser binding
V7 Session management — revocation In-flight revocation gate re-checks the link is live before any side effect and again before AuthenticateDirect Met Api/Session/SessionMinter.cs (#232)
V8 Authorization Un-forgeable role→permission mapping; default-deny; last-admin / break-glass guard so no config strands the server; SoD via the SSO-only lever Met Api/Authz/PermissionRolePolicy.cs, Api/Session/SsoOnlyLoginGuard.cs; Security Model § SSO-only login
V11 Cryptography Secrets AES-256-GCM at rest (ssoenc:v1, separate key file, redacted on export); no weak-primitive acceptance (SHA-1 XML-DSig rejected); a fresh nonce per encryption; tamper → fail-closed Met Api/Secrets/SecretEnvelope.cs, SecretStore.cs; Security Model § Secrets encrypted at rest
V11 Cryptography — key strength Minimum asymmetric signing-key-strength floor for IdP JWKS keys and SAML certs: RSA keys below 2048 bits and EC keys off the approved NIST P-256/384/521 curves are rejected (a single shared floor gates both the OIDC id_token JWKS and SAML-certificate paths, fail-closed with a sanitized log) Met Api/Crypto/SigningKeyStrength.cs, Api/Oidc/OidcIdTokenValidator.cs, Api/Saml/SamlCertificate.cs; Security Model § OpenID id_token validation
V12 Secure outbound / SSRF Both the avatar fetch and the OpenID backchannel (discovery / JWKS / token / userinfo) route every connection — incl. redirect hops — through one shared ConnectCallback that resolves the host and connects only to a non-blocked public IP, closing SSRF + DNS-rebinding Met Api/Net/SsoHttp.cs (the shared hardened transport), Api/Net/IpAddressClassifier.cs, Api/Avatar/AvatarService.cs; the OIDC parity landed in #755
V6/V7 — brute force Optional per-client rate limiting that throttles, never permanently locks (sole-org availability); keyed on the Net client-IP classifier; fail-open on an unattributable client Met Api/Shared/SsoRateLimitGate.cs, Api/RateLimit/SsoRateLimiter.cs; Security Model § Rate limiting

OAuth 2.0 Security BCP (RFC 9700)

BCP item Status Note
PKCE (S256) for the code flow Met Sent on every OIDC request; a downgrade (AS not advertising S256 under the require-PKCE setting) is detected. Api/Oidc/*; Security Model § PKCE downgrade detection
Exact redirect-URI matching Met The redirect_uri is built from the canonical base URL (Host-header-independent), never reflected from the request; byte-exact echo. Api/Net/CanonicalBaseUrl.cs, Api/Oidc/OidcRedirectUriBuilder.cs
RFC 9207 issuer identification / mix-up defense Met The authorization-response iss is required and validated against the expected provider when the AS advertises it. Api/Oidc/DiscoveryFacts.cs, OidcDiscoveryReader.cs; Security Model § authorization-response issuer
No implicit / hybrid / ROPC Met Authorization-code flow only; no implicit, hybrid, or resource-owner-password grant is offered
PAR (Pushed Authorization Requests) N/A (opt-out) Not required of a confidential RP whose request is already integrity-protected by state/PKCE; would be a provider-side option, not a change to this RP
DPoP (RFC 9449) / sender-constrained access tokens N/A by role The plugin exchanges the code for an id_token and mints a Jellyfin session; it does not use the OAuth access token downstream, so there is no bearer access token to sender-constrain
JARM (signed authorization responses) N/A by role The authorization response carries only code/state/iss; the security-bearing artifact (the id_token) is itself signed and fully validated, so signing the authorization response adds nothing here

Accepted residuals

Honestly recorded; each has a reasoned status and a tracking issue.

  • Minimum signing-key strength floor (#733) — fixed. A shared floor now rejects an IdP signing key below the bar (RSA < 2048 bits, or an EC key off the approved NIST P-256/384/521 curves) on both the OIDC id_token JWKS path and the SAML-certificate path, fail-closed; closed, recorded here for completeness.
  • Response-header completeness — Met, tracked for drift. The intermediate auth page and error pages carry the CSP + defensive headers; HSTS ownership is the reverse proxy's (documented). No open gap.
  • IdP-error reflection (#708) — fixed (#709). IdP-supplied error text is no longer reflected unsanitized into the served page; closed, recorded here for completeness.

Not a certification

This is the maintainer's own mapping, produced with the AI-assisted process disclosed in the README. It claims no ASVS certification, no external audit, and no CRA/CE conformity (CRA position). It states only which controls the code implements, verified against the cited sources.

Clone this wiki locally