codelaw-rules-security-js 0.3.0__py3-none-any.whl

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 (148) hide show
  1. codelaw_rules_security_js/LICENSE +23 -0
  2. codelaw_rules_security_js/NOTICE +22 -0
  3. codelaw_rules_security_js/README.md +183 -0
  4. codelaw_rules_security_js/codelaw-pack.toml +6 -0
  5. codelaw_rules_security_js/corpus.toml +70 -0
  6. codelaw_rules_security_js/data/sources/browser.json +24 -0
  7. codelaw_rules_security_js/data/sources/express.json +28 -0
  8. codelaw_rules_security_js/data/sources/koa.json +18 -0
  9. codelaw_rules_security_js/data/sources/llm.json +14 -0
  10. codelaw_rules_security_js/data/sources/nextjs.json +13 -0
  11. codelaw_rules_security_js/presets/sec-js/recommended.toml +58 -0
  12. codelaw_rules_security_js/presets/sec-js/strict.toml +15 -0
  13. codelaw_rules_security_js/rules/sec-js/angularjs-sce-disabled.cases.md +129 -0
  14. codelaw_rules_security_js/rules/sec-js/angularjs-sce-disabled.md +132 -0
  15. codelaw_rules_security_js/rules/sec-js/cookie-flags.cases.md +41 -0
  16. codelaw_rules_security_js/rules/sec-js/cookie-flags.md +117 -0
  17. codelaw_rules_security_js/rules/sec-js/express-hardening.cases.md +12 -0
  18. codelaw_rules_security_js/rules/sec-js/express-hardening.md +135 -0
  19. codelaw_rules_security_js/rules/sec-js/express-session-secret.cases.md +21 -0
  20. codelaw_rules_security_js/rules/sec-js/express-session-secret.md +101 -0
  21. codelaw_rules_security_js/rules/sec-js/graphql-hardening.cases.md +21 -0
  22. codelaw_rules_security_js/rules/sec-js/graphql-hardening.md +116 -0
  23. codelaw_rules_security_js/rules/sec-js/helmet-config.cases.md +21 -0
  24. codelaw_rules_security_js/rules/sec-js/helmet-config.md +88 -0
  25. codelaw_rules_security_js/rules/sec-js/jwt-verify.cases.md +41 -0
  26. codelaw_rules_security_js/rules/sec-js/jwt-verify.md +107 -0
  27. codelaw_rules_security_js/rules/sec-js/missing-rate-limit.cases.md +22 -0
  28. codelaw_rules_security_js/rules/sec-js/missing-rate-limit.md +119 -0
  29. codelaw_rules_security_js/rules/sec-js/no-archive-slip.cases.md +11 -0
  30. codelaw_rules_security_js/rules/sec-js/no-archive-slip.md +119 -0
  31. codelaw_rules_security_js/rules/sec-js/no-bad-tag-filter.cases.md +11 -0
  32. codelaw_rules_security_js/rules/sec-js/no-bad-tag-filter.md +85 -0
  33. codelaw_rules_security_js/rules/sec-js/no-biased-random.cases.md +21 -0
  34. codelaw_rules_security_js/rules/sec-js/no-biased-random.md +115 -0
  35. codelaw_rules_security_js/rules/sec-js/no-bidi-characters.cases.md +21 -0
  36. codelaw_rules_security_js/rules/sec-js/no-bidi-characters.md +123 -0
  37. codelaw_rules_security_js/rules/sec-js/no-child-process-shell.cases.md +71 -0
  38. codelaw_rules_security_js/rules/sec-js/no-child-process-shell.md +141 -0
  39. codelaw_rules_security_js/rules/sec-js/no-cleartext-http.cases.md +41 -0
  40. codelaw_rules_security_js/rules/sec-js/no-cleartext-http.md +147 -0
  41. codelaw_rules_security_js/rules/sec-js/no-cors-wildcard-credentials.cases.md +21 -0
  42. codelaw_rules_security_js/rules/sec-js/no-cors-wildcard-credentials.md +92 -0
  43. codelaw_rules_security_js/rules/sec-js/no-csrf-before-method-override.cases.md +12 -0
  44. codelaw_rules_security_js/rules/sec-js/no-csrf-before-method-override.md +128 -0
  45. codelaw_rules_security_js/rules/sec-js/no-dangerously-set-inner-html.cases.md +141 -0
  46. codelaw_rules_security_js/rules/sec-js/no-dangerously-set-inner-html.md +107 -0
  47. codelaw_rules_security_js/rules/sec-js/no-document-cookie-token.cases.md +21 -0
  48. codelaw_rules_security_js/rules/sec-js/no-document-cookie-token.md +89 -0
  49. codelaw_rules_security_js/rules/sec-js/no-dynamic-script-src.cases.md +31 -0
  50. codelaw_rules_security_js/rules/sec-js/no-dynamic-script-src.md +100 -0
  51. codelaw_rules_security_js/rules/sec-js/no-electron-insecure.cases.md +41 -0
  52. codelaw_rules_security_js/rules/sec-js/no-electron-insecure.md +134 -0
  53. codelaw_rules_security_js/rules/sec-js/no-eval.cases.md +52 -0
  54. codelaw_rules_security_js/rules/sec-js/no-eval.md +102 -0
  55. codelaw_rules_security_js/rules/sec-js/no-format-string.cases.md +11 -0
  56. codelaw_rules_security_js/rules/sec-js/no-format-string.md +115 -0
  57. codelaw_rules_security_js/rules/sec-js/no-hardcoded-crypto-key.cases.md +41 -0
  58. codelaw_rules_security_js/rules/sec-js/no-hardcoded-crypto-key.md +96 -0
  59. codelaw_rules_security_js/rules/sec-js/no-hardcoded-secret.cases.md +61 -0
  60. codelaw_rules_security_js/rules/sec-js/no-hardcoded-secret.md +112 -0
  61. codelaw_rules_security_js/rules/sec-js/no-header-injection.cases.md +21 -0
  62. codelaw_rules_security_js/rules/sec-js/no-header-injection.md +95 -0
  63. codelaw_rules_security_js/rules/sec-js/no-incomplete-sanitization.cases.md +41 -0
  64. codelaw_rules_security_js/rules/sec-js/no-incomplete-sanitization.md +113 -0
  65. codelaw_rules_security_js/rules/sec-js/no-incomplete-url-check.cases.md +61 -0
  66. codelaw_rules_security_js/rules/sec-js/no-incomplete-url-check.md +118 -0
  67. codelaw_rules_security_js/rules/sec-js/no-insecure-random.cases.md +51 -0
  68. codelaw_rules_security_js/rules/sec-js/no-insecure-random.md +127 -0
  69. codelaw_rules_security_js/rules/sec-js/no-javascript-url.cases.md +61 -0
  70. codelaw_rules_security_js/rules/sec-js/no-javascript-url.md +102 -0
  71. codelaw_rules_security_js/rules/sec-js/no-jquery-html-sink.cases.md +139 -0
  72. codelaw_rules_security_js/rules/sec-js/no-jquery-html-sink.md +131 -0
  73. codelaw_rules_security_js/rules/sec-js/no-ldap-injection.cases.md +21 -0
  74. codelaw_rules_security_js/rules/sec-js/no-ldap-injection.md +87 -0
  75. codelaw_rules_security_js/rules/sec-js/no-llm-output-to-sink.cases.md +34 -0
  76. codelaw_rules_security_js/rules/sec-js/no-llm-output-to-sink.md +105 -0
  77. codelaw_rules_security_js/rules/sec-js/no-log-injection.cases.md +11 -0
  78. codelaw_rules_security_js/rules/sec-js/no-log-injection.md +113 -0
  79. codelaw_rules_security_js/rules/sec-js/no-mass-assignment.cases.md +51 -0
  80. codelaw_rules_security_js/rules/sec-js/no-mass-assignment.md +100 -0
  81. codelaw_rules_security_js/rules/sec-js/no-new-buffer.cases.md +41 -0
  82. codelaw_rules_security_js/rules/sec-js/no-new-buffer.md +120 -0
  83. codelaw_rules_security_js/rules/sec-js/no-non-literal-fs-filename.cases.md +31 -0
  84. codelaw_rules_security_js/rules/sec-js/no-non-literal-fs-filename.md +151 -0
  85. codelaw_rules_security_js/rules/sec-js/no-non-literal-require.cases.md +41 -0
  86. codelaw_rules_security_js/rules/sec-js/no-non-literal-require.md +88 -0
  87. codelaw_rules_security_js/rules/sec-js/no-nosql-injection.cases.md +41 -0
  88. codelaw_rules_security_js/rules/sec-js/no-nosql-injection.md +114 -0
  89. codelaw_rules_security_js/rules/sec-js/no-open-redirect.cases.md +21 -0
  90. codelaw_rules_security_js/rules/sec-js/no-open-redirect.md +106 -0
  91. codelaw_rules_security_js/rules/sec-js/no-path-traversal.cases.md +54 -0
  92. codelaw_rules_security_js/rules/sec-js/no-path-traversal.md +187 -0
  93. codelaw_rules_security_js/rules/sec-js/no-prompt-injection.cases.md +31 -0
  94. codelaw_rules_security_js/rules/sec-js/no-prompt-injection.md +118 -0
  95. codelaw_rules_security_js/rules/sec-js/no-prototype-pollution.cases.md +41 -0
  96. codelaw_rules_security_js/rules/sec-js/no-prototype-pollution.md +135 -0
  97. codelaw_rules_security_js/rules/sec-js/no-secret-in-log.cases.md +31 -0
  98. codelaw_rules_security_js/rules/sec-js/no-secret-in-log.md +86 -0
  99. codelaw_rules_security_js/rules/sec-js/no-sensitive-get-query.cases.md +21 -0
  100. codelaw_rules_security_js/rules/sec-js/no-sensitive-get-query.md +89 -0
  101. codelaw_rules_security_js/rules/sec-js/no-server-env-in-client.cases.md +42 -0
  102. codelaw_rules_security_js/rules/sec-js/no-server-env-in-client.md +107 -0
  103. codelaw_rules_security_js/rules/sec-js/no-sql-template.cases.md +51 -0
  104. codelaw_rules_security_js/rules/sec-js/no-sql-template.md +112 -0
  105. codelaw_rules_security_js/rules/sec-js/no-ssrf.cases.md +41 -0
  106. codelaw_rules_security_js/rules/sec-js/no-ssrf.md +165 -0
  107. codelaw_rules_security_js/rules/sec-js/no-ssti.cases.md +54 -0
  108. codelaw_rules_security_js/rules/sec-js/no-ssti.md +128 -0
  109. codelaw_rules_security_js/rules/sec-js/no-stack-trace-response.cases.md +41 -0
  110. codelaw_rules_security_js/rules/sec-js/no-stack-trace-response.md +102 -0
  111. codelaw_rules_security_js/rules/sec-js/no-tls-bypass.cases.md +31 -0
  112. codelaw_rules_security_js/rules/sec-js/no-tls-bypass.md +117 -0
  113. codelaw_rules_security_js/rules/sec-js/no-token-in-web-storage.cases.md +41 -0
  114. codelaw_rules_security_js/rules/sec-js/no-token-in-web-storage.md +92 -0
  115. codelaw_rules_security_js/rules/sec-js/no-unsafe-deserialize.cases.md +41 -0
  116. codelaw_rules_security_js/rules/sec-js/no-unsafe-deserialize.md +115 -0
  117. codelaw_rules_security_js/rules/sec-js/no-unsafe-regex.cases.md +41 -0
  118. codelaw_rules_security_js/rules/sec-js/no-unsafe-regex.md +93 -0
  119. codelaw_rules_security_js/rules/sec-js/no-unsanitized-html.cases.md +199 -0
  120. codelaw_rules_security_js/rules/sec-js/no-unsanitized-html.md +143 -0
  121. codelaw_rules_security_js/rules/sec-js/no-unvalidated-dynamic-method.cases.md +34 -0
  122. codelaw_rules_security_js/rules/sec-js/no-unvalidated-dynamic-method.md +94 -0
  123. codelaw_rules_security_js/rules/sec-js/no-user-controlled-auth-bypass.cases.md +11 -0
  124. codelaw_rules_security_js/rules/sec-js/no-user-controlled-auth-bypass.md +102 -0
  125. codelaw_rules_security_js/rules/sec-js/no-weak-cipher.cases.md +41 -0
  126. codelaw_rules_security_js/rules/sec-js/no-weak-cipher.md +95 -0
  127. codelaw_rules_security_js/rules/sec-js/no-weak-hash.cases.md +31 -0
  128. codelaw_rules_security_js/rules/sec-js/no-weak-hash.md +97 -0
  129. codelaw_rules_security_js/rules/sec-js/no-weak-key-size.cases.md +31 -0
  130. codelaw_rules_security_js/rules/sec-js/no-weak-key-size.md +117 -0
  131. codelaw_rules_security_js/rules/sec-js/no-window-open-opener.cases.md +31 -0
  132. codelaw_rules_security_js/rules/sec-js/no-window-open-opener.md +115 -0
  133. codelaw_rules_security_js/rules/sec-js/no-xpath-injection.cases.md +21 -0
  134. codelaw_rules_security_js/rules/sec-js/no-xpath-injection.md +95 -0
  135. codelaw_rules_security_js/rules/sec-js/no-xxe.cases.md +21 -0
  136. codelaw_rules_security_js/rules/sec-js/no-xxe.md +124 -0
  137. codelaw_rules_security_js/rules/sec-js/password-hash-effort.cases.md +41 -0
  138. codelaw_rules_security_js/rules/sec-js/password-hash-effort.md +97 -0
  139. codelaw_rules_security_js/rules/sec-js/postmessage-origin.cases.md +41 -0
  140. codelaw_rules_security_js/rules/sec-js/postmessage-origin.md +125 -0
  141. codelaw_rules_security_js/rules/sec-js/timing-safe-compare.cases.md +41 -0
  142. codelaw_rules_security_js/rules/sec-js/timing-safe-compare.md +142 -0
  143. codelaw_rules_security_js/rules/sec-js/upload-limits.cases.md +21 -0
  144. codelaw_rules_security_js/rules/sec-js/upload-limits.md +115 -0
  145. codelaw_rules_security_js-0.3.0.dist-info/METADATA +193 -0
  146. codelaw_rules_security_js-0.3.0.dist-info/RECORD +148 -0
  147. codelaw_rules_security_js-0.3.0.dist-info/WHEEL +4 -0
  148. codelaw_rules_security_js-0.3.0.dist-info/licenses/LICENSE +23 -0
