pwn 0.5.719 → 0.5.720

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/etc/default_skills/pwn/ai/agent/engagement/SKILL.md +53 -0
  3. data/etc/default_skills/pwn/ai/agent/learning/SKILL.md +4 -0
  4. data/etc/default_skills/pwn/ai/agent/loop/SKILL.md +1 -0
  5. data/etc/default_skills/pwn/ai/agent/swarm/SKILL.md +1 -0
  6. data/etc/default_skills/pwn/ai/agent/tool_guard/SKILL.md +1 -0
  7. data/etc/default_skills/pwn/ai/agent/tools/debug_lane/SKILL.md +45 -0
  8. data/etc/default_skills/pwn/ai/agent/tools/engagement/SKILL.md +45 -0
  9. data/etc/default_skills/pwn/ai/agent/turn_finalizer/SKILL.md +2 -0
  10. data/etc/default_skills/pwn/plugins/bin_workspace/SKILL.md +49 -0
  11. data/etc/default_skills/pwn/plugins/binary_parser/SKILL.md +1 -0
  12. data/etc/default_skills/pwn/plugins/capability/SKILL.md +48 -0
  13. data/etc/default_skills/pwn/plugins/detonate/SKILL.md +47 -0
  14. data/etc/default_skills/pwn/plugins/emulator/SKILL.md +47 -0
  15. data/etc/default_skills/pwn/plugins/findings/SKILL.md +1 -0
  16. data/etc/default_skills/pwn/plugins/gdb/SKILL.md +2 -0
  17. data/etc/default_skills/pwn/plugins/packet/SKILL.md +1 -0
  18. data/etc/default_skills/pwn/plugins/repl/SKILL.md +1 -0
  19. data/etc/default_skills/pwn/plugins/vault/SKILL.md +4 -0
  20. data/etc/default_skills/pwn/reports/engagement/SKILL.md +47 -0
  21. data/lib/pwn/ai/agent/dispatch.rb +67 -0
  22. data/lib/pwn/ai/agent/engagement.rb +167 -0
  23. data/lib/pwn/ai/agent/learning.rb +88 -4
  24. data/lib/pwn/ai/agent/loop.rb +20 -0
  25. data/lib/pwn/ai/agent/reward.rb +76 -12
  26. data/lib/pwn/ai/agent/swarm.rb +36 -0
  27. data/lib/pwn/ai/agent/tool_guard.rb +39 -0
  28. data/lib/pwn/ai/agent/tools/debug_lane.rb +160 -0
  29. data/lib/pwn/ai/agent/tools/engagement.rb +40 -0
  30. data/lib/pwn/ai/agent/turn_finalizer.rb +65 -0
  31. data/lib/pwn/ai/agent.rb +1 -0
  32. data/lib/pwn/config.rb +18 -2
  33. data/lib/pwn/plugins/bin_workspace.rb +81 -0
  34. data/lib/pwn/plugins/binary_parser.rb +27 -0
  35. data/lib/pwn/plugins/capability.rb +68 -0
  36. data/lib/pwn/plugins/detonate.rb +62 -0
  37. data/lib/pwn/plugins/emulator.rb +64 -0
  38. data/lib/pwn/plugins/findings.rb +47 -0
  39. data/lib/pwn/plugins/gdb.rb +42 -0
  40. data/lib/pwn/plugins/packet.rb +26 -0
  41. data/lib/pwn/plugins/repl.rb +25 -2
  42. data/lib/pwn/plugins/vault.rb +116 -0
  43. data/lib/pwn/plugins.rb +4 -0
  44. data/lib/pwn/reports/engagement.rb +63 -0
  45. data/lib/pwn/reports.rb +1 -0
  46. data/lib/pwn/version.rb +1 -1
  47. data/spec/lib/pwn/ai/agent/engagement_spec.rb +27 -0
  48. data/spec/lib/pwn/ai/agent/learning_spec.rb +23 -0
  49. data/spec/lib/pwn/ai/agent/reward_spec.rb +16 -0
  50. data/spec/lib/pwn/ai/agent/swarm_spec.rb +11 -0
  51. data/spec/lib/pwn/ai/agent/tools/debug_lane_spec.rb +16 -0
  52. data/spec/lib/pwn/ai/agent/tools/engagement_spec.rb +16 -0
  53. data/spec/lib/pwn/ai/agent/turn_finalizer_spec.rb +18 -0
  54. data/spec/lib/pwn/plugins/bin_workspace_spec.rb +26 -0
  55. data/spec/lib/pwn/plugins/capability_spec.rb +19 -0
  56. data/spec/lib/pwn/plugins/detonate_spec.rb +24 -0
  57. data/spec/lib/pwn/plugins/emulator_spec.rb +18 -0
  58. data/spec/lib/pwn/plugins/findings_spec.rb +13 -0
  59. data/spec/lib/pwn/plugins/gdb_spec.rb +10 -0
  60. data/spec/lib/pwn/plugins/packet_spec.rb +6 -0
  61. data/spec/lib/pwn/plugins/repl_spec.rb +1 -1
  62. data/spec/lib/pwn/plugins/vault_spec.rb +11 -0
  63. data/spec/lib/pwn/reports/engagement_spec.rb +30 -0
  64. data/third_party/pwn_rdoc.jsonl +62 -0
  65. metadata +25 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 898622177b06081e32121144c9ae5461d510482e70a85b62de425967933e4e24
