fix(agent/get.ps1): pin TLS 1.2/1.3 explicitly on both AuthenticateAsClient calls (#961) #32

Merged
amiryahaya merged 1 commit from fix/961-tls-protocol-pin into main 2026-09-23 14:46:39 +02:00
Owner

Fixes the bug behind mirrored triton-repo issue #961 (read-only, from
git.antrapol.tech — not edited/commented/closed there; this PR is the
record).

The bug

Both SslStream.AuthenticateAsClient($RemoteHost) call sites
(Invoke-DownloadFromManageServer, and Invoke-Preflight's TLS
check — the same function fixed for #962) used the single-argument
overload, relying on the OS/.NET default enabled SSL/TLS protocol set.
On a real, hardened Windows Server target this failed outright:

A call to SSPI failed, see inner exception.

Explicitly forcing TLS 1.2 fixed it there.

The fix

Switched both to the 4-argument overload, explicitly requesting
Tls12 | Tls13:

$Ssl.AuthenticateAsClient($RemoteHost, $null,
    ([System.Security.Authentication.SslProtocols]::Tls12 -bor [System.Security.Authentication.SslProtocols]::Tls13),
    $false)
  • Tls12 | Tls13: the customer's verified fix (Tls12), plus Tls13 so
    newer hosts/servers aren't artificially capped.
  • $null client-cert collection, $false revocation-check: match
    what the single-arg overload already defaulted to internally, so
    neither changes behavior beyond the protocol floor.

Testing

Verified empirically, not guessed: a throwaway pwsh script (real
self-signed cert + TcpListener + SslStream, not committed here)
confirms the new call negotiates Tls12 successfully against a
server explicitly restricted to Tls12-only. PowerShell AST parse
clean; PSScriptAnalyzer shows zero new findings in the touched
region. $SCRIPT_VERSION bumped 1.3.10 → 1.3.11.

Found but explicitly out of scope for this PR

The identical vulnerable pattern also exists in:

  • agent/get-airgap.ps1 (this repo) — a read-only reference copy
    per CLAUDE.md, not the actual served artifact.
  • pkg/manageserver/ca/assets/get-airgap.ps1 (triton repo) — the
    real, go:embed'd, genuinely-served air-gapped installer asset
    (#768).

I'm flagging this rather than silently expanding this PR's scope;
whether/how to fix those is a separate decision.

🤖 Generated with Claude Code

Fixes the bug behind mirrored triton-repo issue #961 (read-only, from git.antrapol.tech — not edited/commented/closed there; this PR is the record). ## The bug Both `SslStream.AuthenticateAsClient($RemoteHost)` call sites (`Invoke-DownloadFromManageServer`, and `Invoke-Preflight`'s TLS check — the same function fixed for #962) used the single-argument overload, relying on the OS/.NET default enabled SSL/TLS protocol set. On a real, hardened Windows Server target this failed outright: > A call to SSPI failed, see inner exception. Explicitly forcing TLS 1.2 fixed it there. ## The fix Switched both to the 4-argument overload, explicitly requesting `Tls12 | Tls13`: ```powershell $Ssl.AuthenticateAsClient($RemoteHost, $null, ([System.Security.Authentication.SslProtocols]::Tls12 -bor [System.Security.Authentication.SslProtocols]::Tls13), $false) ``` - `Tls12 | Tls13`: the customer's verified fix (Tls12), plus Tls13 so newer hosts/servers aren't artificially capped. - `$null` client-cert collection, `$false` revocation-check: match what the single-arg overload already defaulted to internally, so neither changes behavior beyond the protocol floor. ## Testing Verified empirically, not guessed: a throwaway `pwsh` script (real self-signed cert + `TcpListener` + `SslStream`, not committed here) confirms the new call negotiates `Tls12` successfully against a server explicitly restricted to Tls12-only. PowerShell AST parse clean; `PSScriptAnalyzer` shows zero new findings in the touched region. `$SCRIPT_VERSION` bumped 1.3.10 → 1.3.11. ## Found but explicitly out of scope for this PR The identical vulnerable pattern also exists in: - `agent/get-airgap.ps1` (this repo) — a **read-only reference copy** per CLAUDE.md, not the actual served artifact. - `pkg/manageserver/ca/assets/get-airgap.ps1` (triton repo) — the **real, go:embed'd, genuinely-served** air-gapped installer asset (#768). I'm flagging this rather than silently expanding this PR's scope; whether/how to fix those is a separate decision. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Both SslStream.AuthenticateAsClient($RemoteHost) call sites
(Invoke-DownloadFromManageServer, and Invoke-Preflight's TLS check)
used the single-argument overload, relying on the OS/.NET default
enabled SSL/TLS protocol set. On a real, hardened Windows Server
target this failed outright: "A call to SSPI failed, see inner
exception." Explicitly forcing TLS 1.2 fixed it there.

Switched both to the 4-argument overload, explicitly requesting
Tls12 | Tls13 (the customer's verified fix, plus 1.3 so newer
hosts/servers aren't artificially capped) — $null client-cert
collection and $false revocation-check match what the single-arg
overload already defaulted to internally, so neither changes
behavior beyond the protocol floor.

Verified empirically (not guessed): a throwaway pwsh script (real
self-signed cert + TcpListener + SslStream) confirms the new call
negotiates Tls12 successfully against a server explicitly restricted
to Tls12-only.

Fixes mirrored issue #961 (read-only, from git.antrapol.tech — not
edited/commented/closed here; this commit message is the record).

Note: the identical vulnerable pattern also exists in
agent/get-airgap.ps1 (this repo, a read-only reference copy per
CLAUDE.md — not the served artifact) and in the actual embedded
air-gapped-installer asset, triton repo's
pkg/manageserver/ca/assets/get-airgap.ps1 (go:embed'd, #768, genuinely
served to customers). Scoping and fixing those is a separate,
to-be-approved follow-up -- flagging here rather than silently
expanding this PR's scope.
Sign in to join this conversation.
No reviewers
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
primatekuntech/triton-install!32
No description provided.