QA Audit Report — CWE-640 Email Injection Remediation & CVE-2026-27141 Dockerfile Patch
Date: 2026-03-06
Auditor: QA Security Agent
Branch: feature/beta-release
Scope: Two changes under review:
- Dockerfile (committed): Added
golang.org/x/net@v0.51.0 via XNET_VERSION ARG to Caddy and CrowdSec builder stages (CVE-2026-27141 patch)
- Backend (uncommitted): Added
sanitizeForEmail() in notification_service.go, applied in dispatchEmail(), removed invalid // codeql[...] comments from mail_service.go, added unit tests
Changed Files
| File |
Type |
Change Summary |
Dockerfile |
Committed |
Pin golang.org/x/net@v0.51.0 via XNET_VERSION ARG in Caddy + CrowdSec builders |
backend/internal/services/notification_service.go |
Uncommitted |
Add sanitizeForEmail(), apply in dispatchEmail() |
backend/internal/services/mail_service.go |
Uncommitted |
Replace invalid // codeql[go/email-injection] comments with accurate safety docs |
backend/internal/models/notification_config.go |
Uncommitted |
Whitespace-only formatting (trailing spaces removed from struct tags) |
backend/internal/services/notification_service_test.go |
Uncommitted |
Add 8 unit tests for sanitizeForEmail and CRLF injection prevention |
backend/internal/services/mail_service_test.go |
Uncommitted |
Test additions (email construction) |
docs/plans/current_spec.md |
Uncommitted |
CWE-640 remediation plan documentation |
QA Step Results
Step 1: Backend Tests with Coverage
| Metric |
Result |
| Status |
PASS |
| Tests |
All passed, 0 failures |
| Statement Coverage |
87.9% |
| Line Coverage |
88.1% |
| Coverage Gate |
PASS (minimum 87%) |
| Command |
bash scripts/go-test-coverage.sh |
All new sanitizeForEmail tests pass. All existing mail_service_test.go and notification_service_test.go tests pass. No regressions.
Step 2: Frontend Tests with Coverage
| Metric |
Result |
| Status |
PASS |
| Test Files |
158 passed, 5 skipped, 0 failed (163 total) |
| Tests |
1867 passed, 90 skipped, 0 failed (1957 total) |
| Statement Coverage |
89.0% |
| Branch Coverage |
81.07% |
| Function Coverage |
86.26% |
| Line Coverage |
89.73% |
| Coverage Gate |
PASS (minimum 85%) |
| LCOV Artifact |
frontend/coverage/lcov.info (209 KB) |
| Command |
bash scripts/frontend-test-coverage.sh |
Re-run note: The 2 previously failing tests (notifications.test.ts and SecurityNotificationSettingsModal.test.tsx) have been fixed and now pass. All 1867 tests pass with 0 failures.
Step 3: TypeScript Type Check
| Metric |
Result |
| Status |
PASS |
| Errors |
0 |
| Command |
cd frontend && npm run type-check |
Step 4: Static Analysis (Staticcheck)
| Metric |
Result |
| Status |
PASS |
| Issues |
0 |
| Command |
cd backend && golangci-lint run --config .golangci-fast.yml ./... |
Step 5: Pre-commit Hooks
| Metric |
Result |
| Status |
PASS |
| Hooks Run |
16/16 passed |
| Command |
pre-commit run --all-files |
All hooks passed:
- fix end of files — Passed
- trim trailing whitespace — Passed
- check yaml — Passed
- check for added large files — Passed
- shellcheck — Passed
- actionlint (GitHub Actions) — Passed
- dockerfile validation — Passed
- Go Vet — Passed
- golangci-lint (Fast Linters - BLOCKING) — Passed
- Check .version matches latest Git tag — Passed
- Prevent large files not tracked by LFS — Passed
- Prevent committing CodeQL DB artifacts — Passed
- Prevent committing data/backups files — Passed
- Frontend TypeScript Check — Passed
- Frontend Lint (Fix) — Passed
Step 6: Trivy Filesystem Scan
| Metric |
Result |
| Status |
DEFERRED TO CI |
| Reason |
Trivy not installed in local development environment |
| CI Coverage |
Trivy runs in CI workflows (trivy-scan.yml) on every PR |
Step 7: GORM Security Scan
| Metric |
Result |
| Status |
PASS |
| CRITICAL |
0 |
| HIGH |
0 |
| MEDIUM |
0 |
| INFO |
2 (pre-existing: missing indexes on UserPermittedHost foreign keys) |
| Files Scanned |
41 Go files (2252 lines) |
| Command |
bash scripts/scan-gorm-security.sh --check |
Trigger: backend/internal/models/notification_config.go was modified (whitespace-only change to struct tags).
Result: Zero blocking issues. The model change is cosmetic (removed trailing whitespace from bool → bool in struct field types). No security impact.
Step 8: Local Patch Coverage Preflight
| Metric |
Result |
| Status |
PASS |
| Artifacts |
Both exist: test-results/local-patch-report.md, test-results/local-patch-report.json |
| Patch Coverage |
87.0% (advisory threshold 90%, non-blocking) |
| Frontend LCOV |
Present (frontend/coverage/lcov.info, 209 KB) |
| Command |
bash scripts/local-patch-report.sh |
Re-run note: Frontend LCOV is now available after Step 2 fix. Both backend and frontend coverage inputs consumed successfully.
Security Review
CWE-640 Email Injection Remediation
| Aspect |
Assessment |
sanitizeForEmail() implementation |
Correct. Uses strings.ReplaceAll for \r and \n — recognized by CodeQL's taint model as a sanitizer. |
| Placement |
Correct. Applied at the dispatchEmail() boundary before subject/body construction. |
| Defense-in-depth |
Maintained. Existing rejectCRLF(), encodeSubject(), html.EscapeString(), and sanitizeEmailBody() remain unchanged. |
| HTML body newlines |
Correct. sanitizeForEmail() is NOT applied to HTML body template — only to title and message inputs. HTML formatting preserved. |
| Invalid suppression comments |
Removed. 3 invalid // codeql[go/email-injection] comments replaced with accurate defense-in-depth documentation. |
| Test coverage |
8 new tests covering: empty string, clean string, CRLF stripping, embedded CR, embedded LF, multiple CRLF, CRLF in title→subject, CRLF in message→body. |
| XSS protection |
Preserved. html.EscapeString() still applied after sanitizeForEmail(). |
Verdict: Remediation is correct and complete. No security concerns.
CVE-2026-27141 Dockerfile Patch
| Aspect |
Assessment |
| Pin version |
golang.org/x/net@v0.51.0 via XNET_VERSION ARG |
| Caddy builder |
Applied: go get golang.org/x/net@v${XNET_VERSION} |
| CrowdSec builder |
Applied: go get golang.org/x/net@v${XNET_VERSION} |
| Renovate support |
# renovate: datasource=go depName=golang.org/x/net comment present on ARG |
| Image build verification |
Deferred to CI (Docker build not available locally) |
Verdict: Patch correctly applied to both builder stages. Version centralized via ARG for maintainability.
Gotify Token Review
- No Gotify tokens found in diffs, test output, or log artifacts.
- No tokenized URLs exposed in any output.
Summary
| Step |
Status |
Notes |
| 1. Backend Tests + Coverage |
PASS |
88.1% line coverage, 0 failures |
| 2. Frontend Tests + Coverage |
PASS |
89.73% line coverage, 0 failures (1867 tests, 158 files) |
| 3. TypeScript Type Check |
PASS |
0 errors |
| 4. Static Analysis |
PASS |
0 issues |
| 5. Pre-commit Hooks |
PASS |
16/16 passed (re-verified) |
| 6. Trivy Filesystem Scan |
DEFERRED |
Trivy not installed locally; covered by CI |
| 7. GORM Security Scan |
PASS |
0 CRITICAL/HIGH, model change is whitespace-only |
| 8. Local Patch Coverage |
PASS |
Artifacts generated, patch coverage 87.0% (advisory) |
Blocking Issues
None
All previously blocking issues have been resolved. The 2 frontend test failures (notifications.test.ts and SecurityNotificationSettingsModal.test.tsx) were fixed and now pass.
Non-Blocking
- Trivy filesystem scan deferred to CI (not locally installable)
- Patch coverage 87.0% is below advisory threshold of 90% (non-blocking)
- GORM INFO findings (missing indexes on
UserPermittedHost) are pre-existing and unrelated
lint-staticcheck-only Makefile target has a flag incompatibility (--disable-all not supported by installed golangci-lint); staticcheck runs successfully via make lint-fast (0 issues)
Recommendation
All QA gates pass. The CWE-640 remediation and CVE-2026-27141 Dockerfile patch are security-correct, fully tested, and ready to merge. Frontend test regressions from the email notification feature have been resolved. Coverage exceeds the 85% minimum on both backend (88.1%) and frontend (89.73%).