Skip to content

feat: enforce engagement authorization framing#15

Merged
SALhik merged 12 commits into
mainfrom
system-prompt-authorization-framing
Jul 18, 2026
Merged

feat: enforce engagement authorization framing#15
SALhik merged 12 commits into
mainfrom
system-prompt-authorization-framing

Conversation

@SALhik

@SALhik SALhik commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • add canonical EngagementScope target normalization and validation
  • enforce configured scope before LLM generation and every executor path
  • add session-independent ScopeGuard with JSONL auditing
  • centralize authorization-aware system prompts with neutral defaults
  • propagate scope through factories, agents, exploitation, OPSEC, and API sessions
  • isolate router cache entries by system-prompt identity
  • document configuration, lifecycle, API semantics, and audit-log operations

Validation

  • Full pytest suite: 5,713 passed, 11 skipped, 8 deselected
  • Ruff: passed
  • MyPy: passed across 626 source files
  • Black: passed for all changed Python files
  • Documentation pre-commit hooks: passed

Summary by CodeRabbit

  • New Features
    • Added optional engagement authorization scope configuration (authorized hosts/IP ranges, engagement metadata, rules of engagement).
    • Enforced scope-aware gating across planning, command generation, exploitation, and tool execution with fail-closed behavior.
    • Added authorization-aware AI prompt framing and an append-only scope decision audit log; OPSEC sessions now honor the provided authorized scope.
  • Documentation
    • Updated configuration, API, integration, security, getting-started, and changelog guidance for the authorization scope and audit logging.
  • Bug Fixes
    • Improved LLM response cache isolation so results don’t collide across different system prompts and generation settings.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 842f3008-016c-42f4-873e-caa39d321234

📥 Commits

Reviewing files that changed from the base of the PR and between 0f1cba4 and ff1e78b.

📒 Files selected for processing (10)
  • .gitignore
  • pentestgpt/agents/opsec_agent.py
  • pentestgpt/agents/results_verifier.py
  • pentestgpt/core/engagement.py
  • pentestgpt/orchestrator.py
  • tests/agents/test_opsec_agent.py
  • tests/agents/test_results_verifier.py
  • tests/core/test_engagement.py
  • tests/integration/test_scope_guard_lifecycle.py
  • tests/prompts/test_route_task_coverage.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • tests/agents/test_results_verifier.py
  • tests/integration/test_scope_guard_lifecycle.py
  • .gitignore
  • pentestgpt/orchestrator.py
  • tests/agents/test_opsec_agent.py
  • pentestgpt/agents/results_verifier.py
  • pentestgpt/core/engagement.py
  • pentestgpt/agents/opsec_agent.py

📝 Walkthrough

Walkthrough

This PR adds canonical engagement-scope validation, append-only audit logging, fail-closed orchestration and agent checks, authorization-aware prompts, scope propagation through OPSEC APIs and factories, router cache isolation, configuration updates, and comprehensive tests and documentation.

Changes

Engagement authorization lifecycle