4
- data.tar.gz: ddfe5cac2e3db9bab8ab9cafdb1f48a2e2191545a2d0ad5bb7245cb7f45ab45f
3
+ metadata.gz: 0dd0d654d48c9ead7f9a92893f88443e1cfd7cd9a867c53cb2ffc25cbb60fe27
4
+ data.tar.gz: 3960e8501cbd0139184cd0981569a28a4f9b37e47ddddeb5dab001b2d0eefb1b
5
5
  SHA512:
6
- metadata.gz: 2751aa2984fe13fe852a6f12577bd840f097e5d84f240a05642e374938bbf8fe9095dcaee15a607b0b1c3c4b90d65b787f041ffbda26ec3868f26f68a400b28b
7
- data.tar.gz: db70fe6f75eaa22625849d30ab0e1a73dec982e160db005cce3096e625346eaea5d68653a4fb27a6e452f4ba01c63ab0313a5bd484b54a874f95bf44944ea149
6
+ metadata.gz: defca7be52f6960bbaa318f5e40e4927cafa8a1e679ce27dd8e74b73feae4b89a9766b725a5731b2e2fa5a8e93c58a2fa3622f0c37df6b0355bf6b12e9affbae
7
+ data.tar.gz: 29de8ee9497ec7004c4752ddaf3fc359016c6007368e051e891e191ad18bf069a3a44d32aa73ed480dc60cb30bba46551efa2f636009b8d50752e0101917900b
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: pwn-ai-agent-engagement
3
+ description: Drive PWN::AI::Agent::Engagement from pwn_eval.
4
+ license: MIT
5
+ allowed-tools: [pwn, pwn_eval]
6
+ metadata:
7
+ bundled: true
8
+ generated: true
9
+ module: PWN::AI::Agent::Engagement
10
+ source: pwn/ai/agent/engagement.rb
11
+ ---
12
+
13
+ # PWN::AI::Agent::Engagement
14
+
15
+ First-class engagement scope, RoE, and findings pointer.
16
+
17
+ ## When to use
18
+
19
+ Call `PWN::AI::Agent::Engagement` from `pwn_eval` when the task needs this module.
20
+ Do not reimplement it in shell.
21
+
22
+ ## Methodologies
23
+
24
+ Generated from `pwn/ai/agent/engagement.rb`. Prefer the public class methods below.
25
+ Class methods take `(opts = {})` and read `opts`.
26
+
27
+ ## How to call
28
+
29
+ ```ruby
30
+ PWN::AI::Agent::Engagement.help
31
+ PWN::AI::Agent::Engagement.open(opts)
32
+ ```
33
+
34
+ ## Public methods
35
+
36
+ - `open`
37
+ - `close`
38
+ - `status`
39
+ - `current_name`
40
+ - `in_scope`
41
+ - `deny_if_out_of_scope`
42
+ - `authors`
43
+ - `help`
44
+ - `in_scope?`
45
+
46
+ ## Source
47
+
48
+ `pwn/ai/agent/engagement.rb`
49
+
50
+ ## Verification
51
+
52
+ `PWN::AI::Agent::Engagement.respond_to?(:open)` after the
53
+ module is loaded. Read the source for parameter names.
@@ -54,8 +54,12 @@ PWN::AI::Agent::Learning.note_outcome(opts)
54
54
  - `lesson_record`
