fix: load ./.env only when private and owned, add --env-file and AEGIS_ENV_FILE (SEC-04)

This commit is contained in:
Latte committed 2026-10-14 17:22:29 +02:00
1 parent 7307214ab6
commit 79aa4f7fc0
11 files changed
+360 -20

No files matched your search

+22 -3
View File
@@ -1,9 +1,28 @@
# Configuration
All settings are environment variables. They are read case-insensitively from the process
environment and from a `.env` file in the working directory (the environment wins). Unknown
variables are ignored. A blank value (`KEY=` in `.env`) counts as unset for the optional
secrets, URLs and paths. List values accept commas or whitespace as separators.
environment and from an env file (the environment always wins). Unknown variables are ignored.
A blank value (`KEY=` in the env file) counts as unset for the optional secrets, URLs and
paths. List values accept commas or whitespace as separators.
## Which env file is read
The env file is never trusted just because it sits in the working directory: MCP clients start
stdio servers inside the project they work on, which can be a cloned repository carrying a
planted `.env` that switches off secret masking or the audit log or points `GITEA_URL` at
another host. The file is chosen in this order:
1. `--env-file PATH` of `serve` (and `setup`): used as given. It must exist and be a regular
file.
2. The `AEGIS_ENV_FILE` environment variable: same rules.
3. `./.env`, but only when it is a regular file (not a symlink), owned by the user running the
server, with no group or other permissions (mode 0600, which `setup` writes). Otherwise it is
ignored and one warning goes to stderr that says why and how to fix it:
`chmod 600 .env`, or pass `--env-file`.
Real environment variables take precedence over every file. A missing `./.env` is silent.
Containers pass settings as environment variables (`env_file:` in compose), not through the
working directory.
`.env.example` is the annotated template. `uv run aegis-gitea-mcp setup` fills one in for you
(see [getting-started.md](getting-started.md)). Secret settings never appear in logs, errors or
+1 -1
View File
@@ -29,7 +29,7 @@ Setup prompts for the Gitea URL and the token (hidden input). For unattended use
| `--gitea-url` | Gitea base URL |
| `--public-base-url` | Public https URL of this server. Enables registration of the OAuth application |
| `--no-oauth` | Do not create the Gitea OAuth application |
| `--env-file` | Env file to create or update (default `./.env`) |
| `--env-file` | Env file to create or update (default `AEGIS_ENV_FILE`, else `./.env`) |
| `--template` | Env template (default `./.env.example`, else the copy built into the package) |
| `--yes` | Never prompt, and accept regenerating an OAuth client secret |
+1 -1
View File
@@ -72,7 +72,7 @@ Tampering
| Query smuggling of credentials or Sudo | `token`, `access_token`, `sudo`, `_sudo` refused as query names (any case) | `gitea/encoding.py` |
| Malformed arguments | JSON Schema validation (Draft 2020-12, `additionalProperties: false`) before anything runs; messages never echo values | `server.py` |
| Store tampering or wrong key | Fernet (authenticated encryption) with an HKDF-SHA256 key; undecryptable store stops startup instead of being wiped; symlinks refused | `oauth/store.py` (rollback residual: SEC-13) |
| Settings injection from a planted `.env` | none yet | `config.py` (SEC-04) |
| Settings injection from a planted `.env` | `./.env` is loaded only when it is a regular file, not a symlink, owned by the user, mode 0600; otherwise ignored with a warning; `--env-file` or `AEGIS_ENV_FILE` name a file explicitly; the environment wins | `config.py` (`select_env_file`), `cli.py` |
Repudiation
+3 -1
View File
@@ -8,7 +8,9 @@ Gitea's sanitized message, and the audit log has one event per call (see
| Message or exit | Cause and fix |
|---|---|
| Exit code 2, "GITEA_TOKEN" required (stdio) | stdio needs `GITEA_TOKEN`. Put it in the client's `env` block or in `.env` in the working directory the client starts the server in. |
| Exit code 2, "GITEA_TOKEN" required (stdio) | stdio needs `GITEA_TOKEN`. Put it in the client's `env` block, or in an env file passed with `--env-file` (or `AEGIS_ENV_FILE`). A `.env` in the working directory counts only when it is a regular file you own with mode 0600. |
| Warning "ignoring ./.env: ..." | The working directory's `.env` is a symlink, owned by someone else or accessible to group or others, so its settings are not loaded. Run `chmod 600 .env`, or pass `--env-file PATH`. See "Which env file is read" in [configuration.md](configuration.md). |
| Exit code 2, "env file ... does not exist" | The file named by `--env-file` or `AEGIS_ENV_FILE` is missing or not a regular file. |
| Exit code 2, refuses a non-loopback bind | `MCP_HOST` is not loopback and there is no `MCP_BEARER_TOKEN` or complete OAuth setup. Set one of them, or bind `127.0.0.1` behind a reverse proxy. |
| Exit code 2, lists OAuth settings | `OAUTH_ENABLED=true` needs `GITEA_OAUTH_CLIENT_ID`, `GITEA_OAUTH_CLIENT_SECRET`, `TOKEN_ENCRYPTION_KEY` and `PUBLIC_BASE_URL`. |
| Validation error naming a setting | See the rules in [configuration.md](configuration.md): URLs must be http(s) without credentials, `PUBLIC_BASE_URL` must be https, secrets need 32 characters, `OAUTH_SCOPES` accepts only granular scopes. |