You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
scheduledauth: enforce HTTPS scheme on SCHEDULED_TASK_OIDC_JWKS_URL #66
Spun out of the adversarial review of PR LeanerCloud/cloud-commitments-cli#1231 (SEC-04, hardened HTTP client for JWKS warmup and fetch). Filed separately because the in-scope SEC-04 work was the move from providers/azure/internal/httpclient to pkg/httpclient with IMDS-blocking parity; this is additional hardening on top.
Gap
internal/server/scheduledauth.validateAbsoluteURL accepts any scheme with a non-empty host:
funcvalidateAbsoluteURL(raw, labelstring) error {
u, err:=url.Parse(raw)
iferr!=nil {
returnfmt.Errorf("%w: %s must be an absolute URL: %v", ErrConfigInvalid, label, err)
}
ifu.Scheme==""||u.Host=="" {
returnfmt.Errorf("%w: %s must be an absolute URL", ErrConfigInvalid, label)
}
returnnil
}
So SCHEDULED_TASK_OIDC_JWKS_URL=http://www.googleapis.com/... would pass. JWKS responses sign every inbound JWT in oidc mode; cleartext retrieval is a classic MITM vector.
Fix sketch
In validateAbsoluteURL (or a dedicated validator for the JWKS URL specifically), require u.Scheme == "https". Test that:
http://... is rejected at startup with a clear error
https://... is accepted
An empty value still falls back to GoogleJWKSURL (which is already https)
Reviewed commit: be11bdcb5. Note: origin/main moved to 3e9660d06 during the review; re-verify against current main before changing code, since a finding may have been fixed or moved.
The 2026-07-28 full-repo review re-derived this independently and confirmed it is still present. Two additions: an in-tree precedent that settles the "should we require https" question, and the reachability argument, which suggests severity/medium is understated.
Where
internal/server/scheduledauth/validator.go:217 (validateAbsoluteURL), called from internal/server/scheduledauth/validator.go:145
The codebase already enforces the stricter rule one package over.oidc.SetIssuerURL rejects anything that is not an absolute https URL. So CUDly enforces https on its own issuer URL and not on the URL it fetches trusted verification keys from. That asymmetry is the whole finding, and it means the fix is a copy of an existing validator rather than a new policy decision.
The blast radius is money movement, not just token forgery./api/scheduled/* is the surface that fires purchase executions. If an attacker substitutes the JWKS, go-oidc verifies attacker-signed RS256 tokens as genuine; issuer, audience and subject are all string claims inside a token the attacker now controls, so every remaining check passes. There is no second gate behind the token.
Failure scenario
An operator sets SCHEDULED_TASK_OIDC_JWKS_URL to an http:// endpoint: an internal mirror, a cached copy behind a corporate proxy, or a test double left in place after a staging exercise. An attacker with a network position on that path, or DNS control over the host, serves their own JWKS. Every subsequent /api/scheduled/* call they make is accepted as an authenticated scheduled task, which yields unauthenticated purchase execution.
The failure is silent in both directions: the operator's config looks correct, and nothing in the logs distinguishes a substituted key set from a legitimate one.
Fix direction
As already sketched here: require u.Scheme == "https" in validateAbsoluteURL, with an explicit localhost carve-out if the test suite needs one, matching SetIssuerURL. Given the effort is xs and the outcome is unauthenticated money movement, this looks worth pulling forward from urgency/this-quarter.
Activity
cristim commentedon Jul 28, 2026
Reviewed commit:
be11bdcb5. Note:origin/mainmoved to3e9660d06during the review; re-verify against currentmainbefore changing code, since a finding may have been fixed or moved.The 2026-07-28 full-repo review re-derived this independently and confirmed it is still present. Two additions: an in-tree precedent that settles the "should we require https" question, and the reachability argument, which suggests
severity/mediumis understated.Where
internal/server/scheduledauth/validator.go:217(validateAbsoluteURL), called frominternal/server/scheduledauth/validator.go:145internal/oidc/issuer_cache.go:38(oidc.SetIssuerURL)What the review adds
The codebase already enforces the stricter rule one package over.
oidc.SetIssuerURLrejects anything that is not an absolutehttpsURL. So CUDly enforces https on its own issuer URL and not on the URL it fetches trusted verification keys from. That asymmetry is the whole finding, and it means the fix is a copy of an existing validator rather than a new policy decision.The blast radius is money movement, not just token forgery.
/api/scheduled/*is the surface that fires purchase executions. If an attacker substitutes the JWKS,go-oidcverifies attacker-signed RS256 tokens as genuine; issuer, audience and subject are all string claims inside a token the attacker now controls, so every remaining check passes. There is no second gate behind the token.Failure scenario
An operator sets
SCHEDULED_TASK_OIDC_JWKS_URLto anhttp://endpoint: an internal mirror, a cached copy behind a corporate proxy, or a test double left in place after a staging exercise. An attacker with a network position on that path, or DNS control over the host, serves their own JWKS. Every subsequent/api/scheduled/*call they make is accepted as an authenticated scheduled task, which yields unauthenticated purchase execution.The failure is silent in both directions: the operator's config looks correct, and nothing in the logs distinguishes a substituted key set from a legitimate one.
Fix direction
As already sketched here: require
u.Scheme == "https"invalidateAbsoluteURL, with an explicit localhost carve-out if the test suite needs one, matchingSetIssuerURL. Given the effort isxsand the outcome is unauthenticated money movement, this looks worth pulling forward fromurgency/this-quarter.