Tencent/WeKnora · error
unsafe S3 endpoint: %w
Error message
unsafe S3 endpoint: %w
What it means
newS3Client runs utils.ValidateURLForSSRF on the configured S3 endpoint before creating the SDK client. This error means the endpoint URL failed SSRF validation — typically a private/loopback/link-local IP, a disallowed scheme, or a non-URL value. WeKnora refuses to build an S3 client against endpoints that could be used for server-side request forgery.
Source
Thrown at internal/application/service/file/s3.go:35
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/google/uuid"
)
// s3FileService AWS S3 file service implementation
type s3FileService struct {
client *s3.Client
bucketName string
pathPrefix string
}
// newS3Client creates a bare s3FileService with just the SDK client initialised.
func newS3Client(endpoint, accessKey, secretKey, bucketName, region, pathPrefix string, forcePathStyle bool) (*s3FileService, error) {
if err := utils.ValidateURLForSSRF(endpoint); err != nil {
return nil, fmt.Errorf("unsafe S3 endpoint: %w", err)
}
var cfg aws.Config
var err error
// With no explicit AK/SK, keep the AWS default credential chain intact. This
// supports IAM roles for EC2/ECS/EKS (IRSA), web identity, shared config, and
// environment credentials without persisting long-lived keys in WeKnora.
loadOptions := []func(*config.LoadOptions) error{config.WithRegion(region)}
if accessKey != "" || secretKey != "" {
if accessKey == "" || secretKey == "" {
return nil, fmt.Errorf("S3 access key and secret key must be provided together")
}
loadOptions = append(loadOptions, config.WithCredentialsProvider(
credentials.NewStaticCredentialsProvider(accessKey, secretKey, ""),
))
}
cfg, err = config.LoadDefaultConfig(context.Background(), loadOptions...)
View on GitHub (pinned to 988cbb0330)
Solutions
- Use a publicly resolvable https endpoint, or the internal address is blocked — deploy with an allowed DNS name/IP
- If internal S3-compatible storage is intentional, adjust utils.ValidateURLForSSRF allowlist configuration
- Check the endpoint value for typos and include the http(s):// scheme
- Ensure the endpoint is not accidentally set to metadata or proxy addresses
Example fix
// before
svc, err := NewS3FileService("http://127.0.0.1:9000", ak, sk, bucket, region, prefix) // SSRF check fails
// after
svc, err := NewS3FileService("https://s3.example.com", ak, sk, bucket, region, prefix) Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(endpoint)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") { return errors.New("endpoint must be an absolute http(s) URL") }
if err := utils.ValidateURLForSSRF(endpoint); err != nil { return err } Type guard
func isPublicEndpoint(endpoint string) bool {
return utils.ValidateURLForSSRF(endpoint) == nil
} Prevention
- Pre-configure vetted endpoints instead of accepting user-supplied URLs
- Validate endpoints at config load time, not client construction time
- Avoid localhost/link-local/metadata addresses in storage config
- Document the SSRF allowlist for teams needing internal MinIO
When it happens
Trigger: Configuring file storage with an endpoint like http://127.0.0.1:9000, http://169.254.169.254, localhost, an internal 10.x/192.168.x address, or a scheme other than http/https in newS3Client (used by NewS3FileService and connectivity checks).
Common situations: Local MinIO/MinIO-style development setups using localhost endpoints, container-internal hostnames resolving to private IPs, typos in the endpoint URL, environments that intentionally allow internal S3-compatible stores but have not widened the SSRF allowlist.
Related errors
- unsafe OSS endpoint: %w
- unsafe MinIO endpoint: %w
- S3 access key and secret key must be provided together
- failed to load AWS config: %w
- unsafe TOS endpoint: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/9a4ea9f2149ef97f.
Report an issue: GitHub.