Tencent/WeKnora · error

unsafe OSS endpoint: %w

Error message

unsafe OSS endpoint: %w

What it means

newOSSClient runs utils.ValidateURLForSSRF on the endpoint before building the Aliyun OSS client; if the endpoint URL fails the SSRF safety validation (e.g. points at localhost, private/link-local IPs, or is not a valid http(s) URL) the client is not created and this error wraps the validation failure. It is a deliberate security guard, not a connectivity failure.

Source

Thrown at internal/application/service/file/oss.go:38

	"github.com/google/uuid"
)

// ossFileService implements the FileService interface for Aliyun OSS
// using the official Aliyun OSS SDK v2 (github.com/aliyun/alibabacloud-oss-go-sdk-v2).
type ossFileService struct {
	client         *oss.Client
	tempClient     *oss.Client
	pathPrefix     string
	bucketName     string
	tempBucketName string
}

const ossScheme = "oss://"

// newOSSClient creates an OSS client using the official Aliyun SDK v2.
func newOSSClient(endpoint, region, accessKey, secretKey string) (*oss.Client, error) {
	if err := utils.ValidateURLForSSRF(endpoint); err != nil {
		return nil, fmt.Errorf("unsafe OSS endpoint: %w", err)
	}
	creds := credentials.NewStaticCredentialsProvider(accessKey, secretKey, "")

	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(creds).
		WithRegion(region).
		WithEndpoint(endpoint).
		WithHttpClient(utils.NewSSRFSafeHTTPClient(utils.DefaultSSRFSafeHTTPClientConfig()))

	return oss.NewClient(cfg), nil
}

// ossEnsureBucket checks if the bucket exists and creates it if missing.
func ossEnsureBucket(client *oss.Client, bucketName string) error {
	exists, err := client.IsBucketExist(context.Background(), bucketName)
	if err != nil {
		return fmt.Errorf("failed to check OSS bucket: %w", err)
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Set the endpoint to the official public OSS endpoint (e.g. https://oss-cn-hangzhou.aliyuncs.com) over https
  2. If a private/internal endpoint is genuinely required, use the officially allowed internal endpoint form so the SSRF validator accepts it (not raw loopback/link-local IPs)
  3. Fix env/config: ensure OSS_ENDPOINT is a valid absolute http(s) URL with hostname, not an IP or bare hostname like 'localhost'
  4. If the check wrongly rejects a legitimate endpoint, update utils.ValidateURLForSSRF's allowlist rather than bypassing validation

Example fix

// before
client, err := newOSSClient("http://127.0.0.1:9000", region, ak, sk) // rejected: unsafe OSS endpoint
// after
client, err := newOSSClient("https://oss-cn-hangzhou.aliyuncs.com", region, ak, sk)
Defensive patterns

Strategy: validation

Validate before calling

endpoint := os.Getenv("OSS_ENDPOINT")
u, err := url.Parse(endpoint)
if err != nil || (u.Scheme != "https" && u.Scheme != "http") || u.Host == "" {
    return fmt.Errorf("OSS_ENDPOINT must be an absolute http(s) URL, got %q", endpoint)
}
host := u.Hostname()
if host == "localhost" || net.ParseIP(host) != nil {
    return fmt.Errorf("OSS_ENDPOINT must not be loopback/raw IP: %q", endpoint)
}

Try / catch

client, err := newOSSClient(endpoint, region, ak, sk)
if err != nil {
    return fmt.Errorf("refusing to start with endpoint %q (SSRF check): %w", endpoint, err)
}

Prevention

When it happens

Trigger: Constructing an OSS client (via NewOssFileServiceWithTempBucket, CheckOssConnectivity, or config init) with endpoint set to http://127.0.0.1:9000, http://localhost, 169.254.x.x metadata addresses, or a non-URL string.

Common situations: Local MinIO/OSS-emulator endpoints in dev configs that pass a deploy-time SSRF check; user-supplied endpoint from a request or DB row; env var typos (OSS_ENDPOINT=127.0.0.1); unit tests explicitly asserting unsafe endpoints are rejected.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/c890cb23724f4f9e. Report an issue: GitHub.