pi-lens 3.8.21 → 3.8.23
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.
- package/CHANGELOG.md +28 -0
- package/README.md +2 -0
- package/clients/dispatch/dispatcher.ts +75 -91
- package/clients/dispatch/fact-provider-types.ts +22 -0
- package/clients/dispatch/fact-rule-runner.ts +22 -0
- package/clients/dispatch/fact-runner.ts +28 -0
- package/clients/dispatch/fact-scheduler.ts +78 -0
- package/clients/dispatch/fact-store.ts +67 -0
- package/clients/dispatch/facts/comment-facts.ts +59 -0
- package/clients/dispatch/facts/file-content.ts +20 -0
- package/clients/dispatch/facts/function-facts.ts +177 -0
- package/clients/dispatch/facts/try-catch-facts.ts +80 -0
- package/clients/dispatch/integration.ts +130 -24
- package/clients/dispatch/priorities.ts +22 -0
- package/clients/dispatch/rules/async-noise.ts +43 -0
- package/clients/dispatch/rules/error-obscuring.ts +40 -0
- package/clients/dispatch/rules/error-swallowing.ts +35 -0
- package/clients/dispatch/rules/pass-through-wrappers.ts +52 -0
- package/clients/dispatch/rules/placeholder-comments.ts +47 -0
- package/clients/dispatch/runners/architect.ts +2 -1
- package/clients/dispatch/runners/ast-grep-napi.ts +2 -1
- package/clients/dispatch/runners/biome-check.ts +40 -8
- package/clients/dispatch/runners/biome.ts +2 -1
- package/clients/dispatch/runners/eslint.ts +34 -6
- package/clients/dispatch/runners/go-vet.ts +2 -1
- package/clients/dispatch/runners/golangci-lint.ts +2 -1
- package/clients/dispatch/runners/index.ts +29 -27
- package/clients/dispatch/runners/lsp.ts +60 -4
- package/clients/dispatch/runners/oxlint.ts +2 -1
- package/clients/dispatch/runners/pyright.ts +2 -1
- package/clients/dispatch/runners/python-slop.ts +2 -1
- package/clients/dispatch/runners/rubocop.ts +2 -1
- package/clients/dispatch/runners/ruff.ts +2 -1
- package/clients/dispatch/runners/rust-clippy.ts +2 -1
- package/clients/dispatch/runners/shellcheck.ts +2 -1
- package/clients/dispatch/runners/similarity.ts +2 -1
- package/clients/dispatch/runners/spellcheck.ts +2 -1
- package/clients/dispatch/runners/sqlfluff.ts +2 -1
- package/clients/dispatch/runners/tree-sitter.ts +469 -1
- package/clients/dispatch/runners/ts-lsp.ts +2 -1
- package/clients/dispatch/runners/type-safety.ts +2 -1
- package/clients/dispatch/runners/yamllint.ts +2 -1
- package/clients/dispatch/tool-profile.ts +40 -0
- package/clients/dispatch/types.ts +3 -13
- package/clients/lsp/client.ts +366 -12
- package/clients/lsp/index.ts +374 -76
- package/clients/lsp/launch.ts +42 -2
- package/clients/lsp/server.ts +186 -12
- package/clients/pipeline.ts +2 -2
- package/clients/runtime-context.ts +2 -2
- package/clients/runtime-session.ts +43 -5
- package/clients/session-summary.ts +21 -0
- package/clients/tree-sitter-client.ts +162 -0
- package/clients/tree-sitter-logger.ts +47 -0
- package/clients/tree-sitter-query-loader.ts +13 -2
- package/index.ts +67 -17
- package/package.json +3 -1
- package/rules/rule-catalog.json +64 -0
- package/rules/tree-sitter-queries/go/go-bare-error.yml +19 -7
- package/rules/tree-sitter-queries/go/go-command-injection.yml +55 -0
- package/rules/tree-sitter-queries/go/go-direct-panic.yml +45 -0
- package/rules/tree-sitter-queries/go/go-empty-if-err.yml +47 -0
- package/rules/tree-sitter-queries/go/go-goroutine-loop-capture.yml +49 -0
- package/rules/tree-sitter-queries/go/go-ignored-call-result.yml +51 -0
- package/rules/tree-sitter-queries/go/go-insecure-random.yml +51 -0
- package/rules/tree-sitter-queries/go/go-log-fatal.yml +49 -0
- package/rules/tree-sitter-queries/go/go-path-traversal.yml +51 -0
- package/rules/tree-sitter-queries/go/go-shared-map-write-goroutine.yml +54 -0
- package/rules/tree-sitter-queries/go/go-sql-injection.yml +55 -0
- package/rules/tree-sitter-queries/go/go-weak-hash.yml +51 -0
- package/rules/tree-sitter-queries/python/python-command-injection.yml +63 -0
- package/rules/tree-sitter-queries/python/python-insecure-deserialization.yml +48 -0
- package/rules/tree-sitter-queries/python/python-insecure-random.yml +51 -0
- package/rules/tree-sitter-queries/python/python-path-traversal.yml +55 -0
- package/rules/tree-sitter-queries/python/python-sql-injection.yml +47 -0
- package/rules/tree-sitter-queries/python/python-ssrf.yml +50 -0
- package/rules/tree-sitter-queries/python/python-thread-global-write.yml +58 -0
- package/rules/tree-sitter-queries/python/python-weak-hash.yml +51 -0
- package/rules/tree-sitter-queries/ruby/ruby-command-injection.yml +56 -0
- package/rules/tree-sitter-queries/ruby/ruby-insecure-deserialization.yml +47 -0
- package/rules/tree-sitter-queries/ruby/ruby-insecure-random.yml +54 -0
- package/rules/tree-sitter-queries/ruby/ruby-weak-hash.yml +50 -0
- package/rules/tree-sitter-queries/rust/rust-lock-held-across-await.yml +59 -0
- package/rules/tree-sitter-queries/typescript/ts-command-injection.yml +60 -0
- package/rules/tree-sitter-queries/typescript/ts-detached-async-call.yml +56 -0
- package/rules/tree-sitter-queries/typescript/ts-insecure-random.yml +54 -0
- package/rules/tree-sitter-queries/typescript/ts-ssrf.yml +53 -0
- package/rules/tree-sitter-queries/typescript/ts-weak-hash.yml +54 -0
- package/scripts/validate-rule-catalog.mjs +227 -0
- package/skills/lsp-navigation/SKILL.md +15 -3
- package/tools/lsp-navigation.js +466 -79
- package/tools/lsp-navigation.ts +587 -85
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Ruby Security
|
|
2
|
+
# Detects shell execution sinks frequently involved in command injection.
|
|
3
|
+
id: ruby-command-injection
|
|
4
|
+
name: Command Injection Sink
|
|
5
|
+
severity: warning
|
|
6
|
+
category: security
|
|
7
|
+
defect_class: injection
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: ruby
|
|
10
|
+
|
|
11
|
+
message: "Potential command injection sink — avoid shell execution with untrusted input"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Ruby shell execution APIs (`system`, `exec`, `spawn`, backticks) can execute
|
|
15
|
+
user-controlled command strings.
|
|
16
|
+
|
|
17
|
+
✅ FIX: avoid shell interpolation and use safer APIs with strict allowlists.
|
|
18
|
+
|
|
19
|
+
query: |
|
|
20
|
+
(call
|
|
21
|
+
method: (identifier) @FN
|
|
22
|
+
arguments: (argument_list) @ARGS)
|
|
23
|
+
(#match? @FN "^(system|exec|spawn|popen|capture3|capture2|capture2e)$")
|
|
24
|
+
|
|
25
|
+
(command
|
|
26
|
+
method: (identifier) @FN
|
|
27
|
+
argument: (_) @ARGS)
|
|
28
|
+
(#match? @FN "^(system|exec|spawn|popen)$")
|
|
29
|
+
|
|
30
|
+
(call_expression
|
|
31
|
+
receiver: (constant) @NS
|
|
32
|
+
method: (identifier) @FN
|
|
33
|
+
arguments: (argument_list) @ARGS)
|
|
34
|
+
(#match? @FN "^(system|exec|spawn|popen|capture3|capture2|capture2e)$")
|
|
35
|
+
|
|
36
|
+
metavars:
|
|
37
|
+
- FN
|
|
38
|
+
- ARGS
|
|
39
|
+
|
|
40
|
+
post_filter: ruby_command_injection_sink
|
|
41
|
+
|
|
42
|
+
has_fix: false
|
|
43
|
+
|
|
44
|
+
tags:
|
|
45
|
+
- ruby
|
|
46
|
+
- security
|
|
47
|
+
- command-injection
|
|
48
|
+
- cwe-78
|
|
49
|
+
- owasp-a03
|
|
50
|
+
|
|
51
|
+
examples:
|
|
52
|
+
bad: |
|
|
53
|
+
system("sh -c #{params[:cmd]}")
|
|
54
|
+
|
|
55
|
+
good: |
|
|
56
|
+
Open3.capture3("git", "status")
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Ruby Security
|
|
2
|
+
# Detects unsafe deserialization APIs.
|
|
3
|
+
id: ruby-insecure-deserialization
|
|
4
|
+
name: Insecure Deserialization
|
|
5
|
+
severity: warning
|
|
6
|
+
category: security
|
|
7
|
+
defect_class: injection
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: ruby
|
|
10
|
+
|
|
11
|
+
message: "Potential insecure deserialization sink — avoid unsafe loaders"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Deserializing untrusted data with Marshal/YAML loaders can enable code execution.
|
|
15
|
+
|
|
16
|
+
✅ FIX: use safe serialization formats and strict schema validation.
|
|
17
|
+
|
|
18
|
+
query: |
|
|
19
|
+
(call_expression
|
|
20
|
+
receiver: (constant) @MOD
|
|
21
|
+
method: (identifier) @FN
|
|
22
|
+
arguments: (argument_list (_) @DATA))
|
|
23
|
+
(#match? @MOD "^(Marshal|YAML|Psych)$")
|
|
24
|
+
(#match? @FN "^(load|unsafe_load)$")
|
|
25
|
+
|
|
26
|
+
metavars:
|
|
27
|
+
- MOD
|
|
28
|
+
- FN
|
|
29
|
+
- DATA
|
|
30
|
+
|
|
31
|
+
post_filter: ruby_insecure_deserialization_sink
|
|
32
|
+
|
|
33
|
+
has_fix: false
|
|
34
|
+
|
|
35
|
+
tags:
|
|
36
|
+
- ruby
|
|
37
|
+
- security
|
|
38
|
+
- deserialization
|
|
39
|
+
- cwe-502
|
|
40
|
+
- owasp-a08
|
|
41
|
+
|
|
42
|
+
examples:
|
|
43
|
+
bad: |
|
|
44
|
+
Marshal.load(payload)
|
|
45
|
+
|
|
46
|
+
good: |
|
|
47
|
+
JSON.parse(payload)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Ruby Security
|
|
2
|
+
# Detects non-cryptographic randomness usage.
|
|
3
|
+
id: ruby-insecure-random
|
|
4
|
+
name: Insecure Randomness
|
|
5
|
+
severity: warning
|
|
6
|
+
category: security
|
|
7
|
+
defect_class: injection
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: ruby
|
|
10
|
+
|
|
11
|
+
message: "Insecure randomness source detected — use SecureRandom for security-sensitive values"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Kernel.rand/Random.new are not suitable for security-sensitive tokens.
|
|
15
|
+
|
|
16
|
+
✅ FIX: use SecureRandom.hex/base64/uuid.
|
|
17
|
+
|
|
18
|
+
query: |
|
|
19
|
+
[
|
|
20
|
+
(call
|
|
21
|
+
method: (identifier) @FN
|
|
22
|
+
arguments: (argument_list) @ARGS)
|
|
23
|
+
(call_expression
|
|
24
|
+
receiver: (constant) @MOD
|
|
25
|
+
method: (identifier) @FN
|
|
26
|
+
arguments: (argument_list) @ARGS)
|
|
27
|
+
]
|
|
28
|
+
(#match? @FN "^(rand|srand)$")
|
|
29
|
+
|
|
30
|
+
metavars:
|
|
31
|
+
- MOD
|
|
32
|
+
- FN
|
|
33
|
+
- ARGS
|
|
34
|
+
|
|
35
|
+
cwe:
|
|
36
|
+
- CWE-330
|
|
37
|
+
owasp:
|
|
38
|
+
- A02
|
|
39
|
+
confidence: medium
|
|
40
|
+
|
|
41
|
+
has_fix: false
|
|
42
|
+
|
|
43
|
+
tags:
|
|
44
|
+
- ruby
|
|
45
|
+
- security
|
|
46
|
+
- randomness
|
|
47
|
+
- weak-prng
|
|
48
|
+
|
|
49
|
+
examples:
|
|
50
|
+
bad: |
|
|
51
|
+
token = rand(10_000_000)
|
|
52
|
+
|
|
53
|
+
good: |
|
|
54
|
+
token = SecureRandom.hex(16)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Ruby Security
|
|
2
|
+
# Detects weak digest algorithm usage.
|
|
3
|
+
id: ruby-weak-hash
|
|
4
|
+
name: Weak Hash Primitive
|
|
5
|
+
severity: warning
|
|
6
|
+
category: security
|
|
7
|
+
defect_class: injection
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: ruby
|
|
10
|
+
|
|
11
|
+
message: "Weak hash primitive detected (MD5/SHA1) — use SHA-256+ for security-sensitive contexts"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Digest::MD5 and Digest::SHA1 are not suitable for secure hashing.
|
|
15
|
+
|
|
16
|
+
✅ FIX: use Digest::SHA256 or stronger algorithms.
|
|
17
|
+
|
|
18
|
+
query: |
|
|
19
|
+
(call_expression
|
|
20
|
+
receiver: (constant) @MOD
|
|
21
|
+
method: (identifier) @FN
|
|
22
|
+
arguments: (argument_list) @ARGS)
|
|
23
|
+
(#match? @MOD "^(Digest::MD5|Digest::SHA1)$")
|
|
24
|
+
(#match? @FN "^(hexdigest|digest|base64digest)$")
|
|
25
|
+
|
|
26
|
+
metavars:
|
|
27
|
+
- MOD
|
|
28
|
+
- FN
|
|
29
|
+
- ARGS
|
|
30
|
+
|
|
31
|
+
cwe:
|
|
32
|
+
- CWE-327
|
|
33
|
+
owasp:
|
|
34
|
+
- A02
|
|
35
|
+
confidence: high
|
|
36
|
+
|
|
37
|
+
has_fix: false
|
|
38
|
+
|
|
39
|
+
tags:
|
|
40
|
+
- ruby
|
|
41
|
+
- security
|
|
42
|
+
- crypto
|
|
43
|
+
- weak-hash
|
|
44
|
+
|
|
45
|
+
examples:
|
|
46
|
+
bad: |
|
|
47
|
+
Digest::MD5.hexdigest(data)
|
|
48
|
+
|
|
49
|
+
good: |
|
|
50
|
+
Digest::SHA256.hexdigest(data)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Rust Concurrency
|
|
2
|
+
# Detects lock guards obtained via lock().await and additional await in same block.
|
|
3
|
+
id: rust-lock-held-across-await
|
|
4
|
+
name: Lock Held Across Await
|
|
5
|
+
severity: warning
|
|
6
|
+
category: concurrency
|
|
7
|
+
defect_class: async-misuse
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: rust
|
|
10
|
+
|
|
11
|
+
message: "Lock guard may be held across await — release lock before awaiting other work"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Awaiting while holding a mutex guard can cause contention and deadlocks.
|
|
15
|
+
|
|
16
|
+
✅ FIX: limit lock scope, clone needed data, then await outside lock lifetime.
|
|
17
|
+
|
|
18
|
+
query: |
|
|
19
|
+
(block
|
|
20
|
+
(let_declaration
|
|
21
|
+
pattern: (identifier) @GUARD
|
|
22
|
+
value: (await_expression
|
|
23
|
+
expression: (call_expression
|
|
24
|
+
function: (field_expression
|
|
25
|
+
field: (field_identifier) @LOCKFN))))
|
|
26
|
+
(_)*
|
|
27
|
+
(await_expression) @LATER_AWAIT)
|
|
28
|
+
(#eq? @LOCKFN "lock")
|
|
29
|
+
|
|
30
|
+
metavars:
|
|
31
|
+
- GUARD
|
|
32
|
+
- LOCKFN
|
|
33
|
+
- LATER_AWAIT
|
|
34
|
+
|
|
35
|
+
cwe:
|
|
36
|
+
- CWE-833
|
|
37
|
+
owasp:
|
|
38
|
+
- A09
|
|
39
|
+
confidence: low
|
|
40
|
+
|
|
41
|
+
has_fix: false
|
|
42
|
+
|
|
43
|
+
tags:
|
|
44
|
+
- rust
|
|
45
|
+
- concurrency
|
|
46
|
+
- mutex
|
|
47
|
+
- async
|
|
48
|
+
|
|
49
|
+
examples:
|
|
50
|
+
bad: |
|
|
51
|
+
let guard = state.lock().await;
|
|
52
|
+
do_network().await;
|
|
53
|
+
|
|
54
|
+
good: |
|
|
55
|
+
{
|
|
56
|
+
let guard = state.lock().await;
|
|
57
|
+
update(&guard);
|
|
58
|
+
}
|
|
59
|
+
do_network().await;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# JS/TS Security
|
|
2
|
+
# Detects command execution sinks via child_process APIs.
|
|
3
|
+
id: ts-command-injection
|
|
4
|
+
name: Command Injection Sink
|
|
5
|
+
severity: warning
|
|
6
|
+
category: security
|
|
7
|
+
defect_class: injection
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: typescript
|
|
10
|
+
|
|
11
|
+
message: "Potential command injection sink — avoid child_process command execution with untrusted input"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
child_process command APIs (`exec`, `execSync`) execute shell commands and are
|
|
15
|
+
vulnerable when command strings include untrusted input.
|
|
16
|
+
|
|
17
|
+
✅ FIX: prefer `spawn`/`execFile` with explicit argument arrays and strict allowlists.
|
|
18
|
+
|
|
19
|
+
query: |
|
|
20
|
+
[
|
|
21
|
+
(call_expression
|
|
22
|
+
function: (member_expression
|
|
23
|
+
object: (identifier) @MOD
|
|
24
|
+
property: (property_identifier) @FN)
|
|
25
|
+
arguments: (arguments) @ARGS)
|
|
26
|
+
(call_expression
|
|
27
|
+
function: (member_expression
|
|
28
|
+
object: (member_expression
|
|
29
|
+
object: (identifier) @MOD
|
|
30
|
+
property: (property_identifier) @NS)
|
|
31
|
+
property: (property_identifier) @FN)
|
|
32
|
+
arguments: (arguments) @ARGS)
|
|
33
|
+
]
|
|
34
|
+
(#eq? @MOD "child_process")
|
|
35
|
+
(#match? @FN "^(exec|execSync)$")
|
|
36
|
+
|
|
37
|
+
metavars:
|
|
38
|
+
- MOD
|
|
39
|
+
- NS
|
|
40
|
+
- FN
|
|
41
|
+
- ARGS
|
|
42
|
+
|
|
43
|
+
post_filter: ts_command_injection_sink
|
|
44
|
+
|
|
45
|
+
has_fix: false
|
|
46
|
+
|
|
47
|
+
tags:
|
|
48
|
+
- javascript
|
|
49
|
+
- typescript
|
|
50
|
+
- security
|
|
51
|
+
- command-injection
|
|
52
|
+
- cwe-78
|
|
53
|
+
- owasp-a03
|
|
54
|
+
|
|
55
|
+
examples:
|
|
56
|
+
bad: |
|
|
57
|
+
child_process.exec(userInput)
|
|
58
|
+
|
|
59
|
+
good: |
|
|
60
|
+
spawn("git", ["status"])
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# JS/TS Concurrency
|
|
2
|
+
# Detects detached async/suspicious promise calls used as bare statements.
|
|
3
|
+
id: ts-detached-async-call
|
|
4
|
+
name: Detached Async Call
|
|
5
|
+
severity: warning
|
|
6
|
+
category: concurrency
|
|
7
|
+
defect_class: async-misuse
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: typescript
|
|
10
|
+
|
|
11
|
+
message: "Detached async call — ensure this Promise is awaited or explicitly handled"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Bare async calls can drop errors and cause race conditions when results are ignored.
|
|
15
|
+
|
|
16
|
+
✅ FIX: await the call, return the promise, or explicitly handle it with .catch/.then.
|
|
17
|
+
|
|
18
|
+
query: |
|
|
19
|
+
(expression_statement
|
|
20
|
+
(call_expression
|
|
21
|
+
function: [
|
|
22
|
+
(identifier) @FN
|
|
23
|
+
(member_expression
|
|
24
|
+
property: (property_identifier) @FN)
|
|
25
|
+
]
|
|
26
|
+
arguments: (arguments) @ARGS))
|
|
27
|
+
(#match? @FN "(Async$|fetch$|request$)")
|
|
28
|
+
|
|
29
|
+
metavars:
|
|
30
|
+
- FN
|
|
31
|
+
- ARGS
|
|
32
|
+
|
|
33
|
+
post_filter: ts_detached_async_call
|
|
34
|
+
|
|
35
|
+
cwe:
|
|
36
|
+
- CWE-703
|
|
37
|
+
owasp:
|
|
38
|
+
- A09
|
|
39
|
+
confidence: medium
|
|
40
|
+
|
|
41
|
+
has_fix: false
|
|
42
|
+
|
|
43
|
+
tags:
|
|
44
|
+
- javascript
|
|
45
|
+
- typescript
|
|
46
|
+
- concurrency
|
|
47
|
+
- async
|
|
48
|
+
|
|
49
|
+
examples:
|
|
50
|
+
bad: |
|
|
51
|
+
fetch(url)
|
|
52
|
+
saveAsync(record)
|
|
53
|
+
|
|
54
|
+
good: |
|
|
55
|
+
await fetch(url)
|
|
56
|
+
await saveAsync(record)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# JS/TS Security
|
|
2
|
+
# Detects non-cryptographic randomness usage.
|
|
3
|
+
id: ts-insecure-random
|
|
4
|
+
name: Insecure Randomness
|
|
5
|
+
severity: warning
|
|
6
|
+
category: security
|
|
7
|
+
defect_class: injection
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: typescript
|
|
10
|
+
|
|
11
|
+
message: "Insecure randomness source detected — use crypto.getRandomValues or secure RNG APIs"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Math.random is not suitable for security-sensitive tokens and identifiers.
|
|
15
|
+
|
|
16
|
+
✅ FIX: use crypto.getRandomValues / crypto.randomUUID / secure server-side RNG.
|
|
17
|
+
|
|
18
|
+
query: |
|
|
19
|
+
(call_expression
|
|
20
|
+
function: (member_expression
|
|
21
|
+
object: (identifier) @OBJ
|
|
22
|
+
property: (property_identifier) @FN)
|
|
23
|
+
arguments: (arguments) @ARGS)
|
|
24
|
+
(#eq? @OBJ "Math")
|
|
25
|
+
(#eq? @FN "random")
|
|
26
|
+
|
|
27
|
+
metavars:
|
|
28
|
+
- OBJ
|
|
29
|
+
- FN
|
|
30
|
+
- ARGS
|
|
31
|
+
|
|
32
|
+
post_filter: ts_insecure_random_source
|
|
33
|
+
|
|
34
|
+
cwe:
|
|
35
|
+
- CWE-330
|
|
36
|
+
owasp:
|
|
37
|
+
- A02
|
|
38
|
+
confidence: medium
|
|
39
|
+
|
|
40
|
+
has_fix: false
|
|
41
|
+
|
|
42
|
+
tags:
|
|
43
|
+
- javascript
|
|
44
|
+
- typescript
|
|
45
|
+
- security
|
|
46
|
+
- randomness
|
|
47
|
+
- weak-prng
|
|
48
|
+
|
|
49
|
+
examples:
|
|
50
|
+
bad: |
|
|
51
|
+
const token = Math.random().toString(36)
|
|
52
|
+
|
|
53
|
+
good: |
|
|
54
|
+
const token = crypto.randomUUID()
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# JS/TS Security
|
|
2
|
+
# Detects outbound HTTP sinks invoked with dynamic URL expressions.
|
|
3
|
+
id: ts-ssrf
|
|
4
|
+
name: SSRF Risk
|
|
5
|
+
severity: warning
|
|
6
|
+
category: security
|
|
7
|
+
defect_class: injection
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: typescript
|
|
10
|
+
|
|
11
|
+
message: "Potential SSRF sink — validate and allowlist outbound URLs"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Outbound requests with untrusted URL input can lead to server-side request forgery.
|
|
15
|
+
|
|
16
|
+
✅ FIX: validate URL host/scheme and allowlist external targets.
|
|
17
|
+
|
|
18
|
+
query: |
|
|
19
|
+
[
|
|
20
|
+
(call_expression
|
|
21
|
+
function: (identifier) @FN
|
|
22
|
+
arguments: (arguments [(identifier) (member_expression) (call_expression)] @URL))
|
|
23
|
+
(call_expression
|
|
24
|
+
function: (member_expression
|
|
25
|
+
object: (identifier) @OBJ
|
|
26
|
+
property: (property_identifier) @FN)
|
|
27
|
+
arguments: (arguments [(identifier) (member_expression) (call_expression)] @URL))
|
|
28
|
+
]
|
|
29
|
+
(#match? @FN "^(fetch|get|post|put|patch|delete|request)$")
|
|
30
|
+
|
|
31
|
+
metavars:
|
|
32
|
+
- OBJ
|
|
33
|
+
- FN
|
|
34
|
+
- URL
|
|
35
|
+
|
|
36
|
+
post_filter: ts_ssrf_sink
|
|
37
|
+
|
|
38
|
+
has_fix: false
|
|
39
|
+
|
|
40
|
+
tags:
|
|
41
|
+
- javascript
|
|
42
|
+
- typescript
|
|
43
|
+
- security
|
|
44
|
+
- ssrf
|
|
45
|
+
- cwe-918
|
|
46
|
+
- owasp-a10
|
|
47
|
+
|
|
48
|
+
examples:
|
|
49
|
+
bad: |
|
|
50
|
+
await fetch(userUrl)
|
|
51
|
+
|
|
52
|
+
good: |
|
|
53
|
+
if (ALLOWED_HOSTS.has(url.host)) await fetch(url.toString())
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# JS/TS Security
|
|
2
|
+
# Detects weak hash algorithm selection in crypto hashing APIs.
|
|
3
|
+
id: ts-weak-hash
|
|
4
|
+
name: Weak Hash Primitive
|
|
5
|
+
severity: warning
|
|
6
|
+
category: security
|
|
7
|
+
defect_class: injection
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: typescript
|
|
10
|
+
|
|
11
|
+
message: "Weak hash primitive selected (md5/sha1) — use sha256+ for security-sensitive contexts"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Using MD5/SHA1 in cryptographic hashing contexts is insecure.
|
|
15
|
+
|
|
16
|
+
✅ FIX: use SHA-256 or stronger algorithms.
|
|
17
|
+
|
|
18
|
+
query: |
|
|
19
|
+
(call_expression
|
|
20
|
+
function: (member_expression
|
|
21
|
+
property: (property_identifier) @FN)
|
|
22
|
+
arguments: (arguments
|
|
23
|
+
(string (string_fragment) @ALG)
|
|
24
|
+
(_)*))
|
|
25
|
+
(#eq? @FN "createHash")
|
|
26
|
+
(#match? @ALG "^(md5|sha1)$")
|
|
27
|
+
|
|
28
|
+
metavars:
|
|
29
|
+
- FN
|
|
30
|
+
- ALG
|
|
31
|
+
|
|
32
|
+
post_filter: ts_weak_hash_algorithm
|
|
33
|
+
|
|
34
|
+
cwe:
|
|
35
|
+
- CWE-327
|
|
36
|
+
owasp:
|
|
37
|
+
- A02
|
|
38
|
+
confidence: high
|
|
39
|
+
|
|
40
|
+
has_fix: false
|
|
41
|
+
|
|
42
|
+
tags:
|
|
43
|
+
- javascript
|
|
44
|
+
- typescript
|
|
45
|
+
- security
|
|
46
|
+
- crypto
|
|
47
|
+
- weak-hash
|
|
48
|
+
|
|
49
|
+
examples:
|
|
50
|
+
bad: |
|
|
51
|
+
const hash = crypto.createHash("md5").update(data).digest("hex")
|
|
52
|
+
|
|
53
|
+
good: |
|
|
54
|
+
const hash = crypto.createHash("sha256").update(data).digest("hex")
|