## Summary
SimpleHelp 5.5.15 accepts a forged OpenID Connect (OIDC) ID token during the real technician-login OIDC callback flow. In the reproduced configuration, an unauthenticated client requests a legitimate SimpleHelp OIDC login URL from `/auth/v1/account/oidc_get`, receives a server-generated pending `state`, completes the callback at `/oidc`, and supplies an attacker-controlled JWT with `alg: none` and a bogus signature. The vulnerable 5.5.15 server creates a fully authenticated technician session for the forged identity `attacker` / `Forged Attacker`; the patched 5.5.16 server rejects the same forged token and remains unauthenticated.

## Impact
- **Package/component affected:** SimpleHelp server technician authentication, specifically the OIDC authentication provider and `/oidc` callback path.
- **Affected versions:** SimpleHelp 5.5.15 and earlier, and 6.0 prerelease builds before the fixed release.
- **Patched versions tested:** SimpleHelp 5.5.16 (`SimpleHelp-linux-amd64.tar.gz`, SHA256 `9360af980277e1ef4330eb1ed08d981c9dfdcc4e25d87ed0552a47f5ebd5161a`).
- **Risk level and consequences:** Critical. A remote unauthenticated attacker can authenticate as a group-authenticated technician using forged identity claims. A technician account can access the SimpleHelp technician console and, depending on group permissions and deployment, remote support / remote access capabilities.

## Impact Parity
- **Disclosed/claimed maximum impact:** Remote authentication/authorization bypass via forged OIDC token, yielding an authenticated technician session and potential MFA bypass.
- **Reproduced impact from this run:** Full remote API/OIDC authentication bypass on the real SimpleHelp 5.5.15 server. The script obtains a legitimate pending OIDC state from the product API, submits a forged ID token through the genuine `/oidc` callback, and observes `FULLY_AUTHENTICATED` status for the attacker-controlled technician identity.
- **Parity:** `full`
- **Not demonstrated:** Post-auth remote-control actions against managed endpoints were not performed; the reproduced impact stops at a concrete authenticated technician session and technician-console page access.

## Root Cause
The vulnerable SimpleHelp OIDC implementation parses JWT claims from the ID token but does not cryptographically verify the token signature before using those claims for technician authentication. Runtime/class evidence shows that SimpleHelp 5.5.15 includes `utils/oauth/oidc/IDToken.class` and OIDC callback classes, but no `IDTokenVerifier` class. The patched 5.5.16 build adds `utils/oauth/oidc/IDTokenVerifier.class` and related JWKS caching classes, and its callback rejects the same forged token.

The key behavioral difference is:
- **5.5.15 vulnerable:** The forged token reaches `OIDCAuthenticator`, is parsed into an `IDToken`, passes group-authentication logic, registers a new anonymous/group-authenticated technician, and registers a session token.
- **5.5.16 patched:** The same forged token causes the callback to fail closed; the status endpoint remains `UNAUTHENTICATED`.

No public fix commit hash was provided in the ticket because SimpleHelp is a commercial binary distribution; the script anchors the negative control to the vendor fixed 5.5.16 release identified in the advisory.

## Reproduction Steps
1. Run `bundle/repro/reproduction_steps.sh`.
2. The script:
   - Verifies/downloads the official SimpleHelp 5.5.15 and 5.5.16 Linux server tarballs.
   - Extracts clean vulnerable and patched server instances.
   - Initializes each real SimpleHelp server through the first-launch path.
   - Configures a real OIDC authentication provider and a non-admin `Technicians` technician group that allows group-authenticated/OIDC-created logins.
   - Starts a local fake OIDC IdP that returns a JWT with `alg: none` and a bogus signature segment.
   - Requests a real OIDC authorization URL from `https://127.0.0.1/auth/v1/account/oidc_get`, preserving the server-issued `state`.
   - Delivers the forged token through the genuine `https://127.0.0.1/oidc?code=...&state=...` callback.
   - Checks `https://127.0.0.1/auth/v1/account/status` as the post-login authorization proof.
   - Repeats the same flow against patched 5.5.16 as the negative control.