Layer / File(s) Summary
Scope model and audit enforcement
pentestgpt/core/engagement.py, pentestgpt/core/scope_guard.py, pentestgpt/core/exceptions.py, pentestgpt/config/settings.py, tests/core/*
Adds normalized engagement target handling, CIDR validation, ScopeDecision, immutable EngagementScope with configurable state detection, ScopeGuard with per-phase audit checkpoints, OutOfScopeError exception, JSONL audit persistence, and target extraction from commands and nested contexts. Tests cover normalization, validation, CIDR containment, unconfigured/neutral scope behavior, and audit entry recording.
Scope wiring and orchestration gates
pentestgpt/api/stealth_api.py, pentestgpt/agents/opsec_agent.py, pentestgpt/orchestrator.py, pentestgpt/utils/dependency_injection.py, pentestgpt/utils/orchestrator_factory.py, tests/api/*, tests/integration/*, tests/utils/*
Propagates scope and guards through OPSEC session creation, AgentFactory wiring, and PentestOrchestrator lifecycle phases (session_start, command_generation, command_execution) with per-phase guard checks before LLM or executor operations. Factories construct default ScopeGuard with JSONL audit sinks unless explicitly provided. OPSEC sessions optionally bind engagement scopes and create per-session audit paths.
Scope-aware agent execution
pentestgpt/agents/agent_abstract.py, pentestgpt/agents/advanced_exploitation_agent.py, pentestgpt/agents/strategy_agent.py, pentestgpt/agents/command_generator.py, pentestgpt/agents/results_verifier.py, pentestgpt/agents/opsec_agent.py, pentestgpt/agents/stealth_operations_agent.py, pentestgpt/agents/exploit_developer.py, tests/agents/*
Updates agent base and protocol interfaces to require set_engagement_scope(scope, guard), replaces hardcoded system prompts with _build_system_prompt(role, phase, context) calls, extracts effective targets from context or command strings, enforces guard.check(phase, targets) before model/executor operations, and explicitly propagates OutOfScopeError instead of handling as generic exceptions. Supports both direct guard injection and fallback to EngagementScope.validate_targets when no guard is present.
Authorization prompts and cache isolation
pentestgpt/prompts/authorization.py, pentestgpt/prompts/mitre_prompts.py, pentestgpt/prompts/prompt_class.py, pentestgpt/prompts/prompt_class_v1.py, pentestgpt/prompts/prompt_class_v2.py, pentestgpt/llms/router.py, pentestgpt/{monitoring,effectiveness,detection_resistance}/*, pentestgpt/report_generator.py, pentestgpt/utils/strategy_adaptation_controller.py, tests/prompts/*, tests/llms/*, tests/regression/*
Centralizes role-based authorization-aware system prompts via build_authorization_preamble() (returns neutral/violation/authorized framing) and build_system_prompt(role, scope, targets) (prepends preamble to role prompt). Defines 18 role constants covering MITRE, OPSEC, evasion, security, and analysis archetypes. Updates ~20 modules' LLM routing calls to use role-based builders instead of hardcoded prompts. Removes unconditional authorization claims from v1/v2/base prompt templates. Changes router cache identity from (TaskType, message-prefix) to (TaskType, request-hash, system-prompt-hash) and gates caching on conversation_id is None to isolate cache by both request content and system-prompt identity.
Configuration and documentation
.env.example, docs/configuration/ENVIRONMENT_VARIABLES.md, docs/getting-started/README.md, docs/api/README.md, docs/guides/INTEGRATION.md, docs/operations/SECURITY.md, docs/CHANGELOG.md, .gitignore
Documents engagement scope environment variables (ENGAGEMENT_CLIENT, ENGAGEMENT_ID, AUTHORIZED_HOSTS, AUTHORIZED_IP_RANGES, RULES_OF_ENGAGEMENT) with JSON list formatting. Updates API documentation for POST /stealth/sessions canonical scope mapping, hostname/IP/CIDR normalization, error responses. Adds integration-lifecycle subsection and architecture diagram branch. Documents scope_audit.jsonl schema, retention handling, and operational compliance. Updates changelog with authorization features, orchestration gating, OPSEC scope attachment, router cache isolation. Adds ignore entries for output/, .qodo/, node_modules/, and bandit-report.json.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • SALhik/AutoPentester#2: Both modify LLM routing in results_verifier.py for analyze_results—main PR adds scope-aware prompts and error propagation; retrieved PR adds deterministic structured parsing.
  • SALhik/AutoPentester#8: Both modify PentestOrchestrator initialization and lifecycle wiring—main PR adds scope/guard injection and phase checkpoints; retrieved PR refactors orchestrator construction.
  • SALhik/AutoPentester#9: Both modify OrchestratorFactory and orchestrator setup paths—main PR adds engagement-scope configuration and agent wiring; retrieved PR refactors factory construction.
  • SALhik/AutoPentester#13: Both modify OPSEC scope validation in opsec_agent.py—main PR integrates canonical EngagementScope.validate_targets; retrieved PR updates compliance audit behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and captures the main theme of the PR: engagement authorization framing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch system-prompt-authorization-framing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@SALhik

SALhik commented Jul 16, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai help

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai rate limit to show your current review rate limit status.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
  • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
  • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai emit path instructions to emit generated path-specific review instructions for this repository.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit configuration file (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

SALhik added 3 commits July 17, 2026 00:20
The static prompt templates asserted the engagement was authorized
("certified experiment", "obtained valid certificates and approval",
"valid permission to perform") regardless of configured scope. Only the
scope-aware preamble in pentestgpt.prompts.authorization should assert
authorization, so neutralize these claims across the base, v1, and v2
templates. This keeps the neutralization consistent if any of these
otherwise-dead templates is ever revived.

Add a regression guard asserting no template field makes an
unconditional authorization claim.
OPSECAgent.create_session hardcoded the "sessions" directory for its
scope audit sink, ignoring the orchestrator's configured session_dir on
the standalone path. Add a session_dir parameter (default "sessions")
and propagate the orchestrator's value so scope audit logs land
alongside the rest of the session state.
CodeRabbit exceeds its per-PR file limit on this branch. Temporarily skip
the docs/ folder so it can review the code changes. Revert once the review
is complete.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (5)
pentestgpt/prompts/prompt_class.py (2)

43-44: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove redundant sentence in the prompt.

The first two sentences are repetitive ("You're required to work as a cybersecurity penetration tester assistant." vs "You're an assistant for a cybersecurity penetration tester."). Removing the first sentence will make the prompt more concise and save a few tokens.

♻️ Proposed refactor
-    input_parsing_init: str = """You're required to work as a cybersecurity penetration tester assistant.
-You're an assistant for a cybersecurity penetration tester. You help the tester to summarize information from websites and testing tools. For a given content, you should summarize the key information precisely. In particular,
+    input_parsing_init: str = """You're an assistant for a cybersecurity penetration tester. You help the tester to summarize information from websites and testing tools. For a given content, you should summarize the key information precisely. In particular,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pentestgpt/prompts/prompt_class.py` around lines 43 - 44, Remove the
redundant opening sentence from the input_parsing_init prompt, keeping “You're
an assistant for a cybersecurity penetration tester.” as the sole role statement
and preserving the remaining prompt content unchanged.

54-71: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Include missing column descriptions in the prompt.

The table lists 15 columns (including Port and Name), but the description section only provides descriptions for 13 of them (missing Port and Name). While LLMs can often infer these, providing the complete mapping aligns with the strict 15-element requirement and reduces hallucination risk.

♻️ Proposed refactor
     Host - The IP or the name of the Host
     Service - The service name that is tested
+    Port - The port number where the service is running
+    Name - The name of the vulnerability
     Description -  a short description about the vulnerability
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pentestgpt/prompts/prompt_class.py` around lines 54 - 71, The
report_generator_init prompt lists Port and Name as columns but does not
describe them. Add explicit descriptions for both headings in the header-mapping
section, defining Port as the tested network port and Name as the vulnerability
or finding name, while preserving the required 15-column order and output
format.
tests/prompts/test_prompt_templates.py (1)

267-270: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Defensively check if the field value is a string.

Calling .lower() directly on the field value will raise an AttributeError if a non-string field is ever added to these dataclasses. It is safer to check the type first, mirroring the logic in the adjacent test_all_dataclass_fields_non_empty test.

🛡️ Proposed fix
         for f in dataclasses.fields(instance):
-            value = getattr(instance, f.name).lower()
-            for phrase in UNCONDITIONAL_AUTHORIZATION_PHRASES:
-                assert phrase not in value, f"{cls.__name__}.{f.name} asserts authorization: {phrase!r}"
+            value = getattr(instance, f.name)
+            if isinstance(value, str):
+                value_lower = value.lower()
+                for phrase in UNCONDITIONAL_AUTHORIZATION_PHRASES:
+                    assert phrase not in value_lower, f"{cls.__name__}.{f.name} asserts authorization: {phrase!r}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/prompts/test_prompt_templates.py` around lines 267 - 270, Update the
field-value handling in the dataclass authorization test to verify the value is
a string before calling lower(), mirroring the defensive type check used by the
adjacent test_all_dataclass_fields_non_empty test; only scan lowercase text
values for prohibited phrases.
tests/api/test_opsec_session_scope.py (1)

11-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Type the monkeypatch fixture.

Use monkeypatch: pytest.MonkeyPatch so this new test remains fully typed.

As per coding guidelines, “All new code must be fully typed in strict MyPy mode.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/api/test_opsec_session_scope.py` at line 11, Add the pytest.MonkeyPatch
type annotation to the monkeypatch parameter of
test_authorized_scope_reaches_opsec_session, preserving the test’s existing
behavior and satisfying strict MyPy typing.

Source: Coding guidelines

pentestgpt/utils/dependency_injection.py (1)

419-423: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a narrow protocol for set_engagement_scope. In pentestgpt/utils/dependency_injection.py:419-423, hasattr does not narrow T, so strict MyPy still flags the method call. Use a small Protocol or a targeted cast instead of Any.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pentestgpt/utils/dependency_injection.py` around lines 419 - 423, Update
wire_engagement_scope to type-narrow agents exposing set_engagement_scope by
introducing a narrow Protocol for that method and using an isinstance-compatible
check or targeted cast before invocation. Keep the existing _scope_guard
condition, arguments, and agent return behavior unchanged, and do not use Any.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pentestgpt/agents/exploit_developer.py`:
- Around line 340-347: Update the outer exploitation workflow handlers around
_generate_exploit_candidate and develop_and_test_exploits to explicitly catch
OutOfScopeError and re-raise it before any generic exception handling. Add the
same propagation clauses at the additional affected layers so scope denial
reaches the public API instead of being converted into an empty result.

In `@pentestgpt/agents/opsec_agent.py`:
- Around line 596-600: Preserve authorization failures in both OPSEC LLM entry
points: in pentestgpt/agents/opsec_agent.py at lines 596-600, update the
target-analysis exception handler to re-raise OutOfScopeError before the generic
fallback handler; apply the same change at lines 830-834 for the recommendations
flow, while retaining fallback handling for other exceptions.
- Around line 534-540: Update the _scope_guard initialization flow to create a
new JsonlAuditSink using the current session_dir and session_id for every OPSEC
session, rather than reusing self._scope_guard.audit_sink when the scope
changes. Ensure the replacement ScopeGuard retains the current _engagement_scope
while writing audit events to that session’s scope_audit.jsonl destination.

In `@pentestgpt/api/stealth_api.py`:
- Around line 316-317: Update the scope handling around
EngagementScope.from_authorized_scope and opsec_agent.create_session so
ValueError from malformed authorization scopes is caught and returned as a
sanitized HTTP 422 client error without exposing exception details. Keep
unexpected exceptions on the existing HTTP 500 path.

In `@pentestgpt/core/engagement.py`:
- Around line 128-138: Update Engagement.__post_init__ to reject any invalid
authorized host or IP-range value instead of silently filtering it out; preserve
normalized values only after every configured value validates. In the runtime
authorization logic using normalize_target, retain invalid targets and classify
each one as offending rather than excluding it from evaluation, so mixed
valid/invalid input cannot pass based only on valid targets.
- Around line 50-52: Update normalize_target() around the urlsplit() call to
catch ValueError raised for malformed bracketed URLs and return an empty string.
Preserve the existing hostname extraction for valid URLs and the current
normalization behavior for non-URL candidates.

In `@pentestgpt/orchestrator.py`:
- Line 604: Update the command-dispatch flow around the scope_guard.check call
to inspect every command in verified_commands before selecting an executor. Use
the canonical command/parser layer to extract each command’s effective targets,
validate them against the active scope, and reject out-of-scope commands while
preserving the existing target_info and discovered-host checks.

In `@pentestgpt/utils/orchestrator_factory.py`:
- Around line 680-688: Ensure one authoritative engagement scope is used for
both prompts and enforcement: in pentestgpt/utils/orchestrator_factory.py lines
680-688, reject a supplied ScopeGuard whose scope differs from engagement_scope
or derive the effective scope from that guard before calling
AgentFactory.set_engagement_scope; apply the same invariant in
pentestgpt/orchestrator.py lines 108-117 for direct constructor callers.

In `@tests/agents/test_opsec_agent.py`:
- Around line 302-313: Extend
test_create_session_audit_uses_configured_session_dir to create a second session
and assert its audit sink path is under the second session ID, while retaining
the first path assertion. Update OPSECAgent.create_session and its
session-scoped audit sink setup so each invocation recreates or rotates the sink
for the new session instead of reusing the existing guard’s sink.

In `@tests/prompts/test_prompt_templates.py`:
- Line 244: Update the global UNCONDITIONAL_AUTHORIZATION_PHRASES declaration
with an explicit strict type annotation for its list elements, using the
appropriate string collection type and preserving the existing values.

---

Nitpick comments:
In `@pentestgpt/prompts/prompt_class.py`:
- Around line 43-44: Remove the redundant opening sentence from the
input_parsing_init prompt, keeping “You're an assistant for a cybersecurity
penetration tester.” as the sole role statement and preserving the remaining
prompt content unchanged.
- Around line 54-71: The report_generator_init prompt lists Port and Name as
columns but does not describe them. Add explicit descriptions for both headings
in the header-mapping section, defining Port as the tested network port and Name
as the vulnerability or finding name, while preserving the required 15-column
order and output format.

In `@pentestgpt/utils/dependency_injection.py`:
- Around line 419-423: Update wire_engagement_scope to type-narrow agents
exposing set_engagement_scope by introducing a narrow Protocol for that method
and using an isinstance-compatible check or targeted cast before invocation.
Keep the existing _scope_guard condition, arguments, and agent return behavior
unchanged, and do not use Any.

In `@tests/api/test_opsec_session_scope.py`:
- Line 11: Add the pytest.MonkeyPatch type annotation to the monkeypatch
parameter of test_authorized_scope_reaches_opsec_session, preserving the test’s
existing behavior and satisfying strict MyPy typing.

In `@tests/prompts/test_prompt_templates.py`:
- Around line 267-270: Update the field-value handling in the dataclass
authorization test to verify the value is a string before calling lower(),
mirroring the defensive type check used by the adjacent
test_all_dataclass_fields_non_empty test; only scan lowercase text values for
prohibited phrases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7ede42db-7328-4598-bfad-909616696f7f

📥 Commits

Reviewing files that changed from the base of the PR and between d203db5 and 6f5ca19.

📒 Files selected for processing (55)
  • .coderabbit.yaml
  • .env.example
  • docs/CHANGELOG.md
  • docs/api/README.md
  • docs/configuration/ENVIRONMENT_VARIABLES.md
  • docs/getting-started/README.md
  • docs/guides/INTEGRATION.md
  • docs/operations/SECURITY.md
  • pentestgpt/agents/advanced_exploitation_agent.py
  • pentestgpt/agents/agent_abstract.py
  • pentestgpt/agents/command_generator.py
  • pentestgpt/agents/exploit_developer.py
  • pentestgpt/agents/opsec_agent.py
  • pentestgpt/agents/repetition_detector.py
  • pentestgpt/agents/results_verifier.py
  • pentestgpt/agents/stealth_operations_agent.py
  • pentestgpt/agents/strategy_agent.py
  • pentestgpt/api/stealth_api.py
  • pentestgpt/config/settings.py
  • pentestgpt/core/engagement.py
  • pentestgpt/core/exceptions.py
  • pentestgpt/core/scope_guard.py
  • pentestgpt/detection_resistance/evasion_engine.py
  • pentestgpt/effectiveness/success_rate_analytics.py
  • pentestgpt/effectiveness/validation_confirmation_system.py
  • pentestgpt/experimental/_mitre_prototype.py
  • pentestgpt/llms/router.py
  • pentestgpt/monitoring/alert_correlation.py
  • pentestgpt/monitoring/detection_intelligence.py
  • pentestgpt/monitoring/detection_monitor.py
  • pentestgpt/monitoring/security_event_analyzer.py
  • pentestgpt/orchestrator.py
  • pentestgpt/prompts/authorization.py
  • pentestgpt/prompts/mitre_prompts.py
  • pentestgpt/prompts/prompt_class.py
  • pentestgpt/prompts/prompt_class_v1.py
  • pentestgpt/prompts/prompt_class_v2.py
  • pentestgpt/report_generator.py
  • pentestgpt/utils/dependency_injection.py
  • pentestgpt/utils/orchestrator_factory.py
  • pentestgpt/utils/strategy_adaptation_controller.py
  • tests/agents/test_exploit_scope.py
  • tests/agents/test_opsec_agent.py
  • tests/api/test_opsec_session_scope.py
  • tests/core/test_engagement.py
  • tests/core/test_scope_guard.py
  • tests/integration/test_scope_guard_lifecycle.py
  • tests/llms/test_router_cache_isolation.py
  • tests/prompts/test_authorization_preamble.py
  • tests/prompts/test_prompt_templates.py
  • tests/prompts/test_route_task_coverage.py
  • tests/regression/test_critical_fixes.py
  • tests/regression/test_fixes_quick.py
  • tests/stealth/test_stealth_components.py
  • tests/utils/test_orchestrator_factory.py

Comment thread pentestgpt/agents/exploit_developer.py
Comment thread pentestgpt/agents/opsec_agent.py Outdated
Comment thread pentestgpt/agents/opsec_agent.py
Comment thread pentestgpt/api/stealth_api.py
Comment thread pentestgpt/core/engagement.py Outdated
Comment thread pentestgpt/core/engagement.py Outdated
Comment thread pentestgpt/orchestrator.py Outdated
Comment thread pentestgpt/utils/orchestrator_factory.py
Comment on lines +302 to +313
def test_create_session_audit_uses_configured_session_dir(self, tmp_path: Any) -> None:
agent = OPSECAgent(
model_router=make_mock_router(route_task_return=("Mocked response", "openai", 0.01)),
config=StealthConfig(),
session_dir=str(tmp_path),
)
session_id = agent.create_session()
assert agent._scope_guard is not None
sink = agent._scope_guard.audit_sink
assert isinstance(sink, JsonlAuditSink)
assert sink.path == Path(tmp_path) / session_id / "scope_audit.jsonl"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Verify audit-sink rotation when creating another session.

This only tests the initial session. The current OPSECAgent.create_session() reuses the existing guard’s sink, so a second session writes audit records beneath the first session ID. Recreate the session-scoped sink each time and assert both paths separately.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/agents/test_opsec_agent.py` around lines 302 - 313, Extend
test_create_session_audit_uses_configured_session_dir to create a second session
and assert its audit sink path is under the second session ID, while retaining
the first path assertion. Update OPSECAgent.create_session and its
session-scoped audit sink setup so each invocation recreates or rotates the sink
for the new session instead of reusing the existing guard’s sink.

Comment thread tests/prompts/test_prompt_templates.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.gitignore:
- Line 214: Update the .gitignore entry for the CI-generated Bandit report from
bandit_results.json to bandit-report.json, matching the filename produced by CI.

In `@pentestgpt/core/engagement.py`:
- Around line 249-305: Update command target extraction and
_extract_command_tool to return an explicit completeness/status indicator
alongside targets, marking unsupported or ambiguous parsing as incomplete so the
executor gate denies configured-scope execution rather than relying on existing
authorized targets. Preserve bare hostname targets such as ping
outside.example.test, and extend wrapper parsing to consume argument-bearing
flags like sudo -u root so the actual tool is identified. Update all callers to
enforce the fail-closed status.
- Around line 235-238: Update the ValueError handling in the command
tokenization flow to avoid adding the raw malformed command to the audit target
set. Return a non-sensitive sentinel target for malformed non-empty commands
that still causes ScopeGuard to fail closed, while preserving the empty-command
behavior and normal shlex.split handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 30852441-3840-4cf8-a645-95c51a458414

📥 Commits

Reviewing files that changed from the base of the PR and between 6f5ca19 and 0f1cba4.

📒 Files selected for processing (28)
  • .gitignore
  • bandit_results.json
  • docs/api/README.md
  • pentestgpt/agents/command_generator.py
  • pentestgpt/agents/exploit_developer.py
  • pentestgpt/agents/opsec_agent.py
  • pentestgpt/agents/results_verifier.py
  • pentestgpt/agents/strategy_agent.py
  • pentestgpt/api/stealth_api.py
  • pentestgpt/core/engagement.py
  • pentestgpt/core/scope_guard.py
  • pentestgpt/llms/router.py
  • pentestgpt/orchestrator.py
  • pentestgpt/prompts/authorization.py
  • pentestgpt/prompts/prompt_class.py
  • pentestgpt/utils/dependency_injection.py
  • pentestgpt/utils/orchestrator_factory.py
  • tests/agents/test_exploit_scope.py
  • tests/agents/test_opsec_agent.py
  • tests/agents/test_results_verifier.py
  • tests/api/test_opsec_session_scope.py
  • tests/core/test_engagement.py
  • tests/core/test_scope_guard.py
  • tests/integration/test_scope_guard_lifecycle.py
  • tests/llms/test_router_cache_isolation.py
  • tests/prompts/test_authorization_preamble.py
  • tests/prompts/test_prompt_templates.py
  • tests/utils/test_orchestrator_factory.py
🚧 Files skipped from review as they are similar to previous changes (18)
  • pentestgpt/api/stealth_api.py
  • tests/prompts/test_prompt_templates.py
  • pentestgpt/agents/command_generator.py
  • tests/prompts/test_authorization_preamble.py
  • tests/utils/test_orchestrator_factory.py
  • pentestgpt/prompts/authorization.py
  • tests/core/test_scope_guard.py
  • tests/agents/test_exploit_scope.py
  • tests/agents/test_opsec_agent.py
  • pentestgpt/utils/dependency_injection.py
  • docs/api/README.md
  • pentestgpt/orchestrator.py
  • pentestgpt/agents/results_verifier.py
  • pentestgpt/agents/opsec_agent.py
  • pentestgpt/prompts/prompt_class.py
  • pentestgpt/agents/exploit_developer.py
  • pentestgpt/agents/strategy_agent.py
  • tests/integration/test_scope_guard_lifecycle.py

Comment thread .gitignore Outdated
Comment thread pentestgpt/core/engagement.py Outdated
Comment thread pentestgpt/core/engagement.py Outdated
SALhik added 4 commits July 17, 2026 22:03
extract_command_targets only validated the second positional of nxc,
netexec, crackmapexec, and cme commands, so extra hostname targets in a
multi-target command bypassed scope enforcement (e.g. an out-of-scope
host alongside an authorized one executed unchecked). Treat these tools
as protocol-then-targets and validate positional[1:], and move curl to
the all-positional set since every curl positional is a URL target.
OPSECAgent.create_session rebuilt its ScopeGuard unconditionally, so a
guard injected by the orchestrator via set_engagement_scope was replaced
by a session-scoped one, splitting the unified audit trail and resetting
shared last-allowed-target state. Track whether the guard was injected
externally and only build a session-scoped guard when the agent owns it.
Replace the hardcoded `assert calls == 40` with a non-zero floor and swap
the line-numbered benchmark allowlist for a whole-file entry, so adding
or moving an unrelated route_task call no longer breaks the test. The
invariant that production route_task calls carry a preamble-bearing
system_prompt stays enforced by the violations check.
@SALhik
SALhik merged commit 188ed6c into main Jul 18, 2026
2 of 5 checks passed
@SALhik
SALhik deleted the system-prompt-authorization-framing branch July 19, 2026 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant