JuliusBrussee/caveman · error
githubapp: request path must be a single-host absolute path
Error message
githubapp: request path must be a single-host absolute path
What it means
SSRF guard in do(): the request path must be a single-host absolute path — it must start with exactly one '/', contain no backslashes, and not start with '//'. This blocks protocol-relative URLs, UNC-style escapes, and other path shapes that could redirect the request off the configured GitHub host.
Source
Thrown at shared/platform/githubapp/githubapp.go:350
return nil, fmt.Errorf("githubapp: decode repository proof content: %w", err)
}
if len(decoded) > 64<<10 || int64(len(decoded)) != payload.Size {
return nil, fmt.Errorf("githubapp: repository proof size mismatch")
}
return decoded, nil
}
// DoToken issues an authenticated GitHub REST call with an installation token and
// returns the status + raw body for the caller to parse. It is the reusable
// primitive the worker's PR opener builds the Git Data API flow on, so every
// GitHub egress goes through the one SSRF-guarded client + fixed base host.
func (a *App) DoToken(ctx context.Context, token, method, path string, body any) (int, []byte, error) {
return a.do(ctx, "Bearer "+token, method, path, body)
}
func (a *App) do(ctx context.Context, authorization, method, path string, body any) (int, []byte, error) {
if !strings.HasPrefix(path, "/") || strings.HasPrefix(path, "//") || strings.Contains(path, "\\") {
return 0, nil, fmt.Errorf("githubapp: request path must be a single-host absolute path")
}
base, err := url.Parse(a.baseURL)
if err != nil || base.Scheme == "" || base.Host == "" || base.User != nil {
return 0, nil, fmt.Errorf("githubapp: invalid base URL")
}
relative, err := url.ParseRequestURI(path)
if err != nil || relative.IsAbs() || relative.Host != "" || relative.User != nil {
return 0, nil, fmt.Errorf("githubapp: invalid request path")
}
target, err := url.Parse(a.baseURL + path)
if err != nil || target.Scheme != base.Scheme || !strings.EqualFold(target.Host, base.Host) || target.User != nil {
return 0, nil, fmt.Errorf("githubapp: request path escaped configured host")
}
var reader io.Reader
if body != nil {
b, err := json.Marshal(body)
if err != nil {
return 0, nil, fmt.Errorf("githubapp: marshal request: %w", err)View on GitHub (pinned to 766dce6b13)
Solutions
- Pass plain absolute API paths like /repos/owner/name; never full URLs or paths beginning with '//'
- Strip backslashes and normalize the path before calling the API layer
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at shared/platform/githubapp/githubapp.go:350 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18).
Data as JSON: /api/errors/71101d88666da324.
Report an issue: GitHub.