T09 · Insecure Skill Coding Practices
Error
- Location
- main.go:63
- Finding
- Server-Side Request Forgery Through Insufficient URL and Redirect Validation<![CDATA[ ## Vulnerability Details **File Location**: `main.go:63-66`, `main.go:112-116`, `main.go:205-214`, `main.go:349` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```go postURL := os.Args[1] printBanner() if !strings.Contains(postURL, "linkedin.com") { printError("The URL does not appear to be from LinkedIn") os.Exit(1) } ``` ```go client := &http.Client{ Timeout: 30 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error { req.Header.Set("User-Agent", userAgent) return nil }, } ``` ```go // Pattern 5: contentUrl in JSON-LD contentURLPattern := regexp.MustCompile(`"contentUrl"\s*:\s*"(https?://[^"]+)"`) for _, match := range contentURLPattern.FindAllStringSubmatch(html, -1) { if len(match) > 1 { cleaned := cleanURL(match[1]) if cleaned != "" && !seen[cleaned] { seen[cleaned] = true urls = append(urls, cleaned) } } } ``` ```go resp, err := client.Do(req) ``` ### Technical Analysis The application attempts to restrict input to LinkedIn by checking whether the raw argument contains the substring `linkedin.com`. This is not a valid origin check. An arbitrary URL can satisfy the condition by placing that text in its path, query string, user-information component, or attacker-controlled hostname. For example, `http://127.0.0.1:8080/?linkedin.com` passes the check while directing the HTTP request to localhost. The page-fetching client also follows redirects without validating the destination. Consequently, even a genuinely permitted origin could redirect the client to a private or otherwise prohibited address. The extracted media URL is also insufficiently constrained. In particular, the JSON-LD `contentUrl` pattern accepts any HTTP or HTTPS origin. `cleanURL` only checks whether Go can parse the value; it does not enforce an approved hostname, scheme policy beyond the regular expression, or destination IP policy. The resulting URL is subsequently req ...[truncated 1549 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse the supplied post URL with `url.ParseRequestURI` before any network operation. 2. Require an explicit `https` scheme and reject URLs containing user information. 3. Compare normalized hostnames against an exact allowlist, such as `www.linkedin.com`, rather than using substring matching. 4. Validate every redirect target in `CheckRedirect`; reject redirects outside the approved LinkedIn origins and impose a maximum redirect count. 5. Validate every extracted media URL against a separate, explicit CDN allowlist, such as the exact expected host or carefully implemented `licdn.com` subdomains. 6. Resolve destination hostnames and reject loopback, private, link-local, multicast, unspecified, and reserved IP ranges for every resolved address. 7. Protect against DNS rebinding by ensuring that the validated address is the address used for the connection, or by applying equivalent checks in a custom transport dialer. 8. Do not accept arbitrary JSON-LD `contentUrl` origins merely because they were present in fetched HTML. ]]>
