aws / aws/amazon-q-developer-cli
Agent toolsSettings relative path patterns fail to normalize causing inconsistent security behavior
- 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
Assessment
This issue has not been assessed yet.