@sun-asterisk/sunlint 1.3.40 → 1.3.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/core/rule-selection-service.js +11 -0
  2. package/package.json +1 -1
  3. package/skill-assets/sunlint-code-quality/rules/go/C006-verb-noun-functions.md +45 -0
  4. package/skill-assets/sunlint-code-quality/rules/go/C013-no-dead-code.md +48 -0
  5. package/skill-assets/sunlint-code-quality/rules/go/C014-dependency-injection.md +85 -0
  6. package/skill-assets/sunlint-code-quality/rules/go/C017-no-constructor-logic.md +67 -0
  7. package/skill-assets/sunlint-code-quality/rules/go/C018-generic-errors.md +63 -0
  8. package/skill-assets/sunlint-code-quality/rules/go/C019-error-log-level.md +50 -0
  9. package/skill-assets/sunlint-code-quality/rules/go/C020-no-unused-imports.md +45 -0
  10. package/skill-assets/sunlint-code-quality/rules/go/C022-no-unused-variables.md +34 -0
  11. package/skill-assets/sunlint-code-quality/rules/go/C023-no-duplicate-names.md +41 -0
  12. package/skill-assets/sunlint-code-quality/rules/go/C024-centralize-constants.md +55 -0
  13. package/skill-assets/sunlint-code-quality/rules/go/C029-catch-log-root-cause.md +56 -0
  14. package/skill-assets/sunlint-code-quality/rules/go/C030-custom-error-classes.md +69 -0
  15. package/skill-assets/sunlint-code-quality/rules/go/C033-separate-data-access.md +68 -0
  16. package/skill-assets/sunlint-code-quality/rules/go/C035-error-context-logging.md +48 -0
  17. package/skill-assets/sunlint-code-quality/rules/go/C041-no-hardcoded-secrets.md +45 -0
  18. package/skill-assets/sunlint-code-quality/rules/go/C042-boolean-naming.md +42 -0
  19. package/skill-assets/sunlint-code-quality/rules/go/C052-controller-parsing.md +62 -0
  20. package/skill-assets/sunlint-code-quality/rules/go/C060-superclass-logic.md +60 -0
  21. package/skill-assets/sunlint-code-quality/rules/go/C067-no-hardcoded-config.md +51 -0
  22. package/skill-assets/sunlint-code-quality/rules/go/S003-open-redirect.md +80 -0
  23. package/skill-assets/sunlint-code-quality/rules/go/S004-no-log-credentials.md +66 -0
  24. package/skill-assets/sunlint-code-quality/rules/go/S005-server-authorization.md +55 -0
  25. package/skill-assets/sunlint-code-quality/rules/go/S006-default-credentials.md +47 -0
  26. package/skill-assets/sunlint-code-quality/rules/go/S007-output-encoding.md +50 -0
  27. package/skill-assets/sunlint-code-quality/rules/go/S009-approved-crypto.md +63 -0
  28. package/skill-assets/sunlint-code-quality/rules/go/S010-csprng.md +53 -0
  29. package/skill-assets/sunlint-code-quality/rules/go/S011-encrypted-client-hello.md +34 -0
  30. package/skill-assets/sunlint-code-quality/rules/go/S012-secrets-management.md +49 -0
  31. package/skill-assets/sunlint-code-quality/rules/go/S013-tls-connections.md +61 -0
  32. package/skill-assets/sunlint-code-quality/rules/go/S016-no-sensitive-query-string.md +42 -0
  33. package/skill-assets/sunlint-code-quality/rules/go/S017-parameterized-queries.md +36 -0
  34. package/skill-assets/sunlint-code-quality/rules/go/S019-email-input-sanitization.md +44 -0
  35. package/skill-assets/sunlint-code-quality/rules/go/S020-eval-code-execution.md +47 -0
  36. package/skill-assets/sunlint-code-quality/rules/go/S022-context-escaping.md +49 -0
  37. package/skill-assets/sunlint-code-quality/rules/go/S023-dynamic-js-encoding.md +51 -0
  38. package/skill-assets/sunlint-code-quality/rules/go/S025-server-validation.md +57 -0
  39. package/skill-assets/sunlint-code-quality/rules/go/S026-tls-encryption.md +46 -0
  40. package/skill-assets/sunlint-code-quality/rules/go/S027-mtls-validation.md +52 -0
  41. package/skill-assets/sunlint-code-quality/rules/go/S028-upload-limits.md +58 -0
  42. package/skill-assets/sunlint-code-quality/rules/go/S029-csrf-protection.md +53 -0
  43. package/skill-assets/sunlint-code-quality/rules/go/S030-directory-browsing.md +53 -0
  44. package/skill-assets/sunlint-code-quality/rules/go/S031-secure-cookie-flag.md +48 -0
  45. package/skill-assets/sunlint-code-quality/rules/go/S032-httponly-cookie.md +42 -0
  46. package/skill-assets/sunlint-code-quality/rules/go/S033-samesite-cookie.md +49 -0
  47. package/skill-assets/sunlint-code-quality/rules/go/S034-host-prefix-cookie.md +44 -0
  48. package/skill-assets/sunlint-code-quality/rules/go/S035-app-hostnames.md +50 -0
  49. package/skill-assets/sunlint-code-quality/rules/go/S036-internal-file-paths.md +56 -0
  50. package/skill-assets/sunlint-code-quality/rules/go/S037-anti-cache-headers.md +43 -0
  51. package/skill-assets/sunlint-code-quality/rules/go/S039-tls-certificate-validation.md +41 -0
  52. package/skill-assets/sunlint-code-quality/rules/go/S041-logout-invalidation.md +46 -0
  53. package/skill-assets/sunlint-code-quality/rules/go/S042-long-lived-sessions.md +58 -0
  54. package/skill-assets/sunlint-code-quality/rules/go/S044-critical-changes-reauth.md +53 -0
  55. package/skill-assets/sunlint-code-quality/rules/go/S045-brute-force-protection.md +55 -0
  56. package/skill-assets/sunlint-code-quality/rules/go/S047-oauth-csrf-protection.md +51 -0
  57. package/skill-assets/sunlint-code-quality/rules/go/S048-oauth-redirect-validation.md +58 -0
  58. package/skill-assets/sunlint-code-quality/rules/go/S049-auth-code-expiry.md +52 -0
  59. package/skill-assets/sunlint-code-quality/rules/go/S050-token-entropy.md +53 -0
  60. package/skill-assets/sunlint-code-quality/rules/go/S051-password-length.md +49 -0
  61. package/skill-assets/sunlint-code-quality/rules/go/S052-otp-entropy.md +48 -0
  62. package/skill-assets/sunlint-code-quality/rules/go/S053-generic-error-messages.md +51 -0
  63. package/skill-assets/sunlint-code-quality/rules/go/S054-no-default-admin.md +43 -0
  64. package/skill-assets/sunlint-code-quality/rules/go/S055-content-type-validation.md +52 -0
  65. package/skill-assets/sunlint-code-quality/rules/go/S056-log-injection.md +40 -0
  66. package/skill-assets/sunlint-code-quality/rules/go/S057-synchronized-time.md +40 -0
  67. package/skill-assets/sunlint-code-quality/rules/go/S058-ssrf-protection.md +70 -0
