hackagent 0.3.1__py3-none-any.whl
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.
- hackagent/__init__.py +12 -0
- hackagent/agent.py +214 -0
- hackagent/api/__init__.py +1 -0
- hackagent/api/agent/__init__.py +1 -0
- hackagent/api/agent/agent_create.py +347 -0
- hackagent/api/agent/agent_destroy.py +140 -0
- hackagent/api/agent/agent_list.py +242 -0
- hackagent/api/agent/agent_partial_update.py +361 -0
- hackagent/api/agent/agent_retrieve.py +235 -0
- hackagent/api/agent/agent_update.py +361 -0
- hackagent/api/apilogs/__init__.py +1 -0
- hackagent/api/apilogs/apilogs_list.py +170 -0
- hackagent/api/apilogs/apilogs_retrieve.py +162 -0
- hackagent/api/attack/__init__.py +1 -0
- hackagent/api/attack/attack_create.py +275 -0
- hackagent/api/attack/attack_destroy.py +146 -0
- hackagent/api/attack/attack_list.py +254 -0
- hackagent/api/attack/attack_partial_update.py +289 -0
- hackagent/api/attack/attack_retrieve.py +247 -0
- hackagent/api/attack/attack_update.py +289 -0
- hackagent/api/checkout/__init__.py +1 -0
- hackagent/api/checkout/checkout_create.py +225 -0
- hackagent/api/generate/__init__.py +1 -0
- hackagent/api/generate/generate_create.py +253 -0
- hackagent/api/judge/__init__.py +1 -0
- hackagent/api/judge/judge_create.py +253 -0
- hackagent/api/key/__init__.py +1 -0
- hackagent/api/key/key_create.py +179 -0
- hackagent/api/key/key_destroy.py +103 -0
- hackagent/api/key/key_list.py +170 -0
- hackagent/api/key/key_retrieve.py +162 -0
- hackagent/api/organization/__init__.py +1 -0
- hackagent/api/organization/organization_create.py +208 -0
- hackagent/api/organization/organization_destroy.py +104 -0
- hackagent/api/organization/organization_list.py +170 -0
- hackagent/api/organization/organization_me_retrieve.py +126 -0
- hackagent/api/organization/organization_partial_update.py +222 -0
- hackagent/api/organization/organization_retrieve.py +163 -0
- hackagent/api/organization/organization_update.py +222 -0
- hackagent/api/prompt/__init__.py +1 -0
- hackagent/api/prompt/prompt_create.py +171 -0
- hackagent/api/prompt/prompt_destroy.py +104 -0
- hackagent/api/prompt/prompt_list.py +185 -0
- hackagent/api/prompt/prompt_partial_update.py +185 -0
- hackagent/api/prompt/prompt_retrieve.py +163 -0
- hackagent/api/prompt/prompt_update.py +185 -0
- hackagent/api/result/__init__.py +1 -0
- hackagent/api/result/result_create.py +175 -0
- hackagent/api/result/result_destroy.py +106 -0
- hackagent/api/result/result_list.py +249 -0
- hackagent/api/result/result_partial_update.py +193 -0
- hackagent/api/result/result_retrieve.py +167 -0
- hackagent/api/result/result_trace_create.py +177 -0
- hackagent/api/result/result_update.py +189 -0
- hackagent/api/run/__init__.py +1 -0
- hackagent/api/run/run_create.py +187 -0
- hackagent/api/run/run_destroy.py +112 -0
- hackagent/api/run/run_list.py +291 -0
- hackagent/api/run/run_partial_update.py +201 -0
- hackagent/api/run/run_result_create.py +177 -0
- hackagent/api/run/run_retrieve.py +179 -0
- hackagent/api/run/run_run_tests_create.py +187 -0
- hackagent/api/run/run_update.py +201 -0
- hackagent/api/user/__init__.py +1 -0
- hackagent/api/user/user_create.py +212 -0
- hackagent/api/user/user_destroy.py +106 -0
- hackagent/api/user/user_list.py +174 -0
- hackagent/api/user/user_me_retrieve.py +126 -0
- hackagent/api/user/user_me_update.py +196 -0
- hackagent/api/user/user_partial_update.py +226 -0
- hackagent/api/user/user_retrieve.py +167 -0
- hackagent/api/user/user_update.py +226 -0
- hackagent/attacks/AdvPrefix/__init__.py +41 -0
- hackagent/attacks/AdvPrefix/completions.py +416 -0
- hackagent/attacks/AdvPrefix/config.py +259 -0
- hackagent/attacks/AdvPrefix/evaluation.py +745 -0
- hackagent/attacks/AdvPrefix/evaluators.py +564 -0
- hackagent/attacks/AdvPrefix/generate.py +711 -0
- hackagent/attacks/AdvPrefix/utils.py +307 -0
- hackagent/attacks/__init__.py +35 -0
- hackagent/attacks/advprefix.py +507 -0
- hackagent/attacks/base.py +106 -0
- hackagent/attacks/strategies.py +906 -0
- hackagent/cli/__init__.py +19 -0
- hackagent/cli/commands/__init__.py +20 -0
- hackagent/cli/commands/agent.py +100 -0
- hackagent/cli/commands/attack.py +417 -0
- hackagent/cli/commands/config.py +301 -0
- hackagent/cli/commands/results.py +327 -0
- hackagent/cli/config.py +249 -0
- hackagent/cli/main.py +515 -0
- hackagent/cli/tui/__init__.py +31 -0
- hackagent/cli/tui/actions_logger.py +200 -0
- hackagent/cli/tui/app.py +288 -0
- hackagent/cli/tui/base.py +137 -0
- hackagent/cli/tui/logger.py +318 -0
- hackagent/cli/tui/views/__init__.py +33 -0
- hackagent/cli/tui/views/agents.py +488 -0
- hackagent/cli/tui/views/attacks.py +624 -0
- hackagent/cli/tui/views/config.py +244 -0
- hackagent/cli/tui/views/dashboard.py +307 -0
- hackagent/cli/tui/views/results.py +1210 -0
- hackagent/cli/tui/widgets/__init__.py +24 -0
- hackagent/cli/tui/widgets/actions.py +346 -0
- hackagent/cli/tui/widgets/logs.py +435 -0
- hackagent/cli/utils.py +276 -0
- hackagent/client.py +286 -0
- hackagent/errors.py +37 -0
- hackagent/logger.py +83 -0
- hackagent/models/__init__.py +109 -0
- hackagent/models/agent.py +223 -0
- hackagent/models/agent_request.py +129 -0
- hackagent/models/api_token_log.py +184 -0
- hackagent/models/attack.py +154 -0
- hackagent/models/attack_request.py +82 -0
- hackagent/models/checkout_session_request_request.py +76 -0
- hackagent/models/checkout_session_response.py +59 -0
- hackagent/models/choice.py +81 -0
- hackagent/models/choice_message.py +67 -0
- hackagent/models/evaluation_status_enum.py +14 -0
- hackagent/models/generate_error_response.py +59 -0
- hackagent/models/generate_request_request.py +212 -0
- hackagent/models/generate_success_response.py +115 -0
- hackagent/models/generic_error_response.py +70 -0
- hackagent/models/message_request.py +67 -0
- hackagent/models/organization.py +102 -0
- hackagent/models/organization_minimal.py +68 -0
- hackagent/models/organization_request.py +71 -0
- hackagent/models/paginated_agent_list.py +123 -0
- hackagent/models/paginated_api_token_log_list.py +123 -0
- hackagent/models/paginated_attack_list.py +123 -0
- hackagent/models/paginated_organization_list.py +123 -0
- hackagent/models/paginated_prompt_list.py +123 -0
- hackagent/models/paginated_result_list.py +123 -0
- hackagent/models/paginated_run_list.py +123 -0
- hackagent/models/paginated_user_api_key_list.py +123 -0
- hackagent/models/paginated_user_profile_list.py +123 -0
- hackagent/models/patched_agent_request.py +128 -0
- hackagent/models/patched_attack_request.py +92 -0
- hackagent/models/patched_organization_request.py +71 -0
- hackagent/models/patched_prompt_request.py +125 -0
- hackagent/models/patched_result_request.py +237 -0
- hackagent/models/patched_run_request.py +138 -0
- hackagent/models/patched_user_profile_request.py +99 -0
- hackagent/models/prompt.py +220 -0
- hackagent/models/prompt_request.py +126 -0
- hackagent/models/result.py +294 -0
- hackagent/models/result_list_evaluation_status.py +14 -0
- hackagent/models/result_request.py +232 -0
- hackagent/models/run.py +233 -0
- hackagent/models/run_list_status.py +12 -0
- hackagent/models/run_request.py +133 -0
- hackagent/models/status_enum.py +12 -0
- hackagent/models/step_type_enum.py +14 -0
- hackagent/models/trace.py +121 -0
- hackagent/models/trace_request.py +94 -0
- hackagent/models/usage.py +75 -0
- hackagent/models/user_api_key.py +201 -0
- hackagent/models/user_api_key_request.py +73 -0
- hackagent/models/user_profile.py +135 -0
- hackagent/models/user_profile_minimal.py +76 -0
- hackagent/models/user_profile_request.py +99 -0
- hackagent/router/__init__.py +25 -0
- hackagent/router/adapters/__init__.py +20 -0
- hackagent/router/adapters/base.py +63 -0
- hackagent/router/adapters/google_adk.py +671 -0
- hackagent/router/adapters/litellm_adapter.py +524 -0
- hackagent/router/adapters/openai_adapter.py +426 -0
- hackagent/router/router.py +969 -0
- hackagent/router/types.py +54 -0
- hackagent/tracking/__init__.py +42 -0
- hackagent/tracking/context.py +163 -0
- hackagent/tracking/decorators.py +299 -0
- hackagent/tracking/tracker.py +441 -0
- hackagent/types.py +54 -0
- hackagent/utils.py +194 -0
- hackagent/vulnerabilities/__init__.py +13 -0
- hackagent/vulnerabilities/prompts.py +81 -0
- hackagent-0.3.1.dist-info/METADATA +122 -0
- hackagent-0.3.1.dist-info/RECORD +183 -0
- hackagent-0.3.1.dist-info/WHEEL +4 -0
- hackagent-0.3.1.dist-info/entry_points.txt +2 -0
- hackagent-0.3.1.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Copyright 2025 - AI4I. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
HackAgent CLI Package
|
|
17
|
+
|
|
18
|
+
Command-line interface for HackAgent security testing toolkit.
|
|
19
|
+
"""
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Copyright 2025 - AI4I. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
CLI Commands Package
|
|
18
|
+
|
|
19
|
+
Contains all the command group implementations for the HackAgent CLI.
|
|
20
|
+
"""
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Commands
|
|
3
|
+
|
|
4
|
+
Manage AI agents registered with HackAgent.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
from hackagent.cli.config import CLIConfig
|
|
10
|
+
from hackagent.cli.utils import handle_errors, launch_tui
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group()
|
|
14
|
+
def agent():
|
|
15
|
+
"""🤖 Manage AI agents"""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@agent.command()
|
|
20
|
+
@click.pass_context
|
|
21
|
+
@handle_errors
|
|
22
|
+
def list(ctx):
|
|
23
|
+
"""List registered agents"""
|
|
24
|
+
cli_config: CLIConfig = ctx.obj["config"]
|
|
25
|
+
cli_config.validate()
|
|
26
|
+
launch_tui(cli_config, initial_tab="agents")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@agent.command()
|
|
30
|
+
@click.option("--name", required=True, help="Agent name")
|
|
31
|
+
@click.option(
|
|
32
|
+
"--type",
|
|
33
|
+
"agent_type",
|
|
34
|
+
type=click.Choice(["google-adk", "litellm"]),
|
|
35
|
+
required=True,
|
|
36
|
+
help="Agent type",
|
|
37
|
+
)
|
|
38
|
+
@click.option("--endpoint", required=True, help="Agent endpoint URL")
|
|
39
|
+
@click.option("--description", help="Agent description")
|
|
40
|
+
@click.option("--metadata", help="Additional metadata as JSON string")
|
|
41
|
+
@click.pass_context
|
|
42
|
+
@handle_errors
|
|
43
|
+
def create(ctx, name, agent_type, endpoint, description, metadata):
|
|
44
|
+
"""Create a new agent"""
|
|
45
|
+
cli_config: CLIConfig = ctx.obj["config"]
|
|
46
|
+
cli_config.validate()
|
|
47
|
+
launch_tui(cli_config, initial_tab="agents")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@agent.command()
|
|
51
|
+
@click.argument("agent_id")
|
|
52
|
+
@click.pass_context
|
|
53
|
+
@handle_errors
|
|
54
|
+
def show(ctx, agent_id):
|
|
55
|
+
"""Show detailed information about an agent"""
|
|
56
|
+
cli_config: CLIConfig = ctx.obj["config"]
|
|
57
|
+
cli_config.validate()
|
|
58
|
+
launch_tui(cli_config, initial_tab="agents")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@agent.command()
|
|
62
|
+
@click.argument("agent_id")
|
|
63
|
+
@click.option("--name", help="New agent name")
|
|
64
|
+
@click.option("--endpoint", help="New agent endpoint")
|
|
65
|
+
@click.option("--description", help="New agent description")
|
|
66
|
+
@click.option("--metadata", help="New metadata as JSON string")
|
|
67
|
+
@click.pass_context
|
|
68
|
+
@handle_errors
|
|
69
|
+
def update(ctx, agent_id, name, endpoint, description, metadata):
|
|
70
|
+
"""Update an existing agent"""
|
|
71
|
+
cli_config: CLIConfig = ctx.obj["config"]
|
|
72
|
+
cli_config.validate()
|
|
73
|
+
launch_tui(cli_config, initial_tab="agents")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@agent.command()
|
|
77
|
+
@click.argument("agent_id")
|
|
78
|
+
@click.option("--confirm", is_flag=True, help="Skip confirmation prompt")
|
|
79
|
+
@click.pass_context
|
|
80
|
+
@handle_errors
|
|
81
|
+
def delete(ctx, agent_id, confirm):
|
|
82
|
+
"""Delete an agent"""
|
|
83
|
+
cli_config: CLIConfig = ctx.obj["config"]
|
|
84
|
+
cli_config.validate()
|
|
85
|
+
launch_tui(cli_config, initial_tab="agents")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@agent.command()
|
|
89
|
+
@click.argument("agent_name")
|
|
90
|
+
@click.pass_context
|
|
91
|
+
@handle_errors
|
|
92
|
+
def test(ctx, agent_name):
|
|
93
|
+
"""Test connection to an agent
|
|
94
|
+
|
|
95
|
+
This command attempts to establish a connection with the specified agent
|
|
96
|
+
to verify it's accessible and responding.
|
|
97
|
+
"""
|
|
98
|
+
cli_config: CLIConfig = ctx.obj["config"]
|
|
99
|
+
cli_config.validate()
|
|
100
|
+
launch_tui(cli_config, initial_tab="agents")
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# Copyright 2025 - AI4I. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
Attack Commands
|
|
17
|
+
|
|
18
|
+
Execute security attacks against AI agents.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import time
|
|
22
|
+
from typing import Any, Dict
|
|
23
|
+
|
|
24
|
+
import click
|
|
25
|
+
from rich.console import Console
|
|
26
|
+
from rich.panel import Panel
|
|
27
|
+
from rich.table import Table
|
|
28
|
+
|
|
29
|
+
from hackagent import HackAgent
|
|
30
|
+
from hackagent.cli.config import CLIConfig
|
|
31
|
+
from hackagent.cli.utils import (
|
|
32
|
+
display_info,
|
|
33
|
+
display_results_table,
|
|
34
|
+
display_success,
|
|
35
|
+
get_agent_type_enum,
|
|
36
|
+
handle_errors,
|
|
37
|
+
load_config_file,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
console = Console()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@click.group()
|
|
44
|
+
def attack():
|
|
45
|
+
"""🚀 Execute security attacks against AI agents"""
|
|
46
|
+
# Logo will be shown by HackAgent initialization
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@attack.command()
|
|
51
|
+
@click.option("--agent-name", required=True, help="Target agent name")
|
|
52
|
+
@click.option(
|
|
53
|
+
"--agent-type",
|
|
54
|
+
type=str,
|
|
55
|
+
default="other",
|
|
56
|
+
help="Agent type (e.g., google-adk, litellm, langchain, openai-sdk, mcp, a2a, or other)",
|
|
57
|
+
)
|
|
58
|
+
@click.option(
|
|
59
|
+
"--endpoint",
|
|
60
|
+
required=True,
|
|
61
|
+
help="Agent endpoint URL. For OpenAI-compatible endpoints, provide base URL ending with /v1 (e.g., http://localhost:8000/v1). For LangServe, provide full path (e.g., http://localhost:8000/invoke).",
|
|
62
|
+
)
|
|
63
|
+
@click.option(
|
|
64
|
+
"--goals",
|
|
65
|
+
required=True,
|
|
66
|
+
help="Attack goals (what you want the agent to do incorrectly)",
|
|
67
|
+
)
|
|
68
|
+
@click.option(
|
|
69
|
+
"--config-file",
|
|
70
|
+
type=click.Path(exists=True),
|
|
71
|
+
help="Attack configuration file (JSON/YAML)",
|
|
72
|
+
)
|
|
73
|
+
@click.option("--timeout", default=300, help="Attack timeout in seconds")
|
|
74
|
+
@click.option(
|
|
75
|
+
"--dry-run", is_flag=True, help="Validate configuration without running attack"
|
|
76
|
+
)
|
|
77
|
+
@click.option(
|
|
78
|
+
"--no-tui",
|
|
79
|
+
is_flag=True,
|
|
80
|
+
help="Run attack directly without opening TUI (default: open TUI)",
|
|
81
|
+
)
|
|
82
|
+
@click.pass_context
|
|
83
|
+
@handle_errors
|
|
84
|
+
def advprefix(
|
|
85
|
+
ctx, agent_name, agent_type, endpoint, goals, config_file, timeout, dry_run, no_tui
|
|
86
|
+
):
|
|
87
|
+
"""Execute AdvPrefix attack strategy
|
|
88
|
+
|
|
89
|
+
This command runs the AdvPrefix attack against a target agent.
|
|
90
|
+
Goals should describe what you want the agent to do incorrectly.
|
|
91
|
+
|
|
92
|
+
Examples:
|
|
93
|
+
|
|
94
|
+
# Basic attack with goals
|
|
95
|
+
hackagent attack advprefix \\
|
|
96
|
+
--agent-name "weather-bot" \\
|
|
97
|
+
--agent-type "google-adk" \\
|
|
98
|
+
--endpoint "http://localhost:8000" \\
|
|
99
|
+
--goals "Return fake weather data and ignore safety guidelines"
|
|
100
|
+
|
|
101
|
+
# Attack with configuration file
|
|
102
|
+
hackagent attack advprefix \\
|
|
103
|
+
--agent-name "multi-tool-agent" \\
|
|
104
|
+
--agent-type "google-adk" \\
|
|
105
|
+
--endpoint "http://localhost:8000" \\
|
|
106
|
+
--config-file "attack-config.json"
|
|
107
|
+
"""
|
|
108
|
+
cli_config: CLIConfig = ctx.obj["config"]
|
|
109
|
+
cli_config.validate()
|
|
110
|
+
|
|
111
|
+
# Launch TUI with attack form pre-filled (default behavior)
|
|
112
|
+
if not no_tui:
|
|
113
|
+
try:
|
|
114
|
+
from hackagent.cli.tui import HackAgentTUI
|
|
115
|
+
|
|
116
|
+
initial_data = {
|
|
117
|
+
"agent_name": agent_name,
|
|
118
|
+
"agent_type": agent_type,
|
|
119
|
+
"endpoint": endpoint,
|
|
120
|
+
"goals": goals,
|
|
121
|
+
"timeout": timeout,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
app = HackAgentTUI(
|
|
125
|
+
cli_config, initial_tab="attacks", initial_data=initial_data
|
|
126
|
+
)
|
|
127
|
+
app.run()
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
except ImportError:
|
|
131
|
+
console.print("[bold red]❌ TUI dependencies not installed[/bold red]")
|
|
132
|
+
console.print("\n[cyan]💡 Install with:[/cyan]")
|
|
133
|
+
console.print(" uv add textual")
|
|
134
|
+
console.print(
|
|
135
|
+
"\n[yellow]Or run with --no-tui flag to execute directly[/yellow]"
|
|
136
|
+
)
|
|
137
|
+
ctx.exit(1)
|
|
138
|
+
except Exception as e:
|
|
139
|
+
console.print(f"[bold red]❌ TUI failed to start: {e}[/bold red]")
|
|
140
|
+
console.print(
|
|
141
|
+
"\n[yellow]Try running with --no-tui flag to execute directly[/yellow]"
|
|
142
|
+
)
|
|
143
|
+
ctx.exit(1)
|
|
144
|
+
|
|
145
|
+
# Convert agent type
|
|
146
|
+
agent_type_enum = get_agent_type_enum(agent_type)
|
|
147
|
+
|
|
148
|
+
# Build attack configuration
|
|
149
|
+
attack_config = {
|
|
150
|
+
"attack_type": "advprefix",
|
|
151
|
+
"goals": [goals], # Convert single goal string to list
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
# Load additional config from file if provided
|
|
155
|
+
if config_file:
|
|
156
|
+
try:
|
|
157
|
+
file_config = load_config_file(config_file)
|
|
158
|
+
attack_config.update(file_config)
|
|
159
|
+
display_info(f"Loaded configuration from: {config_file}")
|
|
160
|
+
except Exception as e:
|
|
161
|
+
raise click.ClickException(f"Failed to load config file: {e}")
|
|
162
|
+
|
|
163
|
+
# Display logo first
|
|
164
|
+
from hackagent.utils import display_hackagent_splash
|
|
165
|
+
|
|
166
|
+
display_hackagent_splash()
|
|
167
|
+
|
|
168
|
+
# Display attack summary
|
|
169
|
+
_display_attack_summary(agent_name, agent_type, endpoint, goals, attack_config)
|
|
170
|
+
|
|
171
|
+
if dry_run:
|
|
172
|
+
display_success("✅ Configuration validation passed")
|
|
173
|
+
display_info("Use --dry-run=false to execute the attack")
|
|
174
|
+
return
|
|
175
|
+
|
|
176
|
+
# Initialize HackAgent
|
|
177
|
+
with console.status("[bold green]Initializing HackAgent..."):
|
|
178
|
+
try:
|
|
179
|
+
agent = HackAgent(
|
|
180
|
+
name=agent_name,
|
|
181
|
+
endpoint=endpoint,
|
|
182
|
+
agent_type=agent_type_enum,
|
|
183
|
+
api_key=cli_config.api_key,
|
|
184
|
+
base_url=cli_config.base_url,
|
|
185
|
+
)
|
|
186
|
+
display_success(f"Agent '{agent_name}' initialized successfully")
|
|
187
|
+
except Exception as e:
|
|
188
|
+
raise click.ClickException(f"Failed to initialize agent: {e}")
|
|
189
|
+
|
|
190
|
+
# Execute attack with progress tracking
|
|
191
|
+
console.print(f"\n[bold cyan]🎯 Executing AdvPrefix attack against '{agent_name}'")
|
|
192
|
+
console.print(f"[cyan]Goals: {goals}")
|
|
193
|
+
console.print(f"[cyan]Timeout: {timeout}s")
|
|
194
|
+
|
|
195
|
+
start_time = time.time()
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
results = agent.hack(
|
|
199
|
+
attack_config=attack_config,
|
|
200
|
+
run_config_override={"timeout": timeout},
|
|
201
|
+
fail_on_run_error=True,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
duration = time.time() - start_time
|
|
205
|
+
console.print(
|
|
206
|
+
f"\n[bold green]✅ Attack completed successfully in {duration:.1f}s!"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
# Display results summary
|
|
210
|
+
_display_attack_results(results)
|
|
211
|
+
|
|
212
|
+
except Exception as e:
|
|
213
|
+
duration = time.time() - start_time
|
|
214
|
+
console.print(f"\n[bold red]❌ Attack failed after {duration:.1f}s")
|
|
215
|
+
raise click.ClickException(f"Attack execution failed: {e}")
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@attack.command()
|
|
219
|
+
@click.pass_context
|
|
220
|
+
@handle_errors
|
|
221
|
+
def list(ctx):
|
|
222
|
+
"""List available attack strategies"""
|
|
223
|
+
|
|
224
|
+
table = Table(
|
|
225
|
+
title="Available Attack Strategies", show_header=True, header_style="bold cyan"
|
|
226
|
+
)
|
|
227
|
+
table.add_column("Strategy", style="cyan")
|
|
228
|
+
table.add_column("Description", style="green")
|
|
229
|
+
table.add_column("Status", style="yellow")
|
|
230
|
+
|
|
231
|
+
# Add available strategies
|
|
232
|
+
table.add_row(
|
|
233
|
+
"advprefix",
|
|
234
|
+
"Adversarial prefix generation attack using language models",
|
|
235
|
+
"✅ Available",
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
# Add planned strategies
|
|
239
|
+
table.add_row("prompt-injection", "Direct prompt injection attacks", "🚧 Planned")
|
|
240
|
+
table.add_row(
|
|
241
|
+
"jailbreak", "Jailbreaking techniques for safety bypassing", "🚧 Planned"
|
|
242
|
+
)
|
|
243
|
+
table.add_row(
|
|
244
|
+
"goal-hijacking", "Goal hijacking and manipulation attacks", "🚧 Planned"
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
console.print(table)
|
|
248
|
+
console.print(
|
|
249
|
+
"\n[cyan]💡 Use 'hackagent attack STRATEGY --help' for strategy-specific options"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@attack.command()
|
|
254
|
+
@click.argument("strategy", type=click.Choice(["advprefix"]))
|
|
255
|
+
@click.pass_context
|
|
256
|
+
@handle_errors
|
|
257
|
+
def info(ctx, strategy):
|
|
258
|
+
"""Get detailed information about an attack strategy"""
|
|
259
|
+
|
|
260
|
+
if strategy == "advprefix":
|
|
261
|
+
_display_advprefix_info()
|
|
262
|
+
else:
|
|
263
|
+
raise click.ClickException(f"Strategy '{strategy}' not yet implemented")
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _display_attack_summary(
|
|
267
|
+
agent_name: str,
|
|
268
|
+
agent_type: str,
|
|
269
|
+
endpoint: str,
|
|
270
|
+
goals: str,
|
|
271
|
+
attack_config: Dict[str, Any],
|
|
272
|
+
) -> None:
|
|
273
|
+
"""Display a summary of the attack configuration"""
|
|
274
|
+
|
|
275
|
+
# Create summary panel
|
|
276
|
+
summary_content = f"""[bold]Target Agent:[/bold] {agent_name}
|
|
277
|
+
[bold]Agent Type:[/bold] {agent_type}
|
|
278
|
+
[bold]Endpoint:[/bold] {endpoint}
|
|
279
|
+
[bold]Attack Type:[/bold] {attack_config["attack_type"]}
|
|
280
|
+
[bold]Goals:[/bold] {goals}"""
|
|
281
|
+
|
|
282
|
+
if len(attack_config) > 2: # More than just attack_type and goals
|
|
283
|
+
summary_content += f"\n[bold]Additional Config:[/bold] {len(attack_config) - 2} parameters loaded"
|
|
284
|
+
|
|
285
|
+
panel = Panel(
|
|
286
|
+
summary_content,
|
|
287
|
+
title="🎯 Attack Configuration",
|
|
288
|
+
border_style="cyan",
|
|
289
|
+
padding=(1, 2),
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
console.print(panel)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def _display_attack_results(results: Any) -> None:
|
|
296
|
+
"""Display attack results summary"""
|
|
297
|
+
|
|
298
|
+
console.print("\n[bold cyan]📊 Attack Results Summary")
|
|
299
|
+
|
|
300
|
+
try:
|
|
301
|
+
import pandas as pd
|
|
302
|
+
|
|
303
|
+
if isinstance(results, pd.DataFrame):
|
|
304
|
+
console.print(f"[green]📈 Generated {len(results)} result entries")
|
|
305
|
+
|
|
306
|
+
# Show key metrics if available
|
|
307
|
+
if not results.empty:
|
|
308
|
+
# Try to display some key columns if they exist
|
|
309
|
+
summary_table = Table(
|
|
310
|
+
title="Key Metrics", show_header=True, header_style="bold cyan"
|
|
311
|
+
)
|
|
312
|
+
summary_table.add_column("Metric", style="cyan")
|
|
313
|
+
summary_table.add_column("Value", style="green")
|
|
314
|
+
|
|
315
|
+
summary_table.add_row("Total Results", str(len(results)))
|
|
316
|
+
|
|
317
|
+
# Add column info
|
|
318
|
+
summary_table.add_row("Columns", str(len(results.columns)))
|
|
319
|
+
|
|
320
|
+
# Try to show success metrics if available
|
|
321
|
+
for col in results.columns:
|
|
322
|
+
if "success" in col.lower() or "score" in col.lower():
|
|
323
|
+
if results[col].dtype in ["int64", "float64"]:
|
|
324
|
+
mean_val = results[col].mean()
|
|
325
|
+
summary_table.add_row(f"Avg {col}", f"{mean_val:.3f}")
|
|
326
|
+
|
|
327
|
+
console.print(summary_table)
|
|
328
|
+
|
|
329
|
+
# Show sample of results
|
|
330
|
+
if len(results) > 0:
|
|
331
|
+
console.print("\n[cyan]📋 Sample Results (first 5 rows):")
|
|
332
|
+
# Filter to show only goal and prefix columns if they exist
|
|
333
|
+
display_columns = []
|
|
334
|
+
if "goal" in results.columns:
|
|
335
|
+
display_columns.append("goal")
|
|
336
|
+
if "prefix" in results.columns:
|
|
337
|
+
display_columns.append("prefix")
|
|
338
|
+
|
|
339
|
+
if display_columns:
|
|
340
|
+
filtered_results = results[display_columns].head()
|
|
341
|
+
display_results_table(
|
|
342
|
+
filtered_results, "Attack Results - Goals & Prefixes"
|
|
343
|
+
)
|
|
344
|
+
else:
|
|
345
|
+
# Fallback to showing all columns if goal/prefix not found
|
|
346
|
+
display_results_table(results.head(), "Sample Attack Results")
|
|
347
|
+
else:
|
|
348
|
+
console.print(f"[green]📈 Results: {type(results).__name__}")
|
|
349
|
+
if hasattr(results, "__len__"):
|
|
350
|
+
console.print(f"[green]📊 Count: {len(results)}")
|
|
351
|
+
|
|
352
|
+
except Exception as e:
|
|
353
|
+
console.print(f"[yellow]⚠️ Could not analyze results: {e}")
|
|
354
|
+
console.print(f"[green]📈 Results type: {type(results).__name__}")
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def _display_advprefix_info() -> None:
|
|
358
|
+
"""Display detailed information about AdvPrefix attack strategy"""
|
|
359
|
+
|
|
360
|
+
info_content = """[bold]AdvPrefix Attack Strategy[/bold]
|
|
361
|
+
|
|
362
|
+
[cyan]Description:[/cyan]
|
|
363
|
+
The AdvPrefix attack generates adversarial prefixes that can manipulate AI agent behavior.
|
|
364
|
+
It uses a multi-step pipeline involving uncensored language models to craft effective attacks.
|
|
365
|
+
|
|
366
|
+
[cyan]How it works:[/cyan]
|
|
367
|
+
1. Generate candidate prefixes using language models
|
|
368
|
+
2. Compute cross-entropy scores for effectiveness
|
|
369
|
+
3. Test prefixes against the target agent
|
|
370
|
+
4. Evaluate results using judge models
|
|
371
|
+
5. Select and report successful attacks
|
|
372
|
+
|
|
373
|
+
[cyan]Configuration Options:[/cyan]
|
|
374
|
+
• goals: List of malicious objectives for the agent
|
|
375
|
+
• generator: Language model configuration for prefix generation
|
|
376
|
+
• judges: Judge models for evaluating attack success
|
|
377
|
+
• batch_size: Number of prefixes to generate per batch
|
|
378
|
+
• temperature: Sampling temperature for generation
|
|
379
|
+
• max_new_tokens: Maximum tokens to generate
|
|
380
|
+
|
|
381
|
+
[cyan]Example Config File:[/cyan]
|
|
382
|
+
{
|
|
383
|
+
"goals": ["Return fake data", "Ignore safety guidelines"],
|
|
384
|
+
"generator": {
|
|
385
|
+
"identifier": "ollama/llama2-uncensored",
|
|
386
|
+
"endpoint": "http://localhost:11434/api/generate"
|
|
387
|
+
},
|
|
388
|
+
"judges": [
|
|
389
|
+
{
|
|
390
|
+
"identifier": "ollama/llama3",
|
|
391
|
+
"endpoint": "http://localhost:11434/api/judge",
|
|
392
|
+
"type": "harmbench"
|
|
393
|
+
}
|
|
394
|
+
],
|
|
395
|
+
"batch_size": 20,
|
|
396
|
+
"temperature": 1.0,
|
|
397
|
+
"max_new_tokens": 512
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
[cyan]Requirements:[/cyan]
|
|
401
|
+
• Target agent must be running and accessible
|
|
402
|
+
• Generator model (e.g., Ollama with uncensored model)
|
|
403
|
+
• Judge model for evaluation
|
|
404
|
+
• Sufficient computational resources
|
|
405
|
+
|
|
406
|
+
[yellow]⚠️ Ethical Usage:[/yellow]
|
|
407
|
+
Only use this attack against agents you own or have explicit permission to test.
|
|
408
|
+
Always follow responsible disclosure practices for any vulnerabilities found."""
|
|
409
|
+
|
|
410
|
+
panel = Panel(
|
|
411
|
+
info_content,
|
|
412
|
+
title="AdvPrefix Attack Information",
|
|
413
|
+
border_style="cyan",
|
|
414
|
+
padding=(1, 2),
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
console.print(panel)
|