{"record":{"id":"757db5bb921c743b","repo":"Tencent/WeKnora","slug":"s","errorCode":null,"errorMessage":"%s","messagePattern":"%s","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/utils/inject.go","lineNumber":859,"sourceCode":"\t\t}\n\t}\n\n\treturn result, validationResult\n}\n\n// ValidateAndSecureSQL validates SQL and returns a secured version with tenant isolation\n// This is a convenience function that combines validation and SQL rewriting\nfunc ValidateAndSecureSQL(sql string, opts ...SQLValidationOption) (string, *SQLValidationResult, error) {\n\t// Parse and validate\n\t_, validationResult := ValidateSQL(sql, opts...)\n\n\t// If validation failed, return error\n\tif !validationResult.Valid {\n\t\terrMsg := \"SQL validation failed\"\n\t\tif len(validationResult.Errors) > 0 {\n\t\t\terrMsg = validationResult.Errors[0].Message\n\t\t}\n\t\treturn \"\", validationResult, fmt.Errorf(\"%s\", errMsg)\n\t}\n\n\t// Find validator config to check if tenant injection is enabled\n\tvalidator := &sqlValidator{\n\t\ttablesWithTenantID:  make(map[string]bool),\n\t\ttablesWithDeletedAt: make(map[string]bool),\n\t}\n\tfor _, opt := range opts {\n\t\topt(validator)\n\t}\n\n\t// If no SQL rewriting is enabled, return original SQL\n\tif !validator.enableTenantInjection && !validator.enableSoftDeleteInjection && !validator.enableHiddenKBFilter &&\n\t\t!validator.enableChunkEnabledFilter && !validator.enableSearchScopeFilter {\n\t\treturn sql, validationResult, nil\n\t}\n\n\t// Parse again to get normalized SQL","sourceCodeStart":841,"sourceCodeEnd":877,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/utils/inject.go#L841-L877","documentation":"ValidateAndSecureSQL validates a SQL string and, if the validation result is invalid, returns an error whose message is the first SQLValidationError's Message (or the generic 'SQL validation failed'). The library throws this because it refuses to secure or return SQL that failed its policy checks (not SELECT, disallowed tables, injection risk, multiple statements, etc.). The returned *SQLValidationResult contains the full Errors list for diagnosis.","triggerScenarios":"Calling ValidateAndSecureSQL with SQL that fails any validation phase: input contains a null byte, is too short/long, is not a single SELECT statement, references a table not in allowedTables, or matches injection-risk patterns in the WHERE clause.","commonSituations":"Developers passing user-supplied or dynamically built SQL that uses non-SELECT statements; forgetting to register a table via WithAllowedTables; queries with suspicious string concatenation in WHERE clauses; accidentally passing empty or truncated SQL.","solutions":["Inspect the returned validationResult.Errors[0] (Type and Details) to see which phase failed","Ensure the query is a single SELECT statement over tables registered via WithAllowedTables","If you control the query construction, fix the SQL itself rather than bypassing validation","If validation is too strict for a legitimate query, adjust the relevant options (e.g. disable checkInjectionRisk) knowingly"],"exampleFix":"// before\nsecured, res, err := utils.ValidateAndSecureSQL(userSQL)\nif err != nil { return err }\n// after\nsecured, res, err := utils.ValidateAndSecureSQL(userSQL,\n    utils.WithAllowedTables([]string{\"knowledge_bases\", \"documents\"}))\nif err != nil {\n    for _, e := range res.Errors {\n        log.Printf(\"SQL rejected [%s]: %s (%s)\", e.Type, e.Message, e.Details)\n    }\n    return fmt.Errorf(\"query rejected: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"func preCheck(sql string) error {\n    t := strings.TrimSpace(sql)\n    if t == \"\" || !strings.HasPrefix(strings.ToUpper(t), \"SELECT\") {\n        return fmt.Errorf(\"only single SELECT statements are supported\")\n    }\n    if strings.ContainsAny(sql, \";\\x00\") {\n        return fmt.Errorf(\"multiple statements or invalid characters\")\n    }\n    return nil\n}","typeGuard":"func hasValidationErrors(res *utils.SQLValidationResult) bool {\n    return res != nil && len(res.Errors) > 0\n}","tryCatchPattern":"secured, res, err := utils.ValidateAndSecureSQL(sql)\nif err != nil {\n    if hasValidationErrors(res) {\n        return fmt.Errorf(\"query rejected (%s): %s\",\n            res.Errors[0].Type, res.Errors[0].Details)\n    }\n    return err\n}","preventionTips":["Always log the full validationResult.Errors list, not just err","Whitelist tables explicitly with WithAllowedTables","Generate only parameterized single-statement SELECTs from application code","Pre-check that the SQL starts with SELECT before calling"],"tags":["sql","validation","security"],"backgroundTag":"sql-validation-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}