BUG-HUNT: [security] Path traversal vulnerability in PlanGenerationGraph #1952

Open
opened 2026-04-03 00:21:32 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: fix/security-path-traversal-plan-generation-graph
  • Commit Message: fix(agents): validate file paths against permitted base directory in PlanGenerationGraph._generate_plan
  • Milestone: v3.6.0
  • Parent Epic: #400

Bug Report: [security] — Path traversal vulnerability in PlanGenerationGraph

Severity Assessment

  • Impact: An attacker could write to arbitrary files on the file system where the agent is running, by providing specially crafted file paths in the prompt. This could lead to the modification of sensitive files, denial of service, or arbitrary code execution.
  • Likelihood: Medium. An attacker would need to be able to control the prompt input to the PlanGenerationGraph.
  • Priority: High

Location

  • File: src/cleveragents/agents/graphs/plan_generation.py
  • Function/Class: PlanGenerationGraph._generate_plan
  • Lines: 400-450

Description

The _generate_plan method in the PlanGenerationGraph extracts a file path from the user's prompt via the _extract_path_from_prompt function. This path is then used to determine the file to be created or modified. The application does not properly validate the extracted file path, which can lead to a path traversal vulnerability. An attacker can craft a prompt containing a malicious path, such as @{/etc/passwd}, to write to arbitrary files on the system.

Evidence

    def _generate_plan(self, state: PlanGenerationState) -> dict[str, Any]:
        # ...
            explicit_path = self._extract_path_from_prompt(state.get("prompt", ""))

            if operation == "modify" and contexts:
                # ...
            elif explicit_path:
                file_path = explicit_path
                # ...
                existing_path = Path(file_path)
                if existing_path.exists():
                    # ...
                elif existing_path.suffix == "":
                    file_path = str(existing_path / "generated.py")
            # ...

Expected Behavior

The agent should only be able to write to files within a predefined and restricted directory. Any attempt to write to files outside of this directory should be blocked.

Actual Behavior

The agent can write to any file on the file system that the user running the agent has write access to.

Suggested Fix

Before writing to a file, its absolute path should be resolved and checked to ensure it is within a permitted base directory.

Example:

import os
from pathlib import Path

# Assume a permitted base directory is defined, for example, the current working directory.
PERMITTED_BASE_DIR = os.path.abspath(os.getcwd())

# ... inside _generate_plan ...
            elif explicit_path:
                abs_path = os.path.abspath(explicit_path)
                if not abs_path.startswith(PERMITTED_BASE_DIR):
                    return {
                        "generated_changes": [],
                        "error": f"Access denied: {explicit_path} is outside the permitted directory.",
                    }
                file_path = explicit_path
                # ...

Category

security

Subtasks

  • Identify and define the permitted base directory for PlanGenerationGraph file write operations
  • Implement path resolution and validation logic in _generate_plan to reject paths outside the permitted base directory
  • Add appropriate error return (with "error" key in state dict) when a path traversal attempt is detected
  • Write Behave unit tests covering: valid paths within permitted directory, path traversal attempts (e.g. @{/etc/passwd}, ../../../../etc/shadow), symlink-based traversal attempts
  • Ensure all nox stages pass (nox -e lint, nox -e typecheck, nox -e unit_tests)
  • Verify coverage remains >= 97%

Definition of Done

  • PlanGenerationGraph._generate_plan resolves all extracted file paths to their absolute form before use
  • Any path that resolves outside the permitted base directory is rejected with a clear error returned in the state dict
  • No path traversal attack vector remains in _generate_plan via the _extract_path_from_prompt code path
  • Behave unit tests cover all path validation scenarios (valid, traversal, symlink)
  • All nox stages pass
  • Coverage >= 97%

