{"record":{"id":"10e0589a6dbd693d","repo":"JuliusBrussee/caveman","slug":"githubapp-base-url-rejected-by-ssrf-guard-w","errorCode":null,"errorMessage":"githubapp: base_url rejected by SSRF guard: %w","messagePattern":"githubapp: base_url rejected by SSRF guard: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/githubapp/githubapp.go","lineNumber":89,"sourceCode":"\tif len(cfg.PrivateKeyPEM) == 0 {\n\t\treturn nil, fmt.Errorf(\"githubapp: private key PEM is required\")\n\t}\n\tkey, err := parseRSAPrivateKey(cfg.PrivateKeyPEM)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbase := strings.TrimRight(strings.TrimSpace(cfg.BaseURL), \"/\")\n\tif base == \"\" {\n\t\tbase = defaultBaseURL\n\t}\n\tclient := cfg.HTTPClient\n\tif client == nil {\n\t\t// Production path: SSRF-guarded client + pre-flight host check on a custom\n\t\t// (GHE) base. When a caller injects a client (tests), it owns the host policy,\n\t\t// so we skip the pre-flight — but production never injects one.\n\t\tif base != defaultBaseURL {\n\t\t\tif err := ssrf.ValidateURL(context.Background(), base, ssrf.ManagedConfig()); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"githubapp: base_url rejected by SSRF guard: %w\", err)\n\t\t\t}\n\t\t}\n\t\tclient = ssrf.NewHTTPClient(ssrf.ManagedConfig())\n\t\tclient.Timeout = 20 * time.Second\n\t}\n\treturn &App{\n\t\tappID:         strings.TrimSpace(cfg.AppID),\n\t\tslug:          strings.TrimSpace(cfg.AppSlug),\n\t\tprivateKey:    key,\n\t\twebhookSecret: cfg.WebhookSecret,\n\t\tbaseURL:       base,\n\t\thttpClient:    client,\n\t}, nil\n}\n\n// Slug returns the App slug used to build the install URL.\nfunc (a *App) Slug() string { return a.slug }\n","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/shared/platform/githubapp/githubapp.go#L71-L107","documentation":"Fires in githubapp.New() when the configured base URL is rejected by the SSRF guard's pre-flight host check — the caller supplied a custom (GHE) base URL whose host is not an allowed GitHub endpoint. This prevents redirecting App credentials to attacker-controlled hosts.","triggerScenarios":"Thrown at shared/platform/githubapp/githubapp.go:89 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Use the standard https://api.github.com base or a legitimate GitHub Enterprise Server host allowed by the SSRF policy","Correct typos or schemes in BaseURL (must be a proper https URL) and re-check the allowlist configuration"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}