aws / aws/amazon-q-developer-cli

Agent toolsSettings relative path patterns fail to normalize causing inconsistent security behavior

Open
#2,818 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
2k
Forks
439
PR merge metrics
No merged PRs in 30d

Description

### Checks

- [x] I have searched [github.com/aws/amazon-q-developer-cli/issues](https://github.com/aws/amazon-q-developer-cli/issues?q=) and there are no duplicates of my issue
- [x] I have run `q doctor` in the affected terminal session
- [x] I have run `q restart` and replicated the issue again

### Operating system

Linux

### Expected behaviour

Agent toolsSettings with relative path patterns should consistently enforce access restrictions regardless of how paths are specified. Both `./denied/test.txt` and `denied/test.txt` should be treated identically since they refer to the same file location.

### Actual behaviour

The `canonicalizes_path()` function only performs environment variable expansion (`$HOME`, `~`) but doesn't normalize relative paths to absolute paths. This causes inconsistent pattern matching:

**Test Configuration:**
```json
{
"name": "test-agent",
"tools": ["*"],
"toolsSettings": {
"fs_write": {
"deniedPaths": ["./denied/**"]
}
}
}
```

**Results:**
- Input: `./denied/test.txt` → **DENY** ✅ (correctly blocked)
- Input: `denied/test.txt` → **ASK** ❌ (should be blocked but isn't)

This creates a security inconsistency where the same file can be accessed or blocked depending on path format.

### Steps to reproduce

1. Create agent config with relative path restrictions:
``` json
{
"name": "test-agent",
"tools": ["*"],
"toolsSettings": {
"fs_write": {
"deniedPaths": ["./denied/**"]
}
}
}
```

2. Test with explicit relative path:
``` bash
q chat --agent test-agent
# Try: fs_write tool with path "./denied/test.txt"
# Result: Correctly denied
```

3. Test with implicit relative path:
``` bash
q chat --agent test-agent
# Try: fs_write tool with path "denied/test.txt"
# Result: Asks for permission (should be denied)
```

### Root Cause

The canonicalizes_path() function in crates/chat-cli/src/util/
directories.rs
only expands environment variables but doesn't resolve relative paths to absolute paths:

``` rust
pub fn canonicalizes_path(os: &Os, path_as_str: &str) -> Result {
let context = |input: &str| Ok(os.env.get(input).ok());
let home_dir = || os.env.home().map(|p| p.to_string_lossy().to_string());

Ok(shellexpand::full_with_context(path_as_str, home_dir, context)?.to_string())
// Missing: relative path to absolute path conversion
}
```

**What happens:**
- Pattern: `./denied/**` remains as `./denied/**` (not normalized)
- Input: `denied/test.txt` remains as `denied/test.txt` (not normalized)
- Result: Pattern `./denied/**` doesn't match input `denied/test.txt`

### Security Impact

This allows users to potentially bypass `deniedPaths` restrictions by omitting the `./` prefix, creating inconsistent security enforcement. The same directory can be accessed or blocked depending on how the path is specified.

### Affected Components

- fs_read tool permission evaluation
- fs_write tool permission evaluation
- Agent toolsSettings pattern matching
- Both relative patterns (`./path/**`) and relative inputs (`path/file`)

### Environment

```yaml
[q-details]
version = "1.15.0"

[system-info]
os = "Linux"
```

### Proposed Solution

Enhance `canonicalizes_path()` to normalize relative paths to absolute paths:
- Pattern: `./denied/**` → `/current/working/directory/denied/**`
- Input: `denied/test.txt` → `/current/working/directory/denied/test.txt`

This ensures consistent pattern matching regardless of path format.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.