juanfont/headscale · warning · HTTPError

ErrSSHAuthSessionNotBound

ErrSSHAuthSessionNotBound

Error message

auth session is not for SSH check

What it means

Returned when the cached auth entry referenced by auth_id exists but is not an SSH check session (IsSSHCheck() false). The auth cache is shared by registration and SSH check flows; this guard ensures a follow-up URL only consumes sessions of the right kind, preventing cross-flow confusion.

Source

Thrown at hscontrol/noise.go:625

			)
		}

		return nil, NewHTTPError(
			http.StatusBadRequest,
			"Invalid auth_id",
			fmt.Errorf("%w: %s", ErrNoAuthSession, authID),
		)
	}

	// Verify the cached binding matches the (src, dst) pair the
	// follow-up URL claims. Without this check an attacker who knew an
	// auth_id could submit a follow-up for any other (src, dst) pair
	// and have its verdict recorded against that pair instead.
	if !auth.IsSSHCheck() {
		return nil, NewHTTPError(
			http.StatusBadRequest,
			"auth session is not for SSH check",
			fmt.Errorf("%w: %s", ErrSSHAuthSessionNotBound, authID),
		)
	}

	binding := auth.SSHCheckBinding()
	if binding.SrcNodeID != srcNodeID || binding.DstNodeID != dstNodeID {
		return nil, NewHTTPError(
			http.StatusUnauthorized,
			"src/dst pair does not match auth session",
			fmt.Errorf(
				"%w: cached %d->%d, request %d->%d",
				ErrSSHBindingMismatch,
				binding.SrcNodeID, binding.DstNodeID,
				srcNodeID, dstNodeID,
			),
		)
	}

	reqLog.Trace().Caller().Msg("SSH action follow-up")

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Confirm the auth_id in the URL is the one issued for this SSH check, not a registration auth_id
  2. Restart the SSH session to obtain a fresh, correctly-bound auth_id
  3. If writing clients, keep auth IDs strictly scoped to the flow that created them
Defensive patterns

Strategy: type-guard

Type guard

func isSSHCheckSession(a types.AuthRequest) bool {
    return a.IsSSHCheck()
}

Prevention

When it happens

Trigger: Using an auth_id issued for a different purpose (e.g. node registration) against the /machine/ssh/action follow-up endpoint.

Common situations: Client bugs mixing up auth IDs between flows; manual experimentation with URLs; extremely unlikely organically since IDs are random and single-purpose.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/870b8cee1b71e50d. Report an issue: GitHub.