Automated by CleverAgents Bot
Supervisor: Bug Hunting | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/security-path-traversal-plan-generation-graph` - **Commit Message**: `fix(agents): validate file paths against permitted base directory in PlanGenerationGraph._generate_plan` - **Milestone**: v3.6.0 - **Parent Epic**: #400 ## Bug Report: [security] — Path traversal vulnerability in PlanGenerationGraph ### Severity Assessment - **Impact**: An attacker could write to arbitrary files on the file system where the agent is running, by providing specially crafted file paths in the prompt. This could lead to the modification of sensitive files, denial of service, or arbitrary code execution. - **Likelihood**: Medium. An attacker would need to be able to control the prompt input to the `PlanGenerationGraph`. - **Priority**: High ### Location - **File**: `src/cleveragents/agents/graphs/plan_generation.py` - **Function/Class**: `PlanGenerationGraph._generate_plan` - **Lines**: 400-450 ### Description The `_generate_plan` method in the `PlanGenerationGraph` extracts a file path from the user's prompt via the `_extract_path_from_prompt` function. This path is then used to determine the file to be created or modified. The application does not properly validate the extracted file path, which can lead to a path traversal vulnerability. An attacker can craft a prompt containing a malicious path, such as `@{/etc/passwd}`, to write to arbitrary files on the system. ### Evidence ```python def _generate_plan(self, state: PlanGenerationState) -> dict[str, Any]: # ... explicit_path = self._extract_path_from_prompt(state.get("prompt", "")) if operation == "modify" and contexts: # ... elif explicit_path: file_path = explicit_path # ... existing_path = Path(file_path) if existing_path.exists(): # ... elif existing_path.suffix == "": file_path = str(existing_path / "generated.py") # ... ``` ### Expected Behavior The agent should only be able to write to files within a predefined and restricted directory. Any attempt to write to files outside of this directory should be blocked. ### Actual Behavior The agent can write to any file on the file system that the user running the agent has write access to. ### Suggested Fix Before writing to a file, its absolute path should be resolved and checked to ensure it is within a permitted base directory. Example: ```python import os from pathlib import Path # Assume a permitted base directory is defined, for example, the current working directory. PERMITTED_BASE_DIR = os.path.abspath(os.getcwd()) # ... inside _generate_plan ... elif explicit_path: abs_path = os.path.abspath(explicit_path) if not abs_path.startswith(PERMITTED_BASE_DIR): return { "generated_changes": [], "error": f"Access denied: {explicit_path} is outside the permitted directory.", } file_path = explicit_path # ... ``` ### Category security ## Subtasks - [ ] Identify and define the permitted base directory for `PlanGenerationGraph` file write operations - [ ] Implement path resolution and validation logic in `_generate_plan` to reject paths outside the permitted base directory - [ ] Add appropriate error return (with `"error"` key in state dict) when a path traversal attempt is detected - [ ] Write Behave unit tests covering: valid paths within permitted directory, path traversal attempts (e.g. `@{/etc/passwd}`, `../../../../etc/shadow`), symlink-based traversal attempts - [ ] Ensure all nox stages pass (`nox -e lint`, `nox -e typecheck`, `nox -e unit_tests`) - [ ] Verify coverage remains >= 97% ## Definition of Done - [ ] `PlanGenerationGraph._generate_plan` resolves all extracted file paths to their absolute form before use - [ ] Any path that resolves outside the permitted base directory is rejected with a clear error returned in the state dict - [ ] No path traversal attack vector remains in `_generate_plan` via the `_extract_path_from_prompt` code path - [ ] Behave unit tests cover all path validation scenarios (valid, traversal, symlink) - [ ] All nox stages pass - [ ] Coverage >= 97% --- **Automated by CleverAgents Bot** Supervisor: Bug Hunting | Agent: ca-new-issue-creator
freemo added this to the v3.6.0 milestone 2026-04-03 00:21:42 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • MoSCoW: MoSCoW/Should Have — bug or error handling improvement.

Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: ca-project-owner

Issue triaged by project owner: - **State**: Verified - **MoSCoW**: MoSCoW/Should Have — bug or error handling improvement. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
freemo removed this from the v3.6.0 milestone 2026-04-07 01:32:53 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#400 Epic: Post-MVP Security
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#1952
No description provided.