@@ -0,0 +1,68 @@
1
+ ---
2
+ title: Separate Processing And Data Access
3
+ impact: HIGH
4
+ impactDescription: enables testable business logic
5
+ tags: separation, repository, service, architecture, quality
6
+ ---
7
+
8
+ ## Separate Processing And Data Access
9
+
10
+ Mixing business logic with database queries creates tight coupling and makes testing require real databases.
11
+
12
+ **Incorrect (mixed concerns):**
13
+
14
+ ```go
15
+ type OrderService struct {
16
+ db *sql.DB
17
+ }
18
+
19
+ func (s *OrderService) CalculateDiscount(userId string) (int, error) {
20
+ // Business logic mixed with data access
21
+ var isPremium bool
22
+ db.QueryRow("SELECT is_premium FROM users WHERE id = ?", userId).Scan(&isPremium)
23
+
24
+ var orderCount int
25
+ db.QueryRow("SELECT count(*) FROM orders WHERE user_id = ?", userId).Scan(&orderCount)
26
+
27
+ discount := 0
28
+ if orderCount > 10 { discount += 5 }
29
+ if isPremium { discount += 10 }
30
+
31
+ return discount, nil
32
+ }
33
+ ```
34
+
35
+ **Correct (separated layers):**
36
+
37
+ ```go
38
+ // Repository - data access only
39
+ type UserRepository interface {
40
+ FindByID(id string) (*User, error)
41
+ }
42
+
43
+ type OrderRepository interface {
44
+ CountByUserID(id string) (int, error)
45
+ }
46
+
47
+ // Service - business logic only
48
+ type DiscountService struct {
49
+ userRepo UserRepository
50
+ orderRepo OrderRepository
51
+ }
52
+
53
+ func (s *DiscountService) CalculateDiscount(userId string) (int, error) {
54
+ user, _ := s.userRepo.FindByID(userId)
55
+ count, _ := s.orderRepo.CountByUserID(userId)
56
+
57
+ return s.computeDiscount(user, count), nil
58
+ }
59
+
60
+ func (s *DiscountService) computeDiscount(user *User, orderCount int) int {
61
+ discount := 0
62
+ if orderCount > 10 { discount += 5 }
63
+ if user != nil && user.IsPremium { discount += 10 }
64
+ return discount
65
+ }
66
+ ```
67
+
68
+ **Tools:** Architectural review, Code Review
@@ -0,0 +1,48 @@
1
+ ---
2
+ title: Log All Relevant Context On Errors
3
+ impact: HIGH
4
+ impactDescription: enables quick debugging and incident response
5
+ tags: error-handling, logging, context, debugging, quality
6
+ ---
7
+
8
+ ## Log All Relevant Context On Errors
9
+
10
+ Context-rich logs enable quick debugging. Without proper context, finding root causes is difficult.
11
+
12
+ **Incorrect (minimal context):**
13
+
14
+ ```go
15
+ slog.Error("error occurred")
16
+ slog.Error(err.Error())
17
+ ```
18
+
19
+ **Correct (comprehensive context using slog):**
20
+
21
+ ```go
22
+ slog.Error("failed to process order",
23
+ // What happened
24
+ "error", err,
25
+ "stack", string(debug.Stack()), // Optional: but useful for critical errors
26
+
27
+ // Context
28
+ "order_id", order.ID,
29
+ "user_id", user.ID,
30
+ "request_id", ctx.Value("request_id"),
31
+
32
+ // Input that caused the issue
33
+ "item_count", len(order.Items),
34
+ "total_amount", order.Total,
35
+
36
+ // Timing
37
+ "processing_time_ms", time.Since(startTime).Milliseconds(),
38
+ )
39
+ ```
40
+
41
+ **Essential context:**
42
+ - Error details
43
+ - Entity identifiers
44
+ - Request/correlation IDs
45
+ - Relevant input summary
46
+ - Timing information
47
+
48
+ **Tools:** `slog`, `zap`, `logback` equivalent
@@ -0,0 +1,45 @@
1
+ ---
2
+ title: No Hardcoded Secrets In Repo
3
+ impact: HIGH
4
+ impactDescription: prevents credential exposure
5
+ tags: secrets, credentials, security, git, quality
6
+ ---
7
+
8
+ ## No Hardcoded Secrets In Repo
9
+
10
+ Secrets in code are exposed to everyone with repo access and can be scraped by attackers.
11
+
12
+ **Incorrect (secrets in code):**
13
+
14
+ ```go
15
+ const APIKey = "sk-abc123xyz789"
16
+ const DBPassword = "admin123"
17
+
18
+ func init() {
19
+ client := stripe.NewClient("sk_live_xxx")
20
+ }
21
+ ```
22
+
23
+ **Correct (environment/secrets manager):**
24
+
25
+ ```go
26
+ // From environment
27
+ apiKey := os.Getenv("API_KEY")
28
+
29
+ // From secrets manager
30
+ apiKey, err := secretManager.GetSecret(ctx, "stripe-api-key")
31
+
32
+ // Validation at startup
33
+ if os.Getenv("API_KEY") == "" {
34
+ log.Fatal("API_KEY environment variable is required")
35
+ }
36
+ ```
37
+
38
+ ```gitignore
39
+ # .gitignore
40
+ .env
41
+ *.pem
42
+ *.key
43
+ ```
44
+
45
+ **Tools:** GitLeaks, TruffleHog, pre-commit hooks
@@ -0,0 +1,42 @@
1
+ ---
2
+ title: Boolean Names Is/Has/Should
3
+ impact: HIGH
4
+ impactDescription: makes conditions instantly readable
5
+ tags: naming, booleans, readability, quality
6
+ ---
7
+
8
+ ## Boolean Names Is/Has/Should
9
+
10
+ Boolean prefixes make conditions instantly readable.
11
+
12
+ **Incorrect (unclear boolean names):**
13
+
14
+ ```go
15
+ active := user.Status == "active"
16
+ admin := checkAdminRole(user)
17
+ items := len(cart) > 0
18
+ update := needsRefresh()
19
+ ```
20
+
21
+ **Correct (boolean prefixes):**
22
+
23
+ ```go
24
+ isActive := user.Status == "active"
25
+ isAdmin := checkAdminRole(user)
26
+ hasItems := len(cart) > 0
27
+ shouldUpdate := needsRefresh()
28
+ canEdit := hasPermission(user, "edit")
29
+ willExpire := expirationDate.Before(time.Now())
30
+ ```
31
+
32
+ **Boolean prefixes:**
33
+
34
+ | Prefix | Use For |
35
+ |--------|---------|
36
+ | `Is` | State (IsActive, IsEnabled) |
37
+ | `Has` | Ownership (HasPermission, HasError) |
38
+ | `Should` | Decision (ShouldUpdate, ShouldRetry) |
39
+ | `Can` | Capability (CanEdit, CanDelete) |
40
+ | `Will` | Future (WillExpire, WillRetry) |
41
+
42
+ **Tools:** Linter, Code Review
@@ -0,0 +1,62 @@
1
+ ---
2
+ title: Separate Parsing From Handlers
3
+ impact: HIGH
4
+ impactDescription: keeps handlers thin and focused
5
+ tags: handler, parsing, transformation, patterns, quality
6
+ ---
7
+
8
+ ## Separate Parsing From Handlers
9
+
10
+ Handlers (controllers) should be thin - only handling HTTP concerns. Transformation logic should be extracted.
11
+
12
+ **Incorrect (transformation in handler):**
13
+
14
+ ```go
15
+ func GetUserHandler(w http.ResponseWriter, r *http.Request) {
16
+ user, _ := userService.FindByID(r.URL.Query().Get("id"))
17
+
18
+ // Transformation logic in handler
19
+ response := map[string]any{
20
+ "id": user.ID,
21
+ "full_name": user.FirstName + " " + user.LastName,
22
+ "email": strings.ToLower(user.Email),
23
+ "created_at": user.CreatedAt.Format("2006-01-02"),
24
+ }
25
+
26
+ json.NewEncoder(w).Encode(response)
27
+ }
28
+ ```
29
+
30
+ **Correct (separate mapper/DTO):**
31
+
32
+ ```go
33
+ type UserResponse struct {
34
+ ID string `json:"id"`
35
+ FullName string `json:"full_name"`
36
+ Email string `json:"email"`
37
+ CreatedAt string `json:"created_at"`
38
+ }
39
+
40
+ func ToUserResponse(user *User) UserResponse {
41
+ return UserResponse{
42
+ ID: user.ID,
43
+ FullName: user.FirstName + " " + user.LastName,
44
+ Email: strings.ToLower(user.Email),
45
+ CreatedAt: user.CreatedAt.Format("2006-01-02"),
46
+ }
47
+ }
48
+
49
+ // Clean handler
50
+ func GetUserHandler(w http.ResponseWriter, r *http.Request) {
51
+ user, _ := userService.FindByID(r.URL.Query().Get("id"))
52
+ json.NewEncoder(w).Encode(ToUserResponse(user))
53
+ }
54
+ ```
55
+
56
+ **Benefits:**
57
+ - Reusable transformation logic
58
+ - Testable mappers
59
+ - Clean handlers
60
+ - Consistent response format
61
+
62
+ **Tools:** Code review, Architecture rules
@@ -0,0 +1,60 @@
1
+ ---
2
+ title: Do Not Ignore Embedded Struct Logic
3
+ impact: HIGH
4
+ impactDescription: ensures proper composition behavior
5
+ tags: composition, embedding, override, quality
6
+ ---
7
+
8
+ ## Do Not Ignore Embedded Struct Logic
9
+
10
+ When "overriding" methods of an embedded struct, ensure the embedded behavior is preserved unless explicitly intended otherwise.
11
+
12
+ **Incorrect (ignoring embedded logic):**
13
+
14
+ ```go
15
+ type BaseService struct{}
16
+
17
+ func (s *BaseService) Save(entity any) error {
18
+ s.Validate(entity)
19
+ s.BeforeSave(entity)
20
+ // ... actual save logic ...
21
+ return nil
22
+ }
23
+
24
+ type UserService struct {
25
+ BaseService
26
+ }
27
+
28
+ func (s *UserService) Save(user any) error {
29
+ // Completely ignores BaseService.Save logic (validation, hooks, etc.)
30
+ return s.repo.Save(user)
31
+ }
32
+ ```
33
+
34
+ **Correct (explicitly calling embedded method):**
35
+
36
+ ```go
37
+ type UserService struct {
38
+ BaseService
39
+ }
40
+
41
+ func (s *UserService) Save(user *User) error {
42
+ // Add user-specific preprocessing
43
+ user.UpdatedAt = time.Now()
44
+
45
+ // Call embedded struct implementation
46
+ if err := s.BaseService.Save(user); err != nil {
47
+ return err
48
+ }
49
+
50
+ // Add user-specific postprocessing
51
+ return s.updateSearchIndex(user)
52
+ }
53
+ ```
54
+
55
+ **When to skip:**
56
+ - Complete replacement is intentional
57
+ - Base implementation doesn't apply
58
+ - Document the reason clearly
59
+
60
+ **Tools:** Static Analysis, Code Review
@@ -0,0 +1,51 @@
1
+ ---
2
+ title: Do Not Hardcode Configuration
3
+ impact: HIGH
4
+ impactDescription: enables environment-specific deployments
5
+ tags: configuration, environment, deployment, quality
6
+ ---
7
+
8
+ ## Do Not Hardcode Configuration
9
+
10
+ Hardcoded configuration requires code changes to deploy to different environments.
11
+
12
+ **Incorrect (hardcoded config):**
13
+
14
+ ```go
15
+ const APIUrl = "https://api.production.example.com"
16
+ const Timeout = 5000
17
+ const MaxFileSize = 10485760
18
+ ```
19
+
20
+ **Correct (externalized config):**
21
+
22
+ ```go
23
+ type Config struct {
24
+ API struct {
25
+ URL string
26
+ Timeout time.Duration
27
+ }
28
+ Upload struct {
29
+ MaxFileSize int64
30
+ }
31
+ }
32
+
33
+ func LoadConfig() *Config {
34
+ return &Config{
35
+ API: struct {
36
+ URL string
37
+ Timeout time.Duration
38
+ }{
39
+ URL: getEnv("API_URL", "http://localhost:3000"),
40
+ Timeout: time.Duration(getEnvInt("API_TIMEOUT", 5000)) * time.Millisecond,
41
+ },
42
+ // ...
43
+ }
44
+ }
45
+
46
+ // Usage
47
+ cfg := LoadConfig()
48
+ client := &http.Client{Timeout: cfg.API.Timeout}
49
+ ```
50
+
51
+ **Tools:** `os.Getenv`, `viper`, `clever-env`, Manual review
@@ -0,0 +1,80 @@
1
+ ---
2
+ title: URL Redirects Must Be In Allow List
3
+ impact: LOW
4
+ impactDescription: prevents open redirect vulnerabilities
5
+ tags: redirect, url, allow-list, validation, security
6
+ ---
7
+
8
+ ## URL Redirects Must Be In Allow List
9
+
10
+ Open redirect vulnerabilities allow attackers to redirect users to malicious sites, often used in phishing attacks.
11
+
12
+ **Incorrect (unvalidated redirect URL):**
13
+
14
+ ```go
15
+ // Open redirect vulnerability
16
+ http.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
17
+ url := r.URL.Query().Get("url")
18
+ http.Redirect(w, r, url, http.StatusFound) // Attacker: ?url=https://evil.com
19
+ })
20
+
21
+ // Partial validation (can be bypassed)
22
+ http.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
23
+ url := r.URL.Query().Get("url")
24
+ if strings.Contains(url, "example.com") {
25
+ http.Redirect(w, r, url, http.StatusFound) // Bypass: evil.com?example.com
26
+ }
27
+ })
28
+ ```
29
+
30
+ **Correct (allow list validation):**
31
+
32
+ ```go
33
+ var allowedRedirectHosts = []string{
34
+ "example.com",
35
+ "app.example.com",
36
+ "admin.example.com",
37
+ }
38
+
39
+ func isAllowedHost(host string) bool {
40
+ for _, h := range allowedRedirectHosts {
41
+ if h == host {
42
+ return true
43
+ }
44
+ }
45
+ return false
46
+ }
47
+
48
+ http.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
49
+ targetURL := r.URL.Query().Get("url")
50
+
51
+ parsed, err := url.Parse(targetURL)
52
+ if err != nil || !isAllowedHost(parsed.Hostname()) {
53
+ http.Error(w, "Invalid redirect URL", http.StatusBadRequest)
54
+ return
55
+ }
56
+
57
+ http.Redirect(w, r, targetURL, http.StatusFound)
58
+ })
59
+
60
+ // Or use relative URLs only
61
+ http.HandleFunc("/relative-redirect", func(w http.ResponseWriter, r *http.Request) {
62
+ path := r.URL.Query().Get("path")
63
+
64
+ // Only allow relative paths starting with /
65
+ if !strings.HasPrefix(path, "/") || strings.HasPrefix(path, "//") {
66
+ http.Error(w, "Invalid path", http.StatusBadRequest)
67
+ return
68
+ }
69
+
70
+ http.Redirect(w, r, path, http.StatusFound)
71
+ })
72
+ ```
73
+
74
+ **Protection strategies:**
75
+ 1. Allow list of trusted domains
76
+ 2. Use relative URLs only
77
+ 3. Validate URL structure
78
+ 4. Warning page before external redirects
79
+
80
+ **Tools:** SonarQube, Semgrep, Manual Review
@@ -0,0 +1,66 @@
1
+ ---
2
+ title: Do Not Log Credentials Or Tokens
3
+ impact: MEDIUM
4
+ impactDescription: prevents credential exposure in logs
5
+ tags: logging, credentials, tokens, secrets, security
6
+ ---
7
+
8
+ ## Do Not Log Credentials Or Tokens
9
+
10
+ Logs are often stored unencrypted and accessed by many people. Credentials in logs can be harvested by attackers or accidentally exposed.
11
+
12
+ **Incorrect (logging sensitive data):**
13
+
14
+ ```go
15
+ // Logging passwords
16
+ slog.Info("Login attempt",
17
+ "username", user.Username,
18
+ "password", user.Password, // NEVER!
19
+ )
20
+
21
+ // Logging tokens
22
+ slog.Debug("Request headers", "headers", r.Header)
23
+ // Authorization header contains token!
24
+
25
+ // Logging full request body
26
+ body, _ := io.ReadAll(r.Body)
27
+ slog.Info("Incoming request", "body", string(body))
28
+ // May contain password, credit card, etc.
29
+ ```
30
+
31
+ **Correct (sanitized logging):**
32
+
33
+ ```go
34
+ // Mask or omit sensitive fields
35
+ slog.Info("Login attempt",
36
+ "username", user.Username,
37
+ // password omitted
38
+ )
39
+
40
+ // Sanitize headers
41
+ safeHeader := r.Header.Clone()
42
+ if safeHeader.Get("Authorization") != "" {
43
+ safeHeader.Set("Authorization", "[REDACTED]")
44
+ }
45
+ slog.Debug("Request headers", "headers", safeHeader)
46
+
47
+ // Use a sanitizer for request body
48
+ func sanitizeForLog(data map[string]any) map[string]any {
49
+ sensitiveFields := []string{"password", "token", "secret", "credit_card"}
50
+ for _, field := range sensitiveFields {
51
+ if _, ok := data[field]; ok {
52
+ data[field] = "[REDACTED]"
53
+ }
54
+ }
55
+ return data
56
+ }
57
+ ```
58
+
59
+ **Never log:**
60
+ - Passwords (plaintext or hashed)
61
+ - API keys and tokens
62
+ - Credit card numbers
63
+ - Social Security Numbers
64
+ - Session identifiers
65
+
66
+ **Tools:** SonarQube, Semgrep, Log Audit
@@ -0,0 +1,55 @@
1
+ ---
2
+ title: Enforce Authorization At Trusted Service Layer
3
+ impact: CRITICAL
4
+ impactDescription: prevents client-side authorization bypass
5
+ tags: authorization, server-side, middleware, access-control, security
6
+ ---
7
+
8
+ ## Enforce Authorization At Trusted Service Layer
9
+
10
+ Client-side authorization can be bypassed. All permission checks must occur server-side where they cannot be manipulated.
11
+
12
+ **Incorrect (client-side or trusting client data):**
13
+
14
+ ```go
15
+ // Trusting client-sent role
16
+ func deleteUserHandler(w http.ResponseWriter, r *http.Request) {
17
+ userRole := r.FormValue("role") // From client!
18
+ if userRole == "admin" {
19
+ deleteUser(r.FormValue("id"))
20
+ }
21
+ }
22
+ ```
23
+
24
+ **Correct (server-side authorization middleware):**
25
+
26
+ ```go
27
+ func authMiddleware(requiredRole string, next http.HandlerFunc) http.HandlerFunc {
28
+ return func(w http.ResponseWriter, r *http.Request) {
29
+ token := r.Header.Get("Authorization")
30
+ user, err := getUserFromToken(token)
31
+ if err != nil {
32
+ http.Error(w, "Unauthorized", http.StatusUnauthorized)
33
+ return
34
+ }
35
+
36
+ if !checkPermission(user.ID, requiredRole) {
37
+ http.Error(w, "Forbidden", http.StatusForbidden)
38
+ return
39
+ }
40
+
41
+ next.ServeHTTP(w, r)
42
+ }
43
+ }
44
+
45
+ // Router usage
46
+ http.HandleFunc("/users/delete", authMiddleware("admin", deleteUserHandler))
47
+ ```
48
+
49
+ **Never trust:**
50
+ - Client-side JavaScript checks
51
+ - Hidden form fields
52
+ - URL parameters for access control
53
+ - Unvalidated tokens from browser storage
54
+
55
+ **Tools:** Manual Review, Static Analysis, Penetration Testing
@@ -0,0 +1,47 @@
1
+ ---
2
+ title: Do Not Use Default Credentials
3
+ impact: CRITICAL
4
+ impactDescription: prevents trivial compromise via known credentials
5
+ tags: credentials, default, passwords, configuration, security
6
+ ---
7
+
8
+ ## Do Not Use Default Credentials
9
+
10
+ Default credentials are publicly known. Attackers scan for them automatically, making any system using them trivially compromised.
11
+
12
+ **Incorrect (default or hardcoded credentials):**
13
+
14
+ ```yaml
15
+ # Docker Compose with defaults
16
+ services:
17
+ postgres:
18
+ image: postgres
19
+ environment:
20
+ POSTGRES_USER: postgres
21
+ POSTGRES_PASSWORD: postgres # Default!
22
+ ```
23
+
24
+ **Correct (environment/secrets management):**
25
+
26
+ ```go
27
+ // Application code
28
+ dbConfig := struct {
29
+ User string
30
+ Password string
31
+ }{
32
+ User: os.Getenv("DB_USER"),
33
+ Password: os.Getenv("DB_PASSWORD"),
34
+ }
35
+
36
+ // Validate no defaults
37
+ if dbConfig.Password == "admin" || dbConfig.Password == "password" || dbConfig.Password == "postgres" {
38
+ log.Fatal("Default credentials detected - deployment blocked")
39
+ }
40
+ ```
41
+
42
+ **Blocked defaults:**
43
+ - `admin/admin`, `root/root`, `test/test`
44
+ - `postgres/postgres`, `mysql/mysql`
45
+ - Factory default API keys
46
+
47
+ **Tools:** Secret Scanner, GitLeaks, TruffleHog, CI/CD checks
@@ -0,0 +1,50 @@
1
+ ---
2
+ title: Output Encoding Before Interpreter Use
3
+ impact: HIGH
4
+ impactDescription: prevents XSS and injection attacks
5
+ tags: xss, encoding, output, html, security
6
+ ---
7
+
8
+ ## Output Encoding Before Interpreter Use
9
+
10
+ XSS and injection attacks occur when unescaped user data is interpreted by browsers or other systems.
11
+
12
+ **Incorrect (no encoding):**
13
+
14
+ ```go
15
+ // XSS vulnerability
16
+ http.HandleFunc("/search", func(w http.ResponseWriter, r *http.Request) {
17
+ query := r.URL.Query().Get("q")
18
+ fmt.Fprintf(w, "<h1>Results for: %s</h1>", query) // XSS!
19
+ })
20
+ ```
21
+
22
+ **Correct (context-aware encoding):**
23
+
24
+ ```go
25
+ import "html"
26
+
27
+ // HTML context
28
+ http.HandleFunc("/search", func(w http.ResponseWriter, r *http.Request) {
29
+ query := r.URL.Query().Get("q")
30
+ // html.EscapeString escapes <, >, &, ', "
31
+ fmt.Fprintf(w, "<h1>Results for: %s</h1>", html.EscapeString(query))
32
+ })
33
+
34
+ // Using html/template (auto-escapes by default)
35
+ tmpl := template.Must(template.New("res").Parse("<h1>Results for: {{.}}</h1>"))
36
+ tmpl.Execute(w, query)
37
+
38
+ // URL context
39
+ safeURL := url.QueryEscape(userInput)
40
+ ```
41
+
42
+ **Encoding by Context:**
43
+
44
+ | Context | Encoding |
45
+ |---------|----------|
46
+ | HTML body | `html.EscapeString()` |
47
+ | URL | `url.QueryEscape()` |
48
+ | JSON | `json.Marshal()` |
49
+
50
+ **Tools:** SonarQube, Semgrep, `html/template` (enforced escaping)