55
55
  - `lesson_observe`
56
56
  - `lesson_prompt`
57
+ - `list_conflicted`
58
+ - `requeue_conflicted`
59
+ - `compact`
57
60
  - `authors`
58
61
  - `help`
62
+ - `compact!`
59
63
  - `gc_stores!`
60
64
  - `lean!`
61
65
  - `prune_outcomes!`
@@ -41,6 +41,7 @@ PWN::AI::Agent::Loop.debug_on(opts)
41
41
  - `openai_wire_messages`
42
42
  - `request_intent`
43
43
  - `run`
44
+ - `budget_status`
44
45
  - `authors`
45
46
  - `help`
46
47
  - `catalog_lookup?`
@@ -46,6 +46,7 @@ PWN::AI::Agent::Swarm.personas(opts)
46
46
  - `map_targets`
47
47
  - `fact_record`
48
48
  - `facts_prompt`
49
+ - `claim`
49
50
  - `authors`
50
51
  - `help`
51
52
 
@@ -60,6 +60,7 @@ PWN::AI::Agent::ToolGuard.present(opts)
60
60
  - `timeout_prior_count`
61
61
  - `refuse_copied_persist`
62
62
  - `scope_refusal`
63
+ - `policy_decision`
63
64
  - `rfc1918`
64
65
  - `ip_in_cidr`
65
66
  - `command_class`
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: pwn-ai-agent-tools-debuglane
3
+ description: Drive PWN::Ai::Agent::Tools::DebugLane from pwn_eval.
4
+ license: MIT
5
+ allowed-tools: [pwn, pwn_eval]
6
+ metadata:
7
+ bundled: true
8
+ generated: true
9
+ module: PWN::Ai::Agent::Tools::DebugLane
10
+ source: pwn/ai/agent/tools/debug_lane.rb
11
+ ---
12
+
13
+ # PWN::Ai::Agent::Tools::DebugLane
14
+
15
+ Public API for PWN::Ai::Agent::Tools::DebugLane.
16
+
17
+ ## When to use
18
+
19
+ Call `PWN::Ai::Agent::Tools::DebugLane` from `pwn_eval` when the task needs this module.
20
+ Do not reimplement it in shell.
21
+
22
+ ## Methodologies
23
+
24
+ Generated from `pwn/ai/agent/tools/debug_lane.rb`. Prefer the public class methods below.
25
+ Class methods take `(opts = {})` and read `opts`.
26
+
27
+ ## How to call
28
+
29
+ ```ruby
30
+ PWN::Ai::Agent::Tools::DebugLane.help
31
+ PWN::Ai::Agent::Tools::DebugLane.help(opts)
32
+ ```
33
+
34
+ ## Public methods
35
+
36
+ - _(no public class methods parsed)_
37
+
38
+ ## Source
39
+
40
+ `pwn/ai/agent/tools/debug_lane.rb`
41
+
42
+ ## Verification
43
+
44
+ `PWN::Ai::Agent::Tools::DebugLane.respond_to?(:help)` after the
45
+ module is loaded. Read the source for parameter names.
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: pwn-ai-agent-tools-engagement
3
+ description: Drive PWN::Ai::Agent::Tools::Engagement from pwn_eval.
4
+ license: MIT
5
+ allowed-tools: [pwn, pwn_eval]
6
+ metadata:
7
+ bundled: true
8
+ generated: true
9
+ module: PWN::Ai::Agent::Tools::Engagement
10
+ source: pwn/ai/agent/tools/engagement.rb
11
+ ---
12
+
13
+ # PWN::Ai::Agent::Tools::Engagement
14
+
15
+ Public API for PWN::Ai::Agent::Tools::Engagement.
16
+
17
+ ## When to use
18
+
19
+ Call `PWN::Ai::Agent::Tools::Engagement` from `pwn_eval` when the task needs this module.
20
+ Do not reimplement it in shell.
21
+
22
+ ## Methodologies
23
+
24
+ Generated from `pwn/ai/agent/tools/engagement.rb`. Prefer the public class methods below.
25
+ Class methods take `(opts = {})` and read `opts`.
26
+
27
+ ## How to call
28
+
29
+ ```ruby
30
+ PWN::Ai::Agent::Tools::Engagement.help
31
+ PWN::Ai::Agent::Tools::Engagement.help(opts)
32
+ ```
33
+
34
+ ## Public methods
35
+
36
+ - _(no public class methods parsed)_
37
+
38
+ ## Source
39
+
40
+ `pwn/ai/agent/tools/engagement.rb`
41
+
42
+ ## Verification
43
+
44
+ `PWN::Ai::Agent::Tools::Engagement.respond_to?(:help)` after the
45
+ module is loaded. Read the source for parameter names.
@@ -41,6 +41,8 @@ PWN::AI::Agent::TurnFinalizer.enter_user_path(opts)
41
41
  - `finalize`
