Module: PWN::AI::Agent::Confirmation

Defined in:
lib/pwn/ai/agent/confirmation.rb

Overview

Per-engagement ACK for exploit/destructive tool calls (PWN-AI-005 tiers).

Constant Summary collapse

TIERS =
%w[read_only active_scan exploit destructive].freeze
DEFAULTS =
{ 'read_only' => 'auto', 'active_scan' => 'auto', 'exploit' => 'prompt', 'destructive' => 'prompt' }.freeze
AUTONOMOUS =
{ 'read_only' => 'auto', 'active_scan' => 'auto', 'exploit' => 'auto', 'destructive' => 'auto' }.freeze

Class Method Summary collapse

Class Method Details

.authorsObject



65
66
67
# File 'lib/pwn/ai/agent/confirmation.rb', line 65

public_class_method def self.authors
  "AUTHOR(S):\n  0day Inc. <[email protected]>\n"
end

.gate(opts = {}) ⇒ Object

Return an ACK pause hash, or nil when the call may proceed.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/pwn/ai/agent/confirmation.rb', line 37

public_class_method def self.gate(opts = {})
  name = opts[:name].to_s
  args = opts[:args]
  args = {} unless args.is_a?(Hash)
  klass = tier(name: name, args: args)
  policy = load_policy(opts)
  action = (policy[klass] || DEFAULTS[klass] || 'auto').to_s
  return { success: false, error: "confirmation deny for #{klass}", code: 'ACK_DENY', tier: klass } if action == 'deny'
  return nil unless action == 'prompt'

  eng = engagement_id(opts.merge(args: args))
  return nil if acked?(engagement_id: eng)

  if truthy?(value: opts[:operator_ack] || args[:operator_ack] || args['operator_ack'])
    persist_ack(engagement_id: eng)
    return nil
  end
  {
    success: false,
    needs_ack: true,
    code: 'ACK_REQUIRED',
    tier: klass,
    engagement_id: eng,
    diff: intended_diff(name: name, args: args, tier: klass),
    error: "operator ACK required for #{klass}-tier tool call"
  }
end

.helpObject



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/pwn/ai/agent/confirmation.rb', line 69

public_class_method def self.help
  puts "USAGE:
    # List host binaries this module expects to be installed.
    #{self}.required_bins

    # Classify a tool call into a PWN-AI-005 side-effect tier.
    #{self}.tier(
      name: 'required - registry tool name',
      args: 'optional - Hash of tool arguments'
    )

    # Return an ACK pause hash, or nil when the call may proceed.
    #{self}.gate(
      name: 'required - registry tool name',
      args: 'optional - Hash of tool arguments',
      engagement_id: 'optional - engagement id used to cache the ACK',
      operator_ack: 'optional - true records a one-time ACK for this engagement',
      scope_path: 'optional - scope.yaml path; defaults to ~/.pwn/scope.yaml'
    )

    # Print the AUTHOR(S) string for this module.
    #{self}.authors
  "
  constants.sort
end

.required_binsObject



17
18
19
# File 'lib/pwn/ai/agent/confirmation.rb', line 17

public_class_method def self.required_bins
  []
end

.tier(opts = {}) ⇒ Object

Classify a tool call into a PWN-AI-005 side-effect tier.



22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/pwn/ai/agent/confirmation.rb', line 22

public_class_method def self.tier(opts = {})
  name = opts[:name].to_s
  args = opts[:args]
  args = {} unless args.is_a?(Hash)
  tagged = (args[:side_effect] || args['side_effect']).to_s
  return tagged if TIERS.include?(tagged)
  return 'exploit' if name.match?(/exploit|gdb_run_to_crash|fuzz_campaign/)
  return 'active_scan' if name.match?(/nmap_scan|nuclei_scan|sbom_scan|http_proxy/)
  return payload_tier(payload: args[:command] || args['command']) if name == 'shell'
  return payload_tier(payload: args[:code] || args['code']) if name == 'pwn_eval'

  'read_only'
end