Relica is currently in beta. We provide security updates for the following versions:
| Version | Supported |
|---|---|
| 0.1.0-beta | ✅ |
| < 0.1.0 | ❌ |
After 1.0.0 release, we will support:
- Latest major version
- Previous major version (security fixes only)
We take security seriously. If you discover a security vulnerability in Relica, please report it responsibly.
DO NOT open a public GitHub issue for security vulnerabilities.
Instead, please report security issues by emailing:
Or open a private security advisory on GitHub: https://github.com/coregx/relica/security/advisories/new
Please include the following information in your report:
- Description of the vulnerability
- Steps to reproduce the issue
- Affected versions (which versions are impacted)
- Potential impact (what can an attacker do?)
- Proof of concept (code sample, if possible)
- Suggested fix (if you have one)
- Your contact information (for follow-up questions)
- Initial Response: Within 48 hours
- Triage & Assessment: Within 1 week
- Fix & Disclosure: Coordinated with reporter
We aim to:
- Acknowledge receipt within 48 hours
- Provide an initial assessment within 1 week
- Work with you on a coordinated disclosure timeline
- Credit you in the security advisory (unless you prefer to remain anonymous)
- Release a patch as soon as possible
When using Relica in your application:
Relica uses prepared statements by default, but you must use them correctly:
// ✅ GOOD - Parameterized queries (safe)
db.Builder().
Select().
From("users").
Where("email = ?", userEmail). // Safe - parameterized
One(&user)
// ❌ BAD - String concatenation (VULNERABLE!)
query := "SELECT * FROM users WHERE email = '" + userEmail + "'"
db.DB().Query(query) // UNSAFE!
// ❌ BAD - Direct string interpolation
db.Builder().
Select().
From("users").
Where(fmt.Sprintf("email = '%s'", userEmail)). // VULNERABLE!
One(&user)Golden Rule: Always use ? placeholders, never string concatenation!
Never hardcode credentials:
// ❌ BAD - Hardcoded credentials
dsn := "postgres://user:password@localhost/db"
// ✅ GOOD - Environment variables
dsn := os.Getenv("DATABASE_URL")
if dsn == "" {
log.Fatal("DATABASE_URL not set")
}
// ✅ BETTER - Secrets management
dsn := secretsManager.GetSecret("db/connection-string")Choose appropriate isolation level for your security requirements:
// For financial operations, use Serializable
tx, err := db.BeginTx(ctx, &relica.TxOptions{
Isolation: sql.LevelSerializable, // Strongest isolation
})
// Default (ReadCommitted) may allow race conditions
tx, err := db.BeginTx(ctx, nil) // Be aware of implicationsAlways set timeouts to prevent resource exhaustion:
// ✅ GOOD - With timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
db.Builder().
WithContext(ctx).
Select().
From("users").
All(&users)
// ❌ BAD - No timeout
db.Builder().
Select().
From("large_table"). // Could hang forever
All(&data)Don't leak sensitive information in errors:
// ❌ BAD - Exposes SQL in error messages
if err != nil {
return fmt.Errorf("query failed: %w", err) // May leak SQL
}
// ✅ GOOD - Generic error for users
if err != nil {
log.Error("DB error", "error", err) // Log details
return errors.New("database operation failed") // Generic to user
}Be aware of statement cache implications:
// Statement cache is bounded (default 1000)
// But can still consume memory with many unique queries
// ✅ GOOD - Reuse query patterns
for _, id := range ids {
db.Builder().Select().From("users").Where("id = ?", id).One(&user)
// Same SQL pattern, cache reused
}
// ⚠️ WARNING - Cache pollution
for _, table := range dynamicTables {
db.Builder().Select().From(table).All(&data)
// Different SQL each time, fills cache
}Relica does not parameterize table/column names (this is a database limitation):
// ⚠️ DANGEROUS - User input as table name
tableName := getUserInput()
db.Builder().Select().From(tableName).All(&data) // Vulnerable!
// ✅ MITIGATION - Whitelist table names
allowedTables := map[string]bool{"users": true, "posts": true}
if !allowedTables[tableName] {
return errors.New("invalid table")
}
db.Builder().Select().From(tableName).All(&data) // SafeRecommendation: Never use user input directly for table/column names. Use a whitelist.
Without proper timeouts, connections can be exhausted:
// ⚠️ RISK - No limits
db, err := relica.Open("postgres", dsn) // Defaults may not fit your needs
// ✅ MITIGATION - Configure pool
db, err := relica.Open("postgres", dsn,
relica.WithMaxOpenConns(25), // Limit total connections
relica.WithMaxIdleConns(5), // Limit idle connections
)Recommendation: Configure connection pool based on your application's needs.
Improper transaction handling can cause deadlocks:
// ⚠️ RISK - Long-running transaction
tx, _ := db.BeginTx(ctx, nil)
// ... many operations ...
// ... sleep or external API call ...
tx.Commit() // May cause deadlocks
// ✅ MITIGATION - Keep transactions short
tx, _ := db.BeginTx(ctx, nil)
defer tx.Rollback()
// Only DB operations here
tx.Commit()Recommendation: Keep transactions short and focused.
Unbounded queries can exhaust resources:
// ⚠️ RISK - Unbounded query
db.Builder().Select().From("huge_table").All(&data) // May load millions of rows
// ✅ MITIGATION - Pagination
db.Builder().
Select().
From("huge_table").
Where("id > ?", lastID).
Limit(100). // Process in batches
All(&data)Recommendation: Always use LIMIT for large datasets.
Relica has zero production dependencies (only Go stdlib).
Test dependencies:
github.com/stretchr/testify- Testing assertionsmodernc.org/sqlite- Pure Go SQLite (tests only)
Monitoring:
- Dependabot enabled
- Weekly dependency audit
- No transitive dependencies in production
Relica requires external database drivers at runtime:
import _ "github.com/lib/pq" // PostgreSQL
import _ "github.com/go-sql-driver/mysql" // MySQLImportant: Keep these drivers updated! Relica doesn't bundle them.
No security vulnerabilities have been reported or fixed yet (project is in beta).
When vulnerabilities are addressed, they will be listed here with:
- CVE ID (if assigned)
- Affected versions
- Fixed in version
- Severity (Critical/High/Medium/Low)
- Credit to reporter
- Last Audit: Not yet audited
- Planned: After 1.0.0 release
- Scope: SQL injection, statement caching, connection pooling
- Email: security@coregx.dev
- GitHub: https://github.com/coregx/relica/security
- Response Time: Within 48 hours
Relica does not currently have a bug bounty program. We rely on responsible disclosure from the security community.
If you report a valid security vulnerability:
- ✅ Public credit in security advisory (if desired)
- ✅ Acknowledgment in CHANGELOG
- ✅ Listed as security contributor
- ✅ Our gratitude 🙏
Relica is designed to be used in compliance with:
- OWASP Top 10 - Prevents SQL injection (#3)
- CWE-89 - Parameterized queries prevent SQL injection
- CWE-400 - Connection pool limits prevent resource exhaustion
- CWE-209 - Careful error handling prevents information disclosure
When using Relica, consider:
- Static Analysis:
gosec,golangci-lint - Dependency Scanning:
govulncheck - Database Auditing: Enable query logging in production
- Connection Encryption: Use SSL/TLS for database connections
- Secrets Management: Use vault/secret manager for credentials
Thank you for helping keep Relica secure! 🔒
If you have security questions that are not vulnerabilities, feel free to open a GitHub Discussion.