42
42
  - `join_all`
43
43
  - `pending`
44
+ - `arbitrate`
45
+ - `evidence_ledger`
44
46
  - `authors`
45
47
  - `help`
46
48
  - `enter_user_path!`
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: pwn-plugins-binworkspace
3
+ description: Drive PWN::Plugins::BinWorkspace from pwn_eval.
4
+ license: MIT
5
+ allowed-tools: [pwn, pwn_eval]
6
+ metadata:
7
+ bundled: true
8
+ generated: true
9
+ module: PWN::Plugins::BinWorkspace
10
+ source: pwn/plugins/bin_workspace.rb
11
+ ---
12
+
13
+ # PWN::Plugins::BinWorkspace
14
+
15
+ Persistent per-binary analysis workspace keyed by sha256.
16
+
17
+ ## When to use
18
+
19
+ Call `PWN::Plugins::BinWorkspace` from `pwn_eval` when the task needs this module.
20
+ Do not reimplement it in shell.
21
+
22
+ ## Methodologies
23
+
24
+ Generated from `pwn/plugins/bin_workspace.rb`. Prefer the public class methods below.
25
+ Class methods take `(opts = {})` and read `opts`.
26
+
27
+ ## How to call
28
+
29
+ ```ruby
30
+ PWN::Plugins::BinWorkspace.help
31
+ PWN::Plugins::BinWorkspace.for(opts)
32
+ ```
33
+
34
+ ## Public methods
35
+
36
+ - `for`
37
+ - `annotate`
38
+ - `notes`
39
+ - `authors`
40
+ - `help`
41
+
42
+ ## Source
43
+
44
+ `pwn/plugins/bin_workspace.rb`
45
+
46
+ ## Verification
47
+
48
+ `PWN::Plugins::BinWorkspace.respond_to?(:for)` after the
49
+ module is loaded. Read the source for parameter names.
@@ -42,6 +42,7 @@ PWN::Plugins::BinaryParser.required_bins(opts)
42
42
  - `exports`
43
43
  - `relocations`
44
44
  - `triage`
45
+ - `diff`
45
46
  - `authors`
46
47
  - `help`
