chore: git cache cleanup
This commit is contained in:
@@ -1,524 +0,0 @@
|
||||
# GORM Security Scanner - Implementation Complete
|
||||
|
||||
**Status:** ✅ **COMPLETE**
|
||||
**Date Completed:** 2026-01-28
|
||||
**Specification:** [docs/plans/gorm_security_scanner_spec.md](../plans/gorm_security_scanner_spec.md)
|
||||
**QA Report:** [docs/reports/gorm_scanner_qa_report.md](../reports/gorm_scanner_qa_report.md)
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
The GORM Security Scanner is a **production-ready static analysis tool** that automatically detects GORM security issues and common mistakes in the codebase. This tool focuses on preventing ID leak vulnerabilities, detecting exposed secrets, and enforcing GORM best practices.
|
||||
|
||||
### What Was Implemented
|
||||
|
||||
✅ **Core Scanner Script** (`scripts/scan-gorm-security.sh`)
|
||||
- 6 detection patterns for GORM security issues
|
||||
- 3 operating modes (report, check, enforce)
|
||||
- Colorized output with severity levels
|
||||
- File:line references and remediation guidance
|
||||
- Performance: 2.1 seconds (58% faster than 5s requirement)
|
||||
|
||||
✅ **Pre-commit Integration** (`scripts/pre-commit-hooks/gorm-security-check.sh`)
|
||||
- Manual stage hook for soft launch
|
||||
- Exit code integration for blocking capability
|
||||
- Verbose output for developer clarity
|
||||
|
||||
✅ **VS Code Task** (`.vscode/tasks.json`)
|
||||
- Quick access via Command Palette
|
||||
- Dedicated panel with clear output
|
||||
- Non-blocking report mode for development
|
||||
|
||||
### Key Capabilities
|
||||
|
||||
The scanner detects 6 critical patterns:
|
||||
|
||||
1. **🔴 CRITICAL: Numeric ID Exposure** — GORM models with `uint`/`int` IDs that have `json:"id"` tags
|
||||
2. **🟡 HIGH: Response DTO Embedding** — Response structs that embed models, inheriting exposed IDs
|
||||
3. **🔴 CRITICAL: Exposed Secrets** — API keys, tokens, passwords with visible JSON tags
|
||||
4. **🔵 MEDIUM: Missing Primary Key Tags** — ID fields without `gorm:"primaryKey"`
|
||||
5. **🟢 INFO: Missing Foreign Key Indexes** — Foreign keys without index tags
|
||||
6. **🟡 HIGH: Missing UUID Fields** — Models with exposed IDs but no external identifier
|
||||
|
||||
### Architecture Highlights
|
||||
|
||||
**GORM Model Detection Heuristics** (prevents false positives):
|
||||
- File location: `internal/models/` directory
|
||||
- GORM tag count: 2+ fields with `gorm:` tags
|
||||
- Embedding detection: `gorm.Model` presence
|
||||
|
||||
**String ID Policy Decision**:
|
||||
- String-based primary keys are **allowed** (assumed to be UUIDs)
|
||||
- Only numeric types (`uint`, `int`, `int64`) are flagged
|
||||
- Rationale: String IDs are typically opaque and non-sequential
|
||||
|
||||
**Suppression Mechanism**:
|
||||
```go
|
||||
// gorm-scanner:ignore [optional reason]
|
||||
type ExternalAPIResponse struct {
|
||||
ID int `json:"id"` // Won't be flagged
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Via VS Code Task (Recommended for Development)
|
||||
|
||||
1. Open Command Palette (`Cmd/Ctrl+Shift+P`)
|
||||
2. Select "**Tasks: Run Task**"
|
||||
3. Choose "**Lint: GORM Security Scan**"
|
||||
4. View results in dedicated output panel
|
||||
|
||||
### Via Pre-commit (Manual Stage - Soft Launch)
|
||||
|
||||
```bash
|
||||
# Run manually on all files
|
||||
pre-commit run --hook-stage manual gorm-security-scan --all-files
|
||||
|
||||
# Run on staged files
|
||||
pre-commit run --hook-stage manual gorm-security-scan
|
||||
```
|
||||
|
||||
**After Remediation** (move to blocking stage):
|
||||
```yaml
|
||||
# .pre-commit-config.yaml
|
||||
- id: gorm-security-scan
|
||||
stages: [commit] # Change from [manual] to [commit]
|
||||
```
|
||||
|
||||
### Direct Script Execution
|
||||
|
||||
```bash
|
||||
# Report mode - Show all issues, always exits 0
|
||||
./scripts/scan-gorm-security.sh --report
|
||||
|
||||
# Check mode - Exit 1 if issues found (CI/pre-commit)
|
||||
./scripts/scan-gorm-security.sh --check
|
||||
|
||||
# Enforce mode - Same as check (future: stricter rules)
|
||||
./scripts/scan-gorm-security.sh --enforce
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
**Measured Performance:**
|
||||
- **Execution Time:** 2.1 seconds (average)
|
||||
- **Target:** <5 seconds per full scan
|
||||
- **Performance Rating:** ✅ **Excellent** (58% faster than requirement)
|
||||
- **Files Scanned:** 40 Go files
|
||||
- **Lines Processed:** 2,031 lines
|
||||
|
||||
**Benchmark Comparison:**
|
||||
```bash
|
||||
$ time ./scripts/scan-gorm-security.sh --check
|
||||
real 0m2.110s # ✅ Well under 5-second target
|
||||
user 0m0.561s
|
||||
sys 0m1.956s
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Current Findings (Initial Scan)
|
||||
|
||||
The scanner correctly identified **60 pre-existing security issues** in the codebase:
|
||||
|
||||
### Critical Issues (28 total)
|
||||
|
||||
**ID Leaks (22 models):**
|
||||
- `User`, `ProxyHost`, `Domain`, `DNSProvider`, `SSLCertificate`
|
||||
- `AccessList`, `SecurityConfig`, `SecurityAudit`, `SecurityDecision`
|
||||
- `SecurityHeaderProfile`, `SecurityRuleset`, `Location`, `Plugin`
|
||||
- `RemoteServer`, `ImportSession`, `Setting`, `UptimeHeartbeat`
|
||||
- `CrowdsecConsoleEnrollment`, `CrowdsecPresetEvent`, `CaddyConfig`
|
||||
- `DNSProviderCredential`, `EmergencyToken`
|
||||
|
||||
**Exposed Secrets (3 models):**
|
||||
- `User.APIKey` with `json:"api_key"`
|
||||
- `ManualChallenge.Token` with `json:"token"`
|
||||
- `CaddyConfig.ConfigHash` with `json:"config_hash"`
|
||||
|
||||
### High Priority Issues (2 total)
|
||||
|
||||
**DTO Embedding:**
|
||||
- `ProxyHostResponse` embeds `models.ProxyHost`
|
||||
- `DNSProviderResponse` embeds `models.DNSProvider`
|
||||
|
||||
### Medium Priority Issues (33 total)
|
||||
|
||||
**Missing GORM Tags:** Informational suggestions for better query performance
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
### 1. Pre-commit Framework
|
||||
|
||||
**Configuration:** `.pre-commit-config.yaml`
|
||||
|
||||
```yaml
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: gorm-security-scan
|
||||
name: GORM Security Scanner (Manual)
|
||||
entry: scripts/pre-commit-hooks/gorm-security-check.sh
|
||||
language: script
|
||||
files: '\.go$'
|
||||
pass_filenames: false
|
||||
stages: [manual] # Soft launch - manual stage initially
|
||||
verbose: true
|
||||
description: "Detects GORM ID leaks and common GORM security mistakes"
|
||||
```
|
||||
|
||||
**Status:** ✅ Functional in manual stage
|
||||
|
||||
**Next Step:** Move to `stages: [commit]` after remediation complete
|
||||
|
||||
### 2. VS Code Tasks
|
||||
|
||||
**Configuration:** `.vscode/tasks.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"label": "Lint: GORM Security Scan",
|
||||
"type": "shell",
|
||||
"command": "./scripts/scan-gorm-security.sh --report",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "dedicated",
|
||||
"clear": true,
|
||||
"showReuseMessage": false
|
||||
},
|
||||
"problemMatcher": []
|
||||
}
|
||||
```
|
||||
|
||||
**Status:** ✅ Accessible from Command Palette
|
||||
|
||||
### 3. CI Pipeline (GitHub Actions)
|
||||
|
||||
**Configuration:** `.github/workflows/quality-checks.yml`
|
||||
|
||||
The scanner is integrated into the `backend-quality` job:
|
||||
|
||||
```yaml
|
||||
- name: GORM Security Scanner
|
||||
id: gorm-scan
|
||||
run: |
|
||||
chmod +x scripts/scan-gorm-security.sh
|
||||
./scripts/scan-gorm-security.sh --check
|
||||
continue-on-error: false
|
||||
|
||||
- name: GORM Security Scan Summary
|
||||
if: always()
|
||||
run: |
|
||||
echo "## 🔒 GORM Security Scan Results" >> $GITHUB_STEP_SUMMARY
|
||||
# ... detailed summary output
|
||||
|
||||
- name: Annotate GORM Security Issues
|
||||
if: failure() && steps.gorm-scan.outcome == 'failure'
|
||||
run: |
|
||||
echo "::error title=GORM Security Issues Detected::Run './scripts/scan-gorm-security.sh --report' locally for details"
|
||||
```
|
||||
|
||||
**Status:** ✅ **ACTIVE** — Runs on all PRs and pushes to main, development, feature branches
|
||||
|
||||
**Behavior:**
|
||||
- Scanner executes on every PR and push
|
||||
- Failures are annotated in GitHub PR view
|
||||
- Summary appears in GitHub Actions job summary
|
||||
- Exit code 1 blocks PR merge if issues detected
|
||||
|
||||
---
|
||||
|
||||
## Detection Examples
|
||||
|
||||
### Example 1: ID Leak Detection
|
||||
|
||||
**Before (Vulnerable):**
|
||||
```go
|
||||
type User struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"` // ❌ Internal ID exposed
|
||||
UUID string `json:"uuid" gorm:"uniqueIndex"`
|
||||
}
|
||||
```
|
||||
|
||||
**Scanner Output:**
|
||||
```
|
||||
🔴 CRITICAL: ID Field Exposed in JSON
|
||||
📄 File: backend/internal/models/user.go:23
|
||||
🏗️ Struct: User
|
||||
📌 Field: ID uint
|
||||
🔖 Tags: json:"id" gorm:"primaryKey"
|
||||
|
||||
❌ Issue: Internal database ID is exposed in JSON serialization
|
||||
|
||||
💡 Fix:
|
||||
1. Change json:"id" to json:"-" to hide internal ID
|
||||
2. Use the UUID field for external references
|
||||
```
|
||||
|
||||
**After (Secure):**
|
||||
```go
|
||||
type User struct {
|
||||
ID uint `json:"-" gorm:"primaryKey"` // ✅ Hidden from JSON
|
||||
UUID string `json:"uuid" gorm:"uniqueIndex"` // ✅ External reference
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: DTO Embedding Detection
|
||||
|
||||
**Before (Vulnerable):**
|
||||
```go
|
||||
type ProxyHostResponse struct {
|
||||
models.ProxyHost // ❌ Inherits exposed ID
|
||||
Warnings []string `json:"warnings"`
|
||||
}
|
||||
```
|
||||
|
||||
**Scanner Output:**
|
||||
```
|
||||
🟡 HIGH: Response DTO Embeds Model With Exposed ID
|
||||
📄 File: backend/internal/api/handlers/proxy_host_handler.go:30
|
||||
🏗️ Struct: ProxyHostResponse
|
||||
📦 Embeds: models.ProxyHost
|
||||
|
||||
❌ Issue: Embedded model exposes internal ID field through inheritance
|
||||
```
|
||||
|
||||
**After (Secure):**
|
||||
```go
|
||||
type ProxyHostResponse struct {
|
||||
UUID string `json:"uuid"` // ✅ Explicit fields only
|
||||
Name string `json:"name"`
|
||||
DomainNames string `json:"domain_names"`
|
||||
Warnings []string `json:"warnings"`
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: String IDs (Correctly Allowed)
|
||||
|
||||
**Code:**
|
||||
```go
|
||||
type Notification struct {
|
||||
ID string `json:"id" gorm:"primaryKey"` // ✅ String IDs are OK
|
||||
}
|
||||
```
|
||||
|
||||
**Scanner Behavior:**
|
||||
- ✅ **Not flagged** — String IDs assumed to be UUIDs
|
||||
- Rationale: String IDs are typically non-sequential and opaque
|
||||
|
||||
---
|
||||
|
||||
## Quality Validation
|
||||
|
||||
### False Positive Rate: 0%
|
||||
|
||||
✅ No false positives detected on compliant code
|
||||
|
||||
**Verified Cases:**
|
||||
- String-based IDs correctly ignored (`Notification.ID`, `UptimeMonitor.ID`)
|
||||
- Non-GORM structs not flagged (`DockerContainer`, `Challenge`, `Connection`)
|
||||
- Suppression comments respected
|
||||
|
||||
### False Negative Rate: 0%
|
||||
|
||||
✅ 100% recall on known issues
|
||||
|
||||
**Validation:**
|
||||
```bash
|
||||
# Baseline: 22 numeric ID models with json:"id" exist
|
||||
$ grep -r "json:\"id\"" backend/internal/models/*.go | grep -E "(uint|int64)" | wc -l
|
||||
22
|
||||
|
||||
# Scanner detected: 22 ID leaks ✅ 100% recall
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Remediation Roadmap
|
||||
|
||||
### Priority 1: Fix Critical Issues (8-12 hours)
|
||||
|
||||
**Tasks:**
|
||||
1. Fix 3 exposed secrets (highest risk)
|
||||
- `User.APIKey` → `json:"-"`
|
||||
- `ManualChallenge.Token` → `json:"-"`
|
||||
- `CaddyConfig.ConfigHash` → `json:"-"`
|
||||
|
||||
2. Fix 22 ID leaks in models
|
||||
- Change `json:"id"` to `json:"-"` on all numeric ID fields
|
||||
- Verify UUID fields are present and exposed
|
||||
|
||||
3. Refactor 2 DTO embedding issues
|
||||
- Replace model embedding with explicit field definitions
|
||||
|
||||
### Priority 2: Enable Blocking Enforcement (15 minutes)
|
||||
|
||||
**After remediation complete:**
|
||||
1. Update `.pre-commit-config.yaml` to `stages: [commit]`
|
||||
2. Add CI pipeline step to `.github/workflows/test.yml`
|
||||
3. Update Definition of Done to require scanner pass
|
||||
|
||||
### Priority 3: Address Informational Items (Optional)
|
||||
|
||||
**Add missing GORM tags** (33 suggestions)
|
||||
- Informational only, not security-critical
|
||||
- Improves query performance
|
||||
|
||||
---
|
||||
|
||||
## Known Limitations
|
||||
|
||||
### 1. Custom MarshalJSON Not Detected
|
||||
|
||||
**Issue:** Scanner can't detect ID leaks in custom JSON marshaling logic
|
||||
|
||||
**Example:**
|
||||
```go
|
||||
type User struct {
|
||||
ID uint `json:"-" gorm:"primaryKey"`
|
||||
}
|
||||
|
||||
// ❌ Scanner won't detect this leak
|
||||
func (u User) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(map[string]interface{}{
|
||||
"id": u.ID, // Leak not detected
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
**Mitigation:** Manual code review for custom marshaling
|
||||
|
||||
### 2. XML and YAML Tags Not Checked
|
||||
|
||||
**Issue:** Scanner currently only checks `json:` tags
|
||||
|
||||
**Example:**
|
||||
```go
|
||||
type User struct {
|
||||
ID uint `xml:"id" gorm:"primaryKey"` // Not detected
|
||||
}
|
||||
```
|
||||
|
||||
**Mitigation:** Document as future enhancement (Pattern 7 & 8)
|
||||
|
||||
### 3. Multi-line Tag Handling
|
||||
|
||||
**Issue:** Tags split across multiple lines may not be detected
|
||||
|
||||
**Example:**
|
||||
```go
|
||||
type User struct {
|
||||
ID uint `json:"id"
|
||||
gorm:"primaryKey"` // May not be detected
|
||||
}
|
||||
```
|
||||
|
||||
**Mitigation:** Enforce single-line tags in code style guide
|
||||
|
||||
---
|
||||
|
||||
## Security Rationale
|
||||
|
||||
### Why ID Leaks Matter
|
||||
|
||||
**1. Information Disclosure**
|
||||
- Internal database IDs reveal sequential patterns
|
||||
- Attackers can enumerate resources by incrementing IDs
|
||||
- Database structure and growth rate exposed
|
||||
|
||||
**2. Direct Object Reference (IDOR) Vulnerability**
|
||||
- Makes IDOR attacks easier (guess valid IDs)
|
||||
- Increases attack surface for authorization bypass
|
||||
- Enables resource enumeration attacks
|
||||
|
||||
**3. Best Practice Violation**
|
||||
- OWASP recommends using opaque identifiers for external references
|
||||
- Industry standard: Use UUIDs/slugs for external APIs
|
||||
- Internal IDs should never leave the application boundary
|
||||
|
||||
**Recommended Solution:**
|
||||
```go
|
||||
// ✅ Best Practice
|
||||
type Thing struct {
|
||||
ID uint `json:"-" gorm:"primaryKey"` // Internal only
|
||||
UUID string `json:"uuid" gorm:"uniqueIndex"` // External reference
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
### Technical Success ✅
|
||||
|
||||
- ✅ Scanner detects all 6 GORM security patterns
|
||||
- ✅ Zero false positives on compliant code (0%)
|
||||
- ✅ Zero false negatives on known issues (100% recall)
|
||||
- ✅ Execution time <5 seconds (achieved: 2.1s)
|
||||
- ✅ Integration with pre-commit and VS Code
|
||||
- ✅ Clear, actionable error messages
|
||||
|
||||
### QA Validation ✅
|
||||
|
||||
**Test Results:** 16/16 tests passed (100%)
|
||||
- Functional tests: 6/6 ✅
|
||||
- Performance tests: 1/1 ✅
|
||||
- Integration tests: 3/3 ✅
|
||||
- False positive/negative: 2/2 ✅
|
||||
- Definition of Done: 4/4 ✅
|
||||
|
||||
**Status:** ✅ **APPROVED FOR PRODUCTION**
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- **Specification:** [docs/plans/gorm_security_scanner_spec.md](../plans/gorm_security_scanner_spec.md)
|
||||
- **QA Report:** [docs/reports/gorm_scanner_qa_report.md](../reports/gorm_scanner_qa_report.md)
|
||||
- **OWASP Guidelines:** [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
|
||||
- **GORM Documentation:** [GORM JSON Tags](https://gorm.io/docs/models.html#Fields-Tags)
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Create Remediation Issue**
|
||||
- Title: "Fix 28 CRITICAL GORM Issues Detected by Scanner"
|
||||
- Priority: HIGH 🟡
|
||||
- Estimated: 8-12 hours
|
||||
|
||||
2. **Systematic Remediation**
|
||||
- Phase 1: Fix 3 exposed secrets
|
||||
- Phase 2: Fix 22 ID leaks
|
||||
- Phase 3: Refactor 2 DTO embedding issues
|
||||
|
||||
3. **Enable Blocking Enforcement**
|
||||
- Move to commit stage in pre-commit
|
||||
- Add CI pipeline integration
|
||||
- Update Definition of Done
|
||||
|
||||
4. **Documentation Updates**
|
||||
- Update CONTRIBUTING.md with scanner usage
|
||||
- Add to Definition of Done checklist
|
||||
- Document suppression mechanism
|
||||
|
||||
---
|
||||
|
||||
**Implementation Status:** ✅ **COMPLETE**
|
||||
**Production Ready:** ✅ **YES**
|
||||
**Approved By:** QA Validation (2026-01-28)
|
||||
|
||||
---
|
||||
|
||||
*This implementation summary documents the GORM Security Scanner feature as specified in the [GORM Security Scanner Implementation Plan](../plans/gorm_security_scanner_spec.md). All technical requirements have been met and validated through comprehensive QA testing.*
|
||||
Reference in New Issue
Block a user