Security: host-agnostic token (MADTEA_TOKEN env / plaintext madtea.token) attaches to origin-derived forge URL - untrusted-clone exfiltration #271

Closed
opened 2026-07-19 03:43:17 +00:00 by hexajon · 0 comments
hexajon commented 2026-07-19 03:43:17 +00:00 (Migrated from codeberg.org)

A credential-lifecycle audit found a real token-exfiltration path that the host-keyed secure backends are specifically designed to prevent, but which the two host-agnostic token sources sidestep.

Mechanism (verified in code):

  • internal/config/config.go:182-184 - resolveSecureOrGitToken returns MADTEA_TOKEN unconditionally for whatever URL was already resolved (to enable non-interactive use), with no host association.
  • internal/config/config.go:240-248 - step 3 reads the plaintext madtea.token via a merged git-config view (getGitConfigValue("--get","madtea.token")) - also unscoped to any host.
  • The URL these tokens pair with is resolved origin-first (getConfigFromGit -> OriginForgeURL), so in a freshly cloned repo the forge host comes from origin, which is attacker-controlled.
  • internal/gitea/client_http.go:102-104 then attaches Authorization: token <token> because the request is same-origin with that origin-derived baseURL. The secure-scheme check does not help - https://attacker passes.

Attack scenario: operator has MADTEA_TOKEN exported (no MADTEA_URL), or uses a --insecure-storage plaintext token. They clone https://attacker.example/repo, cd in, and run any networked madtea command (issue list, pr list, ...). madtea auto-detects the forge from origin and sends the operator's real token to attacker.example.

Severity: medium. Contrast with the host-keyed secure backends (keychain/pass/systemd-creds), where Retrieve(host) misses for an unknown host and fails safe - this is exactly the gap ADR 0025 host-keying closes, and the env + plaintext paths bypass it. gh/glab scope tokens per host and would not do this. Mitigations that lower severity: the default is a host-keyed secure backend (safe); plaintext requires explicit --insecure-storage; the env-only case requires running a command inside an untrusted clone. No ADR treats the origin-derived URL as an accepted trust boundary, so this does not look consciously accepted.

Fix direction: when the token source is host-agnostic, confirm the resolved forge host against a recorded/expected host before attaching the token, or require MADTEA_URL alongside MADTEA_TOKEN rather than accepting an origin-derived URL for a host-agnostic token.

Acceptance: a host-agnostic token is not sent to a forge host derived solely from a clone's origin; a regression test points at a foreign host and asserts the token is withheld.

A credential-lifecycle audit found a real token-exfiltration path that the host-keyed secure backends are specifically designed to prevent, but which the two host-agnostic token sources sidestep. Mechanism (verified in code): - `internal/config/config.go:182-184` - `resolveSecureOrGitToken` returns `MADTEA_TOKEN` unconditionally for whatever URL was already resolved (to enable non-interactive use), with no host association. - `internal/config/config.go:240-248` - step 3 reads the plaintext `madtea.token` via a merged git-config view (`getGitConfigValue("--get","madtea.token")`) - also unscoped to any host. - The URL these tokens pair with is resolved origin-first (`getConfigFromGit` -> `OriginForgeURL`), so in a freshly cloned repo the forge host comes from `origin`, which is attacker-controlled. - `internal/gitea/client_http.go:102-104` then attaches `Authorization: token <token>` because the request is same-origin with that origin-derived `baseURL`. The secure-scheme check does not help - `https://attacker` passes. Attack scenario: operator has `MADTEA_TOKEN` exported (no `MADTEA_URL`), or uses a `--insecure-storage` plaintext token. They clone `https://attacker.example/repo`, cd in, and run any networked madtea command (`issue list`, `pr list`, ...). madtea auto-detects the forge from origin and sends the operator's real token to `attacker.example`. Severity: medium. Contrast with the host-keyed secure backends (keychain/pass/systemd-creds), where `Retrieve(host)` misses for an unknown host and fails safe - this is exactly the gap ADR 0025 host-keying closes, and the env + plaintext paths bypass it. gh/glab scope tokens per host and would not do this. Mitigations that lower severity: the default is a host-keyed secure backend (safe); plaintext requires explicit `--insecure-storage`; the env-only case requires running a command inside an untrusted clone. No ADR treats the origin-derived URL as an accepted trust boundary, so this does not look consciously accepted. Fix direction: when the token source is host-agnostic, confirm the resolved forge host against a recorded/expected host before attaching the token, or require `MADTEA_URL` alongside `MADTEA_TOKEN` rather than accepting an origin-derived URL for a host-agnostic token. Acceptance: a host-agnostic token is not sent to a forge host derived solely from a clone's origin; a regression test points at a foreign host and asserts the token is withheld.
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.

Dependencies

No dependencies set.

Reference
sixfold-space/madtea#271
No description provided.