47
48
 
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: pwn-plugins-capability
3
+ description: Drive PWN::Plugins::Capability from pwn_eval.
4
+ license: MIT
5
+ allowed-tools: [pwn, pwn_eval]
6
+ metadata:
7
+ bundled: true
8
+ generated: true
9
+ module: PWN::Plugins::Capability
10
+ source: pwn/plugins/capability.rb
11
+ ---
12
+
13
+ # PWN::Plugins::Capability
14
+
15
+ Operator-approved capability elevation (never auto-sudo).
16
+
17
+ ## When to use
18
+
19
+ Call `PWN::Plugins::Capability` from `pwn_eval` when the task needs this module.
20
+ Do not reimplement it in shell.
21
+
22
+ ## Methodologies
23
+
24
+ Generated from `pwn/plugins/capability.rb`. Prefer the public class methods below.
25
+ Class methods take `(opts = {})` and read `opts`.
26
+
27
+ ## How to call
28
+
29
+ ```ruby
30
+ PWN::Plugins::Capability.help
31
+ PWN::Plugins::Capability.request(opts)
32
+ ```
33
+
34
+ ## Public methods
35
+
36
+ - `request`
37
+ - `grantable_caps`
38
+ - `authors`
39
+ - `help`
40
+
41
+ ## Source
42
+
43
+ `pwn/plugins/capability.rb`
44
+
45
+ ## Verification
46
+
47
+ `PWN::Plugins::Capability.respond_to?(:request)` after the
48
+ module is loaded. Read the source for parameter names.
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: pwn-plugins-detonate
3
+ description: Drive PWN::Plugins::Detonate from pwn_eval.
4
+ license: MIT
5
+ allowed-tools: [pwn, pwn_eval]
6
+ metadata:
7
+ bundled: true
8
+ generated: true
9
+ module: PWN::Plugins::Detonate
10
+ source: pwn/plugins/detonate.rb
11
+ ---
12
+
13
+ # PWN::Plugins::Detonate
14
+
15
+ Isolated sample detonation. Refuses if podman/isolation is missing.
16
+
17
+ ## When to use
18
+
19
+ Call `PWN::Plugins::Detonate` from `pwn_eval` when the task needs this module.
20
+ Do not reimplement it in shell.
21
+
22
+ ## Methodologies
23
+
24
+ Generated from `pwn/plugins/detonate.rb`. Prefer the public class methods below.
25
+ Class methods take `(opts = {})` and read `opts`.
26
+
27
+ ## How to call
28
+
29
+ ```ruby
30
+ PWN::Plugins::Detonate.help
31
+ PWN::Plugins::Detonate.detonate(opts)
32
+ ```
33
+
34
+ ## Public methods
35
+
36
+ - `detonate`
37
+ - `authors`
38
+ - `help`
39
+
40
+ ## Source
41
+
42
+ `pwn/plugins/detonate.rb`
43
+
44
+ ## Verification
45
+
46
+ `PWN::Plugins::Detonate.respond_to?(:detonate)` after the
47
+ module is loaded. Read the source for parameter names.
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: pwn-plugins-emulator
3
+ description: Drive PWN::Plugins::Emulator from pwn_eval.
4
+ license: MIT
5
+ allowed-tools: [pwn, pwn_eval]
6
+ metadata:
7
+ bundled: true
8
+ generated: true
9
+ module: PWN::Plugins::Emulator
10
+ source: pwn/plugins/emulator.rb
11
+ ---
12
+
13
+ # PWN::Plugins::Emulator
14
+
15
+ Unicorn-backed single-function emulation with a stub backend for tests.
16
+
17
+ ## When to use
18
+
19
+ Call `PWN::Plugins::Emulator` from `pwn_eval` when the task needs this module.
20
+ Do not reimplement it in shell.
21
+
22
+ ## Methodologies
23
+
24
+ Generated from `pwn/plugins/emulator.rb`. Prefer the public class methods below.
25
+ Class methods take `(opts = {})` and read `opts`.
26
+
27
+ ## How to call
28
+
29
+ ```ruby
30
+ PWN::Plugins::Emulator.help
31
+ PWN::Plugins::Emulator.emulate(opts)
32
+ ```
33
+
34
+ ## Public methods
35
+
36
+ - `emulate`
37
+ - `authors`
38
+ - `help`
39
+
40
+ ## Source
41
+
42
+ `pwn/plugins/emulator.rb`
43
+
44
+ ## Verification
45
+
46
+ `PWN::Plugins::Emulator.respond_to?(:emulate)` after the
47
+ module is loaded. Read the source for parameter names.
@@ -35,6 +35,7 @@ PWN::Plugins::Findings.required_bins(opts)
35
35
 
