SECURITY: load_credentials is not re-entrant — a second service load silently returns the FIRST service's credentials with exit 0 (defeats estate separation) #1052
Open
opened 2026-08-05 16:35:01 +00:00 by Mos
·
0 comments
No Branch/Tag Specified
main
next
fix/1138-conditional-federation
feat/webui-p2-data-auth
fix/gateway-runner-image
feat/webui-p1-vite-skeleton
fix/break-c-hooks-and-web-image
docs/webui-fleet-claude-bridge-plan
fix/wizard-gateway-failure
fix/ci-queue-wait-no-status
fix/next-node-gate
fix/mosaic-init-rce
feat/lease-promotion-and-harness-isolation
greenfield/fomo-lin
fix/1099-pipefail-wake
fix/1099-pipefail-tests
fix/1099-pipefail-sweep
fix/framework-shell-portability
fix/1043-pane-git-identity
fix/1081-issue-close-silent-comment-failure
fix/1090-enrollment-wallclock-tolerance
feat/1082-tea-stale-token-diagnostic
fix/detect-platform-silent-128-outside-repo
feat/1050-install-state-machine-red-fixture
fix/pr-merge-message-field
feat/1051-mosaic-brain-installer
feat/1045-mosaic-cred
remediation/state
fix/1056-upgrade-rollback-control-race
fix/1019-ci-queue-timeout-harness
feat/rm-02-gate-registry
fix/rm-01-reproducible-checkout
remediation/mission-setup
fix/hygiene-inert-format-gate
fix/1019-queue-guard-stdin
feat/mos-ste-writing-standard
fix/1007-suite-hermeticity
fix/991-comment-url-scheme-normalise
feat/push-guard-null-case-verification
mos-comms-live
docs/heartbeat-framework-layering-ms-lead
feat/869-c4-version-coupling
feat/869-c2-install-ordering-guard
feat/869-c5-doctor-activation-check
feat/per-agent-gitea-identity
fix/875-belongs-case-insensitive-slug
fix/ci-queue-wait-404-branch-absent
feat/869-c1-activation-probe
feat/869-c3-broker-supervisor
fix/865-tea-cli-comment-invocation
feat/glpi-skills
fix/860-deflake-mutator-lease-gate
fix/850-detect-platform-port-normalization
fix/856-worktree-deps-preflight
fix/835-pr-review-approve-reject-comment-flag
fix/848-truthful-evidence
fix/812-pr-review-comment
fix/849-recovery-runtime-fixture-race
docs/758-ledger-m5-001-sync
feat/834-tc-server-side-doc
feat/833-constrained-recovery-command
feat/827-gate0-probe
governance/gate0-probe3-amendment
fix/795-codex-pr-diff
fix/795-ci-base-jq
fix/795-ci-base-git
feat/791-pr3-fleet-regen
feat/791-pr2-snapshot-restore
fix/807-glpi-206
fix/808-agent-send-false-sender
feat/791-upgrade-config-protection
feat/790-mosaic-yolo-claudex-pr2
feat/790-mosaic-yolo-claudex
feat/758-v1-v2-migrator
fix/766-exact-fleet-comms
test/758-reconciler-lifecycle-gates
docs/771-kbn101-db-role-split
test/758-example-profile-dispositions
feat/758-shared-role-resolution
feat/mos-logical-identity-fencing
feat/769-kbn100-unified-schema
docs/753-kbn010-threat-gate
feat/758-roster-v2-compiler
feat/756-official-discord-plugin
docs/758-fleet-config-management
fix/mos-option2-qualification-format
docs/issue-758-m0
docs/mos-option2-qualification
mos-comms
feat/tess-interaction-agent
fix/tess-docs-format
draft/mosaic-platform-prd
fix/installer-provider-gate-and-local-gateway-redis
release/mosaic-cli-0.0.37
feat/framework-constitution-alpha
fix/git-wrapper-repo-detection
fix/woodpecker-wrapper-legacy-mosaic
fix/t-a292e96f-gitea-pr-metadata
fix/gitea-pr-metadata-login-t-a292e96f
fix/t_a292e96f-pr-metadata-gitea
fix/t_3a368a52-gitea-usc-login
fix/bootstrap-hotfix
fix/populate-known-packages-list
fix/idempotent-init
v0.0.39-alpha
mosaic-v0.0.31
fed-v0.2.0-m2
fed-v0.1.0-m1
mosaic-v0.0.29
mosaic-v0.0.28
mosaic-v0.0.27
mosaic-v0.0.26
mosaic-v0.0.25
mosaic-v0.0.24
v0.2.0
v0.1.0
v0.0.8
v0.0.7
v0.0.6
v0.0.5
v0.0.4
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mosaicstack/stack#1052
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
load_credentialsuses the${VAR:-default}idiom for every exported field. Because the variables itexports are the SAME names across sibling services (
GITEA_URL/GITEA_TOKENfor bothgitea-mosaicstackandgitea-usc), a second call in the same shell cannot overwrite the first.It is a silent no-op that returns 0.
~/.config/mosaic/tools/_lib/credentials.sh:185-189:The guard on the next line can never fire once
GITEA_TOKENis non-empty from a previous load — so thefail-closed check is unreachable exactly when it matters.
Reproduction
The caller asked for HOMELAB and got USC's token pointed at USC's URL, with exit 0 and no
warning. Nothing in the return value or the environment distinguishes this from a successful load.
Impact — this defeats estate separation
Estate separation (HOMELAB
git.mosaicstack.devvs USCgit.uscllc.com) is a binding operatorrequirement. This bug breaks it through ordinary sequential use in one shell: any script or agent that
touches both estates gets the first estate's credentials for the second estate's work, believing it
switched. An agent that "switched to homelab" and then wrote is operating on USC.
It is the same failure class as #1044 (
get_gitea_tokenfail-open on unset identity): a credential paththat, when it cannot do the right thing, silently does a different thing and reports success.
It also has a live victim.
.gitea.mosaicstack.tokenis absent fromcredentials.json, soevery homelab load in a fresh shell fails closed (correct) — but every homelab load after a USC load
silently returns USC. This was found while verifying an unrelated finding; the verification itself ran
unauthenticated without announcing it, because the empty token was passed to
curlas a valid-lookingheader.
Fix
:-for service-scoped fields — a load mustoverwrite, not defer to whatever a previous service left behind.
unset GITEA_URL GITEA_TOKENat the top of each service branch, so apartial config can never be completed by a sibling's values.
MOSAIC_GITEA_MOSAICSTACK_TOKEN) so sibling services cannotcollide by construction.
.gitea.mosaicstack.tokenor remove the service so it fails loudly atconfig level rather than silently at use.
Related
mosaic credumbrella — this is precisely what a single governed, fail-closed, audited credentialpath is meant to eliminate.