Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

120 changes: 120 additions & 0 deletions crates/goose-server/ALLOWLIST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Goose Extension Allowlist

This document describes the extension allowlist feature in goose-server, which provides a security mechanism for controlling which commands can be executed by extensions.

## Overview

The allowlist feature enables administrators to restrict which commands can be executed by Stdio extensions in Goose. This is an important security measure that prevents potentially malicious extensions from executing unauthorized commands on the system.

When enabled, the server will only allow execution of commands that match entries in the allowlist. Commands that are not in the allowlist will be rejected with an error message.

## How It Works

1. The allowlist is fetched from a URL specified by the `GOOSE_ALLOWLIST` environment variable.
2. The allowlist is a YAML file that contains a list of allowed extension commands.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Pairs of extension IDs + Commands?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yes it is technically that (although id doesn't carry any intrinsic meaning)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I was thinking we may want to validate both. In a world where IDs are unique I could see this being better long term validation (as you rightly point out no short term impact)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I think for now, just extension command until we know what id's are for!

3. The allowlist is fetched once when first needed and cached for the lifetime of the server.
4. When a Stdio extension is registered, the command is checked against the allowlist.
5. If the command is not in the allowlist, the extension registration is rejected.

## Configuration

### Setting the Allowlist URL

Set the `GOOSE_ALLOWLIST` environment variable to the URL of your allowlist YAML file:

```bash
export GOOSE_ALLOWLIST=https://example.com/goose-allowlist.yaml

@wendytang wendytang Mar 26, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

how would the env var be passed into goosed? is it going to be built into the app?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yes, built into app, similar to other ones.

```

If this environment variable is not set, no allowlist restrictions will be applied (all commands will be allowed).

### Allowlist File Format

The allowlist file should be a YAML file with the following structure:

```yaml
extensions:
- id: extension-id-1
command: command-name-1
- id: extension-id-2
command: command-name-2
# ... more extensions
```

Example:

```yaml
extensions:
- id: slack
command: uvx mcp_slack
- id: github
command: uvx mcp_github
- id: jira
command: uvx mcp_jira
```

### Command Matching

When a Stdio extension attempts to register with a command, the system:

1. Extracts the base command name (the last part of the path)
- For example, `/Users/username/bin/mcp thing-here` becomes `mcp thing-here`
Comment thread
michaelneale marked this conversation as resolved.
Outdated
2. Checks if this base command **exactly matches** any of the command strings in the allowlist
3. Allows the extension if there's a match, rejects it otherwise

### Special Cases

There are a few special cases in the command matching logic:

1. **goosed commands**: Any command that is either exactly "goosed" or ends with "/goosed" is always allowed, regardless of the allowlist. This ensures that the Goose server itself can always be executed.

2. **No allowlist**: If no allowlist is configured (the `GOOSE_ALLOWLIST` environment variable is not set), all commands are allowed.

3. **Empty allowlist**: If the allowlist is empty (contains no entries), all commands are allowed.

### Best Practices for Defining Allowlist Entries

To effectively use the allowlist with exact matching:

1. **Be specific**: Define the exact command string that you want to allow.
2. **Include full paths if needed**: If you want to allow a command only from a specific path, include the full path in the allowlist.
3. **Regular auditing**: Regularly audit your allowlist to ensure it only contains the commands you intend to allow.

## Security Considerations

1. **HTTPS**: Always use HTTPS URLs for your allowlist to prevent man-in-the-middle attacks.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We can probably validate this in the code too right?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yes

2. **Access Control**: Ensure the allowlist URL is only accessible to authorized users.
3. **Validation**: The allowlist file should be carefully reviewed to ensure only trusted commands are included.
4. **Monitoring**: Monitor extension registrations for any rejected commands, which might indicate attempted abuse.

## Troubleshooting

If extensions are being rejected unexpectedly:

1. Check if the `GOOSE_ALLOWLIST` environment variable is set correctly.
2. Verify that the allowlist file is accessible from the server.
3. Ensure the allowlist file is properly formatted YAML.
4. Check server logs for any errors related to fetching or parsing the allowlist.
5. Verify that the command in the extension registration exactly matches what's in the allowlist.

## Example Usage

1. Create and host an allowlist file:

```yaml
# allowlist.yaml
extensions:
- id: slack
command: uvx mcp_slack
- id: github
command: uvx mcp_github
```

2. Start goose-server with the allowlist URL:

```bash
export GOOSE_ALLOWLIST=https://secure-server.example.com/allowlist.yaml
./goosed
```

3. When extensions are registered, only those with commands matching the allowlist will be accepted.
1 change: 1 addition & 0 deletions crates/goose-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ serde_yaml = "0.9.34"
axum-extra = "0.10.0"
utoipa = { version = "4.1", features = ["axum_extras"] }
dirs = "6.0.0"
reqwest = { version = "0.12.9", features = ["json", "rustls-tls", "blocking"], default-features = false }

[[bin]]
name = "goosed"
Expand Down
Loading