@mossbear/eval-core 0.1.0-alpha.69 → 0.1.0-alpha.71
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/credential-patterns.d.ts +9 -0
- package/dist/credential-patterns.d.ts.map +1 -0
- package/dist/credential-patterns.js +9 -0
- package/dist/credential-patterns.js.map +1 -0
- package/dist/redact-prose.d.ts.map +1 -1
- package/dist/redact-prose.js +116 -3
- package/dist/redact-prose.js.map +1 -1
- package/dist/redact-prose.test.js +164 -0
- package/dist/redact-prose.test.js.map +1 -1
- package/dist/sanitize-command.d.ts +4 -4
- package/dist/sanitize-command.d.ts.map +1 -1
- package/dist/sanitize-command.js +773 -10
- package/dist/sanitize-command.js.map +1 -1
- package/dist/sanitize-command.test.js +679 -0
- package/dist/sanitize-command.test.js.map +1 -1
- package/dist/strip-code-blocks.d.ts.map +1 -1
- package/dist/strip-code-blocks.js +62 -27
- package/dist/strip-code-blocks.js.map +1 -1
- package/dist/strip-code-blocks.test.js +58 -0
- package/dist/strip-code-blocks.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,6 +1,125 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { sanitizeCommand } from './sanitize-command.js';
|
|
3
3
|
describe('sanitizeCommand', () => {
|
|
4
|
+
it('redacts ordinary credential values passed as separate flag arguments', () => {
|
|
5
|
+
for (const flag of ['--password', '--token', '--api-key', '--client-secret']) {
|
|
6
|
+
for (const value of [
|
|
7
|
+
'fixture-credential',
|
|
8
|
+
'"fixture credential"',
|
|
9
|
+
"'fixture credential'",
|
|
10
|
+
]) {
|
|
11
|
+
const redacted = sanitizeCommand(`tool ${flag} ${value} --verbose`);
|
|
12
|
+
expect(redacted).not.toContain('fixture');
|
|
13
|
+
expect(redacted).toContain(`${flag} [redacted] --verbose`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
expect(sanitizeCommand('tool --output result.json')).toBe('tool --output result.json');
|
|
17
|
+
});
|
|
18
|
+
it('redacts Basic authorization payloads rather than just the scheme', () => {
|
|
19
|
+
const payload = Buffer.from('fixture-user:fixture-password').toString('base64');
|
|
20
|
+
expect(sanitizeCommand(`curl -H "Authorization: Basic ${payload}"`)).not.toContain(payload);
|
|
21
|
+
expect(sanitizeCommand(`curl -H 'Authorization: basic ${payload}'`)).not.toContain(payload);
|
|
22
|
+
});
|
|
23
|
+
it('redacts JSON credentials embedded in shell request bodies', () => {
|
|
24
|
+
const body = {
|
|
25
|
+
password: 'fixture-password',
|
|
26
|
+
apiKey: 'fixture-key',
|
|
27
|
+
client_secret: 'fixture-secret',
|
|
28
|
+
message: 'hello',
|
|
29
|
+
};
|
|
30
|
+
const command = `curl -d '${JSON.stringify(body)}'`;
|
|
31
|
+
const redacted = sanitizeCommand(command);
|
|
32
|
+
expect(redacted).not.toContain('fixture');
|
|
33
|
+
expect(redacted).toContain('"message":"hello"');
|
|
34
|
+
expect(sanitizeCommand(String.raw `curl -d '{"password":"fixture\\\"password"}'`)).not.toContain('fixture');
|
|
35
|
+
});
|
|
36
|
+
it('redacts shell-escaped JSON keys and every sensitive value shape', () => {
|
|
37
|
+
const body = {
|
|
38
|
+
password: 'fixture-password',
|
|
39
|
+
authorization: 'Basic fixture-credential',
|
|
40
|
+
tokens: ['fixture-token'],
|
|
41
|
+
nested: { api_keys: { first: 'fixture-key' } },
|
|
42
|
+
message: 'hello',
|
|
43
|
+
};
|
|
44
|
+
const json = JSON.stringify(body);
|
|
45
|
+
for (const argument of [`'${json}'`, JSON.stringify(json)]) {
|
|
46
|
+
const redacted = sanitizeCommand(`curl -d ${argument}`);
|
|
47
|
+
expect(redacted).not.toContain('fixture');
|
|
48
|
+
expect(redacted).toContain('hello');
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
it('redacts JSON bodies with shell-only escapes and malformed JSON', () => {
|
|
52
|
+
for (const command of [
|
|
53
|
+
String.raw `curl -d "{\"password\":\"fixture\$password\"}"`,
|
|
54
|
+
String.raw `curl -d "{\"password\":\"fixture\!password\"}"`,
|
|
55
|
+
String.raw `curl -d "{\"password\":\"fixture\\!password\"}"`,
|
|
56
|
+
'curl -d "{\\"password\\":\\"fixture\\`password\\"}"',
|
|
57
|
+
String.raw `curl -d "{\"authorization\":\"Basic fixture\$credential\"}"`,
|
|
58
|
+
String.raw `curl -d '{"password":"fixture-password",}'`,
|
|
59
|
+
]) {
|
|
60
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
it('redacts token authorization schemes', () => {
|
|
64
|
+
const payload = ['fixture', 'credential'].join('-');
|
|
65
|
+
expect(sanitizeCommand(`curl -H "Authorization: token ${payload}"`)).not.toContain(payload);
|
|
66
|
+
});
|
|
67
|
+
it('redacts credentials in recursively JSON-encoded string values', () => {
|
|
68
|
+
let body = JSON.stringify({ password: 'fixture-password' });
|
|
69
|
+
for (let depth = 0; depth < 4; depth++) {
|
|
70
|
+
body = JSON.stringify({ config: body });
|
|
71
|
+
for (const argument of [`'${body}'`, JSON.stringify(body)]) {
|
|
72
|
+
expect(sanitizeCommand(`curl -d ${argument}`)).not.toContain('fixture');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
it('preserves quoted programs and brace expansion without credentials', () => {
|
|
77
|
+
for (const command of [
|
|
78
|
+
"awk '{print $1}' /var/log/syslog",
|
|
79
|
+
"jq '[.items[] | .name]' resp.json",
|
|
80
|
+
"echo '{a,b}'",
|
|
81
|
+
]) {
|
|
82
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
it('redacts complete shell words with concatenated quote sections', () => {
|
|
86
|
+
const body = JSON.stringify({
|
|
87
|
+
name: "O'Brien",
|
|
88
|
+
config: JSON.stringify({ password: 'fixture-password' }),
|
|
89
|
+
});
|
|
90
|
+
for (const escaped of ["'\\''", "'\"'\"'"]) {
|
|
91
|
+
const argument = `'${body.replaceAll("'", escaped)}'`;
|
|
92
|
+
expect(sanitizeCommand(`curl -d ${argument}`)).not.toContain('fixture');
|
|
93
|
+
const value = `'fixture${escaped}password'`;
|
|
94
|
+
expect(sanitizeCommand(`tool --password ${value}`)).toBe('tool --password [redacted]');
|
|
95
|
+
expect(sanitizeCommand(`PASSWORD=${value} tool`)).toBe('PASSWORD=[redacted] tool');
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
it('bounds scanning time for long malformed JSON-like arguments', () => {
|
|
99
|
+
const command = `jq '{${'x'.repeat(128_000)}: .y}' file.json`;
|
|
100
|
+
const start = performance.now();
|
|
101
|
+
expect(sanitizeCommand(command)).toContain('[... truncated,');
|
|
102
|
+
expect(performance.now() - start).toBeLessThan(2000);
|
|
103
|
+
});
|
|
104
|
+
it('preserves author and oauth metadata', () => {
|
|
105
|
+
for (const command of [
|
|
106
|
+
'git commit --author="Jane Doe <jane@example.com>"',
|
|
107
|
+
`curl -d '${JSON.stringify({ author: 'Jane Doe', oauth_provider: 'example' })}'`,
|
|
108
|
+
'oauth_provider=example tool',
|
|
109
|
+
]) {
|
|
110
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
it('consumes shell-escaped whitespace in flag and assignment credentials', () => {
|
|
114
|
+
for (const command of [
|
|
115
|
+
String.raw `tool --password fixture\ secret --verbose`,
|
|
116
|
+
String.raw `PASSWORD=fixture\ secret tool`,
|
|
117
|
+
]) {
|
|
118
|
+
const redacted = sanitizeCommand(command);
|
|
119
|
+
expect(redacted).not.toContain('fixture');
|
|
120
|
+
expect(redacted).not.toContain(' secret');
|
|
121
|
+
}
|
|
122
|
+
});
|
|
4
123
|
it('leaves short benign commands untouched', () => {
|
|
5
124
|
expect(sanitizeCommand('bun test')).toBe('bun test');
|
|
6
125
|
expect(sanitizeCommand('git commit -m "fix: thing"')).toBe('git commit -m "fix: thing"');
|
|
@@ -78,4 +197,564 @@ describe('sanitizeCommand', () => {
|
|
|
78
197
|
expect(out).toContain('[... truncated,');
|
|
79
198
|
});
|
|
80
199
|
});
|
|
200
|
+
describe('command disclosure regressions', () => {
|
|
201
|
+
it('redacts cookie request headers', () => {
|
|
202
|
+
expect(sanitizeCommand(`curl -H 'Cookie: session=fixture-cookie; csrf=fixture-csrf' https://example.test`)).not.toContain('fixture-cookie');
|
|
203
|
+
expect(sanitizeCommand(`curl -b 'session=fixture-cookie' https://example.test`)).not.toContain('fixture-cookie');
|
|
204
|
+
});
|
|
205
|
+
it('redacts HTTP username/password arguments in short and long forms', () => {
|
|
206
|
+
for (const flag of ['-u ', '-u', '--user ', '--user=', '--proxy-user ']) {
|
|
207
|
+
expect(sanitizeCommand(`curl ${flag}'fixture-user:fixture-password' https://example.test`)).not.toContain('fixture-password');
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
it('redacts credentials after shell line continuations', () => {
|
|
211
|
+
for (const input of [
|
|
212
|
+
'tool --password \\\n fixture-continued',
|
|
213
|
+
'tool --password \\\r\n fixture-continued',
|
|
214
|
+
])
|
|
215
|
+
expect(sanitizeCommand(input)).not.toContain('fixture-continued');
|
|
216
|
+
});
|
|
217
|
+
it('redacts token-only URL userinfo and URL query credentials', () => {
|
|
218
|
+
for (const input of [
|
|
219
|
+
'curl https://fixture-userinfo@example.test/',
|
|
220
|
+
'curl "https://example.test/?api_key=fixture-query&view=summary"',
|
|
221
|
+
]) {
|
|
222
|
+
const output = sanitizeCommand(input);
|
|
223
|
+
expect(output).not.toContain('fixture-userinfo');
|
|
224
|
+
expect(output).not.toContain('fixture-query');
|
|
225
|
+
expect(output).toContain('example.test');
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
it('strips here-string file contents while retaining command evidence', () => {
|
|
229
|
+
const output = sanitizeCommand(`cat <<< 'fixturePrivateSource second word' > output.txt`);
|
|
230
|
+
expect(output).not.toContain('fixturePrivateSource');
|
|
231
|
+
expect(output).toContain('cat <<<');
|
|
232
|
+
expect(output).toContain('output.txt');
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
describe('review command-evidence regressions', () => {
|
|
236
|
+
it('preserves the host after a cookie header and still redacts query credentials', () => {
|
|
237
|
+
const text = sanitizeCommand("curl -H 'Cookie: session=fixture-cookie' https://example.test/?api_key=fixture-query");
|
|
238
|
+
expect(text).not.toContain('fixture-cookie');
|
|
239
|
+
expect(text).not.toContain('fixture-query');
|
|
240
|
+
expect(text).toContain('example.test');
|
|
241
|
+
});
|
|
242
|
+
it.each([
|
|
243
|
+
'sort -u fixtures/input.txt',
|
|
244
|
+
'git add -u .',
|
|
245
|
+
'grep -b pattern src/app.ts',
|
|
246
|
+
'ps -u root',
|
|
247
|
+
'docker run --user 1000:1000',
|
|
248
|
+
])('preserves non-HTTP flags: %s', (command) => {
|
|
249
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
250
|
+
});
|
|
251
|
+
it('redacts HTTP credentials after environment assignments and command separators', () => {
|
|
252
|
+
const credential = ['fixture-user', 'fixture-password'].join(':');
|
|
253
|
+
const text = sanitizeCommand(`SORT=1 sort -u input.txt && env MODE=test /usr/bin/curl -u '${credential}' https://example.test`);
|
|
254
|
+
expect(text).toContain('sort -u input.txt');
|
|
255
|
+
expect(text).not.toContain('fixture-password');
|
|
256
|
+
expect(text).toContain('example.test');
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
describe('HTTPie authentication evidence', () => {
|
|
260
|
+
it.each(['-a ', '-a', '-a=', '--auth ', '--auth='])('redacts auth in the %s form', (flag) => {
|
|
261
|
+
const output = sanitizeCommand(`http ${flag}'fixture-user:fixture-password' example.test`);
|
|
262
|
+
expect(output).not.toContain('fixture-password');
|
|
263
|
+
expect(output).toContain('example.test');
|
|
264
|
+
});
|
|
265
|
+
it('preserves the auth type while redacting a bearer token on https', () => {
|
|
266
|
+
const output = sanitizeCommand('https -A bearer -a fixture-token example.test');
|
|
267
|
+
expect(output).not.toContain('fixture-token');
|
|
268
|
+
expect(output).toContain('-A bearer');
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
describe('credential syntax at the command upload boundary', () => {
|
|
272
|
+
it.each([
|
|
273
|
+
"bash -c 'API_TOKEN=x curl -x reader:fixture-value@proxy.test:3128 https://example.test'",
|
|
274
|
+
"bash -c 'password=x; https_proxy=reader:fixture-value@proxy.test:3128 curl https://example.test'",
|
|
275
|
+
"su -c 'API_TOKEN=x curl -x reader:fixture-value@proxy.test:3128 https://example.test'",
|
|
276
|
+
"env 'PASSWORD=fixture value' curl https://example.test",
|
|
277
|
+
"bash -c '{ curl -x reader:fixture-value@proxy.test:3128 https://example.test; }'",
|
|
278
|
+
"echo 'proxy = reader:fixture-value@proxy.test:3128' | curl -K - https://example.test",
|
|
279
|
+
"curl -K <(echo 'proxy = reader:fixture-value@proxy.test:3128') https://example.test",
|
|
280
|
+
"printf '%s\\n' 'proxy=reader:fixture-value@proxy.test:3128' | curl --config - https://example.test",
|
|
281
|
+
])('redacts assignment-led scripts and inline proxy configuration: %s', (command) => {
|
|
282
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
283
|
+
});
|
|
284
|
+
it.each([
|
|
285
|
+
'echo \'proxy-user = "reader:fixture-password"\' | curl -K - https://example.test',
|
|
286
|
+
'echo \'user = "reader:fixture-password"\' | curl -K - https://example.test',
|
|
287
|
+
'echo \'proxy-user = "reader:fixture-password"\' > cfg && curl -K cfg https://example.test',
|
|
288
|
+
'curl -K <(echo \'user = "reader:fixture-password"\') https://example.test',
|
|
289
|
+
"printf '%s\\n' 'user: reader:fixture-password' | curl -K - https://example.test",
|
|
290
|
+
'echo \'cookie = "SID=fixture-password"\' | curl -K - https://example.test',
|
|
291
|
+
'echo \'cert = "client.pem:fixture-password"\' | curl -K - https://example.test',
|
|
292
|
+
"echo 'proxy-cert = client.pem:fixture-password' | curl -K - https://example.test",
|
|
293
|
+
])('redacts credential fields in inline curl configuration: %s', (command) => {
|
|
294
|
+
const output = sanitizeCommand(command);
|
|
295
|
+
expect(output).not.toContain('fixture');
|
|
296
|
+
expect(output).toContain('[redacted]');
|
|
297
|
+
});
|
|
298
|
+
it.each([
|
|
299
|
+
'echo \'user = "reader"\' | curl -K - https://example.test',
|
|
300
|
+
'echo \'cert = "client.pem"\' | curl -K - https://example.test',
|
|
301
|
+
])('keeps curl configuration without a password: %s', (command) => {
|
|
302
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
303
|
+
});
|
|
304
|
+
it.each([
|
|
305
|
+
'sudo -E curl -x reader:fixture-password@proxy.test:3128 https://example.test',
|
|
306
|
+
'sudo -u deploy curl -x reader:fixture-password@proxy.test:3128 https://example.test',
|
|
307
|
+
'timeout --preserve-status 10 curl -x reader:fixture-password@proxy.test:3128 https://example.test',
|
|
308
|
+
'nice -n 10 curl -x reader:fixture-password@proxy.test:3128 https://example.test',
|
|
309
|
+
'stdbuf -oL curl -x reader:fixture-password@proxy.test:3128 https://example.test',
|
|
310
|
+
'xargs curl -x reader:fixture-password@proxy.test:3128 https://example.test',
|
|
311
|
+
'env -S "curl -x reader:fixture-password@proxy.test:3128 https://example.test"',
|
|
312
|
+
"su -c 'curl -x reader:fixture-password@proxy.test:3128 https://example.test'",
|
|
313
|
+
'sudo -s "curl -x reader:fixture-password@proxy.test:3128 https://example.test"',
|
|
314
|
+
String.raw `env -S "sh -c 'curl -x reader:fixture-password@proxy.test:3128 https://example.test'"`,
|
|
315
|
+
'bash -c "$(echo curl -x reader:fixture-password@proxy.test:3128 https://example.test)"',
|
|
316
|
+
"bash -c $'curl -x reader:fixture-password@proxy.test:3128 https://example.test'",
|
|
317
|
+
String.raw `bash -c $'true\ncurl -x reader:fixture-password@proxy.test:3128 https://example.test'`,
|
|
318
|
+
String.raw `bash -c $'\x63url -x reader:fixture-password@proxy.test:3128 https://example.test'`,
|
|
319
|
+
String.raw `bash -c $'echo \'ready\'; \x63url -x reader:fixture-password@proxy.test:3128 https://example.test'`,
|
|
320
|
+
])('redacts wrapper and encoded-script credentials: %s', (command) => {
|
|
321
|
+
const output = sanitizeCommand(command);
|
|
322
|
+
expect(output).not.toContain('fixture-password');
|
|
323
|
+
expect(output).toContain('proxy.test:3128');
|
|
324
|
+
expect(output).toContain('example.test');
|
|
325
|
+
});
|
|
326
|
+
it.each([
|
|
327
|
+
"sh -c 'export https_proxy=reader:fixture-password@proxy.test:3128; curl https://example.test'",
|
|
328
|
+
"sh -c 'cd /tmp; https_proxy=reader:fixture-password@proxy.test:3128 curl https://example.test'",
|
|
329
|
+
"eval 'export https_proxy=reader:fixture-password@proxy.test:3128' ; curl https://example.test",
|
|
330
|
+
"bash -c 'curl -x reader:fixture-password@proxy.test:3128 https://example.test'",
|
|
331
|
+
'bash -lc "curl -sSx reader:fixture-password@proxy.test:3128 https://example.test"',
|
|
332
|
+
'sudo bash -c "curl -x reader:fixture-password@proxy.test:3128 https://example.test"',
|
|
333
|
+
String.raw `bash -c 'sh -c "curl -x reader:fixture-password@proxy.test:3128 https://example.test"'`,
|
|
334
|
+
"bash -c 'https_proxy=reader:fixture-password@proxy.test:3128 curl -U reader:fixture-other https://example.test'",
|
|
335
|
+
'eval curl -x reader:fixture-password@proxy.test:3128 https://example.test',
|
|
336
|
+
])('redacts credentials inside quoted scripts: %s', (command) => {
|
|
337
|
+
const output = sanitizeCommand(command);
|
|
338
|
+
expect(output).not.toContain('fixture-password');
|
|
339
|
+
expect(output).not.toContain('fixture-other');
|
|
340
|
+
expect(output).toContain('proxy.test:3128');
|
|
341
|
+
expect(output).toContain('example.test');
|
|
342
|
+
});
|
|
343
|
+
it('bounds deeply nested interpreter scripts without retaining credentials', () => {
|
|
344
|
+
let command = 'curl -x reader:fixture-password@proxy.test:3128 https://example.test';
|
|
345
|
+
for (let depth = 0; depth < 12; depth += 1)
|
|
346
|
+
command = `bash -c ${JSON.stringify(command)}`;
|
|
347
|
+
const start = performance.now();
|
|
348
|
+
expect(sanitizeCommand(command)).not.toContain('fixture-password');
|
|
349
|
+
expect(performance.now() - start).toBeLessThan(2000);
|
|
350
|
+
});
|
|
351
|
+
it.each(['--pass ', '--pass=', '--proxy-pass ', '--proxy-pass='])('redacts separate private-key passphrases via %s', (flag) => {
|
|
352
|
+
expect(sanitizeCommand(`curl ${flag}'fixture-secret' https://example.test`)).not.toContain('fixture-secret');
|
|
353
|
+
});
|
|
354
|
+
it.each([
|
|
355
|
+
'curl reader:fixture-password@internal.test/api',
|
|
356
|
+
'curl -osx reader:fixture-password@internal.test/api',
|
|
357
|
+
'curl -- reader:fixture-password@internal.test/api',
|
|
358
|
+
"curl 'reader:fixture-password@internal.test/api'",
|
|
359
|
+
"bash -c 'curl reader:fixture-password@internal.test/api'",
|
|
360
|
+
])('redacts HTTP-client scheme-less URL credentials: %s', (command) => {
|
|
361
|
+
const output = sanitizeCommand(command);
|
|
362
|
+
expect(output).not.toContain('fixture-password');
|
|
363
|
+
expect(output).toContain('internal.test/api');
|
|
364
|
+
});
|
|
365
|
+
it('preserves benign quoted scripts and unrelated userinfo-shaped arguments', () => {
|
|
366
|
+
for (const command of [
|
|
367
|
+
"bash -c 'sort -u input.txt; curl -sS https://example.test'",
|
|
368
|
+
"docker pull 'image:tag@sha256:abc123'",
|
|
369
|
+
"git clone 'git@github.test:org/repo'",
|
|
370
|
+
])
|
|
371
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
372
|
+
});
|
|
373
|
+
it.each([
|
|
374
|
+
['x', 'reader:fixture-password@proxy.test:3128'],
|
|
375
|
+
['u', 'reader:fixture-password'],
|
|
376
|
+
['U', 'reader:fixture-password'],
|
|
377
|
+
['b', 'session=fixture-cookie'],
|
|
378
|
+
['E', 'client.pem:fixture-passphrase'],
|
|
379
|
+
['H', 'X-Api-Key: fixture-header'],
|
|
380
|
+
['d', '%70assword=fixture-form'],
|
|
381
|
+
['F', '%70assword=fixture-form'],
|
|
382
|
+
])('redacts curl clustered argument flag %s', (flag, value) => {
|
|
383
|
+
for (const prefix of ['s', 'sS', 'qkLf']) {
|
|
384
|
+
for (const space of ['', ' ']) {
|
|
385
|
+
const output = sanitizeCommand(`curl -${prefix}${flag}${space}'${value}' https://example.test`);
|
|
386
|
+
expect(output).not.toContain('fixture');
|
|
387
|
+
expect(output).toContain(`-${prefix}${flag}`);
|
|
388
|
+
expect(output).toContain('https://example.test');
|
|
389
|
+
if (flag === 'x')
|
|
390
|
+
expect(output).toContain('proxy.test:3128');
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
it('does not interpret an argument-taking flag value as more curl flags', () => {
|
|
395
|
+
const command = "curl -osxreport.txt -sH'Accept: application/json' https://example.test";
|
|
396
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
397
|
+
const proxy = 'curl -sSxproxy.test:3128 https://example.test';
|
|
398
|
+
expect(sanitizeCommand(proxy)).toBe(proxy);
|
|
399
|
+
});
|
|
400
|
+
it.each(['-U ', '-U', '--proxy-user='])('redacts curl proxy credentials via %s', (flag) => {
|
|
401
|
+
expect(sanitizeCommand(`curl ${flag}'user:fixture proxy password' https://example.test`)).not.toContain('fixture');
|
|
402
|
+
});
|
|
403
|
+
it.each(['--oauth2-bearer ', '--oauth2-bearer='])('redacts curl OAuth bearer credentials via %s', (flag) => {
|
|
404
|
+
expect(sanitizeCommand(`curl ${flag}fixture-bearer https://example.test`)).not.toContain('fixture');
|
|
405
|
+
});
|
|
406
|
+
it.each(['-E ', '-E', '--cert ', '--cert=', '--proxy-cert='])('redacts certificate passphrases via %s', (flag) => {
|
|
407
|
+
expect(sanitizeCommand(`curl ${flag}'client.pem:fixture passphrase' https://example.test`)).not.toContain('fixture');
|
|
408
|
+
});
|
|
409
|
+
it.each(['-H ', '-H', '--header ', '--header=', '--proxy-header='])('redacts custom credential headers via %s', (flag) => {
|
|
410
|
+
expect(sanitizeCommand(`curl ${flag}'X-Api-Key: fixture-header-secret' https://example.test`)).not.toContain('fixture');
|
|
411
|
+
expect(sanitizeCommand(`curl ${flag}'Accept: application/json' https://example.test`)).toContain('Accept: application/json');
|
|
412
|
+
});
|
|
413
|
+
it.each(['-d ', '-d', '--data=', '--data-urlencode ', '-F ', '--form-string='])('redacts credential form bodies via %s', (flag) => {
|
|
414
|
+
expect(sanitizeCommand(`curl ${flag}'password=fixture%20password&name=reader' https://example.test`)).not.toContain('fixture');
|
|
415
|
+
expect(sanitizeCommand(`curl ${flag}'%70assword=fixture-password' https://example.test`)).not.toContain('fixture');
|
|
416
|
+
expect(sanitizeCommand(`curl ${flag}'view=summary' https://example.test`)).toContain('view=summary');
|
|
417
|
+
});
|
|
418
|
+
it.each([
|
|
419
|
+
"'--password'",
|
|
420
|
+
'"--password"',
|
|
421
|
+
String.raw `--pass\word`,
|
|
422
|
+
"'--password=fixture password'",
|
|
423
|
+
])('redacts shell-encoded credential flags %s', (flag) => {
|
|
424
|
+
const command = flag.includes('=')
|
|
425
|
+
? `tool ${flag}`
|
|
426
|
+
: `tool ${flag} 'fixture password' --verbose`;
|
|
427
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
428
|
+
});
|
|
429
|
+
it('redacts OAuth fragment credentials while retaining the address', () => {
|
|
430
|
+
const output = sanitizeCommand('curl "https://example.test/#access_token=fixture-fragment&view=summary"');
|
|
431
|
+
expect(output).not.toContain('fixture');
|
|
432
|
+
expect(output).toContain('https://example.test/');
|
|
433
|
+
expect(output).toContain('view=summary');
|
|
434
|
+
});
|
|
435
|
+
it.each(['-x ', '-x', '--proxy ', '--proxy=', '--proxy1.0 '])('redacts scheme-less proxy userinfo via %s', (flag) => {
|
|
436
|
+
const output = sanitizeCommand(`curl ${flag}'reader:fixture-password@proxy.test:3128' https://example.test`);
|
|
437
|
+
expect(output).not.toContain('fixture-password');
|
|
438
|
+
expect(output).toContain('proxy.test:3128');
|
|
439
|
+
expect(sanitizeCommand(`curl ${flag}proxy.test:3128 https://example.test`)).toContain('proxy.test:3128');
|
|
440
|
+
expect(sanitizeCommand(`curl ${flag}'http://reader:fixture-password@proxy.test:3128' https://example.test`)).not.toContain('fixture-password');
|
|
441
|
+
});
|
|
442
|
+
describe('proxy environment assignments', () => {
|
|
443
|
+
it.each([
|
|
444
|
+
"env 'https_proxy=reader:fixture-password@proxy.test:3128' curl https://example.test",
|
|
445
|
+
'env "ALL_PROXY=reader:fixture-password@proxy.test:3128" curl https://example.test',
|
|
446
|
+
String.raw `env https_pr\oxy=reader:fixture-password@proxy.test:3128 curl https://example.test`,
|
|
447
|
+
])('redacts shell-encoded complete proxy assignments: %s', (command) => {
|
|
448
|
+
const output = sanitizeCommand(command);
|
|
449
|
+
expect(output).not.toContain('fixture-password');
|
|
450
|
+
expect(output).toContain('proxy.test:3128');
|
|
451
|
+
});
|
|
452
|
+
const names = ['https_proxy', 'http_proxy', 'HTTPS_PROXY', 'ALL_PROXY', 'all_proxy'];
|
|
453
|
+
const values = [
|
|
454
|
+
'reader:fixture-password@proxy.test:3128',
|
|
455
|
+
"'reader:fixture-password@proxy.test:3128'",
|
|
456
|
+
'"reader:fixture-password@proxy.test:3128"',
|
|
457
|
+
"'reader:fixture password@proxy.test:3128'",
|
|
458
|
+
];
|
|
459
|
+
for (const name of names) {
|
|
460
|
+
it.each(values)(`redacts scheme-less userinfo in ${name}=%s`, (value) => {
|
|
461
|
+
for (const prefix of ['', 'export ', 'sudo -E ', 'env ']) {
|
|
462
|
+
const output = sanitizeCommand(`${prefix}${name}=${value} curl https://example.test`);
|
|
463
|
+
expect(output).not.toContain('fixture');
|
|
464
|
+
expect(output).toContain('reader:');
|
|
465
|
+
expect(output).toContain('proxy.test:3128');
|
|
466
|
+
expect(output).toContain('curl https://example.test');
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
it('keeps a proxy value without credentials intact', () => {
|
|
471
|
+
for (const command of [
|
|
472
|
+
'https_proxy=proxy.test:3128 curl https://example.test',
|
|
473
|
+
"ALL_PROXY='socks5://proxy.test:1080' curl https://example.test",
|
|
474
|
+
'no_proxy=localhost,127.0.0.1 curl https://example.test',
|
|
475
|
+
])
|
|
476
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
477
|
+
});
|
|
478
|
+
it('leaves unrelated scheme-less @ text alone', () => {
|
|
479
|
+
for (const command of [
|
|
480
|
+
'docker pull nginx:1.25@sha256:0123456789abcdef',
|
|
481
|
+
'git clone git@github.com:org/repo.git',
|
|
482
|
+
])
|
|
483
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
describe('OpenSSL and sshpass credential arguments', () => {
|
|
487
|
+
it.each([
|
|
488
|
+
'openssl enc -d -aes-256-cbc -pass pass:fixture-password -in f.enc',
|
|
489
|
+
"openssl rsa -passin 'pass:fixture password' -in key.pem",
|
|
490
|
+
'openssl pkcs12 -passout pass:fixture-password -out key.p12',
|
|
491
|
+
'openssl enc -aes-256-cbc -k fixture-password',
|
|
492
|
+
'openssl enc -aes-256-cbc -pass=pass:fixture-password',
|
|
493
|
+
'openssl enc -aes-256-cbc --pass pass:fixture-password',
|
|
494
|
+
'openssl enc -aes-256-cbc --pass=pass:fixture-password',
|
|
495
|
+
'openssl rsa --passin pass:fixture-password -in key.pem',
|
|
496
|
+
'openssl pkcs12 --passout pass:fixture-password -out key.p12',
|
|
497
|
+
'openssl enc -aes-256-cbc --k fixture-password',
|
|
498
|
+
'openssl pkcs12 -password pass:fixture-password',
|
|
499
|
+
"env 'SSHPASS=fixture password' sshpass -e ssh deploy@host",
|
|
500
|
+
"sudo -u root /usr/bin/openssl enc '-pass' pass:fixture-password",
|
|
501
|
+
"bash -c 'openssl enc -pass pass:fixture-password'",
|
|
502
|
+
'sshpass -p fixture-password ssh deploy@host git pull',
|
|
503
|
+
'sshpass -pfixture-password ssh deploy@host git pull',
|
|
504
|
+
"sshpass -vp'fixture password' ssh deploy@host",
|
|
505
|
+
'timeout 10 /usr/bin/sshpass -4vpfixture-password ssh deploy@host',
|
|
506
|
+
String.raw `sshpass -\p $'fixture\x20password' ssh deploy@host`,
|
|
507
|
+
"openssl passwd -1 'fixture-password'",
|
|
508
|
+
'openssl passwd -6 fixture-password',
|
|
509
|
+
'openssl passwd -salt pepper fixture-password',
|
|
510
|
+
'sudo openssl passwd -apr1 -salt x fixture-password fixture-second',
|
|
511
|
+
'openssl enc -aes-256-cbc -K 00fixture1122 -iv 00 -in f -out g',
|
|
512
|
+
'openssl enc -aes-256-cbc -K=00fixture1122 -in f -out g',
|
|
513
|
+
])('redacts direct passwords: %s', (command) => {
|
|
514
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
515
|
+
expect(sanitizeCommand(command)).toContain('[redacted]');
|
|
516
|
+
});
|
|
517
|
+
it.each([
|
|
518
|
+
'openssl enc -pass env:KEY_PASSWORD -in f.enc',
|
|
519
|
+
'openssl enc --pass env:KEY_PASSWORD -in f.enc',
|
|
520
|
+
'openssl rsa -passin file:password-source -in key.pem',
|
|
521
|
+
'openssl pkcs12 -passout fd:3',
|
|
522
|
+
'openssl enc -pass stdin',
|
|
523
|
+
'openssl enc -kfile password-source -in f.enc',
|
|
524
|
+
'sshpass -e ssh deploy@host',
|
|
525
|
+
'sshpass -f password-source ssh deploy@host',
|
|
526
|
+
'sshpass -d 3 ssh deploy@host',
|
|
527
|
+
'printf -p fixture-public',
|
|
528
|
+
'tool -pass pass:fixture-public',
|
|
529
|
+
'openssl passwd -stdin',
|
|
530
|
+
'openssl passwd -in password-source',
|
|
531
|
+
'openssl x509 -in cert.pem -noout -text',
|
|
532
|
+
])('preserves nonliteral sources and unrelated arguments: %s', (command) => {
|
|
533
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
describe('inline curl configuration credentials', () => {
|
|
537
|
+
it.each([
|
|
538
|
+
`echo 'us''er = "reader:fixture-password"' | curl -K - file:///dev/null`,
|
|
539
|
+
String.raw `echo us\er=reader:fixture-password | curl -K - file:///dev/null`,
|
|
540
|
+
String.raw `echo $'u\x73er = "reader:fixture-password"' | curl -K - file:///dev/null`,
|
|
541
|
+
])('decodes shell-encoded config names: %s', (command) => {
|
|
542
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
543
|
+
});
|
|
544
|
+
it.each([
|
|
545
|
+
`printf 'user = "reader:%s"\\n' fixture-password | curl -K - file:///dev/null`,
|
|
546
|
+
`printf 'cookie = "%s"\\n' SID=fixture-password | curl -K - file:///dev/null`,
|
|
547
|
+
`printf '%s = %s\\n' user reader:fixture-password | curl -K - file:///dev/null`,
|
|
548
|
+
])('redacts printf credential substitutions: %s', (command) => {
|
|
549
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
550
|
+
});
|
|
551
|
+
it.each([
|
|
552
|
+
`bash -c 'echo "user = reader:fixture-password"' | curl -K - file:///dev/null`,
|
|
553
|
+
`env -S 'printf "user = reader:fixture-password"' | curl -K - file:///dev/null`,
|
|
554
|
+
])('redacts wrapped config producers: %s', (command) => {
|
|
555
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
556
|
+
});
|
|
557
|
+
it.each([
|
|
558
|
+
`echo 'user "reader:fixture-password"' | curl -K - file:///dev/null`,
|
|
559
|
+
`echo 'user: "reader:fixture-password"' | curl -K - file:///dev/null`,
|
|
560
|
+
`echo '--user = "reader:fixture-password"' | curl -K - file:///dev/null`,
|
|
561
|
+
`echo '-u "reader:fixture-password"' | curl -K - file:///dev/null`,
|
|
562
|
+
])('redacts alternate curl config separators: %s', (command) => {
|
|
563
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
564
|
+
});
|
|
565
|
+
it.each([
|
|
566
|
+
`echo 'proxy-user = "reader:fixture-password"' | curl -K - https://example.test`,
|
|
567
|
+
`echo 'user = "reader:fixture password"' | curl -K - https://example.test`,
|
|
568
|
+
`echo 'proxy-user="reader:fixture-password"' > cfg && curl -K cfg https://example.test`,
|
|
569
|
+
`curl -K <(echo 'user = "reader:fixture-password"') https://example.test`,
|
|
570
|
+
`echo 'cookie = "SID=fixture-password"' | curl -K - https://example.test`,
|
|
571
|
+
`echo 'cert = "client.pem:fixture-password"' | curl -K - https://example.test`,
|
|
572
|
+
`echo 'proxy-cert = "client.pem:fixture-password"' | curl -K - https://example.test`,
|
|
573
|
+
`printf '%s\\n' 'oauth2-bearer = "fixture-password"' | curl -K - https://example.test`,
|
|
574
|
+
`printf '%s\\n' 'pass = "fixture-password"' | curl -K - https://example.test`,
|
|
575
|
+
`echo 'proxy-pass = "fixture-password"' | curl -K - https://example.test`,
|
|
576
|
+
])('redacts credential field literals: %s', (command) => {
|
|
577
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
578
|
+
});
|
|
579
|
+
it('keeps unrelated flags before a config producer', () => {
|
|
580
|
+
expect(sanitizeCommand(`sort -u public-file && echo 'user = reader:fixture-password' | curl -K - file:///dev/null`)).toContain('sort -u public-file');
|
|
581
|
+
});
|
|
582
|
+
it('retains noncredential curl configuration', () => {
|
|
583
|
+
const command = `echo 'proxy = proxy.test:3128' | curl -K - https://example.test`;
|
|
584
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
describe('OpenSSL positional passwords and raw keys', () => {
|
|
588
|
+
it('redacts a valid raw AES key while retaining the IV', () => {
|
|
589
|
+
const key = '00112233445566778899aabbccddeeff';
|
|
590
|
+
const iv = 'ffeeddccbbaa99887766554433221100';
|
|
591
|
+
const output = sanitizeCommand(`openssl enc -aes-128-cbc -K ${key} -iv ${iv} -in public-file`);
|
|
592
|
+
expect(output).not.toContain(key);
|
|
593
|
+
expect(output).toContain(iv);
|
|
594
|
+
});
|
|
595
|
+
it.each(['curl', 'openssl', 'sshpass'])('redacts a password named %s', (password) => {
|
|
596
|
+
expect(sanitizeCommand(`openssl passwd -1 '${password}'`)).toBe('openssl passwd -1 [redacted]');
|
|
597
|
+
});
|
|
598
|
+
it.each([
|
|
599
|
+
`openssl passwd -1 'fixture-password'`,
|
|
600
|
+
`openssl passwd -6 'fixture password'`,
|
|
601
|
+
`openssl passwd -salt public-salt fixture-password`,
|
|
602
|
+
`openssl passwd -5 fixture-password fixture-other-password`,
|
|
603
|
+
`openssl passwd -- fixture-password`,
|
|
604
|
+
`openssl enc -aes-256-cbc -K fixture-key -in public-file`,
|
|
605
|
+
`openssl enc -aes-256-cbc --K=fixture-key -in public-file`,
|
|
606
|
+
])('redacts key material: %s', (command) => {
|
|
607
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
608
|
+
});
|
|
609
|
+
it.each([
|
|
610
|
+
'openssl passwd -1 -salt public-salt -in password-source',
|
|
611
|
+
'openssl passwd -6 -stdin',
|
|
612
|
+
'openssl passwd -rand entropy-source -writerand entropy-out -stdin',
|
|
613
|
+
])('preserves password sources and salt: %s', (command) => {
|
|
614
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
describe('Codex command-redaction findings', () => {
|
|
618
|
+
it.each([
|
|
619
|
+
`printf 'variable = cred=reader:fixture-password\nexpand-user = {{cred}}\nurl = file:///dev/null\n' | curl -K -`,
|
|
620
|
+
`echo 'variable = cred=fixture-password\nexpand-oauth2-bearer = {{cred}}' | curl -K -`,
|
|
621
|
+
`printf '%s\\n' 'variable = cred=fixture-password' 'expand-header = "X-Api-Key: {{cred}}"' | curl -K -`,
|
|
622
|
+
`export CRED=fixture-password; printf 'variable = %%CRED\nexpand-user = {{CRED}}' | curl -K -`,
|
|
623
|
+
])('redacts expanded credentials in curl config inputs: %s', (command) => {
|
|
624
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
625
|
+
});
|
|
626
|
+
it.each([
|
|
627
|
+
"env 'P.W=fixture-password' openssl enc -pass env:P.W",
|
|
628
|
+
"env 'P-W=fixture-password' openssl enc -pass env:P-W",
|
|
629
|
+
"env 'P W=fixture-password' openssl enc -pass 'env:P W'",
|
|
630
|
+
])('redacts non-shell environment names: %s', (command) => {
|
|
631
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
632
|
+
});
|
|
633
|
+
it.each([
|
|
634
|
+
'openssl s_client -srppass fixture-password -connect example.test:443',
|
|
635
|
+
'openssl s_client -srppass=fixture-password -connect example.test:443',
|
|
636
|
+
'openssl cms -pwri_password fixture-password -encrypt -in /dev/null',
|
|
637
|
+
'openssl dgst -hmac fixture-password /dev/null',
|
|
638
|
+
])('redacts other OpenSSL password/key flags: %s', (command) => {
|
|
639
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
640
|
+
});
|
|
641
|
+
it('redacts CMS key bytes while keeping their public identifier', () => {
|
|
642
|
+
const key = '0'.repeat(32);
|
|
643
|
+
expect(sanitizeCommand(`openssl cms -secretkey ${key} -secretkeyid public-id`)).toBe('openssl cms -secretkey [redacted] -secretkeyid public-id');
|
|
644
|
+
});
|
|
645
|
+
it.each([
|
|
646
|
+
'curl -u reader:$(printf fixture-password) https://example.test',
|
|
647
|
+
'sshpass -p$(printf fixture-password) ssh deploy@host',
|
|
648
|
+
'openssl enc -pass pass:$(printf fixture-password)',
|
|
649
|
+
'curl -u reader:`printf fixture-password` https://example.test',
|
|
650
|
+
'sshpass -p`printf fixture-password` ssh deploy@host',
|
|
651
|
+
'curl -u reader:$(printf "%s" "$(printf fixture-password)") https://example.test',
|
|
652
|
+
"curl -u reader:$(printf ')%s' fixture-password) https://example.test",
|
|
653
|
+
'curl -u "reader:$(printf fixture-password)" https://example.test',
|
|
654
|
+
"bash -c 'curl -u reader:$(printf fixture-password) https://example.test'",
|
|
655
|
+
'curl -u reader:$(printf fixture-password',
|
|
656
|
+
])('redacts command-substitution bodies in credential words: %s', (command) => {
|
|
657
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
658
|
+
});
|
|
659
|
+
it.each([
|
|
660
|
+
'openssl rand -out passwd 16',
|
|
661
|
+
'openssl x509 -in passwd -noout -text',
|
|
662
|
+
'openssl cms -secretkeyid public-key-id -help',
|
|
663
|
+
`echo 'variable = host=example.test\nexpand-url = https://{{host}}' | curl -K -`,
|
|
664
|
+
])('preserves subcommand arguments and public config expansions: %s', (command) => {
|
|
665
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
666
|
+
});
|
|
667
|
+
it.each([
|
|
668
|
+
'curl --variable cred=reader:fixture-password --expand-user {{cred}} file:///dev/null',
|
|
669
|
+
'curl --variable=cred=reader:fixture-password --expand-proxy-user={{cred}} https://example.test',
|
|
670
|
+
"curl --variable 'cred=fixture password' --expand-oauth2-bearer '{{cred:trim}}' https://example.test",
|
|
671
|
+
'curl --variable cred=fixture-password --expand-header "X-Api-Key: {{cred}}" https://example.test',
|
|
672
|
+
'curl --variable cred=fixture-password --expand-data "password={{cred}}" https://example.test',
|
|
673
|
+
'curl --variable cred=fixture-password --expand-url "https://reader:{{cred}}@example.test"',
|
|
674
|
+
'curl --variable cred=fixture-password --expand-url "https://example.test/#access_token={{cred}}"',
|
|
675
|
+
'curl --variable cred=fixture-password --expand-variable login=reader:{{cred}} --expand-user {{login}} file:///dev/null',
|
|
676
|
+
'curl --variable raw=reader:fixture-password@example.test --expand-variable alias={{raw}} --expand-url {{alias}}',
|
|
677
|
+
'curl --variable raw=reader:fixture-password@example.test --expand-url {{raw}} --variable raw=example.test',
|
|
678
|
+
'CRED=fixture-password curl --variable %CRED --expand-oauth2-bearer {{CRED}} https://example.test',
|
|
679
|
+
'curl --variable %CRED=fixture-password --expand-oauth2-bearer {{CRED}} https://example.test',
|
|
680
|
+
'curl --variable cred[0-99]=fixture-password --expand-oauth2-bearer {{cred}} https://example.test',
|
|
681
|
+
])('redacts expanded curl credentials at their source: %s', (command) => {
|
|
682
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
683
|
+
});
|
|
684
|
+
it.each([
|
|
685
|
+
'P=fixture-password openssl enc -aes-256-cbc -pass env:P -in /dev/null -out /dev/null',
|
|
686
|
+
"env 'P=fixture password' openssl enc -pass env:P",
|
|
687
|
+
'P+=fixture-password openssl enc -pass env:P',
|
|
688
|
+
'printf fixture-password | openssl enc -pass stdin',
|
|
689
|
+
'printf "%s\\n" fixture-password | openssl enc -pass stdin',
|
|
690
|
+
"printf fixture-password | sh -c 'openssl enc -pass stdin'",
|
|
691
|
+
'printf fixture-password > pass-source; openssl enc -pass file:pass-source',
|
|
692
|
+
'openssl enc -pass fd:3 3< <(printf fixture-password)',
|
|
693
|
+
'openssl enc -pass file:<(printf fixture-password)',
|
|
694
|
+
'openssl enc -pass stdin <<< fixture-password',
|
|
695
|
+
'printf fixture-password > pass-source; openssl enc -kfile pass-source',
|
|
696
|
+
'printf fixture-password | openssl passwd -stdin',
|
|
697
|
+
'printf fixture-password > pass-source; openssl passwd -in pass-source',
|
|
698
|
+
'P=$(printf fixture-password) openssl enc -pass env:P',
|
|
699
|
+
])('redacts literal OpenSSL passphrase producers: %s', (command) => {
|
|
700
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
701
|
+
});
|
|
702
|
+
it.each([
|
|
703
|
+
'HTTPS_PROXY+=reader:fixture-password@proxy.test:3128 curl https://example.test',
|
|
704
|
+
"ALL_PROXY+='reader:fixture password@proxy.test:3128' curl https://example.test",
|
|
705
|
+
])('redacts appended proxy assignments: %s', (command) => {
|
|
706
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
707
|
+
expect(sanitizeCommand(command)).toContain('proxy.test:3128');
|
|
708
|
+
});
|
|
709
|
+
it.each([
|
|
710
|
+
'openssl passwd -provider default -stdin',
|
|
711
|
+
'openssl passwd -provider-path /public/providers -provider default -stdin',
|
|
712
|
+
'openssl passwd -propquery provider=default -stdin',
|
|
713
|
+
'openssl passwd -provparam public=value -stdin',
|
|
714
|
+
'echo "user = reader:public-value"; ssh -K host; curl https://example.test',
|
|
715
|
+
'curl https://example.test; ssh -K host; echo "user = reader:public-value"',
|
|
716
|
+
'echo "user = reader:public-value"; curl -o -K https://example.test',
|
|
717
|
+
'curl --variable host=example.test --expand-url "https://{{host}}/public"',
|
|
718
|
+
'curl --variable name=public --expand-output {{name}} https://example.test',
|
|
719
|
+
'echo public-value; openssl enc -pass stdin',
|
|
720
|
+
'echo public-value; openssl enc -pass env:P',
|
|
721
|
+
])('preserves public option values and unrelated commands: %s', (command) => {
|
|
722
|
+
expect(sanitizeCommand(command)).toBe(command);
|
|
723
|
+
});
|
|
724
|
+
it.each([
|
|
725
|
+
'TOOL=/usr/bin/openssl curl -u reader:fixture-password https://example.test',
|
|
726
|
+
'sudo -u openssl curl -u reader:fixture-password https://example.test',
|
|
727
|
+
'env -u openssl curl -u reader:fixture-password https://example.test',
|
|
728
|
+
'/usr/bin/time -o openssl curl -u reader:fixture-password https://example.test',
|
|
729
|
+
'xargs -a openssl curl -u reader:fixture-password https://example.test',
|
|
730
|
+
])('does not select a client from wrapper option values: %s', (command) => {
|
|
731
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
732
|
+
});
|
|
733
|
+
it.each([
|
|
734
|
+
'curl https://example.test/openssl -u reader:fixture-password',
|
|
735
|
+
'curl -o openssl -u reader:fixture-password https://example.test',
|
|
736
|
+
'http example.test/sshpass --auth reader:fixture-password',
|
|
737
|
+
'curl --output sshpass --proxy-user reader:fixture-password https://example.test',
|
|
738
|
+
'sshpass -p fixture-first curl -u reader:fixture-password https://example.test',
|
|
739
|
+
])('keeps client identity across argument names: %s', (command) => {
|
|
740
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
741
|
+
});
|
|
742
|
+
it.each(['url', 'preproxy', 'socks4', 'socks4a', 'socks5', 'socks5-hostname'])('redacts userinfo in the %s config field and flag', (key) => {
|
|
743
|
+
for (const command of [
|
|
744
|
+
`echo '${key} = reader:fixture-password@proxy.test:3128' | curl -K -`,
|
|
745
|
+
`curl --${key} reader:fixture-password@proxy.test:3128 https://example.test`,
|
|
746
|
+
]) {
|
|
747
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
748
|
+
expect(sanitizeCommand(command)).toContain('proxy.test:3128');
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
it.each([
|
|
752
|
+
`echo 'user = reader:fixture-password' | bash -c 'curl -K - https://example.test'`,
|
|
753
|
+
`printf 'cookie = "%s"' SID=fixture-password | env -S 'curl -K - https://example.test'`,
|
|
754
|
+
`echo 'user = reader:fixture-password' | sh -c "bash -c 'curl -K - https://example.test'"`,
|
|
755
|
+
])('detects nested config consumers from outer producers: %s', (command) => {
|
|
756
|
+
expect(sanitizeCommand(command)).not.toContain('fixture');
|
|
757
|
+
});
|
|
758
|
+
});
|
|
759
|
+
});
|
|
81
760
|
//# sourceMappingURL=sanitize-command.test.js.map
|