From vmkteam-developer
Provides security checklist for vmkteam Go services using go-pg, zenrpc, JSON-RPC API, auth middleware. Covers SQL injection, IDOR, vuln scanning with gosec, govulncheck, gitleaks for code reviews and development.
npx claudepluginhub vmkteam/claude-plugins --plugin vmkteam-developerThis skill uses the workspace's default tool permissions.
Справочник по безопасности для vmkteam-стека: JSON-RPC API, go-pg, zenrpc, auth middleware. Используется автоматически при code review (/go-review) и разработке (/solve).
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
Справочник по безопасности для vmkteam-стека: JSON-RPC API, go-pg, zenrpc, auth middleware. Используется автоматически при code review (/go-review) и разработке (/solve).
| Инструмент | Что ищет | Команда |
|---|---|---|
gosec | SQL injection, hardcoded credentials, weak crypto, command injection | gosec ./... |
govulncheck | Уязвимости в зависимостях (только реально используемые функции) | govulncheck ./... |
gitleaks | API keys, tokens, passwords в коде и git-истории | gitleaks detect --source . |
trivy | Уязвимости в Docker-образах | CI only |
Главная точка риска — _repo_ext.go (кастомные запросы).
Плохо — пользовательский ввод в raw SQL:
// УЯЗВИМО: searchText попадает в SQL напрямую
func (r OrderRepo) SearchOrders(ctx context.Context, searchText string) ([]Order, error) {
var orders []Order
_, err := r.db.Query(&orders,
"SELECT * FROM orders WHERE title LIKE '%"+searchText+"%'", nil)
return orders, err
}
Хорошо — параметризованный запрос через go-pg:
func (r OrderRepo) SearchOrders(ctx context.Context, searchText string) ([]Order, error) {
var orders []Order
err := r.db.Model(&orders).
Where("title ILIKE ?", "%"+searchText+"%").
Select()
return orders, err
}
Хорошо — если нужен raw SQL, использовать pg.SafeQuery:
q := r.db.Model(&orders)
q = q.Where("? ILIKE ?", pg.Ident("title"), "%"+searchText+"%")
Правило: go-pg ORM экранирует автоматически. Опасность только в Query() с конкатенацией строк.
Middleware проверяет аутентификацию (есть ли валидный токен), но не авторизацию (может ли этот пользователь делать это действие).
Плохо — middleware пропустил, но метод не проверяет ownership:
func (s OrderService) GetByID(ctx context.Context, id int) (*Order, error) {
// Любой авторизованный пользователь может получить любой заказ
return s.repo.OrderByID(ctx, id)
}
Хорошо — проверка ownership:
func (s OrderService) GetByID(ctx context.Context, id int) (*Order, error) {
user := UserFromContext(ctx)
order, err := s.repo.OrderByID(ctx, id)
if err != nil {
return nil, InternalError(err)
}
if order == nil {
return nil, ErrNotFound
}
if order.UserID != user.ID {
return nil, ErrForbidden
}
return NewOrder(order), nil
}
В server.go middleware пропускает определённые методы без авторизации. Whitelist должен быть минимальным:
// Только auth.Login не требует токен
if ns == NSAuth && method == RPC.AuthService.Login {
return h(ctx, method, params)
}
Плохо — внутренняя ошибка утекает клиенту:
// zenrpc.NewError передаёт err.Error() клиенту в data
return nil, zenrpc.NewError(500, err)
// Клиент увидит: {"error":{"code":500,"message":"pq: relation \"orders\" does not exist"}}
Хорошо — generic message клиенту, детали в Sentry:
// zenrpc.NewStringError — клиент видит только message
return nil, zenrpc.NewStringError(500, "internal error")
// Клиент увидит: {"error":{"code":500,"message":"internal error"}}
// Настоящая ошибка уйдёт в Sentry через WithSentry middleware
Хелпер — err в Sentry, generic клиенту:
func newInternalError(err error) *zenrpc.Error {
return zenrpc.NewError(500, err)
// WithErrorSLog middleware залогирует и отправит в Sentry
// Клиент получит code=500 без деталей
}
zenrpc-middleware (WithSLog, WithAPILogger) логирует параметры запросов. Если метод принимает пароль — он попадёт в логи.
Решение: не передавать секреты как RPC-параметры, или фильтровать в middleware.
/rpc/) — стандартные WAF-правила для REST не работаютAllowOrigins: []string{"*"} допустим в dev, но в production ограничивать доменами| Категория | Проверить |
|---|---|
| SQL | Нет конкатенации строк в _repo_ext.go |
| Auth | Whitelist методов минимальный |
| Authz | Проверка ownership/прав внутри методов (не только middleware) |
| Validation | Все входы через go-playground/validator, max длины строк |
| Errors | NewStringError для клиента, NewError только через middleware |
| Logging | Пароли/токены не в параметрах логируемых методов |
| Secrets | cfg/local.toml в .gitignore, нет hardcoded credentials |
| CORS | Ограничен в production |