openpen 0.2.0
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/LICENSE +21 -0
- package/README.md +30 -0
- package/dist/checks/auth-bypass.d.ts +12 -0
- package/dist/checks/auth-bypass.js +93 -0
- package/dist/checks/bac.d.ts +12 -0
- package/dist/checks/bac.js +107 -0
- package/dist/checks/base.d.ts +22 -0
- package/dist/checks/base.js +13 -0
- package/dist/checks/index.d.ts +7 -0
- package/dist/checks/index.js +40 -0
- package/dist/checks/llm-leak.d.ts +23 -0
- package/dist/checks/llm-leak.js +251 -0
- package/dist/checks/mass-assignment.d.ts +12 -0
- package/dist/checks/mass-assignment.js +169 -0
- package/dist/checks/prompt-injection.d.ts +23 -0
- package/dist/checks/prompt-injection.js +262 -0
- package/dist/checks/security-headers.d.ts +12 -0
- package/dist/checks/security-headers.js +133 -0
- package/dist/checks/sensitive-data.d.ts +12 -0
- package/dist/checks/sensitive-data.js +122 -0
- package/dist/checks/sqli.d.ts +12 -0
- package/dist/checks/sqli.js +178 -0
- package/dist/checks/ssrf.d.ts +12 -0
- package/dist/checks/ssrf.js +126 -0
- package/dist/checks/xss.d.ts +12 -0
- package/dist/checks/xss.js +79 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +300 -0
- package/dist/fuzzer/engine.d.ts +27 -0
- package/dist/fuzzer/engine.js +126 -0
- package/dist/fuzzer/mutator.d.ts +8 -0
- package/dist/fuzzer/mutator.js +54 -0
- package/dist/fuzzer/payloads.d.ts +13 -0
- package/dist/fuzzer/payloads.js +167 -0
- package/dist/reporter/index.d.ts +5 -0
- package/dist/reporter/index.js +5 -0
- package/dist/reporter/json.d.ts +5 -0
- package/dist/reporter/json.js +14 -0
- package/dist/reporter/terminal.d.ts +5 -0
- package/dist/reporter/terminal.js +59 -0
- package/dist/spec/openapi.d.ts +5 -0
- package/dist/spec/openapi.js +119 -0
- package/dist/spec/parser.d.ts +11 -0
- package/dist/spec/parser.js +45 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.js +4 -0
- package/dist/utils/http.d.ts +37 -0
- package/dist/utils/http.js +92 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.js +20 -0
- package/dist/ws/checks.d.ts +18 -0
- package/dist/ws/checks.js +558 -0
- package/dist/ws/engine.d.ts +47 -0
- package/dist/ws/engine.js +139 -0
- package/package.json +41 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket test engine
|
|
3
|
+
* Handles connections, message exchange, and response collection
|
|
4
|
+
*/
|
|
5
|
+
import WebSocket from 'ws';
|
|
6
|
+
/**
|
|
7
|
+
* Open a WebSocket connection to the target
|
|
8
|
+
*/
|
|
9
|
+
export function connect(url, options = {}) {
|
|
10
|
+
const timeout = options.timeout || 5000;
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const ws = new WebSocket(url, {
|
|
13
|
+
headers: options.headers || {},
|
|
14
|
+
handshakeTimeout: timeout,
|
|
15
|
+
});
|
|
16
|
+
const conn = {
|
|
17
|
+
ws,
|
|
18
|
+
messages: [],
|
|
19
|
+
connected: false,
|
|
20
|
+
};
|
|
21
|
+
const timer = setTimeout(() => {
|
|
22
|
+
if (!conn.connected) {
|
|
23
|
+
ws.terminate();
|
|
24
|
+
reject(new Error(`Connection timeout after ${timeout}ms`));
|
|
25
|
+
}
|
|
26
|
+
}, timeout);
|
|
27
|
+
ws.on('open', () => {
|
|
28
|
+
clearTimeout(timer);
|
|
29
|
+
conn.connected = true;
|
|
30
|
+
resolve(conn);
|
|
31
|
+
});
|
|
32
|
+
ws.on('message', (data) => {
|
|
33
|
+
conn.messages.push({
|
|
34
|
+
direction: 'received',
|
|
35
|
+
data: data.toString(),
|
|
36
|
+
timestamp: Date.now(),
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
ws.on('close', (code, reason) => {
|
|
40
|
+
conn.connected = false;
|
|
41
|
+
conn.closedCode = code;
|
|
42
|
+
conn.closedReason = reason.toString();
|
|
43
|
+
});
|
|
44
|
+
ws.on('error', (err) => {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
if (!conn.connected) {
|
|
47
|
+
reject(err);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Send a message and wait for a response
|
|
54
|
+
*/
|
|
55
|
+
export function sendAndWait(conn, data, options = {}) {
|
|
56
|
+
const timeout = options.timeout || 3000;
|
|
57
|
+
const startIdx = conn.messages.length;
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
const timer = setTimeout(() => {
|
|
60
|
+
conn.ws.removeListener('message', onMessage);
|
|
61
|
+
resolve(null);
|
|
62
|
+
}, timeout);
|
|
63
|
+
const check = () => {
|
|
64
|
+
for (let i = startIdx; i < conn.messages.length; i++) {
|
|
65
|
+
const msg = conn.messages[i];
|
|
66
|
+
if (msg.direction === 'received') {
|
|
67
|
+
if (!options.matchFn || options.matchFn(msg.data)) {
|
|
68
|
+
clearTimeout(timer);
|
|
69
|
+
conn.ws.removeListener('message', onMessage);
|
|
70
|
+
resolve(msg.data);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
};
|
|
77
|
+
const onMessage = () => { check(); };
|
|
78
|
+
conn.ws.on('message', onMessage);
|
|
79
|
+
conn.messages.push({
|
|
80
|
+
direction: 'sent',
|
|
81
|
+
data,
|
|
82
|
+
timestamp: Date.now(),
|
|
83
|
+
});
|
|
84
|
+
conn.ws.send(data);
|
|
85
|
+
// Check messages already received
|
|
86
|
+
check();
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Send raw data (string or buffer) without recording
|
|
91
|
+
*/
|
|
92
|
+
export function sendRaw(conn, data) {
|
|
93
|
+
conn.ws.send(data);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Close a connection gracefully
|
|
97
|
+
*/
|
|
98
|
+
export function close(conn) {
|
|
99
|
+
return new Promise((resolve) => {
|
|
100
|
+
if (!conn.connected) {
|
|
101
|
+
resolve();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
conn.ws.on('close', () => resolve());
|
|
105
|
+
conn.ws.close();
|
|
106
|
+
setTimeout(() => resolve(), 1000);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Wait for a specific number of messages or timeout
|
|
111
|
+
*/
|
|
112
|
+
export function waitForMessages(conn, count, timeout = 3000) {
|
|
113
|
+
const startIdx = conn.messages.length;
|
|
114
|
+
return new Promise((resolve) => {
|
|
115
|
+
const timer = setTimeout(() => {
|
|
116
|
+
resolve(conn.messages.slice(startIdx));
|
|
117
|
+
}, timeout);
|
|
118
|
+
const check = () => {
|
|
119
|
+
const received = conn.messages.slice(startIdx).filter(m => m.direction === 'received');
|
|
120
|
+
if (received.length >= count) {
|
|
121
|
+
clearTimeout(timer);
|
|
122
|
+
resolve(conn.messages.slice(startIdx));
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
conn.ws.on('message', () => check());
|
|
126
|
+
check();
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Try to parse a message as JSON
|
|
131
|
+
*/
|
|
132
|
+
export function parseJson(data) {
|
|
133
|
+
try {
|
|
134
|
+
return { parsed: true, value: JSON.parse(data) };
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
return { parsed: false, error: e.message };
|
|
138
|
+
}
|
|
139
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openpen",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Open source CLI for API fuzzing and penetration testing",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"openpen": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"start": "node dist/cli.js",
|
|
12
|
+
"dev": "tsx src/cli.ts",
|
|
13
|
+
"test": "node --test dist/**/*.test.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"api",
|
|
17
|
+
"security",
|
|
18
|
+
"fuzzing",
|
|
19
|
+
"pentest",
|
|
20
|
+
"owasp"
|
|
21
|
+
],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/tjamescouch/openpen"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18.0.0"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"chalk": "^5.0.0",
|
|
32
|
+
"commander": "^12.0.0",
|
|
33
|
+
"yaml": "^2.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^20.0.0",
|
|
37
|
+
"@types/ws": "^8.18.1",
|
|
38
|
+
"tsx": "^4.0.0",
|
|
39
|
+
"typescript": "^5.3.0"
|
|
40
|
+
}
|
|
41
|
+
}
|