seaworthycode 1.1.1 → 1.1.4
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/dist/index.js +269 -59
- package/dist/index.js.map +1 -1
- package/package.json +16 -12
- package/rules/external/configuration/insecure-cookie-flags.test.yaml +114 -0
- package/rules/external/configuration/insecure-cookie-flags.yaml +77 -0
- package/rules/external/configuration/missing-ssl-verification.test.yaml +130 -0
- package/rules/external/configuration/missing-ssl-verification.yaml +123 -0
- package/rules/external/data-exposure/debug-artifacts.test.yaml +143 -0
- package/rules/external/data-exposure/debug-artifacts.yaml +57 -0
- package/rules/external/data-exposure/hardcoded-ip.test.yaml +131 -0
- package/rules/external/data-exposure/hardcoded-ip.yaml +67 -0
- package/rules/external/data-exposure/localstorage-sensitive-data.test.yaml +58 -0
- package/rules/external/data-exposure/localstorage-sensitive-data.yaml +60 -0
- package/rules/external/dependencies/deprecated-functions.test.yaml +92 -0
- package/rules/external/dependencies/deprecated-functions.yaml +66 -0
- package/rules/external/ops/hardcoded-port.test.yaml +141 -0
- package/rules/external/ops/hardcoded-port.yaml +91 -0
- package/rules/external/ops/insecure-file-permissions.test.yaml +111 -0
- package/rules/external/ops/insecure-file-permissions.yaml +91 -0
- package/rules/external/resilience/missing-memory-limit.test.yaml +54 -0
- package/rules/external/resilience/missing-memory-limit.yaml +59 -0
- package/rules/external/resilience/missing-timeout-config.test.yaml +179 -0
- package/rules/external/resilience/missing-timeout-config.yaml +124 -0
- package/rules/external/security/broken-crypto-algorithm.test.yaml +104 -0
- package/rules/external/security/broken-crypto-algorithm.yaml +79 -0
- package/rules/external/security/http-method-override.test.yaml +40 -0
- package/rules/external/security/http-method-override.yaml +35 -0
- package/rules/external/security/http-no-tls.test.yaml +115 -0
- package/rules/external/security/http-no-tls.yaml +59 -0
- package/rules/external/security/path-traversal.test.yaml +188 -0
- package/rules/external/security/path-traversal.yaml +210 -0
- package/rules/external/security/unsafe-innerhtml.test.yaml +72 -0
- package/rules/external/security/unsafe-innerhtml.yaml +46 -0
- package/rules/external/security/untrusted-deserialization.test.yaml +79 -0
- package/rules/external/security/untrusted-deserialization.yaml +48 -0
- package/rules/external/security/weak-encryption-mode.test.yaml +126 -0
- package/rules/external/security/weak-encryption-mode.yaml +104 -0
- package/rules/external/security/weak-hash-algorithm.test.yaml +121 -0
- package/rules/external/security/weak-hash-algorithm.yaml +87 -0
- package/rules/external/security/xxe-parsing.test.yaml +76 -0
- package/rules/external/security/xxe-parsing.yaml +63 -0
- package/rules/internal/security/dangerous-eval.test.yaml +126 -0
- package/rules/internal/security/dangerous-eval.yaml +134 -0
- package/rules/internal/security/no-document-write.test.yaml +33 -0
- package/rules/internal/security/no-document-write.yaml +40 -0
- package/rules/internal/taint/MATRIX.md +16 -0
- package/rules/internal/taint/bash.test.yaml +84 -0
- package/rules/internal/taint/bash.yaml +166 -0
- package/rules/internal/taint/dvwa.test.yaml +217 -0
- package/rules/internal/taint/go.test.yaml +207 -0
- package/rules/internal/taint/go.yaml +325 -0
- package/rules/internal/taint/java.test.yaml +158 -0
- package/rules/internal/taint/java.yaml +318 -0
- package/rules/internal/taint/javascript.test.yaml +374 -0
- package/rules/internal/taint/javascript.yaml +439 -0
- package/rules/internal/taint/php.test.yaml +134 -0
- package/rules/internal/taint/php.yaml +331 -0
- package/rules/internal/taint/python.test.yaml +427 -0
- package/rules/internal/taint/python.yaml +636 -0
- package/rules/internal/taint/ruby.test.yaml +148 -0
- package/rules/internal/taint/ruby.yaml +233 -0
- package/rules/internal/taint/rust.test.yaml +585 -0
- package/rules/internal/taint/rust.yaml +483 -0
- package/rules/internal/taint/tsx.test.yaml +140 -0
- package/rules/internal/taint/tsx.yaml +51 -0
- package/rules/internal/taint/typescript.test.yaml +393 -0
- package/rules/internal/taint/typescript.yaml +660 -0
- package/wasm/tree-sitter-sql.wasm +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
language: bash
|
|
2
|
+
cases:
|
|
3
|
+
- name: "SQL injection from positional argument to psql"
|
|
4
|
+
language: bash
|
|
5
|
+
code: |
|
|
6
|
+
QUERY="$1"
|
|
7
|
+
psql -c "$QUERY"
|
|
8
|
+
expect:
|
|
9
|
+
count: 1
|
|
10
|
+
flows:
|
|
11
|
+
- sourceId: bash.argv
|
|
12
|
+
sinkId: bash.psql
|
|
13
|
+
|
|
14
|
+
- name: "XSS from interactive read to CGI echo"
|
|
15
|
+
language: bash
|
|
16
|
+
code: |
|
|
17
|
+
read INPUT
|
|
18
|
+
echo "$INPUT"
|
|
19
|
+
expect:
|
|
20
|
+
count: 1
|
|
21
|
+
flows:
|
|
22
|
+
- sourceId: bash.read
|
|
23
|
+
sinkId: bash.cgi_echo
|
|
24
|
+
|
|
25
|
+
- name: "Path traversal from positional argument to rm"
|
|
26
|
+
language: bash
|
|
27
|
+
code: |
|
|
28
|
+
DIR="$1"
|
|
29
|
+
rm -rf "$DIR/"
|
|
30
|
+
expect:
|
|
31
|
+
count: 1
|
|
32
|
+
flows:
|
|
33
|
+
- sourceId: bash.argv
|
|
34
|
+
sinkId: bash.path
|
|
35
|
+
|
|
36
|
+
- name: "Command injection from positional argument to eval"
|
|
37
|
+
language: bash
|
|
38
|
+
code: |
|
|
39
|
+
CMD="$1"
|
|
40
|
+
eval "$CMD"
|
|
41
|
+
expect:
|
|
42
|
+
count: 1
|
|
43
|
+
flows:
|
|
44
|
+
- sourceId: bash.argv
|
|
45
|
+
sinkId: bash.eval
|
|
46
|
+
|
|
47
|
+
- name: "Code execution direct positional argument to eval"
|
|
48
|
+
language: bash
|
|
49
|
+
code: |
|
|
50
|
+
eval "$1"
|
|
51
|
+
expect:
|
|
52
|
+
count: 1
|
|
53
|
+
flows:
|
|
54
|
+
- sourceId: bash.argv
|
|
55
|
+
sinkId: bash.eval
|
|
56
|
+
|
|
57
|
+
- name: "URL injection from positional argument to curl"
|
|
58
|
+
language: bash
|
|
59
|
+
code: |
|
|
60
|
+
URL="$1"
|
|
61
|
+
curl "$URL"
|
|
62
|
+
expect:
|
|
63
|
+
count: 1
|
|
64
|
+
flows:
|
|
65
|
+
- sourceId: bash.argv
|
|
66
|
+
sinkId: bash.url
|
|
67
|
+
|
|
68
|
+
- name: "SQL injection sanitised by regex validation"
|
|
69
|
+
language: bash
|
|
70
|
+
code: |
|
|
71
|
+
[[ "$1" =~ ^[0-9]+$ ]] && psql -c "$1"
|
|
72
|
+
expect:
|
|
73
|
+
count: 0
|
|
74
|
+
|
|
75
|
+
- name: "Command injection sanitised by quoted expansion"
|
|
76
|
+
language: bash
|
|
77
|
+
code: |
|
|
78
|
+
MODE="$1"
|
|
79
|
+
exec "$MODE"
|
|
80
|
+
expect:
|
|
81
|
+
count: 1
|
|
82
|
+
flows:
|
|
83
|
+
- sourceId: bash.argv
|
|
84
|
+
sinkId: bash.exec
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# attribution: CWE-78
|
|
2
|
+
attribution: CWE-78
|
|
3
|
+
language: bash
|
|
4
|
+
applies-to: []
|
|
5
|
+
|
|
6
|
+
sources:
|
|
7
|
+
- id: bash.argv
|
|
8
|
+
class: cli-arg
|
|
9
|
+
query: |
|
|
10
|
+
((simple_expansion (variable_name) @name) @source
|
|
11
|
+
(#match? @name "^[0-9]+$"))
|
|
12
|
+
|
|
13
|
+
- id: bash.argv.all
|
|
14
|
+
class: cli-arg
|
|
15
|
+
query: |
|
|
16
|
+
((simple_expansion (special_variable_name) @name) @source
|
|
17
|
+
(#match? @name "^[@*]$"))
|
|
18
|
+
|
|
19
|
+
- id: bash.read
|
|
20
|
+
class: interactive-input
|
|
21
|
+
query: |
|
|
22
|
+
(command
|
|
23
|
+
name: (command_name (word) @cmd)
|
|
24
|
+
argument: (word) @source
|
|
25
|
+
(#eq? @cmd "read"))
|
|
26
|
+
|
|
27
|
+
- id: bash.env
|
|
28
|
+
class: env
|
|
29
|
+
query: |
|
|
30
|
+
((simple_expansion (variable_name) @name) @source
|
|
31
|
+
(#match? @name "^(HOME|PATH|USER|SHELL|PWD|TMPDIR|QUERY_STRING|REQUEST_METHOD|CONTENT_TYPE|CONTENT_LENGTH)$"))
|
|
32
|
+
|
|
33
|
+
- id: bash.command_substitution
|
|
34
|
+
class: external-input
|
|
35
|
+
query: |
|
|
36
|
+
(command_substitution) @source
|
|
37
|
+
|
|
38
|
+
- id: bash.stdin
|
|
39
|
+
class: stdin
|
|
40
|
+
query: |
|
|
41
|
+
(pipeline) @source
|
|
42
|
+
|
|
43
|
+
sinks:
|
|
44
|
+
- id: bash.eval
|
|
45
|
+
sink-class: code-execution
|
|
46
|
+
query: |
|
|
47
|
+
(command
|
|
48
|
+
name: (command_name (word) @cmd)
|
|
49
|
+
argument: (_) @sink
|
|
50
|
+
(#match? @cmd "^(eval|source|\\.)$"))
|
|
51
|
+
|
|
52
|
+
- id: bash.bash_c
|
|
53
|
+
sink-class: code-execution
|
|
54
|
+
query: |
|
|
55
|
+
(command
|
|
56
|
+
name: (command_name (word) @cmd)
|
|
57
|
+
argument: (word) @flag
|
|
58
|
+
argument: (_) @sink
|
|
59
|
+
(#match? @cmd "^(bash|sh|zsh)$")
|
|
60
|
+
(#eq? @flag "-c"))
|
|
61
|
+
|
|
62
|
+
- id: bash.dynamic_command
|
|
63
|
+
sink-class: command-injection
|
|
64
|
+
query: |
|
|
65
|
+
(command
|
|
66
|
+
name: (command_name (simple_expansion) @sink))
|
|
67
|
+
|
|
68
|
+
- id: bash.exec
|
|
69
|
+
sink-class: command-injection
|
|
70
|
+
query: |
|
|
71
|
+
(command
|
|
72
|
+
name: (command_name (word) @cmd)
|
|
73
|
+
argument: (_) @sink
|
|
74
|
+
(#eq? @cmd "exec"))
|
|
75
|
+
|
|
76
|
+
- id: bash.path
|
|
77
|
+
sink-class: path-traversal
|
|
78
|
+
query: |
|
|
79
|
+
(command
|
|
80
|
+
name: (command_name (word) @cmd)
|
|
81
|
+
argument: (_) @sink
|
|
82
|
+
(#match? @cmd "^(rm|cat|mv|cp|mkdir|touch|chmod|chown)$"))
|
|
83
|
+
|
|
84
|
+
- id: bash.redirect_path
|
|
85
|
+
sink-class: path-traversal
|
|
86
|
+
query: |
|
|
87
|
+
(redirected_statement
|
|
88
|
+
redirect: (_ (_) @sink))
|
|
89
|
+
|
|
90
|
+
- id: bash.url
|
|
91
|
+
sink-class: url-injection
|
|
92
|
+
query: |
|
|
93
|
+
(command
|
|
94
|
+
name: (command_name (word) @cmd)
|
|
95
|
+
argument: (_) @sink
|
|
96
|
+
(#match? @cmd "^(curl|wget|lynx)$"))
|
|
97
|
+
|
|
98
|
+
- id: bash.psql
|
|
99
|
+
sink-class: sql-injection
|
|
100
|
+
query: |
|
|
101
|
+
(command
|
|
102
|
+
name: (command_name (word) @cmd)
|
|
103
|
+
argument: (word) @flag
|
|
104
|
+
argument: (_) @sink
|
|
105
|
+
(#eq? @cmd "psql")
|
|
106
|
+
(#eq? @flag "-c"))
|
|
107
|
+
|
|
108
|
+
- id: bash.mysql
|
|
109
|
+
sink-class: sql-injection
|
|
110
|
+
query: |
|
|
111
|
+
(command
|
|
112
|
+
name: (command_name (word) @cmd)
|
|
113
|
+
argument: (word) @flag
|
|
114
|
+
argument: (_) @sink
|
|
115
|
+
(#eq? @cmd "mysql")
|
|
116
|
+
(#eq? @flag "-e"))
|
|
117
|
+
|
|
118
|
+
- id: bash.sqlite3
|
|
119
|
+
sink-class: sql-injection
|
|
120
|
+
query: |
|
|
121
|
+
(command
|
|
122
|
+
name: (command_name (word) @cmd)
|
|
123
|
+
argument: (_) @db
|
|
124
|
+
argument: (_) @sink
|
|
125
|
+
(#eq? @cmd "sqlite3"))
|
|
126
|
+
|
|
127
|
+
- id: bash.cgi_echo
|
|
128
|
+
sink-class: xss
|
|
129
|
+
query: |
|
|
130
|
+
(command
|
|
131
|
+
name: (command_name (word) @cmd)
|
|
132
|
+
argument: (_) @sink
|
|
133
|
+
(#match? @cmd "^(echo|printf)$"))
|
|
134
|
+
|
|
135
|
+
# prototype-pollution is intentionally excluded: shell has no prototype chain.
|
|
136
|
+
|
|
137
|
+
sanitisers:
|
|
138
|
+
- id: bash.regex_validation
|
|
139
|
+
sanitises:
|
|
140
|
+
- command-injection
|
|
141
|
+
- path-traversal
|
|
142
|
+
- sql-injection
|
|
143
|
+
query: |
|
|
144
|
+
(test_command
|
|
145
|
+
(binary_expression
|
|
146
|
+
left: (string (simple_expansion (variable_name) @sanitiser))
|
|
147
|
+
right: (regex)))
|
|
148
|
+
|
|
149
|
+
- id: bash.case_validation
|
|
150
|
+
sanitises:
|
|
151
|
+
- command-injection
|
|
152
|
+
- path-traversal
|
|
153
|
+
- url-injection
|
|
154
|
+
query: |
|
|
155
|
+
(case_statement
|
|
156
|
+
value: (string (simple_expansion (variable_name) @sanitiser)))
|
|
157
|
+
|
|
158
|
+
- id: bash.printf_string
|
|
159
|
+
sanitises:
|
|
160
|
+
- xss
|
|
161
|
+
query: |
|
|
162
|
+
(command
|
|
163
|
+
name: (command_name (word) @cmd)
|
|
164
|
+
argument: (raw_string) @fmt
|
|
165
|
+
(#eq? @cmd "printf")
|
|
166
|
+
(#eq? @fmt "'%s'")) @sanitiser
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
language: php
|
|
2
|
+
cases:
|
|
3
|
+
# Benchmark: DVWA sqli module (low difficulty).
|
|
4
|
+
# Vulnerability class: CWE-89 (SQL Injection).
|
|
5
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
6
|
+
# Recall tier: baseline
|
|
7
|
+
- name: "DVWA/sqli/low: GET id concatenated into mysqli query"
|
|
8
|
+
language: php
|
|
9
|
+
code: |
|
|
10
|
+
<?php
|
|
11
|
+
$userId = $_GET['uid'];
|
|
12
|
+
$sqlText = "SELECT profile FROM accounts WHERE user_id = '" . $userId . "'";
|
|
13
|
+
mysqli_query($dbLink, $sqlText);
|
|
14
|
+
expect:
|
|
15
|
+
count: 1
|
|
16
|
+
flows:
|
|
17
|
+
- sourceId: superglobal.GET
|
|
18
|
+
sinkId: mysqli_query
|
|
19
|
+
|
|
20
|
+
# Benchmark: DVWA sqli module (medium difficulty).
|
|
21
|
+
# Vulnerability class: CWE-89 (SQL Injection).
|
|
22
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
23
|
+
# Recall tier: stretch
|
|
24
|
+
- name: "DVWA/sqli/medium: escaped id still concatenated into query"
|
|
25
|
+
language: php
|
|
26
|
+
code: |
|
|
27
|
+
<?php
|
|
28
|
+
$rawId = $_POST['record_id'];
|
|
29
|
+
$safeId = mysqli_real_escape_string($dbLink, $rawId);
|
|
30
|
+
$sqlText = "SELECT name FROM records WHERE id = " . $safeId;
|
|
31
|
+
mysqli_query($dbLink, $sqlText);
|
|
32
|
+
expect:
|
|
33
|
+
count: 0
|
|
34
|
+
|
|
35
|
+
# Benchmark: DVWA sqli module (impossible difficulty).
|
|
36
|
+
# Vulnerability class: CWE-89 (SQL Injection).
|
|
37
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
38
|
+
# Recall tier: anti
|
|
39
|
+
- name: "DVWA/sqli/impossible: prepared statement"
|
|
40
|
+
language: php
|
|
41
|
+
code: |
|
|
42
|
+
<?php
|
|
43
|
+
$stmt = $pdo->prepare("SELECT name FROM records WHERE id = ?");
|
|
44
|
+
$stmt->execute([$_GET['record_id']]);
|
|
45
|
+
expect:
|
|
46
|
+
count: 0
|
|
47
|
+
|
|
48
|
+
# Benchmark: DVWA sqli_blind module (low difficulty).
|
|
49
|
+
# Vulnerability class: CWE-89 (SQL Injection).
|
|
50
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
51
|
+
# Recall tier: baseline
|
|
52
|
+
- name: "DVWA/sqli_blind/low: blind boolean SQL concat"
|
|
53
|
+
language: php
|
|
54
|
+
code: |
|
|
55
|
+
<?php
|
|
56
|
+
$guess = $_GET['char'];
|
|
57
|
+
$query = "SELECT 1 FROM secrets WHERE SUBSTRING(flag, 1, 1) = '" . $guess . "'";
|
|
58
|
+
mysqli_query($dbLink, $query);
|
|
59
|
+
expect:
|
|
60
|
+
count: 1
|
|
61
|
+
flows:
|
|
62
|
+
- sourceId: superglobal.GET
|
|
63
|
+
sinkId: mysqli_query
|
|
64
|
+
|
|
65
|
+
# Benchmark: DVWA exec module (low difficulty).
|
|
66
|
+
# Vulnerability class: CWE-78 (OS Command Injection).
|
|
67
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
68
|
+
# Recall tier: baseline
|
|
69
|
+
- name: "DVWA/exec/low: shell_exec with user ping target"
|
|
70
|
+
language: php
|
|
71
|
+
code: |
|
|
72
|
+
<?php
|
|
73
|
+
$hostTarget = $_POST['host'];
|
|
74
|
+
shell_exec('ping -c 2 ' . $hostTarget);
|
|
75
|
+
expect:
|
|
76
|
+
count: 1
|
|
77
|
+
flows:
|
|
78
|
+
- sourceId: superglobal.POST
|
|
79
|
+
sinkId: shell_exec
|
|
80
|
+
|
|
81
|
+
# Benchmark: DVWA exec module (impossible difficulty).
|
|
82
|
+
# Vulnerability class: CWE-78 (OS Command Injection).
|
|
83
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
84
|
+
# Recall tier: anti
|
|
85
|
+
- name: "DVWA/exec/impossible: escapeshellarg on command arg"
|
|
86
|
+
language: php
|
|
87
|
+
code: |
|
|
88
|
+
<?php
|
|
89
|
+
shell_exec(escapeshellarg($_POST['host']));
|
|
90
|
+
expect:
|
|
91
|
+
count: 0
|
|
92
|
+
|
|
93
|
+
# Benchmark: DVWA fi module (low difficulty).
|
|
94
|
+
# Vulnerability class: CWE-98 (PHP File Inclusion).
|
|
95
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
96
|
+
# Recall tier: stretch
|
|
97
|
+
- name: "DVWA/fi/low: GET page passed to include"
|
|
98
|
+
language: php
|
|
99
|
+
code: |
|
|
100
|
+
<?php
|
|
101
|
+
$pagePath = $_GET['doc'];
|
|
102
|
+
include($pagePath);
|
|
103
|
+
expect:
|
|
104
|
+
count: 1
|
|
105
|
+
flows:
|
|
106
|
+
- sourceId: superglobal.GET
|
|
107
|
+
sinkId: include
|
|
108
|
+
|
|
109
|
+
# Benchmark: DVWA fi module (high difficulty).
|
|
110
|
+
# Vulnerability class: CWE-98 (PHP File Inclusion).
|
|
111
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
112
|
+
# Recall tier: baseline
|
|
113
|
+
- name: "DVWA/fi/high: GET page with weak fnmatch guard"
|
|
114
|
+
language: php
|
|
115
|
+
code: |
|
|
116
|
+
<?php
|
|
117
|
+
$pagePath = $_GET['doc'];
|
|
118
|
+
if (!fnmatch('docs/*', $pagePath)) {
|
|
119
|
+
exit('blocked');
|
|
120
|
+
}
|
|
121
|
+
include($pagePath);
|
|
122
|
+
expect:
|
|
123
|
+
count: 1
|
|
124
|
+
flows:
|
|
125
|
+
- sourceId: superglobal.GET
|
|
126
|
+
sinkId: include
|
|
127
|
+
|
|
128
|
+
# Benchmark: DVWA xss_r module (low difficulty).
|
|
129
|
+
# Vulnerability class: CWE-79 (Cross-site Scripting).
|
|
130
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
131
|
+
# Recall tier: stretch
|
|
132
|
+
- name: "DVWA/xss_r/low: GET name appended to html buffer"
|
|
133
|
+
language: php
|
|
134
|
+
code: |
|
|
135
|
+
<?php
|
|
136
|
+
$outputHtml .= '<section>' . $_GET['label'] . '</section>';
|
|
137
|
+
echo $outputHtml;
|
|
138
|
+
expect:
|
|
139
|
+
count: 1
|
|
140
|
+
flows:
|
|
141
|
+
- sourceId: superglobal.GET
|
|
142
|
+
sinkId: echo
|
|
143
|
+
|
|
144
|
+
# Benchmark: DVWA xss_r module (impossible difficulty).
|
|
145
|
+
# Vulnerability class: CWE-79 (Cross-site Scripting).
|
|
146
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
147
|
+
# Recall tier: anti
|
|
148
|
+
- name: "DVWA/xss_r/impossible: htmlspecialchars on input"
|
|
149
|
+
language: php
|
|
150
|
+
code: |
|
|
151
|
+
<?php
|
|
152
|
+
$safeLabel = htmlspecialchars($_GET['label']);
|
|
153
|
+
echo $safeLabel;
|
|
154
|
+
expect:
|
|
155
|
+
count: 0
|
|
156
|
+
|
|
157
|
+
# Benchmark: DVWA xss_s module (low difficulty).
|
|
158
|
+
# Vulnerability class: CWE-79 (Cross-site Scripting — stored).
|
|
159
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
160
|
+
# Recall tier: stretch
|
|
161
|
+
- name: "DVWA/xss_s/low: POST message echoed later"
|
|
162
|
+
language: php
|
|
163
|
+
code: |
|
|
164
|
+
<?php
|
|
165
|
+
$storedMessage = $_POST['message'];
|
|
166
|
+
echo $storedMessage;
|
|
167
|
+
expect:
|
|
168
|
+
count: 1
|
|
169
|
+
flows:
|
|
170
|
+
- sourceId: superglobal.POST
|
|
171
|
+
sinkId: echo
|
|
172
|
+
|
|
173
|
+
# Benchmark: DVWA open_redirect module (low difficulty).
|
|
174
|
+
# Vulnerability class: CWE-601 (URL Redirection to Untrusted Site).
|
|
175
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
176
|
+
# Recall tier: baseline
|
|
177
|
+
- name: "DVWA/open_redirect/low: Location header with GET redirect"
|
|
178
|
+
language: php
|
|
179
|
+
code: |
|
|
180
|
+
<?php
|
|
181
|
+
header('Location: ' . $_GET['next']);
|
|
182
|
+
expect:
|
|
183
|
+
count: 1
|
|
184
|
+
flows:
|
|
185
|
+
- sourceId: superglobal.GET
|
|
186
|
+
sinkId: header
|
|
187
|
+
|
|
188
|
+
# Benchmark: DVWA-style Bash exec module (low difficulty).
|
|
189
|
+
# Vulnerability class: CWE-78 (OS Command Injection).
|
|
190
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
191
|
+
# Recall tier: baseline
|
|
192
|
+
- name: "DVWA_BASH/exec/low: positional command executed directly"
|
|
193
|
+
language: bash
|
|
194
|
+
code: |
|
|
195
|
+
#!/usr/bin/env bash
|
|
196
|
+
CMD="$1"
|
|
197
|
+
$CMD
|
|
198
|
+
expect:
|
|
199
|
+
count: 1
|
|
200
|
+
flows:
|
|
201
|
+
- sourceId: bash.argv
|
|
202
|
+
sinkId: bash.dynamic_command
|
|
203
|
+
|
|
204
|
+
# Benchmark: DVWA-style Bash code execution module (low difficulty).
|
|
205
|
+
# Vulnerability class: CWE-94 (Code Injection).
|
|
206
|
+
# Clean-room snippet authored for Seaworthy calibration; no DVWA source copied.
|
|
207
|
+
# Recall tier: baseline
|
|
208
|
+
- name: "DVWA_BASH/code_exec/low: positional argument passed to eval"
|
|
209
|
+
language: bash
|
|
210
|
+
code: |
|
|
211
|
+
#!/usr/bin/env bash
|
|
212
|
+
eval "$1"
|
|
213
|
+
expect:
|
|
214
|
+
count: 1
|
|
215
|
+
flows:
|
|
216
|
+
- sourceId: bash.argv
|
|
217
|
+
sinkId: bash.eval
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
language: go
|
|
2
|
+
cases:
|
|
3
|
+
- name: "AC-4.6: XSS flow — FormValue to fmt.Fprintf"
|
|
4
|
+
language: go
|
|
5
|
+
code: |
|
|
6
|
+
fmt.Fprintf(w, r.FormValue("name"))
|
|
7
|
+
expect:
|
|
8
|
+
count: 1
|
|
9
|
+
flows:
|
|
10
|
+
- sourceId: net/http.FormValue
|
|
11
|
+
sinkId: fmt.Fprintf
|
|
12
|
+
|
|
13
|
+
- name: "AC-4.7: XSS sanitised by html.EscapeString — no finding"
|
|
14
|
+
language: go
|
|
15
|
+
code: |
|
|
16
|
+
fmt.Fprintf(w, html.EscapeString(r.FormValue("name")))
|
|
17
|
+
expect:
|
|
18
|
+
count: 0
|
|
19
|
+
|
|
20
|
+
- name: "AC-4.8: html.EscapeString does not cover sql-injection"
|
|
21
|
+
language: go
|
|
22
|
+
code: |
|
|
23
|
+
db.Query(html.EscapeString(r.FormValue("id")))
|
|
24
|
+
expect:
|
|
25
|
+
count: 1
|
|
26
|
+
flows:
|
|
27
|
+
- sourceId: net/http.FormValue
|
|
28
|
+
sinkId: db.Query
|
|
29
|
+
|
|
30
|
+
- name: "SQL injection — FormValue to db.Query concat"
|
|
31
|
+
language: go
|
|
32
|
+
code: |
|
|
33
|
+
db.Query("SELECT * FROM users WHERE id = " + r.FormValue("id"))
|
|
34
|
+
expect:
|
|
35
|
+
count: 1
|
|
36
|
+
flows:
|
|
37
|
+
- sourceId: net/http.FormValue
|
|
38
|
+
sinkId: db.Query
|
|
39
|
+
|
|
40
|
+
- name: "SQL injection via short var declaration"
|
|
41
|
+
language: go
|
|
42
|
+
code: |
|
|
43
|
+
id := r.FormValue("id")
|
|
44
|
+
db.Query("SELECT * FROM users WHERE id = " + id)
|
|
45
|
+
expect:
|
|
46
|
+
count: 1
|
|
47
|
+
flows:
|
|
48
|
+
- sourceId: net/http.FormValue
|
|
49
|
+
sinkId: db.Query
|
|
50
|
+
|
|
51
|
+
- name: "SQL injection sanitised by parameterised query"
|
|
52
|
+
language: go
|
|
53
|
+
code: |
|
|
54
|
+
db.Query("SELECT * FROM users WHERE id = ?", r.FormValue("id"))
|
|
55
|
+
expect:
|
|
56
|
+
count: 0
|
|
57
|
+
|
|
58
|
+
- name: "Command injection — os.Args to exec.Command"
|
|
59
|
+
language: go
|
|
60
|
+
code: |
|
|
61
|
+
exec.Command("sh", "-c", os.Args[1])
|
|
62
|
+
expect:
|
|
63
|
+
count: 1
|
|
64
|
+
flows:
|
|
65
|
+
- sourceId: os.Args
|
|
66
|
+
sinkId: exec.Command
|
|
67
|
+
|
|
68
|
+
- name: "Path traversal — FormValue to os.Open"
|
|
69
|
+
language: go
|
|
70
|
+
code: |
|
|
71
|
+
os.Open(r.FormValue("file"))
|
|
72
|
+
expect:
|
|
73
|
+
count: 1
|
|
74
|
+
flows:
|
|
75
|
+
- sourceId: net/http.FormValue
|
|
76
|
+
sinkId: os.Open
|
|
77
|
+
|
|
78
|
+
- name: "Path traversal sanitised by filepath.Clean"
|
|
79
|
+
language: go
|
|
80
|
+
code: |
|
|
81
|
+
os.Open(filepath.Clean(r.FormValue("file")))
|
|
82
|
+
expect:
|
|
83
|
+
count: 0
|
|
84
|
+
|
|
85
|
+
- name: "URL injection — FormValue to http.Redirect"
|
|
86
|
+
language: go
|
|
87
|
+
code: |
|
|
88
|
+
http.Redirect(w, r, r.FormValue("next"), 302)
|
|
89
|
+
expect:
|
|
90
|
+
count: 1
|
|
91
|
+
flows:
|
|
92
|
+
- sourceId: net/http.FormValue
|
|
93
|
+
sinkId: http.Redirect
|
|
94
|
+
|
|
95
|
+
- name: "URL injection sanitised by url.QueryEscape"
|
|
96
|
+
language: go
|
|
97
|
+
code: |
|
|
98
|
+
http.Redirect(w, r, url.QueryEscape(r.FormValue("next")), 302)
|
|
99
|
+
expect:
|
|
100
|
+
count: 0
|
|
101
|
+
|
|
102
|
+
- name: "Gin: c.Query to fmt.Fprintf"
|
|
103
|
+
language: go
|
|
104
|
+
code: |
|
|
105
|
+
fmt.Fprintf(w, c.Query("name"))
|
|
106
|
+
expect:
|
|
107
|
+
count: 1
|
|
108
|
+
flows:
|
|
109
|
+
- sourceId: gin.Context.Query
|
|
110
|
+
sinkId: fmt.Fprintf
|
|
111
|
+
|
|
112
|
+
- name: "Echo: c.QueryParam to io.WriteString"
|
|
113
|
+
language: go
|
|
114
|
+
code: |
|
|
115
|
+
io.WriteString(w, c.QueryParam("label"))
|
|
116
|
+
expect:
|
|
117
|
+
count: 1
|
|
118
|
+
flows:
|
|
119
|
+
- sourceId: echo.Context.Query
|
|
120
|
+
sinkId: io.WriteString
|
|
121
|
+
|
|
122
|
+
- name: "Prototype pollution via maps.Copy"
|
|
123
|
+
language: go
|
|
124
|
+
code: |
|
|
125
|
+
maps.Copy(dst, r.FormValue("payload"))
|
|
126
|
+
expect:
|
|
127
|
+
count: 1
|
|
128
|
+
flows:
|
|
129
|
+
- sourceId: net/http.FormValue
|
|
130
|
+
sinkId: maps.Copy
|
|
131
|
+
|
|
132
|
+
- name: "Environment variable to os.Open"
|
|
133
|
+
language: go
|
|
134
|
+
code: |
|
|
135
|
+
os.Open(os.Getenv("USER_PATH"))
|
|
136
|
+
expect:
|
|
137
|
+
count: 1
|
|
138
|
+
flows:
|
|
139
|
+
- sourceId: os.Getenv
|
|
140
|
+
sinkId: os.Open
|
|
141
|
+
|
|
142
|
+
- name: "Request body via io.ReadAll to template.HTML"
|
|
143
|
+
language: go
|
|
144
|
+
code: |
|
|
145
|
+
body, _ := io.ReadAll(r.Body)
|
|
146
|
+
template.HTML(string(body))
|
|
147
|
+
expect:
|
|
148
|
+
count: 1
|
|
149
|
+
flows:
|
|
150
|
+
- sourceId: net/http.Request.Body
|
|
151
|
+
sinkId: template.HTML
|
|
152
|
+
|
|
153
|
+
- name: "URL query param via r.URL.Query().Get"
|
|
154
|
+
language: go
|
|
155
|
+
code: |
|
|
156
|
+
db.Query("SELECT * FROM t WHERE id = " + r.URL.Query().Get("id"))
|
|
157
|
+
expect:
|
|
158
|
+
count: 1
|
|
159
|
+
flows:
|
|
160
|
+
- sourceId: net/http.URL.Query
|
|
161
|
+
sinkId: db.Query
|
|
162
|
+
|
|
163
|
+
- name: "Code execution via plugin.Open"
|
|
164
|
+
language: go
|
|
165
|
+
code: |
|
|
166
|
+
plugin.Open(os.Getenv("PLUGIN"))
|
|
167
|
+
expect:
|
|
168
|
+
count: 1
|
|
169
|
+
flows:
|
|
170
|
+
- sourceId: os.Getenv
|
|
171
|
+
sinkId: plugin.Open
|
|
172
|
+
|
|
173
|
+
- name: "Gin redirect with c.Redirect"
|
|
174
|
+
language: go
|
|
175
|
+
code: |
|
|
176
|
+
c.Redirect(http.StatusFound, c.Query("next"))
|
|
177
|
+
expect:
|
|
178
|
+
count: 1
|
|
179
|
+
flows:
|
|
180
|
+
- sourceId: gin.Context.Query
|
|
181
|
+
sinkId: gin.Context.Redirect
|
|
182
|
+
|
|
183
|
+
- name: "fmt.Sprintf SQL sink"
|
|
184
|
+
language: go
|
|
185
|
+
code: |
|
|
186
|
+
db.Query(fmt.Sprintf("SELECT * FROM users WHERE id = %s", r.FormValue("id")))
|
|
187
|
+
expect:
|
|
188
|
+
count: 1
|
|
189
|
+
flows:
|
|
190
|
+
- sourceId: net/http.FormValue
|
|
191
|
+
sinkId: db.Query
|
|
192
|
+
|
|
193
|
+
- name: "Go — no source match returns zero flows"
|
|
194
|
+
language: go
|
|
195
|
+
code: |
|
|
196
|
+
fmt.Println("hello world")
|
|
197
|
+
expect:
|
|
198
|
+
count: 0
|
|
199
|
+
|
|
200
|
+
- name: "Go safe anti-fixture: escape and parameterised query"
|
|
201
|
+
language: go
|
|
202
|
+
code: |
|
|
203
|
+
safe := html.EscapeString(r.FormValue("name"))
|
|
204
|
+
db.Query("SELECT * FROM users WHERE name = ?", r.FormValue("name"))
|
|
205
|
+
fmt.Fprintf(w, safe)
|
|
206
|
+
expect:
|
|
207
|
+
count: 0
|