36
36
  - `required_bins`
37
37
  - `record`
38
+ - `evidence_verify`
38
39
  - `report`
39
40
  - `query`
40
41
  - `chain`
@@ -40,6 +40,8 @@ PWN::Plugins::GDB.required_bins(opts)
40
40
  - `mitigations`
41
41
  - `core`
42
42
  - `breakpoints`
43
+ - `crash_info`
44
+ - `debug_session`
43
45
  - `authors`
44
46
  - `help`
45
47
 
@@ -44,6 +44,7 @@ PWN::Plugins::Packet.open_pcap_file(opts)
44
44
  - `construct_tcp`
45
45
  - `construct_udp`
46
46
  - `send`
47
+ - `tcp_connect_scan`
47
48
  - `authors`
48
49
  - `help`
49
50
 
@@ -56,6 +56,7 @@ PWN::Plugins::REPL.ready_tty(opts)
56
56
  - `pwn_ai_run_cron`
57
57
  - `pwn_ai_run_sessions`
58
58
  - `pwn_ai_run_memory`
59
+ - `pwn_ai_run_learning`
59
60
  - `pwn_ai_run_skills`
60
61
  - `enable_autocomplete`
61
62
  - `start`
@@ -40,6 +40,10 @@ PWN::Plugins::Vault.refresh_encryption_secrets(opts)
40
40
  - `edit`
41
41
  - `encrypt`
42
42
  - `file_encrypted`
43
+ - `store`
44
+ - `fetch`
45
+ - `expand`
46
+ - `redact`
43
47
  - `authors`
44
48
  - `help`
45
49
  - `file_encrypted?`
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: pwn-reports-engagement
3
+ description: Drive PWN::Reports::Engagement from pwn_eval.
4
+ license: MIT
5
+ allowed-tools: [pwn, pwn_eval]
6
+ metadata:
7
+ bundled: true
8
+ generated: true
9
+ module: PWN::Reports::Engagement
10
+ source: pwn/reports/engagement.rb
11
+ ---
12
+
13
+ # PWN::Reports::Engagement
14
+
15
+ Compile engagement findings into a client-ready HTML/Markdown report.
16
+
17
+ ## When to use
18
+
19
+ Call `PWN::Reports::Engagement` from `pwn_eval` when the task needs this module.
20
+ Do not reimplement it in shell.
21
+
22
+ ## Methodologies
23
+
24
+ Generated from `pwn/reports/engagement.rb`. Prefer the public class methods below.
25
+ Class methods take `(opts = {})` and read `opts`.
26
+
27
+ ## How to call
28
+
29
+ ```ruby
30
+ PWN::Reports::Engagement.help
31
+ PWN::Reports::Engagement.generate(opts)
32
+ ```
33
+
34
+ ## Public methods
35
+
36
+ - `generate`
37
+ - `authors`
38
+ - `help`
39
+
40
+ ## Source
41
+
42
+ `pwn/reports/engagement.rb`
43
+
44
+ ## Verification
45
+
46
+ `PWN::Reports::Engagement.respond_to?(:generate)` after the
47
+ module is loaded. Read the source for parameter names.
@@ -46,6 +46,20 @@ module PWN
46
46
  args = parse_args(raw: raw, entry: entry)
47
47
  required = Array(entry.schema&.dig(:parameters, :required))
48
48
  args = ToolGuard.coerce_args(args: args, required: required) if defined?(ToolGuard)
