OTRS coordinated wave (9 GHSAs): a Remote-User header logs you in, JWTs outlive deactivation by 16 hours, and the login page leaks the route/permission map¶
Wave in one line: Nine advisories against OTRS (fixed 2026.7.X; ((OTRS)) Community Edition 6.x and derivatives "very likely" affected) published at 2026-10-12T09:31Z — one unauthenticated header trick mints an agent session, one token-lifecycle gap keeps a stolen JWT live for ~16 hours after the account is dead, one unauthenticated endpoint hands out the authorization map before you even log in, and six more legs break identity uniqueness, export neutrality, and CSRF gating across the admin plane.
Signal: OTRS is the ticket/helpdesk engine behind a long tail of corporate and government support desks (plus every Zammad-like derivative built on the CE codebase), and helpdesk platforms were already flagged as a recon target class on the Oct 2 Zammad KEV page. This wave reads like a support-desk engagement checklist written by the vendor's own auditor.
Advisory table¶
| GHSA | CVE | Sev. | Boundary |
|---|---|---|---|
| GHSA-prj2-j7v3-mhcv | CVE-2026-93582 | critical 9.4 | HTTP Basic Auth modules in CE 6 and prior accept the authenticated username from REMOTE_USER or HTTP_REMOTE_USER. In CGI/mod_perl deployments arbitrary request headers map to HTTP_* environment variables, so an unauthenticated attacker sends a crafted Remote-User: <agent> header, OTRS treats it as an already-authenticated username with no password check, and authenticates through the Generic Interface as any agent or customer user. Requires HTTP Basic configured as an auth backend + a header-exposing web server (OTRS 7+ uses Mojolicious/Hypnotoad and is not affected by this vector). |
| GHSA-f6jh-p427-pjq6 | CVE-2026-78357 | critical 9.1 | Issued JWTs are not invalidated when an agent/customer account is deactivated or its password is changed — the token stays valid until natural expiry (~16 h). Anyone holding a previously obtained token keeps full agent privileges through the lockout. |
| GHSA-mjfj-wgf2-r3pg | CVE-2026-78355 | high 8.7 | Path traversal in SendSupportBundle: an authenticated admin can reference paths outside the bundle directory, deleting files readable by the OTRS process (CE ≤6 = web-server permissions; OTRS 7+ = dedicated otrs user). Files may additionally be pulled into a support bundle destined for a predefined vendor address. |
| GHSA-8jjm-2gpw-mmqf | CVE-2026-78356 | medium 5.3 | The Agent Frontend configuration endpoint is reachable unauthenticated and returns internal application configuration: frontend routes and their associated authorization groups, authentication configuration, enabled features, third-party integration settings. |
| GHSA-49rp-wmg4-84xg | CVE-2026-78359 | medium 5.4 | Customer-user email uniqueness is checked only within the selected CustomerUser backend. With DB + LDAP configured, a user with customer-create permission can create a customer record whose email already belongs to a customer in the other backend — ticket/email communication gets associated with (or exposed to) the wrong customer identity. |
| GHSA-r7mj-m7cq-4q83 | CVE-2026-93581 | medium 6.1 | CSV export formula injection: values from authenticated submissions or inbound email land in exported CSVs with no formula-prefix neutralization (=, +, -, @) — executes in the analyst's spreadsheet when the export is opened. No attacker account needed if an externally-reachable field feeds the export. |
| GHSA-hq7p-2c9c-64hf | CVE-2026-78358 | medium 4.3 | Several admin actions skip ChallengeToken validation — DBUpdateLogCleanUp fires on a GET, and other unguarded endpoints can trigger deploying/synchronizing existing configuration; log-deletion and forced-sync effects ride an admin's ambient session. |
| GHSA-f36p-fv5h-jf99 | CVE-2026-48211 | medium 5.4 | CSRF on AdminImportExport::TemplateDelete (no ChallengeToken) — lure an admin, delete administrative Import/Export templates. |
| GHSA-x238-8qx9-7hh7 | CVE-2026-48212 | medium 4.8 | Stored JavaScript: an admin-authored Custom Page body is stored and executed in every user's browser — lower-privilege admin → higher-privilege admin session. |
Why this is durable operator value¶
- A pre-authenticated-username channel is only as strong as the web server's header filter — and CGI/mod_perl map every header. The bypass is not a logic bug in OTRS's password check; it's that the auth backend consumes
HTTP_REMOTE_USERand mod_cgi dutifully creates that variable from any client header. This is the third independent sighting of theRemote-User-header identity-injection family on this wiki (Caddy's underscore-aliasRemote_User→ FastCGI collision on the July 24 Caddy page, plus the recurring proxy-injected-identity legs) and now its highest-severity form: a login application choosing to trust the variable with no password step. Operator rule: on any CGI/FastCGI/mod_perl-era app with pluggable auth backends, sendRemote-User:,Remote_User:, and product-specific identity headers with no credentials at all on both the interactive login path and every API/interface endpoint (here the Generic Interface is the exploitable entry — interface endpoints often carry a different, weaker auth path than the UI). Decision table: absent / empty / valid-name header × UI / GenericInterface. Grep fingerprint in source: readingREMOTE_USERorHTTP_REMOTE_USERwithout a preceding verification step. - Token-vs-account-state drift is now a weekly pattern — run the kill-then-replay probe everywhere. OTRS keeps an issued JWT live ~16 h after deactivation or password change; the Oct 9 SmarterMail page keeps a role claim alive past demotion; the Oct 9 Vikunja wave omits artifacts from the revocation sweep; Strapi keeps field ceilings stale. The lifecycle battery for any product with JWTs: (a) issue token → deactivate account → replay API; (b) issue → change password → replay; (c) issue-high-priv → demote → refresh-only; (d) revoke share/webhook/token → sweep every delivery path (REST, WS, CalDAV, feeds). A positive on any leg while fresh login denies is the revocation-gap finding, and the TTL is the attacker's window.
- The pre-login config endpoint is an authorization map, not just info disclosure. The disclosed Agent Frontend configuration lists routes with their authorization groups plus enabled features and integrations. Before any credentials exist, an operator can enumerate exactly which endpoints are privileged, which permission names gate them, which features are on (skip negative tests for disabled modules), and which third-party integrations are wired (next-hop targets). Sweep class: every SPA/bootstrap "fetch my config/frontend config/initial state" endpoint gets an unauthenticated GET; compare its route/authgroup set against the post-login UI to find hidden-but-live endpoints — the same route-family-discovery move as the Keycloak alternate-route and JeecgBoot unguarded-list precedents.
- Multi-backend directories break uniqueness per-backend, and email is the join key. Where the helpdesk resolves "customer" by email across a DB backend and an LDAP backend, an insider (or compromised low-priv account with customer-create) plants a colliding record in the backend the check consults — inbound ticket correspondence for the real customer can land on the attacker's account. On any identity system with N backing stores: uniqueness/dedup claims are scoped to one store unless proven cross-store; probe by creating (in a lab) the same email in backend B that exists in backend A, then exercise the mail-resolution flow. Cross-ref: the Sept 16 IdP page's email-claim linking family — same root assumption (email identifies a person) broken at the storage layer instead of the federation layer.
- Inbound email is an unauthenticated write primitive into analyst-side export sinks. The CSV-injection leg needs no account: the payload rides a support ticket's email body into a field the agent later exports. Helpdesk/ticketing/CRM platforms are formula-injection delivery platforms — the payload's execution context is the analyst's Excel, not the server. Sweep: identify every field an external channel (email, web form, chat) populates that appears in CSV/XLSX export; plant
=HYPERLINK(...)-class inert markers; report as a client-side delivery path. Sibling pattern: the SmarterMail iCal mXSS leg — the ingestion format, not the app's own input forms, is the real attack surface. - CSRF in 2026 admin planes still rides GET + missing per-action tokens — and the interesting targets are sync/deploy verbs. One advisory enumerates an entire class at once: tokenless GET action, tokenless deploy/sync-of-existing-config endpoints, tokenless export/read endpoints (no confidentiality impact, noted honestly). The config deploy/sync CSRF is the operator-relevant one: forcing a running re-apply of existing configuration is an availability/integrity nudge with zero attacker credentials beyond luring one admin click. Audit pattern for any admin UI: enumerate action verbs, diff which carry the CSRF token in their request template; GET-mutable admin state is the finding; deploy/sync/reindex verbs are the payload.
Replayable validation boundaries (lab/authorized scope only)¶
- Header-identity battery (lab CE 6 + Apache CGI/mod_perl fixture): stand up Community Edition ≤6 with HTTP Basic backend; recorder backend or direct GenericInterface calls; send
Remote-User: <lab-agent>with no Authorization header; evidence = authenticated response identity (whoami-style GenericInterface echo) vs negative controls (header absent, header stripped by frontend). Never test header injection against a third-party host outside approved scope; if a front proxy strips underscore/Remote headers, record that as a deployment-specific negative control. - Kill-then-replay (own lab tenant): issue an agent JWT, deactivate the account from a second admin session, replay a read-only ticket endpoint with the captured token until natural expiry; decision table (account state / fresh-login result / replay result / seconds-until-denial). Tokens you were issued only; never collect real user tokens.
- Pre-auth config-oracle diff (own deployment): unauthenticated GET of the frontend-config endpoint; tabulate routes + authgroups + enabled features; diff against post-login visible routes. Synthetic tenant only; redact any integration hostnames from report evidence.
- Colliding-identity resolution (two lab backends): lab DB + lab LDAP with a synthetic shared email; verify which account inbound email resolves to. Synthetic tickets only, never real customer data.
- Export formula marker (own mailbox → own export): send a ticket containing an inert
=HYPERLINK("http://owned-callback/#marker","x")payload via the test email channel, export the queue, inspect raw CSV bytes for unescaped formula prefix. Do not deliver live formula payloads to real analyst workstations.
Cross-references¶
- Header→env identity-injection family: July 24 Caddy REMOTE_USER underscore-alias page.
- Token-lifecycle/revocation-drift lineage: Oct 9 SmarterMail wave, Oct 9 Vikunja wave.
- Helpdesk platform target class and session-state lineage: Oct 2 Zammad KEV page.
- Email-claim-as-identity (federation side): Sept 16 IdP authority page.
- Stored-XSS admin-ladder and export-side effects: Vendure dashboard innerHTML-stripping pattern (Oct 12 tracked wave); ingestion-format attacks: SmarterMail iCal leg above.