Fix #237: SSRF allowlist bypass + anon dangerous #241
No reviewers
Labels
No labels
actions
bug
cli
duplicate
enhancement
fork
forum
git storage
help wanted
insights
invalid
issues
moderation
oidc
ownership transfer
packages
pr/merge protection rules
projects
pull requests
question
releases
sponsorships
tags
webhooks
wiki
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crueber/walhub!241
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/issue-237"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #237. LIVE SECURITY BYPASS fix, fail-closed throughout.
What was wrong
NormalizeSourcederived the allowlist-compared host withu.Hostname()(port-stripping) but kept the full raw URL (u.String(), port/case/slashes intact) as the clone target: the checked string and the fetched string diverged.:443, uppercase host, trailing/,.git/, and plaintext-http variants of an allowlisted host all passed the gate.dangerous:trueflowed straight from the request body intoSSRFConfig. Under auth-none the caller presents asauth.None()(Admin:true, unauthenticated), so any network caller could arm the empty-allowlist escape hatch.Fix
url.go: every non-GitHub source is rebuilt as one canonicalscheme://host/path(lowercased host, default ports stripped, trailing slashes + one.gitfolded; explicit non-default ports refused 400). The allowlist compares the canonical host;CloneMirrorreceives exactly the gated string.http://without token stays allowed (§1 scope stands); token still requireshttps; allowlist is host-only and the scheme is part of the canonical identity.service.goBegin:dangerous:truehonored only for authenticated admins underserver.auth.modetoken/oidc (403 otherwise, namingwalhub import --dangerous); auth-none is CLI-only; anonymous still 401s via the unchanged S6 order. CLI--dangerous(headless runner) unaffected.normalizeSourceis prefill-only by documented contract; the server is the source of truth.Tests (all in
internal/repoimport/issue237_test.go, no network)Verification
gofmt/ clean;go test -racefull package green; single-flight stress-count=20green; coverage 95.8% (≥95% gate holds; touched fns: NormalizeSource 96.8%, isDefaultPort/CheckSSRF/dangerousAllowed/canonicalGenericURL 100%).### Concurrencysubsections in code + doc entries: no new goroutines/locks/channels (pure predicates).Do NOT merge (per task).