49
+ blob = args.inspect
50
+ if defined?(PWN::Plugins::Vault)
51
+ blob = PWN::Plugins::Vault.expand(text: blob)
52
+ args = expand_vault_args(args: args)
53
+ end
54
+ if defined?(Engagement)
55
+ denied = Engagement.deny_if_out_of_scope(args: args, command: blob)
56
+ return JSON.generate(denied) if denied
57
+ end
58
+ if defined?(ToolGuard) && ToolGuard.respond_to?(:policy_decision)
59
+ pol = ToolGuard.policy_decision(name: entry.name, args: args)
60
+ return JSON.generate(pol) if pol.is_a?(Hash) && pol[:action] == 'deny'
61
+ end
62
+ return JSON.generate(success: false, error: 'taint: tool-output instruction in args', code: 'TAINT_DENY') if taint_blocked?(name: entry.name, args: args)
49
63
  if defined?(ToolGuard) && ToolGuard.respond_to?(:canary_leak?) &&
50
64
  ToolGuard.canary_leak?(text: args.inspect)
51
65
  return JSON.generate(success: false, error: 'refused: session canary in outbound args', code: 'CANARY_DENY', rule_id: 'canary')
@@ -59,6 +73,12 @@ module PWN
59
73
  end
60
74
  result = entry.handler.call(args)
61
75
  result = ToolGuard.quarantine_output(text: result) if defined?(ToolGuard) && result.is_a?(String) && ToolGuard.respond_to?(:quarantine_output)
76
+ note_taint(text: result)
77
+ if defined?(PWN::Plugins::Vault) && result.is_a?(String)
78
+ result = PWN::Plugins::Vault.redact(text: result)
79
+ elsif defined?(PWN::Plugins::Vault) && result.is_a?(Hash)
80
+ result = JSON.parse(PWN::Plugins::Vault.redact(text: JSON.generate(result)))
81
+ end
62
82
  JSON.generate(success: true, result: result, effect: effect(name: entry.name, args: args))
63
83
  rescue StandardError => e
64
84
  JSON.generate(
@@ -348,6 +368,53 @@ module PWN
348
368
  hash.each_with_object({}) { |(k, v), m| m[k.to_sym] = v }
349
369
  end
350
370
 
371
+ private_class_method def self.expand_vault_args(opts = {})
372
+ args = opts[:args]
373
+ return args unless args.is_a?(Hash)
374
+
375
+ args.transform_values do |v|
376
+ v.is_a?(String) ? PWN::Plugins::Vault.expand(text: v) : v
377
+ end
378
+ rescue StandardError
379
+ opts[:args]
380
+ end
381
+
382
+ private_class_method def self.note_taint(opts = {})
383
+ text = opts[:text].to_s
384
+ grams = text.scan(/.{12,}/).first(20)
385
+ store = Thread.current[:pwn_taint] ||= []
386
+ grams.each { |g| store << g[0, 64] }
387
+ store.shift while store.length > 200
388
+ store
389
+ end
390
+
391
+ private_class_method def self.taint_blocked?(opts = {})
392
+ mode = taint_mode
393
+ return false if mode == 'off'
394
+
395
+ blob = opts[:args].inspect
396
+ return false if blob.length < 12
397
+ return false if opts[:args].is_a?(Hash) && (opts[:args][:taint_ack] == true || opts[:args]['taint_ack'] == true)
398
+
399
+ hit = Array(Thread.current[:pwn_taint]).any? { |g| g.length >= 12 && blob.include?(g) }
400
+ return false unless hit
401
+ return false unless blob.match?(/curl |bash -c|sh -c|\|\s*sh\b/i)
402
+
403
+ mode == 'enforce'
404
+ rescue StandardError
405
+ false
406
+ end
407
+
408
+ private_class_method def self.taint_mode(opts = {})
409
+ override = opts[:mode]
410
+ return override.to_s unless override.to_s.empty?
411
+ return 'enforce' unless defined?(PWN::Env)
412
+
413
+ (PWN::Env.dig(:ai, :taint, :mode) || 'enforce').to_s
414
+ rescue StandardError
415
+ 'enforce'
416
+ end
417
+
351
418
  # Author(s):: 0day Inc. <support@0dayinc.com>
352
419
 
353
420
  public_class_method def self.authors