From 53da6ac24c29860ef8af6cc869c50b1b62928399 Mon Sep 17 00:00:00 2001 From: Jeff Posluns Date: Mon, 19 Oct 2026 07:00:39 -0400 Subject: [PATCH] authentication.md: cite fail2ban's shipped web jails and filters (TODO 1.293) fail2ban 1.1.1 sshd, nginx-http-auth and webmin-auth filters and jails; panel coverage and setup ease stated as not established. --- CHANGELOG.md | 1 + DONE.md | 1 + TODO.md | 1 - VERSION | 2 +- authentication.md | 18 +++++++++++++----- plugin/plugin.json | 2 +- .../references/MANIFEST.sha256 | 2 +- .../references/authentication.md | 18 +++++++++++++----- site/llms-full.txt | 8 ++++++-- 9 files changed, 37 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35bcc5c7..370d22c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ service can change a gate's answer, and a pull request number is only knowable f ## 2026-10-19 +- `authentication.md`: the fail2ban rule now cites fail2ban 1.1.1's shipped `sshd`, `nginx-http-auth` and `webmin-auth` filters and jails, which are disabled by default; enabling the relevant jails with matching log paths is labelled as this guide's advice, and coverage of any particular login panel and how easy it is to set up are stated as not established; TODO row 1.293 moves to DONE (#694) - `authentication.md`: the Cloudflare Access rule now cites Cloudflare's One-time PIN, identity-provider and generic OIDC pages for the login options, and its existing self-hosted web application scope now reads "published through Access", stating that use with any application unchanged is not established; no command changes; TODO row 1.292 moves to DONE (#692) - Twenty more guides move to the two-section layout (maintainer request, 2026-10-18), with each guide's own tool named first in its header and components listed headline tools first; no guide body or digest changes. Guides: `llm-observability.md`, `agent-builders.md`, `ai-infra-services.md`, `vector-databases.md`, `search-engines.md`, `elasticsearch.md`, `minio.md`, `object-storage.md`, `jupyter.md`, `gradio.md`, `streamlit.md`, `code-server.md`, `n8n.md`, `headless-browser-services.md`, `headless-cms-instant-api.md`, `supabase-self-hosted.md`, `observability-components.md`, `self-hosted-error-trackers.md`, `realtime-webhooks.md`, `realtime-voice-infra.md` (#691) - `pocketbase.md`: the source-limits are traced: PocketBase v0.40.4's root command wrapper and the `--dev` flag (its default and what it changes), and in Appwrite 2.2.0 how a document read is checked against collection and document permissions and how requests are classified as privileged or API-key authenticated, as far as the Appwrite repository shows; matching roles against stored permissions inside the `utopia-php/database` dependency stays open under TODO row 1.291; one previously exempt table row is now marked, so its Verify-marking exemption is removed (#690) diff --git a/DONE.md b/DONE.md index c94ce922..a5a701c7 100644 --- a/DONE.md +++ b/DONE.md @@ -10,6 +10,7 @@ because an item that simply vanishes gets proposed again six months later. | ID | Item | Ended | | --- | --- | --- | +| 1.293 | `authentication.md`: fail2ban: source or narrow the coverage and setup of login panels beyond the cited sshd jail and failure filter. (M, M) | Done, #694. Cited fail2ban 1.1.1 nginx HTTP-auth and Webmin jails and filter patterns, retained the SSH requirement, and labelled log-selection advice and the limits on panel coverage and setup ease. | | 1.292 | `authentication.md`: cloudflare-access: source or narrow the claim that Cloudflare Access can front any application unchanged, including the One-time PIN and SSO options still not established by the cited pages. (M, M) | Done, #692. Cited the pinned one-time PIN, identity-provider options and generic OIDC pages for the login methods, narrowed the fronting statement to a self-hosted web application published through Access, and labelled unchanged any-application use as not established and this guide's assessment. | | 1.291 | `pocketbase.md`: source-limits: trace the PocketBase CLI wrapper and Appwrite document read authorization and privileged/API-key requester classification; establish the `--dev` default. (M, M) | Done, #690. Pinned the PocketBase v0.40.4 wrapper wiring, the `--dev` default (disabled unless probably started with go run) and its dev-mode logging effects, and the Appwrite 2.2.0 keys/privileged requester classification, API-key and admin-mode authorization-status handling, route scope validation and document-read call sites; the utopia-php/database role-to-permission enforcement stays open in TODO.md under the same ID. | | 1.290 | `firebase-supabase.md`: local-guards: cite the recorded ShellCheck release. (M, M) | Done, #689. Cited the ShellCheck v0.11.0 changelog for the release named in the historical runs without attesting to the host binary; unrecorded bash and other tool/parser versions remain open in TODO.md under 1.290. | diff --git a/TODO.md b/TODO.md index 24f7608d..f993b473 100644 --- a/TODO.md +++ b/TODO.md @@ -60,7 +60,6 @@ A real surface the guide never covers. Correct as far as it goes, and not far en | 1.283 | `agent-builders.md`: debug-remedy: establish whether the debug_permission change is available in the console UI; API remedy is already cited and UI availability is unestablished. (M, M) | `[gap]` | | 1.290 | `firebase-supabase.md`: local-guards: establish the unrecorded bash and other tool/parser versions for the historical authoring guard and syntax runs; the ShellCheck v0.11.0 release is cited, but does not attest to the historical host binary. (M, M) | `[gap]` | | 1.291 | `pocketbase.md`: source-limits, remaining dependency gap: trace how utopia-php/database matches requester roles against stored collection/document permissions (including documentSecurity) for document reads and what the disabled default authorization status bypasses; the Appwrite-repository call sites, PocketBase CLI wrapper and `--dev` default are cited. (M, M) | `[gap]` | -| 1.293 | `authentication.md`: fail2ban: source or narrow the coverage and setup of login panels beyond the cited sshd jail and failure filter. (M, M) | `[gap]` | | 1.294 | `authentication.md`: transport-authentication: source or narrow the HTML-login boundary for non-HTTP transports, GraphQL/inference/management APIs and webhook replay rejection. (M, M) | `[gap]` | | 1.295 | `authentication.md`: verify-secret-scan: source or narrow staged, all-ref and merge-commit coverage beyond the cited Gitleaks and `git log -p` material. (M, M) | `[gap]` | | 1.296 | `docker.md`: secrets: source runtime secret-delivery methods and `.env` exclusion from Git beyond the cited Docker build/history behaviour. (M, M) | `[gap]` | diff --git a/VERSION b/VERSION index 402cff3b..f8e358f8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.692 +1.0.694 diff --git a/authentication.md b/authentication.md index cfa24ccc..1841065d 100644 --- a/authentication.md +++ b/authentication.md @@ -3,7 +3,7 @@ version_basis: { "schema": 1, "checked": "2026-10-19", "documentation_checked": "2026-09", - "body_sha256": "d4d2792ff54469edee2c9c1a988a38c695d95f197be34b0304091618954b753f", + "body_sha256": "0ddaa867f7996dc266b18e3f31505a227196859f5e1986e4fc5cda8cfb7aff5b", "components": { "owasp": { "name": "OWASP authentication and password storage", @@ -159,7 +159,11 @@ version_basis: { "sources": { "se7c4e0af046f": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L152-L167", "sc1b6e6bc1f84": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L271-L279", - "s9a6aaa273c73": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/sshd.conf#L104-L111" + "s9a6aaa273c73": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/sshd.conf#L104-L111", + "sa43cf7ba22fb": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L370-L376", + "s568ea00c2482": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/nginx-http-auth.conf#L9-L37", + "s3c53dd330a7b": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L491-L495", + "s099abd84ea19": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/webmin-auth.conf#L4-L20" } }, "grpc-status": { @@ -295,7 +299,7 @@ version_basis: { "session-unissued": {"text": "Reject session identifiers the server never issued to prevent session fixation.", "components": ["owasp", "owasp-docs"], "sources": ["owasp:sc5f1b11d42f4", "owasp-docs:s0b82bc050cf3"], "status": "REASONED"}, "csrf": {"text": "SameSite alone is not a complete CSRF defense: Lax permits a top-level state-changing GET and sibling subdomains can be same-site. Cookie-authenticated state changes need an anti-CSRF token or strict Origin/Sec-Fetch-Site check, and must not use safe methods such as GET.", "components": ["owasp", "owasp-docs"], "sources": ["owasp:sc5f1b11d42f4", "owasp-docs:s232e483ac72b", "owasp-docs:sc088939103f0", "owasp-docs:sa7544ec9e1d7", "owasp-docs:seb3129173dbb"], "status": "REASONED"}, "expensive-endpoint-limits": {"text": "Bound inference, uploads and job submission with request-size, concurrency and timeout limits in addition to per-client rate limits; apply these limits to streaming and webhook transports too.", "components": ["owasp", "api-security", "owasp-docs"], "sources": ["owasp:sc5f1b11d42f4", "api-security:s213afc24aadb", "owasp-docs:s3369d9106dce", "owasp-docs:sd6d35bd1b67d"], "status": "REASONED"}, - "fail2ban": {"text": "For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement): fail2ban ships an sshd jail and failure filter, with jails disabled by default. Other login panels require suitable filters and logs; ease of setup and their coverage are not established by these files.", "components": ["owasp", "fail2ban-jail"], "sources": ["owasp:sc5f1b11d42f4", "fail2ban-jail:se7c4e0af046f", "fail2ban-jail:sc1b6e6bc1f84", "fail2ban-jail:s9a6aaa273c73"], "status": "REASONED"}, + "fail2ban": {"text": "For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement). fail2ban 1.1.1 ships sshd, nginx-http-auth and webmin-auth filters and jails, with jails disabled by default; enabling relevant jails with matching file-backend logpaths is guide advice, while panel coverage and setup ease remain unestablished (guide assessment).", "components": ["owasp", "fail2ban-jail"], "sources": ["owasp:sc5f1b11d42f4", "fail2ban-jail:se7c4e0af046f", "fail2ban-jail:sc1b6e6bc1f84", "fail2ban-jail:s9a6aaa273c73", "fail2ban-jail:sa43cf7ba22fb", "fail2ban-jail:s568ea00c2482", "fail2ban-jail:s3c53dd330a7b", "fail2ban-jail:s099abd84ea19"], "status": "REASONED"}, "federated-allowlist": {"text": "After federated login, check the identity against an application allowlist of tenants, hosted domains, organization or group membership, or explicit users (this guide's recommendation); a Google sign-in alone does not make someone staff. For Google Workspace or Cloud organizations, check the hd claim in the validated ID token; an email domain or request hd parameter is insufficient. Microsoft common serves organizational and personal accounts; validate the token issuer, signing-key issuer and tid, then apply the application tenant allowlist. Vendor sources support the Google hd check and Microsoft token validation; the full allowlist and staff determination are this guide's recommendations.", "components": ["oidc", "google-oidc", "entra-multitenant"], "sources": ["oidc:scfd2790a544c", "google-oidc:s4f815acc2976", "entra-multitenant:s5e0242f87cb7", "entra-multitenant:s95719206c226"], "status": "REASONED"}, "cloudflare-access": {"text": "Cloudflare Access can front a self-hosted web application published through Access with one-time PIN or SSO login; create the Access application before the tunnel route, or it is available to anyone on the Internet. Validate the Access JWT at the origin, verify Tunnel origin TLS, and use Full (strict) for a directly proxied HTTPS origin where applicable; unchanged any-application use is not established.", "components": ["cloudflare-access"], "sources": ["cloudflare-access:sfddb92e438ca", "cloudflare-access:s7cafe1b17afd", "cloudflare-access:s81e5dd28d3e5", "cloudflare-access:s65c224a2e655", "cloudflare-access:sa012410f91eb", "cloudflare-access:sbf4ecbd5ffc1", "cloudflare-access:scb7d48f64a99", "cloudflare-access:sd606ae12de33", "cloudflare-access:s9f8bead847d2"], "status": "REASONED"}, "browser-session": {"text": "Prefer a server-side session in an HttpOnly cookie to tokens in browser storage.", "components": ["owasp", "owasp-docs"], "sources": ["owasp:sc5f1b11d42f4", "owasp-docs:s4f0aa80b1ef6"], "status": "REASONED"}, @@ -391,7 +395,7 @@ Claims (full source mapping in the front matter): - session-unissued (REASONED; owasp, owasp-docs): Reject session identifiers the server never issued to prevent session fixation. - csrf (REASONED; owasp, owasp-docs): SameSite alone is not a complete CSRF defense: Lax permits a top-level state-changing GET and sibling subdomains can be same-site. Cookie-authenticated state changes need an anti-CSRF token or strict Origin/Sec-Fetch-Site check, and must not use safe methods such as GET. - expensive-endpoint-limits (REASONED; owasp, api-security, owasp-docs): Bound inference, uploads and job submission with request-size, concurrency and timeout limits in addition to per-client rate limits; apply these limits to streaming and webhook transports too. -- fail2ban (REASONED; owasp, fail2ban-jail): For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement): fail2ban ships an sshd jail and failure filter, with jails disabled by default. Other login panels require suitable filters and logs; ease of setup and their coverage are not established by these files. +- fail2ban (REASONED; owasp, fail2ban-jail): For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement). fail2ban 1.1.1 ships sshd, nginx-http-auth and webmin-auth filters and jails, with jails disabled by default; enabling relevant jails with matching file-backend logpaths is guide advice, while panel coverage and setup ease remain unestablished (guide assessment). - federated-allowlist (REASONED; oidc, google-oidc, entra-multitenant): After federated login, check the identity against an application allowlist of tenants, hosted domains, organization or group membership, or explicit users (this guide's recommendation); a Google sign-in alone does not make someone staff. For Google Workspace or Cloud organizations, check the hd claim in the validated ID token; an email domain or request hd parameter is insufficient. Microsoft common serves organizational and personal accounts; validate the token issuer, signing-key issuer and tid, then apply the application tenant allowlist. Vendor sources support the Google hd check and Microsoft token validation; the full allowlist and staff determination are this guide's recommendations. - cloudflare-access (REASONED; cloudflare-access): Cloudflare Access can front a self-hosted web application published through Access with one-time PIN or SSO login; create the Access application before the tunnel route, or it is available to anyone on the Internet. Validate the Access JWT at the origin, verify Tunnel origin TLS, and use Full (strict) for a directly proxied HTTPS origin where applicable; unchanged any-application use is not established. - browser-session (REASONED; owasp, owasp-docs): Prefer a server-side session in an HttpOnly cookie to tokens in browser storage. @@ -425,7 +429,7 @@ TLS without authentication leaves a service open to the whole internet over an e 6. **Prefer SSO/OIDC over local accounts** where the product supports it, and enable MFA wherever available. [Cloudflare Access](cloudflare.md) can place an authentication layer in front of a self-hosted web application published through Access; the cited pages show that pattern, not that any application works behind it unchanged (this guide's assessment; no application-compatibility list is cited). For the login step, Cloudflare documents [integrating your organization's identity provider](https://github.com/cloudflare/cloudflare-docs/blob/c896795b8e8bab68d05ae78d64c9cbcda1fdb104/src/content/docs/cloudflare-one/integrations/identity-providers/index.mdx#L14-L18), with multiple identity providers usable simultaneously and a [generic OIDC connector](https://github.com/cloudflare/cloudflare-docs/blob/c896795b8e8bab68d05ae78d64c9cbcda1fdb104/src/content/docs/cloudflare-one/integrations/identity-providers/generic-oidc.mdx#L15) for identity providers not already set in Access, and sending a [one-time PIN to approved email addresses](https://github.com/cloudflare/cloudflare-docs/blob/c896795b8e8bab68d05ae78d64c9cbcda1fdb104/src/content/docs/cloudflare-one/integrations/identity-providers/one-time-pin.mdx#L15) as an alternative; OTP login and the identity provider of your choice can be configured simultaneously so users select their own authentication method. Create the Access application before the tunnel route; without it, the published application is available to anyone on the Internet. Validate the Access JWT at the origin. For a Tunnel route, configure origin TLS verification and Access JWT checking; for a directly proxied HTTPS origin, use Full (strict) where applicable. Where no native MFA exists, add it with an identity layer, an app-level TOTP library, or a hosted service, per [mfa.md](mfa.md). 7. **Scope machine access.** API clients get their own tokens with the least privilege the task needs, not an admin password. Support and exercise rotation; set expiry where the platform allows it. 8. **Harden sessions.** Set cookies `Secure`, `HttpOnly`, and `SameSite` (`Lax` or `Strict`) (per [OWASP session-cookie guidance](https://github.com/OWASP/CheatSheetSeries/blob/668ba7db3d0da5868b8a0305c259f7f6914a6ecd/cheatsheets/Session_Management_Cheat_Sheet.md#L131-L149)), sign them with a strong random secret (this guide's recommendation; the cited passage does not cover signing), and enforce an idle and an absolute timeout server-side (a cookie expiry alone does not stop a replayed cookie). Use an unpredictable session identifier, regenerate it (invalidating the old one) on login and on any privilege change, and reject a session ID the server never issued (session fixation). Invalidate sessions server-side on logout and on password change. `SameSite` is not a complete CSRF defense (`Lax` still allows a top-level state-changing GET, and a sibling subdomain can be same-site), so a cookie-authenticated state-changing request must also carry an anti-CSRF token or a strict `Origin`/`Sec-Fetch-Site` check, and must never change state through a safe method such as GET. -9. **Rate-limit authentication endpoints** and lock or delay after repeated failures. Per-client rate limits do not stop distributed credential stuffing (valid breached passwords spread thin across many addresses), so add account-aware and aggregate abuse controls alongside source-based ones, and avoid a lockout an attacker can use to deny a user access. Keep login, registration, and password-reset responses uniform in message and timing so they do not disclose whether an account exists. Log authentication successes and failures with source address and account, and keep the logs long enough to investigate an incident. For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement): the shipped `sshd` jail uses an `sshd` failure filter, and jails are disabled by default; coverage of other login panels depends on their filters and logs. Bound expensive endpoints too: inference, uploads, and job submission need request-size, concurrency, and timeout limits in addition to per-client rate limits, because an exposed AI endpoint left without them can burn GPU time and money even while correctly rejecting bad credentials, a failure mode known as denial of wallet. [realtime-webhooks.md](realtime-webhooks.md) covers the streaming and webhook transports these limits also apply to. +9. **Rate-limit authentication endpoints** and lock or delay after repeated failures. Per-client rate limits do not stop distributed credential stuffing (valid breached passwords spread thin across many addresses), so add account-aware and aggregate abuse controls alongside source-based ones, and avoid a lockout an attacker can use to deny a user access. Keep login, registration, and password-reset responses uniform in message and timing so they do not disclose whether an account exists. Log authentication successes and failures with source address and account, and keep the logs long enough to investigate an incident. For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement): the shipped `sshd` jail uses an `sshd` failure filter, and jails are [disabled by default](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L152-L167). Beyond SSH, fail2ban 1.1.1 ships the [`nginx-http-auth` jail](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L370-L376) using the nginx error log and the [`webmin-auth` jail](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L491-L495) using `syslog_authpriv` with `syslog_backend`. The `nginx-http-auth` [normal-mode patterns](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/nginx-http-auth.conf#L9-L37) match password-mismatch, user-not-found and authentication-failure messages with a client address; its comments say an extensive search of all nginx authentication failures has not been done. The `webmin-auth` [patterns](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/webmin-auth.conf#L4-L20) match the shown Webmin `Non-existent login` and `Invalid login` messages with a source host. Enable only the relevant jails in local configuration and, for file backends, set `logpath` to the matching logs; the shipped entries are starting points, so confirm the selected filter matches your deployment's failures (this guide's advice based on those settings). These files establish the listed jails and patterns, not coverage of a particular panel's log format or ease of setup (this guide's assessment); other login panels still require suitable filters and logs. Bound expensive endpoints too: inference, uploads, and job submission need request-size, concurrency, and timeout limits in addition to per-client rate limits, because an exposed AI endpoint left without them can burn GPU time and money even while correctly rejecting bad credentials, a failure mode known as denial of wallet. [realtime-webhooks.md](realtime-webhooks.md) covers the streaming and webhook transports these limits also apply to. 10. **Least privilege everywhere.** Separate admin from daily-use accounts, and give database and OS service accounts only the rights the application uses. 11. **Federated login is authentication, not authorization.** After Google, Microsoft, GitHub, or any provider returns an identity, check it against an application allowlist (tenant, hosted domain, organization or group membership, or explicit users) before granting access (this guide's recommendation); a Google sign-in alone does not make someone staff. For Google Workspace or Cloud organizations, check the `hd` claim in the validated ID token against an accepted domain; neither the email domain nor the request `hd` parameter controls access. Microsoft's multi-tenant `common` endpoint serves organizational and personal accounts. Validate the token issuer, signing-key issuer, and `tid`, then apply the application tenant allowlist. [oidc-integration.md](oidc-integration.md) has the checks; [identity-providers.md](identity-providers.md) has the providers. 12. **OIDC and OAuth hygiene.** Authorization code flow with PKCE (`S256`, never `plain`); exact-match redirect URIs; fresh per-transaction `state` and `nonce`, verified and bound to the initiating browser session; ID tokens validated for signature (keys from the provider's JWKS, algorithm pinned, never `none`), issuer, audience, and expiry; short-lived access tokens with refresh-token rotation; tokens never in URLs. Prefer a server-side session in an `HttpOnly` cookie to tokens in browser storage. Link accounts by issuer plus subject, never by email alone. @@ -449,6 +453,10 @@ TLS without authentication leaves a service open to the whole internet over an e - fail2ban default disabled setting (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L152-L167 - fail2ban sshd jail configuration (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L271-L279 - fail2ban sshd filter (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/sshd.conf#L104-L111 +- fail2ban 1.1.1 nginx HTTP-auth jail (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L370-L376 +- fail2ban 1.1.1 nginx HTTP-auth patterns and coverage caveat (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/nginx-http-auth.conf#L9-L37 +- fail2ban 1.1.1 Webmin authentication jail (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L491-L495 +- fail2ban 1.1.1 Webmin authentication patterns and examples (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/webmin-auth.conf#L4-L20 - gRPC authentication and permission status codes (checked October 2026): https://github.com/grpc/grpc/blob/v1.84.0/doc/statuscodes.md#L13-L24 - WebSocket opening handshake (RFC 6455, checked October 2026): https://www.rfc-editor.org/rfc/rfc6455.html#section-1.3 - WebSocket closing handshake (RFC 6455, checked October 2026): https://www.rfc-editor.org/rfc/rfc6455.html#section-1.4 diff --git a/plugin/plugin.json b/plugin/plugin.json index 3f0a06b7..41158b03 100644 --- a/plugin/plugin.json +++ b/plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", "name": "secureconfig", - "version": "1.0.692", + "version": "1.0.694", "description": "Deployment-exposure guides for services AI-assisted projects commonly run: TLS, authentication, MFA, secrets, and network exposure, each line traced to a vendor page.", "author": { "name": "Jeff Posluns", "url": "https://secureconfig.ai" }, "homepage": "https://secureconfig.ai", diff --git a/plugin/skills/secure-deployment-config/references/MANIFEST.sha256 b/plugin/skills/secure-deployment-config/references/MANIFEST.sha256 index e12515f1..bde223d2 100644 --- a/plugin/skills/secure-deployment-config/references/MANIFEST.sha256 +++ b/plugin/skills/secure-deployment-config/references/MANIFEST.sha256 @@ -5,7 +5,7 @@ 86eca64127b4dca3510677732af318246214e54c8bcfd7662cf8d532520564ab cloudflare.md c63b3c46f99d8d1d5c60ef527994618c97a0300629692719ddba0e3eba4403d7 tailscale.md 57dc02171106069655b1ecf67ce77cd86ba505cd306469f48f544ed83482e845 tunnels.md -e878c35534ebe6e237d079c579af7aba9a2ca0584a00267da3e251cff74be0c3 authentication.md +bd1d324fd0e232d952fa2a3ff46c4cd60cf11b9f1f811fb7d783258a6053cd58 authentication.md a4bd1d507a1f15812717e44ed1426892aa789a7b3a955128945bd1930618c453 mfa.md 82f9de47492cc8831a043625ec2553fd53033f56c048c2e04b3eb218981ee888 secrets.md 67ead6128e8115fe289b11db4010b4fc046b44fbf797bb7d3ac6c52f4e4d4959 vault.md diff --git a/plugin/skills/secure-deployment-config/references/authentication.md b/plugin/skills/secure-deployment-config/references/authentication.md index cfa24ccc..1841065d 100644 --- a/plugin/skills/secure-deployment-config/references/authentication.md +++ b/plugin/skills/secure-deployment-config/references/authentication.md @@ -3,7 +3,7 @@ version_basis: { "schema": 1, "checked": "2026-10-19", "documentation_checked": "2026-09", - "body_sha256": "d4d2792ff54469edee2c9c1a988a38c695d95f197be34b0304091618954b753f", + "body_sha256": "0ddaa867f7996dc266b18e3f31505a227196859f5e1986e4fc5cda8cfb7aff5b", "components": { "owasp": { "name": "OWASP authentication and password storage", @@ -159,7 +159,11 @@ version_basis: { "sources": { "se7c4e0af046f": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L152-L167", "sc1b6e6bc1f84": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L271-L279", - "s9a6aaa273c73": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/sshd.conf#L104-L111" + "s9a6aaa273c73": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/sshd.conf#L104-L111", + "sa43cf7ba22fb": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L370-L376", + "s568ea00c2482": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/nginx-http-auth.conf#L9-L37", + "s3c53dd330a7b": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L491-L495", + "s099abd84ea19": "https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/webmin-auth.conf#L4-L20" } }, "grpc-status": { @@ -295,7 +299,7 @@ version_basis: { "session-unissued": {"text": "Reject session identifiers the server never issued to prevent session fixation.", "components": ["owasp", "owasp-docs"], "sources": ["owasp:sc5f1b11d42f4", "owasp-docs:s0b82bc050cf3"], "status": "REASONED"}, "csrf": {"text": "SameSite alone is not a complete CSRF defense: Lax permits a top-level state-changing GET and sibling subdomains can be same-site. Cookie-authenticated state changes need an anti-CSRF token or strict Origin/Sec-Fetch-Site check, and must not use safe methods such as GET.", "components": ["owasp", "owasp-docs"], "sources": ["owasp:sc5f1b11d42f4", "owasp-docs:s232e483ac72b", "owasp-docs:sc088939103f0", "owasp-docs:sa7544ec9e1d7", "owasp-docs:seb3129173dbb"], "status": "REASONED"}, "expensive-endpoint-limits": {"text": "Bound inference, uploads and job submission with request-size, concurrency and timeout limits in addition to per-client rate limits; apply these limits to streaming and webhook transports too.", "components": ["owasp", "api-security", "owasp-docs"], "sources": ["owasp:sc5f1b11d42f4", "api-security:s213afc24aadb", "owasp-docs:s3369d9106dce", "owasp-docs:sd6d35bd1b67d"], "status": "REASONED"}, - "fail2ban": {"text": "For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement): fail2ban ships an sshd jail and failure filter, with jails disabled by default. Other login panels require suitable filters and logs; ease of setup and their coverage are not established by these files.", "components": ["owasp", "fail2ban-jail"], "sources": ["owasp:sc5f1b11d42f4", "fail2ban-jail:se7c4e0af046f", "fail2ban-jail:sc1b6e6bc1f84", "fail2ban-jail:s9a6aaa273c73"], "status": "REASONED"}, + "fail2ban": {"text": "For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement). fail2ban 1.1.1 ships sshd, nginx-http-auth and webmin-auth filters and jails, with jails disabled by default; enabling relevant jails with matching file-backend logpaths is guide advice, while panel coverage and setup ease remain unestablished (guide assessment).", "components": ["owasp", "fail2ban-jail"], "sources": ["owasp:sc5f1b11d42f4", "fail2ban-jail:se7c4e0af046f", "fail2ban-jail:sc1b6e6bc1f84", "fail2ban-jail:s9a6aaa273c73", "fail2ban-jail:sa43cf7ba22fb", "fail2ban-jail:s568ea00c2482", "fail2ban-jail:s3c53dd330a7b", "fail2ban-jail:s099abd84ea19"], "status": "REASONED"}, "federated-allowlist": {"text": "After federated login, check the identity against an application allowlist of tenants, hosted domains, organization or group membership, or explicit users (this guide's recommendation); a Google sign-in alone does not make someone staff. For Google Workspace or Cloud organizations, check the hd claim in the validated ID token; an email domain or request hd parameter is insufficient. Microsoft common serves organizational and personal accounts; validate the token issuer, signing-key issuer and tid, then apply the application tenant allowlist. Vendor sources support the Google hd check and Microsoft token validation; the full allowlist and staff determination are this guide's recommendations.", "components": ["oidc", "google-oidc", "entra-multitenant"], "sources": ["oidc:scfd2790a544c", "google-oidc:s4f815acc2976", "entra-multitenant:s5e0242f87cb7", "entra-multitenant:s95719206c226"], "status": "REASONED"}, "cloudflare-access": {"text": "Cloudflare Access can front a self-hosted web application published through Access with one-time PIN or SSO login; create the Access application before the tunnel route, or it is available to anyone on the Internet. Validate the Access JWT at the origin, verify Tunnel origin TLS, and use Full (strict) for a directly proxied HTTPS origin where applicable; unchanged any-application use is not established.", "components": ["cloudflare-access"], "sources": ["cloudflare-access:sfddb92e438ca", "cloudflare-access:s7cafe1b17afd", "cloudflare-access:s81e5dd28d3e5", "cloudflare-access:s65c224a2e655", "cloudflare-access:sa012410f91eb", "cloudflare-access:sbf4ecbd5ffc1", "cloudflare-access:scb7d48f64a99", "cloudflare-access:sd606ae12de33", "cloudflare-access:s9f8bead847d2"], "status": "REASONED"}, "browser-session": {"text": "Prefer a server-side session in an HttpOnly cookie to tokens in browser storage.", "components": ["owasp", "owasp-docs"], "sources": ["owasp:sc5f1b11d42f4", "owasp-docs:s4f0aa80b1ef6"], "status": "REASONED"}, @@ -391,7 +395,7 @@ Claims (full source mapping in the front matter): - session-unissued (REASONED; owasp, owasp-docs): Reject session identifiers the server never issued to prevent session fixation. - csrf (REASONED; owasp, owasp-docs): SameSite alone is not a complete CSRF defense: Lax permits a top-level state-changing GET and sibling subdomains can be same-site. Cookie-authenticated state changes need an anti-CSRF token or strict Origin/Sec-Fetch-Site check, and must not use safe methods such as GET. - expensive-endpoint-limits (REASONED; owasp, api-security, owasp-docs): Bound inference, uploads and job submission with request-size, concurrency and timeout limits in addition to per-client rate limits; apply these limits to streaming and webhook transports too. -- fail2ban (REASONED; owasp, fail2ban-jail): For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement): fail2ban ships an sshd jail and failure filter, with jails disabled by default. Other login panels require suitable filters and logs; ease of setup and their coverage are not established by these files. +- fail2ban (REASONED; owasp, fail2ban-jail): For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement). fail2ban 1.1.1 ships sshd, nginx-http-auth and webmin-auth filters and jails, with jails disabled by default; enabling relevant jails with matching file-backend logpaths is guide advice, while panel coverage and setup ease remain unestablished (guide assessment). - federated-allowlist (REASONED; oidc, google-oidc, entra-multitenant): After federated login, check the identity against an application allowlist of tenants, hosted domains, organization or group membership, or explicit users (this guide's recommendation); a Google sign-in alone does not make someone staff. For Google Workspace or Cloud organizations, check the hd claim in the validated ID token; an email domain or request hd parameter is insufficient. Microsoft common serves organizational and personal accounts; validate the token issuer, signing-key issuer and tid, then apply the application tenant allowlist. Vendor sources support the Google hd check and Microsoft token validation; the full allowlist and staff determination are this guide's recommendations. - cloudflare-access (REASONED; cloudflare-access): Cloudflare Access can front a self-hosted web application published through Access with one-time PIN or SSO login; create the Access application before the tunnel route, or it is available to anyone on the Internet. Validate the Access JWT at the origin, verify Tunnel origin TLS, and use Full (strict) for a directly proxied HTTPS origin where applicable; unchanged any-application use is not established. - browser-session (REASONED; owasp, owasp-docs): Prefer a server-side session in an HttpOnly cookie to tokens in browser storage. @@ -425,7 +429,7 @@ TLS without authentication leaves a service open to the whole internet over an e 6. **Prefer SSO/OIDC over local accounts** where the product supports it, and enable MFA wherever available. [Cloudflare Access](cloudflare.md) can place an authentication layer in front of a self-hosted web application published through Access; the cited pages show that pattern, not that any application works behind it unchanged (this guide's assessment; no application-compatibility list is cited). For the login step, Cloudflare documents [integrating your organization's identity provider](https://github.com/cloudflare/cloudflare-docs/blob/c896795b8e8bab68d05ae78d64c9cbcda1fdb104/src/content/docs/cloudflare-one/integrations/identity-providers/index.mdx#L14-L18), with multiple identity providers usable simultaneously and a [generic OIDC connector](https://github.com/cloudflare/cloudflare-docs/blob/c896795b8e8bab68d05ae78d64c9cbcda1fdb104/src/content/docs/cloudflare-one/integrations/identity-providers/generic-oidc.mdx#L15) for identity providers not already set in Access, and sending a [one-time PIN to approved email addresses](https://github.com/cloudflare/cloudflare-docs/blob/c896795b8e8bab68d05ae78d64c9cbcda1fdb104/src/content/docs/cloudflare-one/integrations/identity-providers/one-time-pin.mdx#L15) as an alternative; OTP login and the identity provider of your choice can be configured simultaneously so users select their own authentication method. Create the Access application before the tunnel route; without it, the published application is available to anyone on the Internet. Validate the Access JWT at the origin. For a Tunnel route, configure origin TLS verification and Access JWT checking; for a directly proxied HTTPS origin, use Full (strict) where applicable. Where no native MFA exists, add it with an identity layer, an app-level TOTP library, or a hosted service, per [mfa.md](mfa.md). 7. **Scope machine access.** API clients get their own tokens with the least privilege the task needs, not an admin password. Support and exercise rotation; set expiry where the platform allows it. 8. **Harden sessions.** Set cookies `Secure`, `HttpOnly`, and `SameSite` (`Lax` or `Strict`) (per [OWASP session-cookie guidance](https://github.com/OWASP/CheatSheetSeries/blob/668ba7db3d0da5868b8a0305c259f7f6914a6ecd/cheatsheets/Session_Management_Cheat_Sheet.md#L131-L149)), sign them with a strong random secret (this guide's recommendation; the cited passage does not cover signing), and enforce an idle and an absolute timeout server-side (a cookie expiry alone does not stop a replayed cookie). Use an unpredictable session identifier, regenerate it (invalidating the old one) on login and on any privilege change, and reject a session ID the server never issued (session fixation). Invalidate sessions server-side on logout and on password change. `SameSite` is not a complete CSRF defense (`Lax` still allows a top-level state-changing GET, and a sibling subdomain can be same-site), so a cookie-authenticated state-changing request must also carry an anti-CSRF token or a strict `Origin`/`Sec-Fetch-Site` check, and must never change state through a safe method such as GET. -9. **Rate-limit authentication endpoints** and lock or delay after repeated failures. Per-client rate limits do not stop distributed credential stuffing (valid breached passwords spread thin across many addresses), so add account-aware and aggregate abuse controls alongside source-based ones, and avoid a lockout an attacker can use to deny a user access. Keep login, registration, and password-reset responses uniform in message and timing so they do not disclose whether an account exists. Log authentication successes and failures with source address and account, and keep the logs long enough to investigate an incident. For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement): the shipped `sshd` jail uses an `sshd` failure filter, and jails are disabled by default; coverage of other login panels depends on their filters and logs. Bound expensive endpoints too: inference, uploads, and job submission need request-size, concurrency, and timeout limits in addition to per-client rate limits, because an exposed AI endpoint left without them can burn GPU time and money even while correctly rejecting bad credentials, a failure mode known as denial of wallet. [realtime-webhooks.md](realtime-webhooks.md) covers the streaming and webhook transports these limits also apply to. +9. **Rate-limit authentication endpoints** and lock or delay after repeated failures. Per-client rate limits do not stop distributed credential stuffing (valid breached passwords spread thin across many addresses), so add account-aware and aggregate abuse controls alongside source-based ones, and avoid a lockout an attacker can use to deny a user access. Keep login, registration, and password-reset responses uniform in message and timing so they do not disclose whether an account exists. Log authentication successes and failures with source address and account, and keep the logs long enough to investigate an incident. For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement): the shipped `sshd` jail uses an `sshd` failure filter, and jails are [disabled by default](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L152-L167). Beyond SSH, fail2ban 1.1.1 ships the [`nginx-http-auth` jail](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L370-L376) using the nginx error log and the [`webmin-auth` jail](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L491-L495) using `syslog_authpriv` with `syslog_backend`. The `nginx-http-auth` [normal-mode patterns](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/nginx-http-auth.conf#L9-L37) match password-mismatch, user-not-found and authentication-failure messages with a client address; its comments say an extensive search of all nginx authentication failures has not been done. The `webmin-auth` [patterns](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/webmin-auth.conf#L4-L20) match the shown Webmin `Non-existent login` and `Invalid login` messages with a source host. Enable only the relevant jails in local configuration and, for file backends, set `logpath` to the matching logs; the shipped entries are starting points, so confirm the selected filter matches your deployment's failures (this guide's advice based on those settings). These files establish the listed jails and patterns, not coverage of a particular panel's log format or ease of setup (this guide's assessment); other login panels still require suitable filters and logs. Bound expensive endpoints too: inference, uploads, and job submission need request-size, concurrency, and timeout limits in addition to per-client rate limits, because an exposed AI endpoint left without them can burn GPU time and money even while correctly rejecting bad credentials, a failure mode known as denial of wallet. [realtime-webhooks.md](realtime-webhooks.md) covers the streaming and webhook transports these limits also apply to. 10. **Least privilege everywhere.** Separate admin from daily-use accounts, and give database and OS service accounts only the rights the application uses. 11. **Federated login is authentication, not authorization.** After Google, Microsoft, GitHub, or any provider returns an identity, check it against an application allowlist (tenant, hosted domain, organization or group membership, or explicit users) before granting access (this guide's recommendation); a Google sign-in alone does not make someone staff. For Google Workspace or Cloud organizations, check the `hd` claim in the validated ID token against an accepted domain; neither the email domain nor the request `hd` parameter controls access. Microsoft's multi-tenant `common` endpoint serves organizational and personal accounts. Validate the token issuer, signing-key issuer, and `tid`, then apply the application tenant allowlist. [oidc-integration.md](oidc-integration.md) has the checks; [identity-providers.md](identity-providers.md) has the providers. 12. **OIDC and OAuth hygiene.** Authorization code flow with PKCE (`S256`, never `plain`); exact-match redirect URIs; fresh per-transaction `state` and `nonce`, verified and bound to the initiating browser session; ID tokens validated for signature (keys from the provider's JWKS, algorithm pinned, never `none`), issuer, audience, and expiry; short-lived access tokens with refresh-token rotation; tokens never in URLs. Prefer a server-side session in an `HttpOnly` cookie to tokens in browser storage. Link accounts by issuer plus subject, never by email alone. @@ -449,6 +453,10 @@ TLS without authentication leaves a service open to the whole internet over an e - fail2ban default disabled setting (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L152-L167 - fail2ban sshd jail configuration (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L271-L279 - fail2ban sshd filter (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/sshd.conf#L104-L111 +- fail2ban 1.1.1 nginx HTTP-auth jail (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L370-L376 +- fail2ban 1.1.1 nginx HTTP-auth patterns and coverage caveat (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/nginx-http-auth.conf#L9-L37 +- fail2ban 1.1.1 Webmin authentication jail (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L491-L495 +- fail2ban 1.1.1 Webmin authentication patterns and examples (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/webmin-auth.conf#L4-L20 - gRPC authentication and permission status codes (checked October 2026): https://github.com/grpc/grpc/blob/v1.84.0/doc/statuscodes.md#L13-L24 - WebSocket opening handshake (RFC 6455, checked October 2026): https://www.rfc-editor.org/rfc/rfc6455.html#section-1.3 - WebSocket closing handshake (RFC 6455, checked October 2026): https://www.rfc-editor.org/rfc/rfc6455.html#section-1.4 diff --git a/site/llms-full.txt b/site/llms-full.txt index 193a25f3..741b6d86 100644 --- a/site/llms-full.txt +++ b/site/llms-full.txt @@ -1590,7 +1590,7 @@ Claims (full source mapping in the front matter): - session-unissued (REASONED; owasp, owasp-docs): Reject session identifiers the server never issued to prevent session fixation. - csrf (REASONED; owasp, owasp-docs): SameSite alone is not a complete CSRF defense: Lax permits a top-level state-changing GET and sibling subdomains can be same-site. Cookie-authenticated state changes need an anti-CSRF token or strict Origin/Sec-Fetch-Site check, and must not use safe methods such as GET. - expensive-endpoint-limits (REASONED; owasp, api-security, owasp-docs): Bound inference, uploads and job submission with request-size, concurrency and timeout limits in addition to per-client rate limits; apply these limits to streaming and webhook transports too. -- fail2ban (REASONED; owasp, fail2ban-jail): For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement): fail2ban ships an sshd jail and failure filter, with jails disabled by default. Other login panels require suitable filters and logs; ease of setup and their coverage are not established by these files. +- fail2ban (REASONED; owasp, fail2ban-jail): For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement). fail2ban 1.1.1 ships sshd, nginx-http-auth and webmin-auth filters and jails, with jails disabled by default; enabling relevant jails with matching file-backend logpaths is guide advice, while panel coverage and setup ease remain unestablished (guide assessment). - federated-allowlist (REASONED; oidc, google-oidc, entra-multitenant): After federated login, check the identity against an application allowlist of tenants, hosted domains, organization or group membership, or explicit users (this guide's recommendation); a Google sign-in alone does not make someone staff. For Google Workspace or Cloud organizations, check the hd claim in the validated ID token; an email domain or request hd parameter is insufficient. Microsoft common serves organizational and personal accounts; validate the token issuer, signing-key issuer and tid, then apply the application tenant allowlist. Vendor sources support the Google hd check and Microsoft token validation; the full allowlist and staff determination are this guide's recommendations. - cloudflare-access (REASONED; cloudflare-access): Cloudflare Access can front a self-hosted web application published through Access with one-time PIN or SSO login; create the Access application before the tunnel route, or it is available to anyone on the Internet. Validate the Access JWT at the origin, verify Tunnel origin TLS, and use Full (strict) for a directly proxied HTTPS origin where applicable; unchanged any-application use is not established. - browser-session (REASONED; owasp, owasp-docs): Prefer a server-side session in an HttpOnly cookie to tokens in browser storage. @@ -1624,7 +1624,7 @@ TLS without authentication leaves a service open to the whole internet over an e 6. **Prefer SSO/OIDC over local accounts** where the product supports it, and enable MFA wherever available. [Cloudflare Access](cloudflare.md) can place an authentication layer in front of a self-hosted web application published through Access; the cited pages show that pattern, not that any application works behind it unchanged (this guide's assessment; no application-compatibility list is cited). For the login step, Cloudflare documents [integrating your organization's identity provider](https://github.com/cloudflare/cloudflare-docs/blob/c896795b8e8bab68d05ae78d64c9cbcda1fdb104/src/content/docs/cloudflare-one/integrations/identity-providers/index.mdx#L14-L18), with multiple identity providers usable simultaneously and a [generic OIDC connector](https://github.com/cloudflare/cloudflare-docs/blob/c896795b8e8bab68d05ae78d64c9cbcda1fdb104/src/content/docs/cloudflare-one/integrations/identity-providers/generic-oidc.mdx#L15) for identity providers not already set in Access, and sending a [one-time PIN to approved email addresses](https://github.com/cloudflare/cloudflare-docs/blob/c896795b8e8bab68d05ae78d64c9cbcda1fdb104/src/content/docs/cloudflare-one/integrations/identity-providers/one-time-pin.mdx#L15) as an alternative; OTP login and the identity provider of your choice can be configured simultaneously so users select their own authentication method. Create the Access application before the tunnel route; without it, the published application is available to anyone on the Internet. Validate the Access JWT at the origin. For a Tunnel route, configure origin TLS verification and Access JWT checking; for a directly proxied HTTPS origin, use Full (strict) where applicable. Where no native MFA exists, add it with an identity layer, an app-level TOTP library, or a hosted service, per [mfa.md](mfa.md). 7. **Scope machine access.** API clients get their own tokens with the least privilege the task needs, not an admin password. Support and exercise rotation; set expiry where the platform allows it. 8. **Harden sessions.** Set cookies `Secure`, `HttpOnly`, and `SameSite` (`Lax` or `Strict`) (per [OWASP session-cookie guidance](https://github.com/OWASP/CheatSheetSeries/blob/668ba7db3d0da5868b8a0305c259f7f6914a6ecd/cheatsheets/Session_Management_Cheat_Sheet.md#L131-L149)), sign them with a strong random secret (this guide's recommendation; the cited passage does not cover signing), and enforce an idle and an absolute timeout server-side (a cookie expiry alone does not stop a replayed cookie). Use an unpredictable session identifier, regenerate it (invalidating the old one) on login and on any privilege change, and reject a session ID the server never issued (session fixation). Invalidate sessions server-side on logout and on password change. `SameSite` is not a complete CSRF defense (`Lax` still allows a top-level state-changing GET, and a sibling subdomain can be same-site), so a cookie-authenticated state-changing request must also carry an anti-CSRF token or a strict `Origin`/`Sec-Fetch-Site` check, and must never change state through a safe method such as GET. -9. **Rate-limit authentication endpoints** and lock or delay after repeated failures. Per-client rate limits do not stop distributed credential stuffing (valid breached passwords spread thin across many addresses), so add account-aware and aggregate abuse controls alongside source-based ones, and avoid a lockout an attacker can use to deny a user access. Keep login, registration, and password-reset responses uniform in message and timing so they do not disclose whether an account exists. Log authentication successes and failures with source address and account, and keep the logs long enough to investigate an incident. For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement): the shipped `sshd` jail uses an `sshd` failure filter, and jails are disabled by default; coverage of other login panels depends on their filters and logs. Bound expensive endpoints too: inference, uploads, and job submission need request-size, concurrency, and timeout limits in addition to per-client rate limits, because an exposed AI endpoint left without them can burn GPU time and money even while correctly rejecting bad credentials, a failure mode known as denial of wallet. [realtime-webhooks.md](realtime-webhooks.md) covers the streaming and webhook transports these limits also apply to. +9. **Rate-limit authentication endpoints** and lock or delay after repeated failures. Per-client rate limits do not stop distributed credential stuffing (valid breached passwords spread thin across many addresses), so add account-aware and aggregate abuse controls alongside source-based ones, and avoid a lockout an attacker can use to deny a user access. Keep login, registration, and password-reset responses uniform in message and timing so they do not disclose whether an account exists. Log authentication successes and failures with source address and account, and keep the logs long enough to investigate an incident. For SSH on Linux hosts, enable the relevant fail2ban jail (guide requirement): the shipped `sshd` jail uses an `sshd` failure filter, and jails are [disabled by default](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L152-L167). Beyond SSH, fail2ban 1.1.1 ships the [`nginx-http-auth` jail](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L370-L376) using the nginx error log and the [`webmin-auth` jail](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L491-L495) using `syslog_authpriv` with `syslog_backend`. The `nginx-http-auth` [normal-mode patterns](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/nginx-http-auth.conf#L9-L37) match password-mismatch, user-not-found and authentication-failure messages with a client address; its comments say an extensive search of all nginx authentication failures has not been done. The `webmin-auth` [patterns](https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/webmin-auth.conf#L4-L20) match the shown Webmin `Non-existent login` and `Invalid login` messages with a source host. Enable only the relevant jails in local configuration and, for file backends, set `logpath` to the matching logs; the shipped entries are starting points, so confirm the selected filter matches your deployment's failures (this guide's advice based on those settings). These files establish the listed jails and patterns, not coverage of a particular panel's log format or ease of setup (this guide's assessment); other login panels still require suitable filters and logs. Bound expensive endpoints too: inference, uploads, and job submission need request-size, concurrency, and timeout limits in addition to per-client rate limits, because an exposed AI endpoint left without them can burn GPU time and money even while correctly rejecting bad credentials, a failure mode known as denial of wallet. [realtime-webhooks.md](realtime-webhooks.md) covers the streaming and webhook transports these limits also apply to. 10. **Least privilege everywhere.** Separate admin from daily-use accounts, and give database and OS service accounts only the rights the application uses. 11. **Federated login is authentication, not authorization.** After Google, Microsoft, GitHub, or any provider returns an identity, check it against an application allowlist (tenant, hosted domain, organization or group membership, or explicit users) before granting access (this guide's recommendation); a Google sign-in alone does not make someone staff. For Google Workspace or Cloud organizations, check the `hd` claim in the validated ID token against an accepted domain; neither the email domain nor the request `hd` parameter controls access. Microsoft's multi-tenant `common` endpoint serves organizational and personal accounts. Validate the token issuer, signing-key issuer, and `tid`, then apply the application tenant allowlist. [oidc-integration.md](oidc-integration.md) has the checks; [identity-providers.md](identity-providers.md) has the providers. 12. **OIDC and OAuth hygiene.** Authorization code flow with PKCE (`S256`, never `plain`); exact-match redirect URIs; fresh per-transaction `state` and `nonce`, verified and bound to the initiating browser session; ID tokens validated for signature (keys from the provider's JWKS, algorithm pinned, never `none`), issuer, audience, and expiry; short-lived access tokens with refresh-token rotation; tokens never in URLs. Prefer a server-side session in an `HttpOnly` cookie to tokens in browser storage. Link accounts by issuer plus subject, never by email alone. @@ -1648,6 +1648,10 @@ TLS without authentication leaves a service open to the whole internet over an e - fail2ban default disabled setting (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L152-L167 - fail2ban sshd jail configuration (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L271-L279 - fail2ban sshd filter (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/sshd.conf#L104-L111 +- fail2ban 1.1.1 nginx HTTP-auth jail (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L370-L376 +- fail2ban 1.1.1 nginx HTTP-auth patterns and coverage caveat (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/nginx-http-auth.conf#L9-L37 +- fail2ban 1.1.1 Webmin authentication jail (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/jail.conf#L491-L495 +- fail2ban 1.1.1 Webmin authentication patterns and examples (checked October 2026): https://github.com/fail2ban/fail2ban/blob/1.1.1/config/filter.d/webmin-auth.conf#L4-L20 - gRPC authentication and permission status codes (checked October 2026): https://github.com/grpc/grpc/blob/v1.84.0/doc/statuscodes.md#L13-L24 - WebSocket opening handshake (RFC 6455, checked October 2026): https://www.rfc-editor.org/rfc/rfc6455.html#section-1.3 - WebSocket closing handshake (RFC 6455, checked October 2026): https://www.rfc-editor.org/rfc/rfc6455.html#section-1.4