@themoltnet/pi-runtime 0.16.0 → 0.18.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.
@@ -0,0 +1,884 @@
1
+ //#region src/tool-policy/escape-corpus.ts
2
+ /**
3
+ * The policy each shape resolves to. The E2E suite creates real runtime
4
+ * policies from these same values, so a live REST-resolved policy and the unit
5
+ * fixture cannot drift apart.
6
+ */
7
+ var ESCAPE_POLICY_FIXTURES = {
8
+ "no-shell": {
9
+ tools: ["read"],
10
+ shellCommands: []
11
+ },
12
+ "tool-grant-only": {
13
+ tools: [
14
+ "ls",
15
+ "grep",
16
+ "find",
17
+ "gh",
18
+ "git"
19
+ ],
20
+ shellCommands: []
21
+ },
22
+ "narrow-shell": {
23
+ tools: [],
24
+ shellCommands: [{ argvPrefix: ["ls", "-la"] }]
25
+ },
26
+ "multi-token-shell": {
27
+ tools: [],
28
+ shellCommands: [{ argvPrefix: [
29
+ "gh",
30
+ "pr",
31
+ "view"
32
+ ] }]
33
+ },
34
+ "one-token-escape-flags": {
35
+ tools: [],
36
+ shellCommands: [
37
+ { argvPrefix: ["tar"] },
38
+ { argvPrefix: ["rsync"] },
39
+ { argvPrefix: ["ssh"] },
40
+ { argvPrefix: ["scp"] },
41
+ { argvPrefix: ["xargs"] }
42
+ ]
43
+ },
44
+ "one-token-shell": {
45
+ tools: [],
46
+ shellCommands: [{ argvPrefix: ["git"] }]
47
+ },
48
+ "one-token-escapable": {
49
+ tools: [],
50
+ shellCommands: [{ argvPrefix: ["find"] }]
51
+ }
52
+ };
53
+ var TOOL_POLICY_ESCAPE_CASES = [
54
+ {
55
+ name: "a structured-tool-only policy authorizes no shell program",
56
+ policyShape: "no-shell",
57
+ command: "ls",
58
+ expectedAllow: false,
59
+ reasonCode: "tool_not_permitted",
60
+ missing: ["ls"],
61
+ technique: "plain-command",
62
+ e2e: true,
63
+ source: "issue-2275"
64
+ },
65
+ {
66
+ name: "refuses a shell interpreter",
67
+ policyShape: "no-shell",
68
+ command: "sh -c ls",
69
+ expectedAllow: false,
70
+ reasonCode: "arbitrary_code_interpreter",
71
+ missing: ["sh"],
72
+ technique: "arbitrary-code-interpreter",
73
+ e2e: true,
74
+ source: "issue-2275"
75
+ },
76
+ {
77
+ name: "refuses a language interpreter",
78
+ policyShape: "no-shell",
79
+ command: "python -c \"print(1)\"",
80
+ expectedAllow: false,
81
+ reasonCode: "arbitrary_code_interpreter",
82
+ missing: ["python"],
83
+ technique: "arbitrary-code-interpreter",
84
+ source: "issue-2275"
85
+ },
86
+ {
87
+ name: "refuses process substitution as unresolvable",
88
+ policyShape: "no-shell",
89
+ command: "diff <(ls) <(ls)",
90
+ expectedAllow: false,
91
+ reasonCode: "shell_command_unresolvable",
92
+ technique: "process-substitution",
93
+ source: "issue-2275"
94
+ },
95
+ {
96
+ name: "resolves a heredoc body to its executable and refuses it",
97
+ policyShape: "no-shell",
98
+ command: "cat <<EOF\nhi\nEOF",
99
+ expectedAllow: false,
100
+ reasonCode: "tool_not_permitted",
101
+ missing: ["cat"],
102
+ technique: "heredoc",
103
+ source: "issue-2275"
104
+ },
105
+ {
106
+ name: "refuses a shell builtin that runs nothing",
107
+ policyShape: "no-shell",
108
+ command: ":",
109
+ expectedAllow: false,
110
+ reasonCode: "tool_not_permitted",
111
+ missing: [":"],
112
+ technique: "null-builtin",
113
+ source: "issue-2275"
114
+ },
115
+ {
116
+ name: "a shell program granted only as a tool name is refused",
117
+ policyShape: "tool-grant-only",
118
+ command: "gh pr merge 1725",
119
+ expectedAllow: false,
120
+ reasonCode: "tool_not_permitted",
121
+ missing: ["gh"],
122
+ technique: "tool-name-as-executable",
123
+ e2e: true,
124
+ source: "issue-2275"
125
+ },
126
+ {
127
+ name: "an ls tool grant does not authorize the ls program",
128
+ policyShape: "tool-grant-only",
129
+ command: "ls -la",
130
+ expectedAllow: false,
131
+ reasonCode: "tool_not_permitted",
132
+ missing: ["ls"],
133
+ technique: "tool-name-as-executable",
134
+ source: "issue-2275"
135
+ },
136
+ {
137
+ name: "a grep tool grant does not authorize the grep program",
138
+ policyShape: "tool-grant-only",
139
+ command: "grep needle missing",
140
+ expectedAllow: false,
141
+ reasonCode: "tool_not_permitted",
142
+ missing: ["grep"],
143
+ technique: "tool-name-as-executable",
144
+ source: "issue-2275"
145
+ },
146
+ {
147
+ name: "a find tool grant does not authorize a GTFOBins file write",
148
+ policyShape: "tool-grant-only",
149
+ command: "find . -fprint proof.txt",
150
+ expectedAllow: false,
151
+ reasonCode: "tool_not_permitted",
152
+ missing: ["find"],
153
+ technique: "gtfobins-file-write",
154
+ source: "issue-2275"
155
+ },
156
+ {
157
+ name: "a find tool grant does not authorize deletion",
158
+ policyShape: "tool-grant-only",
159
+ command: "find . -delete",
160
+ expectedAllow: false,
161
+ reasonCode: "tool_not_permitted",
162
+ missing: ["find"],
163
+ technique: "destructive-flag",
164
+ source: "issue-2275"
165
+ },
166
+ {
167
+ name: "allows the exact granted invocation",
168
+ policyShape: "narrow-shell",
169
+ command: "ls -la",
170
+ expectedAllow: true,
171
+ reasonCode: "shell_command_prefix_allowed",
172
+ technique: "plain-command",
173
+ e2e: true,
174
+ source: "issue-2275"
175
+ },
176
+ {
177
+ name: "a subshell does not change the invocation being authorized",
178
+ policyShape: "narrow-shell",
179
+ command: "(ls -la)",
180
+ expectedAllow: true,
181
+ reasonCode: "shell_command_prefix_allowed",
182
+ technique: "grouping",
183
+ source: "issue-2275"
184
+ },
185
+ {
186
+ name: "a brace group does not change the invocation being authorized",
187
+ policyShape: "narrow-shell",
188
+ command: "{ ls -la; }",
189
+ expectedAllow: true,
190
+ reasonCode: "shell_command_prefix_allowed",
191
+ technique: "grouping",
192
+ source: "issue-2275"
193
+ },
194
+ {
195
+ name: "every element of a sequence is authorized separately",
196
+ policyShape: "narrow-shell",
197
+ command: "ls -la; ls -la",
198
+ expectedAllow: true,
199
+ reasonCode: "shell_command_prefix_allowed",
200
+ technique: "sequence",
201
+ source: "issue-2275"
202
+ },
203
+ {
204
+ name: "a benign environment assignment prefix does not hide the executable",
205
+ policyShape: "narrow-shell",
206
+ command: "LS_COLORS=x ls -la",
207
+ expectedAllow: true,
208
+ reasonCode: "shell_command_prefix_allowed",
209
+ technique: "env-assignment-prefix",
210
+ source: "issue-2275"
211
+ },
212
+ {
213
+ name: "refuses a PATH prefix that could substitute the executable",
214
+ policyShape: "narrow-shell",
215
+ command: "PATH=/tmp ls -la",
216
+ expectedAllow: false,
217
+ reasonCode: "unsafe_environment_assignment",
218
+ missing: ["PATH"],
219
+ technique: "env-assignment-prefix",
220
+ e2e: true,
221
+ source: "issue-2275"
222
+ },
223
+ {
224
+ name: "refuses a loader preload prefix",
225
+ policyShape: "narrow-shell",
226
+ command: "LD_PRELOAD=/tmp/evil.so ls -la",
227
+ expectedAllow: false,
228
+ reasonCode: "unsafe_environment_assignment",
229
+ missing: ["LD_PRELOAD"],
230
+ technique: "env-assignment-prefix",
231
+ source: "issue-2275"
232
+ },
233
+ {
234
+ name: "refuses a loader search-path prefix",
235
+ policyShape: "narrow-shell",
236
+ command: "LD_LIBRARY_PATH=/tmp ls -la",
237
+ expectedAllow: false,
238
+ reasonCode: "unsafe_environment_assignment",
239
+ missing: ["LD_LIBRARY_PATH"],
240
+ technique: "env-assignment-prefix",
241
+ source: "issue-2275"
242
+ },
243
+ {
244
+ name: "refuses a shell startup-file prefix",
245
+ policyShape: "narrow-shell",
246
+ command: "BASH_ENV=/tmp/x ls -la",
247
+ expectedAllow: false,
248
+ reasonCode: "unsafe_environment_assignment",
249
+ missing: ["BASH_ENV"],
250
+ technique: "env-assignment-prefix",
251
+ source: "issue-2275"
252
+ },
253
+ {
254
+ name: "refuses a field-separator prefix",
255
+ policyShape: "narrow-shell",
256
+ command: "IFS=x ls -la",
257
+ expectedAllow: false,
258
+ reasonCode: "unsafe_environment_assignment",
259
+ missing: ["IFS"],
260
+ technique: "env-assignment-prefix",
261
+ source: "issue-2275"
262
+ },
263
+ {
264
+ name: "refuses an env wrapper the policy does not grant",
265
+ policyShape: "narrow-shell",
266
+ command: "env ls -la",
267
+ expectedAllow: false,
268
+ reasonCode: "tool_not_permitted",
269
+ missing: ["env"],
270
+ technique: "wrapper",
271
+ e2e: true,
272
+ source: "issue-2275"
273
+ },
274
+ {
275
+ name: "refuses a timeout wrapper the policy does not grant",
276
+ policyShape: "narrow-shell",
277
+ command: "timeout 5 ls -la",
278
+ expectedAllow: false,
279
+ reasonCode: "tool_not_permitted",
280
+ missing: ["timeout"],
281
+ technique: "wrapper",
282
+ source: "issue-2275"
283
+ },
284
+ {
285
+ name: "refuses a nice wrapper the policy does not grant",
286
+ policyShape: "narrow-shell",
287
+ command: "nice ls -la",
288
+ expectedAllow: false,
289
+ reasonCode: "tool_not_permitted",
290
+ missing: ["nice"],
291
+ technique: "wrapper",
292
+ source: "issue-2275"
293
+ },
294
+ {
295
+ name: "refuses the command builtin used as a wrapper",
296
+ policyShape: "narrow-shell",
297
+ command: "command ls -la",
298
+ expectedAllow: false,
299
+ reasonCode: "tool_not_permitted",
300
+ missing: ["command"],
301
+ technique: "wrapper",
302
+ source: "issue-2275"
303
+ },
304
+ {
305
+ name: "refuses a backslash-escaped command name as unresolvable",
306
+ policyShape: "narrow-shell",
307
+ command: "\\ls -la",
308
+ expectedAllow: false,
309
+ reasonCode: "shell_command_unresolvable",
310
+ technique: "quoted-command-name",
311
+ e2e: true,
312
+ source: "issue-2275"
313
+ },
314
+ {
315
+ name: "resolves a quoted command name rather than refusing it",
316
+ policyShape: "narrow-shell",
317
+ command: "\"ls\" -la",
318
+ expectedAllow: true,
319
+ reasonCode: "shell_command_prefix_allowed",
320
+ technique: "quoted-command-name",
321
+ source: "issue-2275"
322
+ },
323
+ {
324
+ name: "refuses a concatenated command name as unresolvable",
325
+ policyShape: "narrow-shell",
326
+ command: "l''s -la",
327
+ expectedAllow: false,
328
+ reasonCode: "shell_command_unresolvable",
329
+ technique: "quoted-command-name",
330
+ source: "issue-2275"
331
+ },
332
+ {
333
+ name: "refuses a command name built by substitution as unresolvable",
334
+ policyShape: "narrow-shell",
335
+ command: "$(echo ls) -la",
336
+ expectedAllow: false,
337
+ reasonCode: "shell_command_unresolvable",
338
+ technique: "command-substitution-name",
339
+ source: "issue-2275"
340
+ },
341
+ {
342
+ name: "fails closed on a quoted flag rather than normalizing it",
343
+ policyShape: "narrow-shell",
344
+ command: "ls -l\"a\"",
345
+ expectedAllow: false,
346
+ reasonCode: "tool_not_permitted",
347
+ missing: ["ls"],
348
+ technique: "quoted-flag",
349
+ source: "issue-2275"
350
+ },
351
+ {
352
+ name: "refuses stderr redirection despite a matching rule",
353
+ policyShape: "narrow-shell",
354
+ command: "ls -la 2> proof.txt",
355
+ expectedAllow: false,
356
+ reasonCode: "shell_output_redirection_not_permitted",
357
+ missing: ["ls"],
358
+ technique: "redirection",
359
+ e2e: true,
360
+ source: "issue-2275"
361
+ },
362
+ {
363
+ name: "refuses append redirection despite a matching rule",
364
+ policyShape: "narrow-shell",
365
+ command: "ls -la >> proof.txt",
366
+ expectedAllow: false,
367
+ reasonCode: "shell_output_redirection_not_permitted",
368
+ missing: ["ls"],
369
+ technique: "redirection",
370
+ source: "issue-2275"
371
+ },
372
+ {
373
+ name: "refuses a file-descriptor duplication redirect",
374
+ policyShape: "narrow-shell",
375
+ command: "ls -la 1>&2",
376
+ expectedAllow: false,
377
+ reasonCode: "shell_output_redirection_not_permitted",
378
+ missing: ["ls"],
379
+ technique: "redirection-fd",
380
+ source: "issue-2275"
381
+ },
382
+ {
383
+ name: "refuses the shorthand file-descriptor redirect",
384
+ policyShape: "narrow-shell",
385
+ command: "ls -la >&2",
386
+ expectedAllow: false,
387
+ reasonCode: "shell_output_redirection_not_permitted",
388
+ missing: ["ls"],
389
+ technique: "redirection-fd",
390
+ source: "issue-2275"
391
+ },
392
+ {
393
+ name: "refuses reaching a writer through a pipe",
394
+ policyShape: "narrow-shell",
395
+ command: "ls -la | tee proof.txt",
396
+ expectedAllow: false,
397
+ reasonCode: "tool_not_permitted",
398
+ missing: ["tee"],
399
+ technique: "pipe-to-writer",
400
+ source: "issue-2275"
401
+ },
402
+ {
403
+ name: "a one-token rule allows any arguments to that program",
404
+ policyShape: "one-token-shell",
405
+ command: "git push origin main",
406
+ expectedAllow: true,
407
+ reasonCode: "shell_command_prefix_allowed",
408
+ technique: "plain-command",
409
+ documentsGrantBreadth: true,
410
+ e2e: true,
411
+ source: "issue-2275"
412
+ },
413
+ {
414
+ name: "both sides of a pipe may match the same one-token rule",
415
+ policyShape: "one-token-shell",
416
+ command: "git status | git apply",
417
+ expectedAllow: true,
418
+ reasonCode: "shell_command_prefix_allowed",
419
+ technique: "pipe",
420
+ documentsGrantBreadth: true,
421
+ source: "issue-2275"
422
+ },
423
+ {
424
+ name: "refuses an interpreter reached through a git config override",
425
+ policyShape: "one-token-shell",
426
+ command: "git -c core.pager=sh log",
427
+ expectedAllow: false,
428
+ reasonCode: "arbitrary_code_interpreter",
429
+ missing: ["sh"],
430
+ technique: "arbitrary-code-interpreter",
431
+ e2e: true,
432
+ source: "issue-2275"
433
+ },
434
+ {
435
+ name: "refuses an interpreter reached through a difftool escape flag",
436
+ policyShape: "one-token-shell",
437
+ command: "git difftool -x sh",
438
+ expectedAllow: false,
439
+ reasonCode: "arbitrary_code_interpreter",
440
+ missing: ["sh"],
441
+ technique: "arbitrary-code-interpreter",
442
+ e2e: true,
443
+ source: "issue-2275"
444
+ },
445
+ {
446
+ name: "a quoted subcommand does not hide a scoped escape flag",
447
+ policyShape: "one-token-shell",
448
+ command: "git \"difftool\" -x sh",
449
+ expectedAllow: false,
450
+ reasonCode: "arbitrary_code_interpreter",
451
+ missing: ["sh"],
452
+ technique: "quoted-scope-evasion",
453
+ e2e: true,
454
+ source: "issue-2275"
455
+ },
456
+ {
457
+ name: "a concatenated subcommand does not hide a scoped escape flag",
458
+ policyShape: "one-token-shell",
459
+ command: "git diff\"\"tool -x sh",
460
+ expectedAllow: false,
461
+ reasonCode: "arbitrary_code_interpreter",
462
+ missing: ["sh"],
463
+ technique: "quoted-scope-evasion",
464
+ source: "issue-2275"
465
+ },
466
+ {
467
+ name: "a quoted flag does not hide a scoped escape flag",
468
+ policyShape: "one-token-shell",
469
+ command: "git difftool \"-x\" sh",
470
+ expectedAllow: false,
471
+ reasonCode: "arbitrary_code_interpreter",
472
+ missing: ["sh"],
473
+ technique: "quoted-scope-evasion",
474
+ source: "issue-2275"
475
+ },
476
+ {
477
+ name: "refuses an attached-form difftool escape flag",
478
+ policyShape: "one-token-shell",
479
+ command: "git difftool -xsh",
480
+ expectedAllow: false,
481
+ reasonCode: "arbitrary_code_interpreter",
482
+ missing: ["sh"],
483
+ technique: "attached-escape-flag",
484
+ source: "issue-2275"
485
+ },
486
+ {
487
+ name: "refuses an attached-form rebase escape flag",
488
+ policyShape: "one-token-shell",
489
+ command: "git rebase -xsh main",
490
+ expectedAllow: false,
491
+ reasonCode: "arbitrary_code_interpreter",
492
+ missing: ["sh"],
493
+ technique: "attached-escape-flag",
494
+ source: "issue-2275"
495
+ },
496
+ {
497
+ name: "refuses an inline-form filter-branch filter",
498
+ policyShape: "one-token-shell",
499
+ command: "git filter-branch --tree-filter=sh HEAD",
500
+ expectedAllow: false,
501
+ reasonCode: "arbitrary_code_interpreter",
502
+ missing: ["sh"],
503
+ technique: "attached-escape-flag",
504
+ source: "issue-2275"
505
+ },
506
+ {
507
+ name: "refuses a git program hook set through the environment",
508
+ policyShape: "one-token-shell",
509
+ command: "GIT_SSH_COMMAND=sh git fetch",
510
+ expectedAllow: false,
511
+ reasonCode: "unsafe_environment_assignment",
512
+ missing: ["GIT_SSH_COMMAND"],
513
+ technique: "env-assignment-prefix",
514
+ source: "issue-2275"
515
+ },
516
+ {
517
+ name: "a subcommand name used as a pathspec does not arm a scoped flag",
518
+ policyShape: "one-token-shell",
519
+ command: "git log -- rebase",
520
+ expectedAllow: true,
521
+ reasonCode: "shell_command_prefix_allowed",
522
+ technique: "scoped-flag-namesake",
523
+ documentsGrantBreadth: true,
524
+ source: "issue-2275"
525
+ },
526
+ {
527
+ name: "refuses an interpreter reached through the long difftool flag",
528
+ policyShape: "one-token-shell",
529
+ command: "git difftool --extcmd=sh",
530
+ expectedAllow: false,
531
+ reasonCode: "arbitrary_code_interpreter",
532
+ missing: ["sh"],
533
+ technique: "arbitrary-code-interpreter",
534
+ source: "issue-2275"
535
+ },
536
+ {
537
+ name: "refuses an interpreter reached through a rebase exec flag",
538
+ policyShape: "one-token-shell",
539
+ command: "git rebase -x sh main",
540
+ expectedAllow: false,
541
+ reasonCode: "arbitrary_code_interpreter",
542
+ missing: ["sh"],
543
+ technique: "arbitrary-code-interpreter",
544
+ source: "issue-2275"
545
+ },
546
+ {
547
+ name: "refuses an interpreter reached through a filter-branch filter",
548
+ policyShape: "one-token-shell",
549
+ command: "git filter-branch --tree-filter sh HEAD",
550
+ expectedAllow: false,
551
+ reasonCode: "arbitrary_code_interpreter",
552
+ missing: ["sh"],
553
+ technique: "arbitrary-code-interpreter",
554
+ source: "issue-2275"
555
+ },
556
+ {
557
+ name: "refuses an interpreter reached through a sequence-editor override",
558
+ policyShape: "one-token-shell",
559
+ command: "git -c sequence.editor=sh rebase -i",
560
+ expectedAllow: false,
561
+ reasonCode: "arbitrary_code_interpreter",
562
+ missing: ["sh"],
563
+ technique: "arbitrary-code-interpreter",
564
+ source: "issue-2275"
565
+ },
566
+ {
567
+ name: "refuses an interpreter reached through a credential-helper override",
568
+ policyShape: "one-token-shell",
569
+ command: "git -c credential.helper=sh fetch",
570
+ expectedAllow: false,
571
+ reasonCode: "arbitrary_code_interpreter",
572
+ missing: ["sh"],
573
+ technique: "arbitrary-code-interpreter",
574
+ source: "issue-2275"
575
+ },
576
+ {
577
+ name: "a scoped escape flag does not refuse its benign namesake",
578
+ policyShape: "one-token-shell",
579
+ command: "git clean -x -d",
580
+ expectedAllow: true,
581
+ reasonCode: "shell_command_prefix_allowed",
582
+ technique: "scoped-flag-namesake",
583
+ documentsGrantBreadth: true,
584
+ e2e: true,
585
+ source: "issue-2275"
586
+ },
587
+ {
588
+ name: "refuses redirection even under a one-token rule",
589
+ policyShape: "one-token-shell",
590
+ command: "git diff > proof.txt",
591
+ expectedAllow: false,
592
+ reasonCode: "shell_output_redirection_not_permitted",
593
+ missing: ["git"],
594
+ technique: "redirection",
595
+ source: "issue-2275"
596
+ },
597
+ {
598
+ name: "refuses an xargs wrapper around a granted program",
599
+ policyShape: "one-token-shell",
600
+ command: "xargs git",
601
+ expectedAllow: false,
602
+ reasonCode: "tool_not_permitted",
603
+ missing: ["xargs"],
604
+ technique: "wrapper",
605
+ source: "issue-2275"
606
+ },
607
+ {
608
+ name: "allows an invocation that extends the granted prefix",
609
+ policyShape: "multi-token-shell",
610
+ command: "gh pr view 1725",
611
+ expectedAllow: true,
612
+ reasonCode: "shell_command_prefix_allowed",
613
+ technique: "plain-command",
614
+ e2e: true,
615
+ source: "issue-2275"
616
+ },
617
+ {
618
+ name: "allows an invocation exactly as long as the granted prefix",
619
+ policyShape: "multi-token-shell",
620
+ command: "gh pr view",
621
+ expectedAllow: true,
622
+ reasonCode: "shell_command_prefix_allowed",
623
+ technique: "plain-command",
624
+ source: "issue-2275"
625
+ },
626
+ {
627
+ name: "refuses a sibling subcommand under the same program",
628
+ policyShape: "multi-token-shell",
629
+ command: "gh pr merge 1725",
630
+ expectedAllow: false,
631
+ reasonCode: "tool_not_permitted",
632
+ missing: ["gh"],
633
+ technique: "sibling-subcommand",
634
+ e2e: true,
635
+ source: "issue-2275"
636
+ },
637
+ {
638
+ name: "refuses an invocation shorter than the granted prefix",
639
+ policyShape: "multi-token-shell",
640
+ command: "gh pr",
641
+ expectedAllow: false,
642
+ reasonCode: "tool_not_permitted",
643
+ missing: ["gh"],
644
+ technique: "short-of-prefix",
645
+ source: "issue-2275"
646
+ },
647
+ {
648
+ name: "refuses the bare program under a subcommand-path rule",
649
+ policyShape: "multi-token-shell",
650
+ command: "gh",
651
+ expectedAllow: false,
652
+ reasonCode: "tool_not_permitted",
653
+ missing: ["gh"],
654
+ technique: "short-of-prefix",
655
+ source: "issue-2275"
656
+ },
657
+ {
658
+ name: "refuses redirection under a subcommand-path rule",
659
+ policyShape: "multi-token-shell",
660
+ command: "gh pr view 1725 > out.txt",
661
+ expectedAllow: false,
662
+ reasonCode: "shell_output_redirection_not_permitted",
663
+ missing: ["gh"],
664
+ technique: "redirection",
665
+ source: "issue-2275"
666
+ },
667
+ {
668
+ name: "refuses a wrapper around a granted subcommand path",
669
+ policyShape: "multi-token-shell",
670
+ command: "env gh pr view 1725",
671
+ expectedAllow: false,
672
+ reasonCode: "tool_not_permitted",
673
+ missing: ["env"],
674
+ technique: "wrapper",
675
+ source: "issue-2275"
676
+ },
677
+ {
678
+ name: "a dynamic token after the prefix does not break the match",
679
+ policyShape: "multi-token-shell",
680
+ command: "gh pr view \"$NUM\"",
681
+ expectedAllow: true,
682
+ reasonCode: "shell_command_prefix_allowed",
683
+ technique: "dynamic-trailing-token",
684
+ documentsGrantBreadth: true,
685
+ source: "issue-2275"
686
+ },
687
+ {
688
+ name: "every invocation in a compound must match, not just the first",
689
+ policyShape: "multi-token-shell",
690
+ command: "gh pr view 1 && gh pr merge 1",
691
+ expectedAllow: false,
692
+ reasonCode: "tool_not_permitted",
693
+ missing: ["gh"],
694
+ technique: "compound-partial-match",
695
+ e2e: true,
696
+ source: "issue-2275"
697
+ },
698
+ {
699
+ name: "a one-token tar rule allows an ordinary archive",
700
+ policyShape: "one-token-escape-flags",
701
+ command: "tar -cf a.tar dir",
702
+ expectedAllow: true,
703
+ reasonCode: "shell_command_prefix_allowed",
704
+ technique: "plain-command",
705
+ documentsGrantBreadth: true,
706
+ source: "issue-2275"
707
+ },
708
+ {
709
+ name: "refuses an interpreter passed to tar --to-command",
710
+ policyShape: "one-token-escape-flags",
711
+ command: "tar --to-command='sh -c id' -cf a.tar dir",
712
+ expectedAllow: false,
713
+ reasonCode: "arbitrary_code_interpreter",
714
+ missing: ["sh"],
715
+ technique: "arbitrary-code-interpreter",
716
+ e2e: true,
717
+ source: "issue-2275"
718
+ },
719
+ {
720
+ name: "refuses an interpreter passed to a tar checkpoint action",
721
+ policyShape: "one-token-escape-flags",
722
+ command: "tar --checkpoint-action=exec=sh -cf a.tar d",
723
+ expectedAllow: false,
724
+ reasonCode: "arbitrary_code_interpreter",
725
+ missing: ["sh"],
726
+ technique: "arbitrary-code-interpreter",
727
+ source: "issue-2275"
728
+ },
729
+ {
730
+ name: "a one-token rsync rule allows an ordinary sync",
731
+ policyShape: "one-token-escape-flags",
732
+ command: "rsync -a src dst",
733
+ expectedAllow: true,
734
+ reasonCode: "shell_command_prefix_allowed",
735
+ technique: "plain-command",
736
+ documentsGrantBreadth: true,
737
+ source: "issue-2275"
738
+ },
739
+ {
740
+ name: "refuses an interpreter passed as the rsync remote shell",
741
+ policyShape: "one-token-escape-flags",
742
+ command: "rsync -e sh host:/x /y",
743
+ expectedAllow: false,
744
+ reasonCode: "arbitrary_code_interpreter",
745
+ missing: ["sh"],
746
+ technique: "arbitrary-code-interpreter",
747
+ source: "issue-2275"
748
+ },
749
+ {
750
+ name: "refuses an interpreter passed as the inline rsync remote shell",
751
+ policyShape: "one-token-escape-flags",
752
+ command: "rsync --rsh=sh host:/x /y",
753
+ expectedAllow: false,
754
+ reasonCode: "arbitrary_code_interpreter",
755
+ missing: ["sh"],
756
+ technique: "arbitrary-code-interpreter",
757
+ source: "issue-2275"
758
+ },
759
+ {
760
+ name: "a one-token ssh rule allows an ordinary connection",
761
+ policyShape: "one-token-escape-flags",
762
+ command: "ssh host",
763
+ expectedAllow: true,
764
+ reasonCode: "shell_command_prefix_allowed",
765
+ technique: "plain-command",
766
+ documentsGrantBreadth: true,
767
+ source: "issue-2275"
768
+ },
769
+ {
770
+ name: "refuses an interpreter passed as an ssh proxy command",
771
+ policyShape: "one-token-escape-flags",
772
+ command: "ssh -o ProxyCommand=sh host",
773
+ expectedAllow: false,
774
+ reasonCode: "arbitrary_code_interpreter",
775
+ missing: ["sh"],
776
+ technique: "arbitrary-code-interpreter",
777
+ source: "issue-2275"
778
+ },
779
+ {
780
+ name: "refuses an attached-form ssh proxy command",
781
+ policyShape: "one-token-escape-flags",
782
+ command: "ssh -oProxyCommand=sh host",
783
+ expectedAllow: false,
784
+ reasonCode: "arbitrary_code_interpreter",
785
+ missing: ["sh"],
786
+ technique: "attached-escape-flag",
787
+ source: "issue-2275"
788
+ },
789
+ {
790
+ name: "a benign ssh option is not mistaken for a command",
791
+ policyShape: "one-token-escape-flags",
792
+ command: "ssh -o StrictHostKeyChecking=no host",
793
+ expectedAllow: true,
794
+ reasonCode: "shell_command_prefix_allowed",
795
+ technique: "benign-keyed-option",
796
+ documentsGrantBreadth: true,
797
+ source: "issue-2275"
798
+ },
799
+ {
800
+ name: "refuses an interpreter passed as the scp transfer program",
801
+ policyShape: "one-token-escape-flags",
802
+ command: "scp -S sh a b",
803
+ expectedAllow: false,
804
+ reasonCode: "arbitrary_code_interpreter",
805
+ missing: ["sh"],
806
+ technique: "arbitrary-code-interpreter",
807
+ source: "issue-2275"
808
+ },
809
+ {
810
+ name: "refuses an attached-form scp transfer program",
811
+ policyShape: "one-token-escape-flags",
812
+ command: "scp -Ssh a b",
813
+ expectedAllow: false,
814
+ reasonCode: "arbitrary_code_interpreter",
815
+ missing: ["sh"],
816
+ technique: "attached-escape-flag",
817
+ source: "issue-2275"
818
+ },
819
+ {
820
+ name: "refuses an interpreter launched by a granted xargs",
821
+ policyShape: "one-token-escape-flags",
822
+ command: "xargs sh",
823
+ expectedAllow: false,
824
+ reasonCode: "arbitrary_code_interpreter",
825
+ missing: ["sh"],
826
+ technique: "wrapper",
827
+ source: "issue-2275"
828
+ },
829
+ {
830
+ name: "refuses redirection under a one-token escapable grant",
831
+ policyShape: "one-token-escape-flags",
832
+ command: "tar -cf a.tar dir > out.txt",
833
+ expectedAllow: false,
834
+ reasonCode: "shell_output_redirection_not_permitted",
835
+ missing: ["tar"],
836
+ technique: "redirection",
837
+ source: "issue-2275"
838
+ },
839
+ {
840
+ name: "a one-token find rule permits a GTFOBins file write",
841
+ policyShape: "one-token-escapable",
842
+ command: "find . -fprint proof.txt",
843
+ expectedAllow: true,
844
+ reasonCode: "shell_command_prefix_allowed",
845
+ technique: "gtfobins-file-write",
846
+ documentsGrantBreadth: true,
847
+ source: "issue-2275"
848
+ },
849
+ {
850
+ name: "a one-token find rule permits deletion",
851
+ policyShape: "one-token-escapable",
852
+ command: "find . -delete",
853
+ expectedAllow: true,
854
+ reasonCode: "shell_command_prefix_allowed",
855
+ technique: "destructive-flag",
856
+ documentsGrantBreadth: true,
857
+ source: "issue-2275"
858
+ },
859
+ {
860
+ name: "a nested -exec program must itself be authorized",
861
+ policyShape: "one-token-escapable",
862
+ command: "find . -exec cat {} ;",
863
+ expectedAllow: false,
864
+ reasonCode: "tool_not_permitted",
865
+ missing: ["cat"],
866
+ technique: "nested-exec",
867
+ e2e: true,
868
+ source: "issue-2275"
869
+ },
870
+ {
871
+ name: "refuses an interpreter launched through -exec",
872
+ policyShape: "one-token-escapable",
873
+ command: "find . -exec sh -c ls ;",
874
+ expectedAllow: false,
875
+ reasonCode: "arbitrary_code_interpreter",
876
+ missing: ["sh"],
877
+ technique: "arbitrary-code-interpreter",
878
+ source: "issue-2275"
879
+ }
880
+ ];
881
+ /** The smaller subset the live-policy E2E replays against real runtime policies. */
882
+ var TOOL_POLICY_ESCAPE_E2E_CASES = TOOL_POLICY_ESCAPE_CASES.filter((testCase) => testCase.e2e === true);
883
+ //#endregion
884
+ export { ESCAPE_POLICY_FIXTURES, TOOL_POLICY_ESCAPE_CASES, TOOL_POLICY_ESCAPE_E2E_CASES };