{"record":{"id":"16c2326bc4241848","repo":"larksuite/cli","slug":"nil-connection","errorCode":null,"errorMessage":"nil connection","messagePattern":"nil connection","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/validate/url.go","lineNumber":549,"sourceCode":"func dialConn(ctx context.Context, dialFn func(context.Context, string, string) (net.Conn, error), network, addr string) (net.Conn, error) {\n\tif dialFn != nil {\n\t\treturn dialFn(ctx, network, addr)\n\t}\n\tvar d net.Dialer\n\treturn d.DialContext(ctx, network, addr)\n}\n\nfunc downloadTargetPolicyError(err error) error {\n\treturn errs.NewSecurityPolicyError(\n\t\terrs.SubtypeAccessDenied,\n\t\t\"blocked download target: %v\",\n\t\terr,\n\t).WithCause(err)\n}\n\nfunc validateConnRemoteIP(conn net.Conn) error {\n\tif conn == nil {\n\t\treturn fmt.Errorf(\"nil connection\")\n\t}\n\traddr := conn.RemoteAddr()\n\tif raddr == nil {\n\t\treturn fmt.Errorf(\"missing remote address\")\n\t}\n\thost, _, err := net.SplitHostPort(raddr.String())\n\tif err != nil {\n\t\thost = raddr.String()\n\t}\n\tip := net.ParseIP(strings.Trim(host, \"[]\"))\n\tif ip == nil {\n\t\treturn fmt.Errorf(\"invalid remote IP\")\n\t}\n\tif isRestrictedDownloadIP(ip) {\n\t\treturn fmt.Errorf(\"local/internal host is not allowed\")\n\t}\n\treturn nil\n}","sourceCodeStart":531,"sourceCodeEnd":567,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/validate/url.go#L531-L567","documentation":"validateConnRemoteIP performs the post-dial SSRF check by inspecting the connection's remote address. It throws this error when the net.Conn handed to it is nil, meaning no connection object exists to validate. This is a defensive guard so the validator never dereferences a nil connection.","triggerScenarios":"The dialing helper returns (nil, nil) or the caller ignores the dial error and passes the nil conn to validateConnRemoteIP — typically from an anonymous wrapper around the dial-and-validate sequence.","commonSituations":"Custom DialContext wrappers that swallow dial errors; refactored dial paths returning a nil conn with a nil error; test doubles returning no connection.","solutions":["Ensure the dial result is checked: if err != nil return err before validating the conn","Never call validateConnRemoteIP with a conn from a failed dial","If wrapping the dialer, propagate the dial error instead of continuing with a nil connection"],"exampleFix":"// before\nconn, _ := dialer.DialContext(ctx, network, addr)\nerr := validateConnRemoteIP(conn) // nil conn\n// after\nconn, err := dialer.DialContext(ctx, network, addr)\nif err != nil {\n    return nil, err\n}\nerr = validateConnRemoteIP(conn)","handlingStrategy":"validation","validationCode":"if conn == nil {\n    return fmt.Errorf(\"dial failed: no connection returned\")\n}\nif err := validateConnRemoteIP(conn); err != nil { return err }","typeGuard":"func dialAndValidate(ctx context.Context, d *net.Dialer, network, addr string) (net.Conn, error) {\n    conn, err := d.DialContext(ctx, network, addr)\n    if err != nil || conn == nil {\n        return nil, fmt.Errorf(\"dial %s: %w\", addr, err)\n    }\n    return conn, validateConnRemoteIP(conn)\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"nil connection\") {\n    return fmt.Errorf(\"dialer returned no connection without an error — fix the custom dialer: %w\", err)\n}","preventionTips":["Always check the dial error before using the connection","Never return (nil, nil) from custom DialContext wrappers","Keep custom dialers thin: propagate conn and err verbatim","Test custom dialers return a non-nil conn on success"],"tags":["network","ssrf","dial","validation"],"backgroundTag":"nil-connection","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}