@@ -0,0 +1,132 @@
1
+ ---
2
+ id: sec-js/angularjs-sce-disabled
3
+ title: "No AngularJS strict contextual escaping switched off"
4
+ languages: [javascript, jsx, typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "which sources the application loads from is a decision for the author"
7
+ stability: preview
8
+ security: { cwe: [79], owasp: ["A05:2025"], severity: high }
9
+ since: 0.3.0
10
+ options:
11
+ sanitizers:
12
+ type: "call[]"
13
+ description: "functions whose result may reach the sink: a callee path (global) or { name, module }; `sanitizers_mode: replace` makes them the only ones that count"
14
+ default:
15
+ - { name: DOMPurify.sanitize, module: [dompurify, isomorphic-dompurify] }
16
+ - DOMPurify.sanitize
17
+ - { name: sanitizeHtml, module: sanitize-html }
18
+ - { name: xss, module: xss }
19
+ - { name: filterXSS, module: xss }
20
+ - { name: escapeHtml, module: escape-html }
21
+ - { name: escape, module: [lodash, lodash-es, lodash/escape, he] }
22
+ - { name: _.escape, module: [lodash, lodash-es] }
23
+ - { name: he.escape, module: he }
24
+ - "*.createHTML"
25
+ ---
26
+
27
+ AngularJS's `$sce` stays on, `resourceUrlWhitelist` has no `"**"`, the href and image whitelists are not match-everything, and `$sce.trustAs*` is not given an unsanitized value.
28
+
29
+ **Your sanitizer:** a value passes when it is a call to one of the `sanitizers`: the built-in list (DOMPurify, sanitize-html, xss, escape-html, lodash and he `escape`, Trusted Types `createHTML`) plus your own, each matched by name and by the module it is imported from, so a local `function sanitize(x) { return x }` does not pass. `sanitizers_mode = "replace"` makes yours the only ones that count. It does not follow a value through a variable: `const c = clean(x)` then `c` at the sink is not a call. Add a project function with `sanitizers = [{ name = "sanitizeHtml", module = "@acme/security" }]`.
30
+
31
+ **Why:** `$sce` is what stops a bound string from becoming HTML, a script or a frame source; switching it off or trusting every value turns each binding into an XSS sink (CWE-79).
32
+
33
+ ```codelaw
34
+ match:
35
+ any:
36
+ - pattern: $sceProvider.enabled(false)
37
+ - all:
38
+ - pattern: $SD.resourceUrlWhitelist($A)
39
+ - regex: '["'']\*\*["'']'
40
+ - all:
41
+ - pattern: $CP.$M($R)
42
+ - regex: '(aHref|imgSrc)SanitizationWhitelist\(\s*/(\^?\.\*?\$?|\^)/[a-z]*\s*\)'
43
+ - pattern: $SCE.trustAsHtml($V)
44
+ - pattern: $SCE.trustAsJs($V)
45
+ - pattern: $SCE.trustAsUrl($V)
46
+ - pattern: $SCE.trustAsResourceUrl($V)
47
+ constraints:
48
+ V: { not: { any: [ { kind: string }, { regex: '^`[^`$]*`$' } ] } }
49
+ where:
50
+ $V: { not: { calls: sanitizers } }
51
+ message: "AngularJS's strict contextual escaping is weakened here"
52
+ ```
53
+
54
+ ## How to fix
55
+
56
+ 1. Leave `$sceProvider.enabled` at its default (`true`).
57
+ 2. List the hosts a template may load from in `resourceUrlWhitelist`: `["self", "https://cdn.example.com/**"]`, not `"**"`.
58
+ 3. Pass a value to `$sce.trustAsHtml` only after a sanitizer (`$sanitize`, DOMPurify) has cleaned it.
59
+
60
+ ## Examples
61
+
62
+ ### JavaScript
63
+
64
+ #### Don't
65
+
66
+ ```js
67
+ app.config(function ($sceProvider) {
68
+ $sceProvider.enabled(false);
69
+ });
70
+ ```
71
+
72
+ #### Do
73
+
74
+ ```js
75
+ app.config(function ($sceProvider) {
76
+ $sceProvider.enabled(true);
77
+ });
78
+ ```
79
+
80
+ ### JSX
81
+
82
+ #### Don't
83
+
84
+ ```jsx
85
+ app.config(function ($sceProvider) {
86
+ $sceProvider.enabled(false);
87
+ });
88
+ ```
89
+
90
+ #### Do
91
+
92
+ ```jsx
93
+ app.config(function ($sceProvider) {
94
+ $sceProvider.enabled(true);
95
+ });
96
+ ```
97
+
98
+ ### TypeScript
99
+
100
+ #### Don't
101
+
102
+ ```ts
103
+ app.config(function ($sceProvider) {
104
+ $sceProvider.enabled(false);
105
+ });
106
+ ```
107
+
108
+ #### Do
109
+
110
+ ```ts
111
+ app.config(function ($sceProvider) {
112
+ $sceProvider.enabled(true);
113
+ });
114
+ ```
115
+
116
+ ### TSX
117
+
118
+ #### Don't
119
+
120
+ ```tsx
121
+ app.config(function ($sceProvider) {
122
+ $sceProvider.enabled(false);
123
+ });
124
+ ```
125
+
126
+ #### Do
127
+
128
+ ```tsx
129
+ app.config(function ($sceProvider) {
130
+ $sceProvider.enabled(true);
131
+ });
132
+ ```
@@ -0,0 +1,41 @@
1
+ # sec-js/cookie-flags — cases
2
+
3
+ ### case: options that lack sameSite have no mechanical fix
4
+
5
+ ```js
6
+ res.cookie("sid", sid, { httpOnly: true, secure: true });
7
+ ```
8
+
9
+ ```expect
10
+ 1:1 sec-js/cookie-flags
11
+ ```
12
+
13
+ ### case: all three flags
14
+
15
+ ```js
16
+ res.cookie("sid", sid, { httpOnly: true, secure: true, sameSite: "strict" });
17
+ ```
18
+
19
+ ```expect
20
+ (none)
21
+ ```
22
+
23
+ ### case: koa
24
+
25
+ ```js
26
+ ctx.cookies.set("sid", id);
27
+ ```
28
+
29
+ ```expect
30
+ 1:1 sec-js/cookie-flags
31
+ ```
32
+
33
+ ### case: fastify
34
+
35
+ ```js
36
+ reply.setCookie("sid", id);
37
+ ```
38
+
39
+ ```expect
40
+ 1:1 sec-js/cookie-flags
41
+ ```
@@ -0,0 +1,117 @@
1
+ ---
2
+ id: sec-js/cookie-flags
3
+ title: "A cookie sets httpOnly, secure and sameSite"
4
+ languages: [javascript, jsx, typescript, tsx]
5
+ fix: suggest
6
+ fix_reason: "a cookie a script must read, or one used cross-site, needs different flags"
7
+ stability: preview
8
+ security: { cwe: [614, 1004], owasp: ["A02:2025"], severity: medium }
9
+ since: 0.3.0
10
+ ---
11
+
12
+ `res.cookie`, `reply.setCookie` and `ctx.cookies.set` pass an options object with `httpOnly`, `secure` and `sameSite`.
13
+
14
+ **Why:** Without `httpOnly` a script reads the cookie, without `secure` it travels over plain HTTP, and without `sameSite` the browser sends it on cross-site requests (CWE-614, CWE-1004, CWE-352).
15
+
16
+ ```codelaw
17
+ match:
18
+ any:
19
+ - pattern: $C($N, $V)
20
+ - pattern: $C2($N2, $V2, $OPTS)
21
+ constraints:
22
+ C: { regex: '^(res|response)\.cookie$|^reply\.setCookie$|^ctx\.cookies\.set$' }
23
+ C2: { regex: '^(res|response)\.cookie$|^reply\.setCookie$|^ctx\.cookies\.set$' }
24
+ OPTS:
25
+ any:
26
+ - not: { regex: 'httpOnly' }
27
+ - not: { regex: 'secure' }
28
+ - not: { regex: 'sameSite' }
29
+ message: "This cookie is missing `httpOnly`, `secure` or `sameSite`"
30
+ fix:
31
+ - replace: "$C($N, $V, { httpOnly: true, secure: true, sameSite: \"lax\" })"
32
+ ```
33
+
34
+ ## How to fix
35
+
36
+
37
+ ## Examples
38
+
39
+ ### JavaScript
40
+
41
+ #### Don't
42
+
43
+ ```js
44
+ res.cookie("sid", sid);
45
+ ```
46
+
47
+ #### Do
48
+
49
+ ```js
50
+ res.cookie("sid", sid, { httpOnly: true, secure: true, sameSite: "lax" });
51
+ ```
52
+
53
+ #### Fixed
54
+
55
+ ```js
56
+ res.cookie("sid", sid, { httpOnly: true, secure: true, sameSite: "lax" });
57
+ ```
58
+
59
+ ### JSX
60
+
61
+ #### Don't
62
+
63
+ ```jsx
64
+ res.cookie("sid", sid);
65
+ ```
66
+
67
+ #### Do
68
+
69
+ ```jsx
70
+ res.cookie("sid", sid, { httpOnly: true, secure: true, sameSite: "lax" });
71
+ ```
72
+
73
+ #### Fixed
74
+
75
+ ```jsx
76
+ res.cookie("sid", sid, { httpOnly: true, secure: true, sameSite: "lax" });
77
+ ```
78
+
79
+ ### TypeScript
80
+
81
+ #### Don't
82
+
83
+ ```ts
84
+ res.cookie("sid", sid);
85
+ ```
86
+
87
+ #### Do
88
+
89
+ ```ts
90
+ res.cookie("sid", sid, { httpOnly: true, secure: true, sameSite: "lax" });
91
+ ```
92
+
93
+ #### Fixed
94
+
95
+ ```ts
96
+ res.cookie("sid", sid, { httpOnly: true, secure: true, sameSite: "lax" });
97
+ ```
98
+
99
+ ### TSX
100
+
101
+ #### Don't
102
+
103
+ ```tsx
104
+ res.cookie("sid", sid);
105
+ ```
106
+
107
+ #### Do
108
+
109
+ ```tsx
110
+ res.cookie("sid", sid, { httpOnly: true, secure: true, sameSite: "lax" });
111
+ ```
112
+
113
+ #### Fixed
114
+
115
+ ```tsx
116
+ res.cookie("sid", sid, { httpOnly: true, secure: true, sameSite: "lax" });
117
+ ```
@@ -0,0 +1,12 @@
1
+ # sec-js/express-hardening — cases
2
+
3
+ ### case: disabled in the file
4
+
5
+ ```js
6
+ const app = express();
7
+ app.disable("x-powered-by");
8
+ ```
9
+
10
+ ```expect
11
+ (none)
12
+ ```
@@ -0,0 +1,135 @@
1
+ ---
2
+ id: sec-js/express-hardening
3
+ title: "An Express app turns off x-powered-by or uses helmet"
4
+ languages: [javascript, jsx, typescript, tsx]
5
+ fix: suggest
6
+ fix_reason: "`app.use(helmet())` is the better fix and needs an import; the inserted line only hides the framework"
7
+ stability: preview
8
+ security: { cwe: [200], owasp: ["A02:2025"], severity: low }
9
+ since: 0.3.0
10
+ ---
11
+
12
+ A file that creates an Express app also calls `helmet()` or disables `x-powered-by`.
13
+
14
+ **Why:** The default `X-Powered-By: Express` header names the framework for every scanner, and without `helmet` the app sends none of the headers that limit framing, sniffing and mixed content (CWE-200).
15
+
16
+ ```codelaw
17
+ match:
18
+ all:
19
+ - pattern: const $A = express()
20
+ - not:
21
+ inside:
22
+ kind: program
23
+ stopBy: end
24
+ has:
25
+ stopBy: end
26
+ regex: 'helmet|x-powered-by'
27
+ message: "This Express app does not call `helmet()` or disable `x-powered-by`"
28
+ fix:
29
+ - insert-after: "\n$A.disable(\"x-powered-by\");"
30
+ ```
31
+
32
+ ## How to fix
33
+
34
+
35
+ ## Examples
36
+
37
+ ### JavaScript
38
+
39
+ #### Don't
40
+
41
+ ```js
42
+ const app = express();
43
+ app.get("/", handler);
44
+ ```
45
+
46
+ #### Do
47
+
48
+ ```js
49
+ const app = express();
50
+ app.use(helmet());
51
+ app.get("/", handler);
52
+ ```
53
+
54
+ #### Fixed
55
+
56
+ ```js
57
+ const app = express();
58
+ app.disable("x-powered-by");
59
+ app.get("/", handler);
60
+ ```
61
+
62
+ ### JSX
63
+
64
+ #### Don't
65
+
66
+ ```jsx
67
+ const app = express();
68
+ app.get("/", handler);
69
+ ```
70
+
71
+ #### Do
72
+
73
+ ```jsx
74
+ const app = express();
75
+ app.use(helmet());
76
+ app.get("/", handler);
77
+ ```
78
+
79
+ #### Fixed
80
+
81
+ ```jsx
82
+ const app = express();
83
+ app.disable("x-powered-by");
84
+ app.get("/", handler);
85
+ ```
86
+
87
+ ### TypeScript
88
+
89
+ #### Don't
90
+
91
+ ```ts
92
+ const app = express();
93
+ app.get("/", handler);
94
+ ```
95
+
96
+ #### Do
97
+
98
+ ```ts
99
+ const app = express();
100
+ app.use(helmet());
101
+ app.get("/", handler);
102
+ ```
103
+
104
+ #### Fixed
105
+
106
+ ```ts
107
+ const app = express();
108
+ app.disable("x-powered-by");
109
+ app.get("/", handler);
110
+ ```
111
+
112
+ ### TSX
113
+
114
+ #### Don't
115
+
116
+ ```tsx
117
+ const app = express();
118
+ app.get("/", handler);
119
+ ```
120
+
121
+ #### Do
122
+
123
+ ```tsx
124
+ const app = express();
125
+ app.use(helmet());
126
+ app.get("/", handler);
127
+ ```
128
+
129
+ #### Fixed
130
+
131
+ ```tsx
132
+ const app = express();
133
+ app.disable("x-powered-by");
134
+ app.get("/", handler);
135
+ ```
@@ -0,0 +1,21 @@
1
+ # sec-js/express-session-secret — cases
2
+
3
+ ### case: secure false
4
+
5
+ ```js
6
+ session({ secret: key, cookie: { secure: false } });
7
+ ```
8
+
9
+ ```expect
10
+ 1:1 sec-js/express-session-secret
11
+ ```
12
+
13
+ ### case: cookie-session keys
14
+
15
+ ```js
16
+ cookieSession({ keys: ["a"] });
17
+ ```
18
+
19
+ ```expect
20
+ 1:1 sec-js/express-session-secret
21
+ ```
@@ -0,0 +1,101 @@
1
+ ---
2
+ id: sec-js/express-session-secret
3
+ title: "express-session has a secret from the environment and a secure cookie"
4
+ languages: [javascript, jsx, typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "where the secret comes from is a deployment decision"
7
+ stability: preview
8
+ security: { cwe: [798, 614], owasp: ["A07:2025"], severity: high }
9
+ since: 0.3.0
10
+ ---
11
+
12
+ `express-session`, `cookie-session` and `session()` are not given a literal `secret`, and their cookie does not set `secure: false`.
13
+
14
+ **Why:** A secret in the source is in every clone and every build; anyone who has it forges a session cookie, and `secure: false` lets the cookie travel over plain HTTP (CWE-798, CWE-614).
15
+
16
+ ```codelaw
17
+ match:
18
+ any:
19
+ - all:
20
+ - any:
21
+ - pattern: session($$$A)
22
+ - pattern: expressSession($$$A)
23
+ - pattern: cookieSession($$$A)
24
+ - has:
25
+ kind: pair
26
+ stopBy: end
27
+ regex: '^["'']?(secret|keys?)["'']?\s*:\s*(["'']|\[\s*["''])'
28
+ - all:
29
+ - any:
30
+ - pattern: session($$$B)
31
+ - pattern: expressSession($$$B)
32
+ - pattern: cookieSession($$$B)
33
+ - has:
34
+ kind: pair
35
+ stopBy: end
36
+ regex: '^["'']?secure["'']?\s*:\s*false\s*$'
37
+ message: "The session secret is a literal in the source, or the session cookie is not marked secure"
38
+ ```
39
+
40
+ ## How to fix
41
+
42
+ 1. Read the secret from the environment or a secret store, and rotate it if it was ever committed.
43
+ 2. Set `cookie: { secure: true, httpOnly: true, sameSite: "lax" }` in production (behind a proxy, set `trust proxy`).
44
+
45
+ ## Examples
46
+
47
+ ### JavaScript
48
+
49
+ #### Don't
50
+
51
+ ```js
52
+ app.use(session({ secret: "keyboard cat", resave: false }));
53
+ ```
54
+
55
+ #### Do
56
+
57
+ ```js
58
+ app.use(session({ secret: process.env.SESSION_SECRET, resave: false }));
59
+ ```
60
+
61
+ ### JSX
62
+
63
+ #### Don't
64
+
65
+ ```jsx
66
+ app.use(session({ secret: "keyboard cat", resave: false }));
67
+ ```
68
+
69
+ #### Do
70
+
71
+ ```jsx
72
+ app.use(session({ secret: process.env.SESSION_SECRET, resave: false }));
73
+ ```
74
+
75
+ ### TypeScript
76
+
77
+ #### Don't
78
+
79
+ ```ts
80
+ app.use(session({ secret: "keyboard cat", resave: false }));
81
+ ```
82
+
83
+ #### Do
84
+
85
+ ```ts
86
+ app.use(session({ secret: process.env.SESSION_SECRET, resave: false }));
87
+ ```
88
+
89
+ ### TSX
90
+
91
+ #### Don't
92
+
93
+ ```tsx
94
+ app.use(session({ secret: "keyboard cat", resave: false }));
95
+ ```
96
+
97
+ #### Do
98
+
99
+ ```tsx
100
+ app.use(session({ secret: process.env.SESSION_SECRET, resave: false }));
101
+ ```
@@ -0,0 +1,21 @@
1
+ # sec-js/graphql-hardening — cases
2
+
3
+ ### case: introspection
4
+
5
+ ```js
6
+ const o = { introspection: true };
7
+ ```
8
+
9
+ ```expect
10
+ 1:13 sec-js/graphql-hardening
11
+ ```
12
+
13
+ ### case: yoga without limits
14
+
15
+ ```js
16
+ createYoga({ schema });
17
+ ```
18
+
19
+ ```expect
20
+ 1:1 sec-js/graphql-hardening
21
+ ```
@@ -0,0 +1,116 @@
1
+ ---
2
+ id: sec-js/graphql-hardening
3
+ title: "A GraphQL server limits query depth and cost, and hides introspection"
4
+ languages: [javascript, jsx, typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "the limits that fit the schema are a decision for the author"
7
+ stability: preview
8
+ security: { cwe: [200, 770], owasp: ["A02:2025"], severity: medium }
9
+ since: 0.3.0
10
+ ---
11
+
12
+ An Apollo, Yoga or express-graphql server names a depth or cost limit in its options, and does not set `introspection: true`.
13
+
14
+ **Why:** A query can nest or fan out without bound and exhaust the server, and introspection hands an attacker the whole schema (CWE-770, CWE-200).
15
+
16
+ ```codelaw
17
+ match:
18
+ any:
19
+ - all:
20
+ - any:
21
+ - pattern: new ApolloServer($$$A)
22
+ - pattern: createYoga($$$A)
23
+ - pattern: graphqlHTTP($$$A)
24
+ - pattern: createHandler($$$A)
25
+ - not:
26
+ has:
27
+ stopBy: end
28
+ regex: '(?i)depthLimit|costLimit|queryComplexity|maxDepth|validationRules|cost|complexity|armor'
29
+ - pattern:
30
+ context: '({ introspection: true })'
31
+ selector: pair
32
+ message: "This GraphQL server has no depth or cost limit, or leaves introspection on"
33
+ ```
34
+
35
+ ## How to fix
36
+
37
+ 1. Add a depth limit (`graphql-depth-limit`) and a cost or complexity limit to `validationRules`, and cap the page size of list fields.
38
+ 2. Turn introspection off in production, and use persisted queries where the clients are your own.
39
+
40
+ ## Examples
41
+
42
+ ### JavaScript
43
+
44
+ #### Don't
45
+
46
+ ```js
47
+ const server = new ApolloServer({ typeDefs, resolvers });
48
+ ```
49
+
50
+ #### Do
51
+
52
+ ```js
53
+ const server = new ApolloServer({
54
+ typeDefs,
55
+ resolvers,
56
+ validationRules: [depthLimit(8)],
57
+ introspection: process.env.NODE_ENV !== "production",
58
+ });
59
+ ```
60
+
61
+ ### JSX
62
+
63
+ #### Don't
64
+
65
+ ```jsx
66
+ const server = new ApolloServer({ typeDefs, resolvers });
67
+ ```
68
+
69
+ #### Do
70
+
71
+ ```jsx
72
+ const server = new ApolloServer({
73
+ typeDefs,
74
+ resolvers,
75
+ validationRules: [depthLimit(8)],
76
+ introspection: process.env.NODE_ENV !== "production",
77
+ });
78
+ ```
79
+
80
+ ### TypeScript
81
+
82
+ #### Don't
83
+
84
+ ```ts
85
+ const server = new ApolloServer({ typeDefs, resolvers });
86
+ ```
87
+
88
+ #### Do
89
+
90
+ ```ts
91
+ const server = new ApolloServer({
92
+ typeDefs,
93
+ resolvers,
94
+ validationRules: [depthLimit(8)],
95
+ introspection: process.env.NODE_ENV !== "production",
96
+ });
97
+ ```
98
+
99
+ ### TSX
100
+
101
+ #### Don't
102
+
103
+ ```tsx
104
+ const server = new ApolloServer({ typeDefs, resolvers });
105
+ ```
106
+
107
+ #### Do
108
+
109
+ ```tsx
110
+ const server = new ApolloServer({
111
+ typeDefs,
112
+ resolvers,
113
+ validationRules: [depthLimit(8)],
114
+ introspection: process.env.NODE_ENV !== "production",
115
+ });
116
+ ```