3. Expected evidence:
   - Vulnerable flow: `status_after_body` contains `"state":"FULLY_AUTHENTICATED"` and the forged identity (`Forged Attacker`, `attacker`, `attacker@example.com`).
   - Patched flow: callback contains `Login Failed` and status remains `"state":"UNAUTHENTICATED"`.

## Evidence
Primary evidence files:
- `bundle/logs/reproduction_steps.log` — full script stdout/stderr for the successful run.
- `bundle/logs/vuln_flow.json` — vulnerable HTTP/API/OIDC flow result.
- `bundle/logs/patched_flow.json` — patched negative-control flow result.
- `bundle/logs/vuln_idp.log` — fake IdP requests and the forged ID token returned to the product.
- `bundle/logs/patched_idp.log` — same forged-token IdP interaction for patched version.
- `bundle/logs/vuln_runtime_tail.log` — vulnerable server runtime log excerpts.
- `bundle/logs/patched_runtime_tail.log` — patched server runtime log excerpts.
- `bundle/logs/class_comparison.log` — class-level fix comparison showing `IDTokenVerifier` absent in 5.5.15 and present in 5.5.16.
- `bundle/repro/runtime_manifest.json` — runtime evidence manifest written by the reproduction script.

Key excerpts from the successful run:

```json
// bundle/logs/vuln_flow.json
"status_after_body": "{\"state\":\"FULLY_AUTHENTICATED\",\"user\":{\"uniqueID\":480346,\"displayName\":\"Forged Attacker\",\"username\":\"attacker\",\"emailAddress\":\"attacker@example.com\",\"isOnline\":true},\"code\":1}"
```

```json
// bundle/logs/patched_flow.json
"callback_contains_login_failed": true,
"status_after_body": "{\"state\":\"UNAUTHENTICATED\",\"code\":0}"
```

```text
// bundle/logs/vuln_runtime_tail.log
[OIDCAuthenticator] Received OIDC response (...)
[ProxyServerAuthentication] Group authenticated technician via group 'Technicians'
[ServerConfig] Registering technician login for attacker / (Technicians)
[Server Config] Configuration save requested (Forged Attacker - attacker [(Technicians)] [New Anon])
[ProxyServerAuthentication] Registering session token for Forged Attacker - attacker [(Technicians)] (...)
```

```text
// bundle/logs/class_comparison.log
[*] Vulnerable OIDC classes
     7852 ... utils/oauth/oidc/IDToken.class
     6340 ... com/aem/shelp/proxy/wds/OIDCCallbackManager.class
[*] Patched OIDC classes
     8796 ... utils/oauth/oidc/IDToken.class
      252 ... utils/oauth/oidc/IDTokenVerifier$1.class
     1660 ... utils/oauth/oidc/IDTokenVerifier$CachedJwks.class
    17996 ... utils/oauth/oidc/IDTokenVerifier.class
```

Environment details captured in logs include SimpleHelp server version/build (`5.5.15` build `20260326-092709`, patched `5.5.16` build `20260526-203544`), bundled JRE versions, HTTPS listener startup, and the exact API/callback URLs exercised.

## Recommendations / Next Steps
- Upgrade SimpleHelp servers to 5.5.16 or later, or to the fixed 6.0 release/RC identified by the vendor.
- Ensure OIDC ID tokens are validated using issuer metadata/JWKS before any claims are trusted:
  - Verify the JWT signature.
  - Reject `alg: none` or unsupported algorithms.
  - Validate `iss`, `aud`, `exp`, `iat`, and nonce/state binding.
- Add regression tests that submit unsigned and incorrectly signed ID tokens through the real `/oidc` callback and assert rejection.
- Audit existing SimpleHelp deployments for unexpected group-authenticated/anonymous technician accounts, especially identities created via OIDC.

## Additional Notes
- The script was run successfully twice consecutively after the escaping/configuration fix.
- The reproduction uses the real SimpleHelp server binaries and real HTTPS API/callback paths; the only test double is the OIDC identity provider, which is attacker-controlled by design for this class of vulnerability.
- The script rewrites the IdP redirect host to `127.0.0.1` after preserving the SimpleHelp-issued callback path, `code`, and `state`, because the product derives a public hostname from its local environment. This keeps the callback on the genuine SimpleHelp `/oidc` endpoint while avoiding external DNS/network dependence.
