WeKnora has Unauthorized Cross‑Tenant Knowledge Base Cloning
Medium5.9CVE-2026-30857 · Published Mar 6, 2026 · updated Mar 23, 2026
### Summary A cross-tenant authorization bypass in the knowledge base copy endpoint allows any authenticated user to clone (duplicate) another tenant’s knowledge base into their own tenant by knowing/guessing the source knowledge base ID. This enables bulk data exfiltration (document/FAQ content) across tenants, making the impact critical. ### Details The `POST /api/v1/knowledge-bases/copy` endpoint enqueues an asynchronous KB clone task using the caller-supplied `source_id` without verifying ownership (see `internal/handler/knowledgebase.go`). ```go // Create KB clone payload payload := types.KBClonePayload{ TenantID: tenantID.(uint64), TaskID: taskID, SourceID: req.SourceID, // from attacker's input TargetID: req.TargetID, } payloadBytes, err := json.Marshal(payload) if err != nil { logger.Errorf(ctx, "Failed to marshal KB clone payload: %v", err) c.Error(errors.NewInternalServerError("Failed to create task")) return } // Enqueue KB clone task to Asynq task := asynq.NewTask(types.TypeKBClone, payloadBytes, asynq.TaskID(taskID), asynq.Queue("default"), asynq.MaxRetry(3)) // enqueue task info, err := h.asynqClient.Enqueue(task) if err != nil { logger.Errorf(ct...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| github.com/Tencent/WeKnora Go | < 0.3.0 | 0.3.0 |
Details and references
### Summary A cross-tenant authorization bypass in the knowledge base copy endpoint allows any authenticated user to clone (duplicate) another tenant’s knowledge base into their own tenant by knowing/guessing the source knowledge base ID. This enables bulk data exfiltration (document/FAQ content) across tenants, making the impact critical. ### Details The `POST /api/v1/knowledge-bases/copy` endpoint enqueues an asynchronous KB clone task using the caller-supplied `source_id` without verifying ownership (see `internal/handler/knowledgebase.go`). ```go // Create KB clone payload payload := types.KBClonePayload{ TenantID: tenantID.(uint64), TaskID: taskID, SourceID: req.SourceID, // from attacker's input TargetID: req.TargetID, } payloadBytes, err := json.Marshal(payload) if err != nil { logger.Errorf(ctx, "Failed to marshal KB clone payload: %v", err) c.Error(errors.NewInternalServerError("Failed to create task")) return } // Enqueue KB clone task to Asynq task := asynq.NewTask(types.TypeKBClone, payloadBytes, asynq.TaskID(taskID), asynq.Queue("default"), asynq.MaxRetry(3)) // enqueue task info, err := h.asynqClient.Enqueue(task) if err != nil { logger.Errorf(ctx, "Failed to enqueue KB clone task: %v", err) c.Error(errors.NewInternalServerError("Failed to enqueue task")) return } ``` Then, the asynq task handler (`ProcessKBClone`) invokes the `CopyKnowledgeBase` service method to perform the clone operation (see `internal/application/service/knowledge.go`): ```go // Get source and target knowledge bases srcKB, dstKB, err := s.kbService.CopyKnowledgeBase(ctx, payload.SourceID, payload.TargetID) if err != nil { logger.Errorf(ctx, "Failed to copy knowledge base: %v", err) handleError(progress, err, "Failed to copy knowledge base configuration") return err } ``` After that, the `CopyKnowledgeBase` method calls the repository method to load the source knowledge base (see `internal/application/service/knowledgebase.go`): ```go func (s *knowledgeBaseService) CopyKnowledgeBase(ctx context.Context, srcKB string, dstKB string, ) (*types.KnowledgeBase, *types.KnowledgeBase, error) { sourceKB, err := s.repo.GetKnowledgeBaseByID(ctx, srcKB) if err != nil { logger.Errorf(ctx, "Get source knowledge base failed: %v", err) return nil, nil, err } sourceKB.EnsureDefaults() tenantID := ctx.Value(types.TenantIDContextKey).(uint64) var targetKB *types.KnowledgeBase if dstKB != "" { targetKB, err = s.repo.GetKnowledgeBaseByID(ctx, dstKB) // ... } // ... } ``` > Note: until now, the tenant ID is correctly set in context to the attacker’s tenant (from the payload), which can be used to prevent cross-tenant access. However, the repository method `GetKnowledgeBaseByID` loads knowledge bases by `id` only, allowing cross-tenant reads (see `internal/application/repository/knowledgebase.go`). ```go func (r *knowledgeBaseRepository) GetKnowledgeBaseByID(ctx context.Context, id string) (*types.KnowledgeBase, error) { var kb types.KnowledgeBase if err := r.db.WithContext(ctx).Where("id = ?", id).First(&kb).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrKnowledgeBaseNotFound } return nil, err } return &kb, nil } ``` The data access layer fails to enforce tenant isolation because `GetKnowledgeBaseByID` only filters by ID and ignores the `tenant_id` present in the context. A secure implementation should enforce a tenant-scoped lookup (e.g., `WHERE id = ? AND tenant_id = ?`) or use a tenant-aware repository API to prevent cross-tenant access. Service shallow-copies the KB configuration by calling `GetKnowledgeBaseByID(ctx, srcKB)` for the source KB, then creates a new KB under the attacker’s tenant while copying fields from the victim KB (`internal/application/service/knowledgebase.go`): ```go sourceKB, err := s.repo.GetKnowledgeBaseByID(ctx, srcKB) // not tenant-scoped ... targetKB = &types.KnowledgeBase{ ID: uuid.New().
- CVSS 3.1
- CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
- Severity from
- GitHub (reviewed advisory)
- Weakness
- CWE-639
- Also known as
- CVE-2026-30857, GO-2026-4640
More WeKnora advisories
All WeKnora| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| Mar 6 | WeKnora Vulnerable to Remote Code Execution via SQL Injection Bypass in AI Database Query Tool | Critical10.0 | 0.2.12 |
| Mar 6 | WeKnora has Broken Access Control - Cross-Tenant Data Exposure | High7.5 | 0.2.12 |
| Mar 6 | WeKnora has DNS Rebinding Vulnerability in web_fetch Tool that Allows SSRF to Internal Resources | High7.5 | 0.3.0 |
| Mar 6 | WeKnora: attacker could redirect LLM execution flow | Medium5.4 | 0.3.0 |
| Mar 6 | WeKnora Vulnerable to Broken Access Control in Tenant Management | Critical9.8 | 0.3.2 |
| Mar 5 | WeKnora is Vulnerable to SSRF via Redirection | Medium5.9 | 0.2.12 |