@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,63 @@
1
+ ---
2
+ title: Use Only Approved Crypto Algorithms
3
+ impact: MEDIUM
4
+ impactDescription: ensures cryptographic strength
5
+ tags: cryptography, algorithms, hashing, encryption, security
6
+ ---
7
+
8
+ ## Use Only Approved Crypto Algorithms
9
+
10
+ Weak algorithms are broken. MD5, SHA1, DES, and ECB mode have known vulnerabilities.
11
+
12
+ **Incorrect (weak algorithms):**
13
+
14
+ ```go
15
+ import (
16
+ "crypto/md5"
17
+ "crypto/des"
18
+ "crypto/cipher"
19
+ )
20
+
21
+ // WEAK hash
22
+ h := md5.New()
23
+ h.Write([]byte(password))
24
+ hash := h.Sum(nil)
25
+
26
+ // WEAK algorithm
27
+ block, _ := des.NewCipher(key)
28
+ ```
29
+
30
+ **Correct (approved algorithms):**
31
+
32
+ ```go
33
+ import (
34
+ "crypto/aes"
35
+ "crypto/cipher"
36
+ "crypto/sha256"
37
+ "golang.org/x/crypto/bcrypt"
38
+ )
39
+
40
+ // STRONG hash (for data integrity)
41
+ h := sha256.New()
42
+ h.Write(data)
43
+ hash := h.Sum(nil)
44
+
45
+ // STRONG authenticated encryption (GCM mode)
46
+ block, _ := aes.NewCipher(key)
47
+ aesGCM, _ := cipher.NewGCM(block)
48
+ ciphertext := aesGCM.Seal(nil, nonce, plaintext, associatedData)
49
+
50
+ // For passwords - use specialized functions
51
+ hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
52
+ err := bcrypt.CompareHashAndPassword(hashedPassword, []byte(password))
53
+ ```
54
+
55
+ **Approved vs Prohibited:**
56
+
57
+ | Purpose | Approved | Prohibited |
58
+ |---------|----------|------------|
59
+ | Hash | SHA-256, SHA-3, BLAKE2 | MD5, SHA-1 |
60
+ | Encryption | AES-GCM, ChaCha20-Poly1305 | DES, 3DES, AES-ECB |
61
+ | Password | bcrypt, Argon2, scrypt | MD5, SHA-*, plain AES |
62
+
63
+ **Tools:** SonarQube, Semgrep, `crypto` (standard library)
@@ -0,0 +1,53 @@
1
+ ---
2
+ title: Use CSPRNG For Security Purposes
3
+ impact: HIGH
4
+ impactDescription: prevents predictable tokens and session hijacking
5
+ tags: random, csprng, tokens, session, cryptography, security
6
+ ---
7
+
8
+ ## Use CSPRNG For Security Purposes
9
+
10
+ Non-cryptographic random generators are predictable. Attackers can guess session tokens, OTPs, and password reset links generated with weak random sources.
11
+
12
+ **Incorrect (predictable random):**
13
+
14
+ ```go
15
+ import "math/rand"
16
+
17
+ // INSECURE - predictable!
18
+ sessionId := fmt.Sprintf("%d", rand.Intn(1000000))
19
+
20
+ // INSECURE - Seeded with time isn't enough for security tokens
21
+ rand.Seed(time.Now().UnixNano())
22
+ token := rand.Int63()
23
+ ```
24
+
25
+ **Correct (cryptographically secure):**
26
+
27
+ ```go
28
+ import (
29
+ "crypto/rand"
30
+ "encoding/hex"
31
+ "math/big"
32
+ )
33
+
34
+ // Cryptographically secure session ID
35
+ b := make([]byte, 32)
36
+ rand.Read(b)
37
+ sessionId := hex.EncodeToString(b) // 256-bit entropy
38
+
39
+ // Secure OTP generation
40
+ func generateOTP(length int) string {
41
+ max := big.NewInt(int64(math.Pow10(length)))
42
+ n, _ := rand.Int(rand.Reader, max)
43
+ return fmt.Sprintf("%0*d", length, n)
44
+ }
45
+ ```
46
+
47
+ **CSPRNG by language:**
48
+
49
+ | Language | Secure | Insecure |
50
+ |----------|--------|----------|
51
+ | Go | `crypto/rand` | `math/rand` |
52
+
53
+ **Tools:** SonarQube, Semgrep, `crypto/rand`
@@ -0,0 +1,34 @@
1
+ ---
2
+ title: Enable Encrypted Client Hello (ECH)
3
+ impact: MEDIUM
4
+ impactDescription: protects SNI from eavesdropping
5
+ tags: tls, ech, sni, privacy, security
6
+ ---
7
+
8
+ ## Enable Encrypted Client Hello (ECH)
9
+
10
+ ECH encrypts the Server Name Indication (SNI) to prevent network observers from seeing which site you're connecting to.
11
+
12
+ **About ECH:**
13
+
14
+ Encrypted Client Hello (formerly ESNI) is a TLS extension that encrypts the ClientHello message, hiding the destination hostname from network observers.
15
+
16
+ **Implementation:**
17
+
18
+ ```nginx
19
+ # Nginx with ECH (when supported)
20
+ ssl_ech on;
21
+ ssl_ech_key /path/to/ech-private-key.pem;
22
+ ```
23
+
24
+ **DNS Configuration:**
25
+
26
+ ```
27
+ # HTTPS DNS record for ECH
28
+ _https.example.com. IN HTTPS 1 . alpn="h2,h3" ipv4hint=192.0.2.1 ech="..."
29
+ ```
30
+
31
+ **Go Support:**
32
+ Go's `crypto/tls` currently (as of Go 1.22) has limited native support for ECH, but it can be implemented via specialized packages or handled at the infrastructure level (e.g., Cloudflare).
33
+
34
+ **Tools:** Cloudflare ECH, DNS Configuration
@@ -0,0 +1,49 @@
1
+ ---
2
+ title: Use Secrets Management For Backend Secrets
3
+ impact: CRITICAL
4
+ impactDescription: centralizes and secures credential storage
5
+ tags: secrets, vault, credentials, configuration, security
6
+ ---
7
+
8
+ ## Use Secrets Management For Backend Secrets
9
+
10
+ Hardcoded secrets are exposed in version control and can be accessed by anyone with code access. Use dedicated secrets management systems.
11
+
12
+ **Incorrect (hardcoded or plain env files):**
13
+
14
+ ```go
15
+ // Hardcoded in code
16
+ const APIKey = "sk-abc123xyz789"
17
+
18
+ // .env file committed to repo
19
+ DATABASE_URL=postgres://admin:password@localhost/db
20
+ ```
21
+
22
+ **Correct (secrets management):**
23
+
24
+ ```go
25
+ // Using secrets manager (AWS, HashiCorp Vault, etc.)
26
+ dbPassword, _ := secretManager.GetSecret(ctx, "production/db-password")
27
+
28
+ // Kubernetes secrets
29
+ secret := os.Getenv("DB_PASSWORD") // Mounted from K8s secret
30
+
31
+ // Environment-specific with validation
32
+ config := struct {
33
+ DBPassword string
34
+ }{
35
+ DBPassword: os.Getenv("DB_PASSWORD"),
36
+ }
37
+
38
+ if config.DBPassword == "" {
39
+ log.Fatal("DB_PASSWORD environment variable required")
40
+ }
41
+ ```
42
+
43
+ **Best practices:**
44
+ - Never commit secrets to version control
45
+ - Use secrets rotation
46
+ - Audit secret access
47
+ - Use different secrets per environment
48
+
49
+ **Tools:** HashiCorp Vault, AWS Secrets Manager, Azure Key Vault
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: Always Use TLS For All Connections
3
+ impact: HIGH
4
+ impactDescription: protects data in transit from eavesdropping
5
+ tags: tls, https, encryption, transport, security
6
+ ---
7
+
8
+ ## Always Use TLS For All Connections
9
+
10
+ Unencrypted traffic exposes data to anyone on the network path - ISPs, WiFi operators, and attackers.
11
+
12
+ **Incorrect (unencrypted connections):**
13
+
14
+ ```go
15
+ // HTTP API calls
16
+ resp, _ := http.Get("http://api.example.com/users")
17
+
18
+ // Unencrypted database
19
+ db, _ := sql.Open("postgres", "postgres://user:pass@localhost/db?sslmode=disable")
20
+
21
+ // Redis without TLS
22
+ client := redis.NewClient(&redis.Options{
23
+ Addr: "localhost:6379",
24
+ })
25
+ ```
26
+
27
+ **Correct (TLS everywhere):**
28
+
29
+ ```go
30
+ // HTTPS for all APIs
31
+ resp, _ := http.Get("https://api.example.com/users")
32
+
33
+ // TLS for database
34
+ db, _ := sql.Open("postgres", "postgres://user:pass@localhost/db?sslmode=verify-full")
35
+
36
+ // Redis with TLS
37
+ client := redis.NewClient(&redis.Options{
38
+ Addr: "localhost:6380",
39
+ TLSConfig: &tls.Config{...},
40
+ })
41
+
42
+ // Force HTTPS in a Go web server
43
+ func enforceHTTPS(next http.Handler) http.Handler {
44
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45
+ if r.Header.Get("X-Forwarded-Proto") != "https" && os.Getenv("ENV") == "production" {
46
+ http.Redirect(w, r, "https://"+r.Host+r.RequestURI, http.StatusMovedPermanently)
47
+ return
48
+ }
49
+ next.ServeHTTP(w, r)
50
+ })
51
+ }
52
+ ```
53
+
54
+ **Checklist:**
55
+ - [ ] All HTTP → HTTPS
56
+ - [ ] Database connections encrypted (sslmode=verify-full)
57
+ - [ ] Redis/memcached TLS
58
+ - [ ] Message queues TLS
59
+ - [ ] HSTS headers enabled
60
+
61
+ **Tools:** OWASP ZAP, SSLyze, `crypto/tls`
@@ -0,0 +1,42 @@
1
+ ---
2
+ title: Do Not Pass Sensitive Data In Query String
3
+ impact: HIGH
4
+ impactDescription: prevents credential leakage in logs and history
5
+ tags: url, query-string, sensitive-data, leakage, security
6
+ ---
7
+
8
+ ## Do Not Pass Sensitive Data In Query String
9
+
10
+ Query strings appear in server logs, browser history, referrer headers, and can be cached by proxies and CDNs.
11
+
12
+ **Incorrect (sensitive data in URL):**
13
+
14
+ ```go
15
+ // Tokens in URL
16
+ http.Get(fmt.Sprintf("https://api.example.com/data?token=%s", accessToken))
17
+
18
+ // Password in URL
19
+ http.Post(fmt.Sprintf("https://api.example.com/login?user=admin&pass=%s", password), "application/json", nil)
20
+ ```
21
+
22
+ **Correct (sensitive data in body/headers):**
23
+
24
+ ```go
25
+ // Token in header
26
+ req, _ := http.NewRequest("GET", "https://api.example.com/data", nil)
27
+ req.Header.Set("Authorization", "Bearer "+accessToken)
28
+ client.Do(req)
29
+
30
+ // Credentials in body
31
+ payload := map[string]string{"user": "admin", "pass": password}
32
+ jsonPayload, _ := json.Marshal(payload)
33
+ http.Post("https://api.example.com/login", "application/json", bytes.NewBuffer(jsonPayload))
34
+ ```
35
+
36
+ **Where query strings leak:**
37
+ - Server access logs
38
+ - Browser history
39
+ - Referrer headers
40
+ - Proxy/CDN logs
41
+
42
+ **Tools:** Semgrep, Manual Review, Proxy log scanner
@@ -0,0 +1,36 @@
1
+ ---
2
+ title: Always Use Parameterized Queries
3
+ impact: CRITICAL
4
+ impactDescription: prevents SQL and NoSQL injection attacks
5
+ tags: injection, sql, nosql, database, parameterized, security
6
+ ---
7
+
8
+ ## Always Use Parameterized Queries
9
+
10
+ SQL injection allows attackers to execute arbitrary database commands, steal data, or destroy databases.
11
+
12
+ **Incorrect (string concatenation):**
13
+
14
+ ```go
15
+ // SQL Injection vulnerability
16
+ userId := r.URL.Query().Get("id")
17
+ query := fmt.Sprintf("SELECT * FROM users WHERE id = '%s'", userId)
18
+ db.Query(query)
19
+
20
+ // Attacker input: ' OR '1'='1
21
+ // Resulting query: SELECT * FROM users WHERE id = '' OR '1'='1'
22
+ ```
23
+
24
+ **Correct (parameterized queries):**
25
+
26
+ ```go
27
+ // Parameterized query using database/sql
28
+ userId := r.URL.Query().Get("id")
29
+ db.Query("SELECT * FROM users WHERE id = ?", userId) // Postgres uses $1, $2
30
+
31
+ // Using GORM (safely handles parameters)
32
+ var user User
33
+ db.First(&user, "id = ?", userId)
34
+ ```
35
+
36
+ **Tools:** SonarQube, Semgrep, `sqlclosecheck`, `gosec` (G201, G202)
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Sanitize Input Before Sending Emails
3
+ impact: MEDIUM
4
+ impactDescription: prevents email header injection
5
+ tags: email, injection, sanitization, input-validation, security
6
+ ---
7
+
8
+ ## Sanitize Input Before Sending Emails
9
+
10
+ Email header injection allows attackers to add recipients, change headers, or send spam through your system.
11
+
12
+ **Incorrect (unsanitized email input):**
13
+
14
+ ```go
15
+ // Email injection vulnerability
16
+ subject := r.FormValue("subject") // "Hello\r\nBcc: spam@evil.com"
17
+ msg := []byte("Subject: " + subject + "\r\n\r\n" + "Body")
18
+ smtp.SendMail("smtp.example.com:25", auth, from, to, msg)
19
+ ```
20
+
21
+ **Correct (sanitized email fields):**
22
+
23
+ ```go
24
+ func sanitizeEmailField(input string) string {
25
+ // Remove CRLF characters that could inject headers
26
+ return strings.NewReplacer("\r", "", "\n", "").Replace(input)
27
+ }
28
+
29
+ func validateEmail(email string) bool {
30
+ // Use a robust regex or net/mail
31
+ _, err := mail.ParseAddress(email)
32
+ return err == nil && !strings.ContainsAny(email, "\r\n")
33
+ }
34
+
35
+ // In handler
36
+ subject := sanitizeEmailField(r.FormValue("subject"))
37
+ to := r.FormValue("to")
38
+ if !validateEmail(to) {
39
+ http.Error(w, "Invalid email", 400)
40
+ return
41
+ }
42
+ ```
43
+
44
+ **Tools:** Email Libraries with Built-in Protection, Manual Review, `net/mail`
@@ -0,0 +1,47 @@
1
+ ---
2
+ title: Avoid Dynamic Code Execution
3
+ impact: HIGH
4
+ impactDescription: prevents remote code execution vulnerabilities
5
+ tags: eval, code-execution, rce, injection, security
6
+ ---
7
+
8
+ ## Avoid Dynamic Code Execution
9
+
10
+ Executing arbitrary strings as code is extremely dangerous. Attackers can run any code on your server. While Go doesn't have a native `eval()` function, similar risks exist with certain libraries or `os/exec`.
11
+
12
+ **Incorrect (dynamic execution/dangerous OS calls):**
13
+
14
+ ```go
15
+ // INSECURE: Executing user-provided command
16
+ cmd := exec.Command("bash", "-c", r.URL.Query().Get("cmd"))
17
+ cmd.Run()
18
+
19
+ // INSECURE: Using a dangerous expression library with unsanitized input
20
+ result, _ := govau.Eval(r.URL.Query().Get("formula"))
21
+ ```
22
+
23
+ **Correct (safe alternatives):**
24
+
25
+ ```go
26
+ // Use switch/mapping for dynamic behavior
27
+ var operations = map[string]func(int, int) int{
28
+ "add": func(a, b int) int { return a + b },
29
+ "subtract": func(a, b int) int { return a - b },
30
+ }
31
+
32
+ opFunc, ok := operations[r.FormValue("op")]
33
+ if !ok {
34
+ http.Error(w, "Invalid operation", 400)
35
+ return
36
+ }
37
+ result := opFunc(a, b)
38
+
39
+ // Use safe parsers for math
40
+ // import "github.com/Knetic/govaluate"
41
+ expression, _ := govaluate.NewEvaluable("10 + x")
42
+ parameters := make(map[string]interface{})
43
+ parameters["x"] = 5
44
+ result, _ := expression.Evaluate(parameters)
45
+ ```
46
+
47
+ **Tools:** `gosec` (G204), Semgrep, Code Review
@@ -0,0 +1,49 @@
1
+ ---
2
+ title: Escape Data By Output Context
3
+ impact: MEDIUM
4
+ impactDescription: ensures correct encoding for each output context
5
+ tags: xss, escaping, context, encoding, security
6
+ ---
7
+
8
+ ## Escape Data By Output Context
9
+
10
+ Different contexts require different escaping strategies. Using HTML encoding in a JavaScript context doesn't prevent XSS.
11
+
12
+ **Incorrect (wrong encoding for context):**
13
+
14
+ ```go
15
+ // Wrong: same escape for all contexts
16
+ escaped := html.EscapeString(userInput)
17
+ fmt.Fprintf(w, "<script>var x = '%s';</script>", escaped) // Still vulnerable!
18
+
19
+ // Wrong: no header injection protection
20
+ w.Header().Set("X-Custom", userInput) // Header injection!
21
+ ```
22
+
23
+ **Correct (context-appropriate encoding):**
24
+
25
+ ```go
26
+ import (
27
+ "encoding/json"
28
+ "html"
29
+ "net/url"
30
+ "strings"
31
+ )
32
+
33
+ // HTML content context
34
+ fmt.Fprintf(w, "<p>%s</p>", html.EscapeString(userInput))
35
+
36
+ // JavaScript context
37
+ jsData, _ := json.Marshal(userInput)
38
+ fmt.Fprintf(w, "<script>var x = %s;</script>", jsData)
39
+
40
+ // URL parameter context
41
+ urlParam := url.QueryEscape(userInput)
42
+ http.Redirect(w, r, "/search?q="+urlParam, 302)
43
+
44
+ // HTTP header context - strip CRLF
45
+ safeHeader := strings.NewReplacer("\r", "", "\n", "").Replace(userInput)
46
+ w.Header().Set("X-Custom", safeHeader)
47
+ ```
48
+
49
+ **Tools:** `html/template` (handles context automatically), `gosec`
@@ -0,0 +1,51 @@
1
+ ---
2
+ title: Output Encoding For Dynamic JS/JSON
3
+ impact: HIGH
4
+ impactDescription: prevents injection in JavaScript contexts
5
+ tags: xss, javascript, json, encoding, security
6
+ ---
7
+
8
+ ## Output Encoding For Dynamic JS/JSON
9
+
10
+ Embedding user data in JavaScript or JSON requires proper encoding to prevent code injection.
11
+
12
+ **Incorrect (unescaped data in JS):**
13
+
14
+ ```go
15
+ // XSS in inline script
16
+ func ProfileHandler(w http.ResponseWriter, r *http.Request) {
17
+ username := r.Context().Value("username").(string) // "</script><script>alert('xss')"
18
+ fmt.Fprintf(w, "<script>var user = '%s';</script>", username)
19
+ }
20
+ ```
21
+
22
+ **Correct (proper JSON encoding):**
23
+
24
+ ```go
25
+ func ProfileHandler(w http.ResponseWriter, r *http.Request) {
26
+ user := struct {
27
+ Name string `json:"name"`
28
+ }{
29
+ Name: "User Name",
30
+ }
31
+
32
+ // json.Marshal properly escapes special characters
33
+ safeData, _ := json.Marshal(user)
34
+
35
+ fmt.Fprintf(w, `
36
+ <script>
37
+ var user = %s;
38
+ </script>
39
+ `, safeData)
40
+ }
41
+
42
+ // Using html/template (SAFE)
43
+ tmpl := template.Must(template.New("profile").Parse(`
44
+ <script>
45
+ var user = {{.}};
46
+ </script>
47
+ `))
48
+ tmpl.Execute(w, user) // Automically encodes as JSON for JS context
49
+ ```
50
+
51
+ **Tools:** `html/template`, `json.Marshal`
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: Always Validate Client Data Server-side
3
+ impact: MEDIUM
4
+ impactDescription: ensures input validation cannot be bypassed
5
+ tags: validation, server-side, input, sanitization, security
6
+ ---
7
+
8
+ ## Always Validate Client Data Server-side
9
+
10
+ Client-side validation is for UX only - it can be bypassed easily. All input must be validated server-side.
11
+
12
+ **Incorrect (trusting client validation):**
13
+
14
+ ```go
15
+ // No server validation - trusting frontend
16
+ func TransferHandler(w http.ResponseWriter, r *http.Request) {
17
+ amount, _ := strconv.Atoi(r.FormValue("amount"))
18
+ toAccount := r.FormValue("toAccount")
19
+ transferMoney(r.Context().Value("userId").(string), toAccount, amount)
20
+ }
21
+ ```
22
+
23
+ **Correct (comprehensive server validation):**
24
+
25
+ ```go
26
+ import "github.com/go-playground/validator/v10"
27
+
28
+ type TransferRequest struct {
29
+ Amount int `validate:"required,gt=0,lte=10000"`
30
+ ToAccount string `validate:"required,printascii,len=20"`
31
+ }
32
+
33
+ func TransferHandler(w http.ResponseWriter, r *http.Request) {
34
+ var req TransferRequest
35
+ // Parse and validate
36
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
37
+ http.Error(w, "Invalid request", 400)
38
+ return
39
+ }
40
+
41
+ validate := validator.New()
42
+ if err := validate.Struct(req); err != nil {
43
+ http.Error(w, err.Error(), 400)
44
+ return
45
+ }
46
+
47
+ // Additional business validation
48
+ if !accountExists(req.ToAccount) {
49
+ http.Error(w, "Account not found", 404)
50
+ return
51
+ }
52
+
53
+ transferMoney(r.Context().Value("userId").(string), req.ToAccount, req.Amount)
54
+ }
55
+ ```
56
+
57
+ **Tools:** `go-playground/validator`, `ozzo-validation`, `asaskevich/govalidator`
@@ -0,0 +1,46 @@
1
+ ---
2
+ title: TLS Encryption For All Connections
3
+ impact: CRITICAL
4
+ impactDescription: protects data in transit from interception
5
+ tags: tls, encryption, https, transport, security
6
+ ---
7
+
8
+ ## TLS Encryption For All Connections
9
+
10
+ All network communications must use TLS to prevent eavesdropping and man-in-the-middle attacks.
11
+
12
+ **Incorrect (unencrypted connections):**
13
+
14
+ ```go
15
+ // HTTP instead of HTTPS
16
+ http.Get("http://api.example.com/data")
17
+
18
+ // Unencrypted database connection
19
+ sql.Open("postgres", "host=db.example.com sslmode=disable")
20
+ ```
21
+
22
+ **Correct (TLS everywhere):**
23
+
24
+ ```go
25
+ // HTTPS for all external calls
26
+ http.Get("https://api.example.com/data")
27
+
28
+ // TLS for database
29
+ sql.Open("postgres", "host=db.example.com sslmode=verify-full")
30
+
31
+ // HSTS header in Go
32
+ func hstsMiddleware(next http.Handler) http.Handler {
33
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
34
+ w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
35
+ next.ServeHTTP(w, r)
36
+ })
37
+ }
38
+ ```
39
+
40
+ **Requirements:**
41
+ - All HTTP endpoints must redirect to HTTPS
42
+ - Database connections must use TLS (verify-full)
43
+ - Internal service-to-service calls (gRPC/HTTP) must use TLS
44
+ - HSTS headers should be enabled
45
+
46
+ **Tools:** `crypto/tls`, SSLyze, Qualys SSL Labs
@@ -0,0 +1,52 @@
1
+ ---
2
+ title: Validate mTLS Certificates Before Auth
3
+ impact: CRITICAL
4
+ impactDescription: ensures mutual authentication between services
5
+ tags: mtls, certificates, authentication, service-mesh, security
6
+ ---
7
+
8
+ ## Validate mTLS Certificates Before Auth
9
+
10
+ Mutual TLS ensures both parties are authenticated. Always validate client certificates before processing requests.
11
+
12
+ **Incorrect (skipping certificate validation):**
13
+
14
+ ```go
15
+ // Accepting any client certificate
16
+ server := &http.Server{
17
+ TLSConfig: &tls.Config{
18
+ ClientAuth: tls.RequestClientCert, // Does NOT reject invalid certs
19
+ },
20
+ }
21
+ ```
22
+
23
+ **Correct (proper mTLS validation):**
24
+
25
+ ```go
26
+ // Load CA cert
27
+ caCert, _ := os.ReadFile("ca.crt")
28
+ caCertPool := x509.NewCertPool()
29
+ caCertPool.AppendCertsFromPEM(caCert)
30
+
31
+ tlsConfig := &tls.Config{
32
+ ClientCAs: caCertPool,
33
+ ClientAuth: tls.RequireAndVerifyClientCert, // Require AND Verify
34
+ }
35
+
36
+ server := &http.Server{
37
+ TLSConfig: tlsConfig,
38
+ }
39
+
40
+ // Additional validation in handler
41
+ func handler(w http.ResponseWriter, r *http.Request) {
42
+ if len(r.TLS.PeerCertificates) > 0 {
43
+ cert := r.TLS.PeerCertificates[0]
44
+ if cert.Subject.CommonName != "trusted-service" {
45
+ http.Error(w, "Forbidden", 403)
46
+ return
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ **Tools:** `crypto/tls`, `crypto/x509`, Service Mesh (Istio, Linkerd)