Repository navigation
fix(iac): keep "}" and JSON metacharacters in 8 more deploy scripts' contact email - #1441
Conversation
…contact email
Eight generated scripts that self-register with CUDly pre-filled the
contact email as the default of ${CUDLY_CONTACT_EMAIL:-...}. shellEscape
does not escape "}", which net/mail accepts, so a "}" in the session
email closed the expansion early and registered a garbled address. The
registration heredoc also put CONTACT_EMAIL and ACCOUNT_NAME into the
JSON raw, so a '"', '\' or tab produced an invalid payload. Nothing could
execute ($, `, " and \ stay shell-escaped); it was a correctness bug.
Port the Bicep fix from LeanerCloud#958: assign the env value first and fall back
to the pre-filled email on its own line (same override semantics), and
build the payload from json_escape'd copies of both values, using the
Bicep script's helper verbatim. The templates are shared with
scripts/generate-federation-iac.go, so the generator picks this up too;
its probe template and hostile shell email now match (the "}" no longer
has to be left out).
Tests: every registering script, fetched through getFederationIaC
(azure-wif-deploy.sh.tmpl, which no download ships, through the same
shellEscapeData + renderTemplate), runs its registration block in the
LeanerCloud#958 sandbox for the LeanerCloud#958 hostile emails and env overrides; and a drift
test fails if any registering template puts the email in a
${VAR:-default}, skips json_escape, carries a different helper, or is
missing from the tested list.
Refs LeanerCloud#1436
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reached
This review includes 12 billable files and costs up to $3.00. Or wait 58 minutes for your next included review. View limit details
Comment |
|
Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE Blocking:
Non-blocking:
Attacked:
Body-stale:
Reviewer: rC2. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths. |
|
Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE Blocking:
Non-blocking:
Attacked:
Body-stale:
Reviewer: rC3. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths. |
|
Local verification at |
|
Merged by IAmJSD's agent at IAmJSD's request (IAmJSD is acting owner while the maintainers are away), under the bar IAmJSD set: 2 approving independent review(s) on |
Closes #1436
Root cause
Eight generated scripts that self-register with CUDly pre-filled the contact email as the default of a shell expansion:
CONTACT_EMAIL="${CUDLY_CONTACT_EMAIL:-{{.ContactEmail}}}"shellEscapeescapes\,",`and$, but not}, andnet/mailaccepts}. A}in the session email therefore closed the${...:-...}early, and the script registered a garbled address:a}b@example.combecameab}@example.com. The registration heredoc also putCONTACT_EMAILandACCOUNT_NAMEinto the JSON raw, so a",\or tab produced an invalid payload. Nothing could execute: the shell metacharacters stay escaped. This is a correctness bug, not an injection.Fix
Ported the Bicep fix from #958 / #992 to the 8 templates under
internal/iacfiles/templates/:aws-cfn-deploy,aws-cross-account-cfn-deploy,aws-cross-account-cli,aws-wif-cli,azure-wif-cli,azure-wif-deploy,gcp-sa-impersonation-cli,gcp-wif-cli(all.sh.tmpl).CONTACT_EMAIL="${CUDLY_CONTACT_EMAIL:-}"then[ -n "$CONTACT_EMAIL" ] || CONTACT_EMAIL="{{.ContactEmail}}". No template value sits inside${...}any more. The override semantics are unchanged: a set, non-emptyCUDLY_CONTACT_EMAILwins.json_escape'd copies of the email and account name (CONTACT_EMAIL_JSON,ACCOUNT_NAME_JSON). The helper is the Bicep script's, byte for byte (printf + sed, no jq).scripts/generate-federation-iac.gorenders these same template files with the sameshellEscaperule, so it needs no code change. Its escape test's probe template now uses the new two-line form, and its hostile shell email now includes the}it previously had to leave out.Verification
All local runs, Linux, bash 5:
internal/api/handler_federation_registration_escape_test.go, reusing the Bicep/ARM federation bundle deploy.sh embeds the user's email without shell escaping (command injection) #958 sandbox:evalRegistrationbecameevalRegistrationWith, which takes a stub prelude.TestRegistrationScripts_KeepContactEmailAndPayloadIntactfetches each of the 7 shipped scripts throughgetFederationIaC, the real download path (format=clifor the 5 CLI scripts,format=cfnfor the 2 CFN deploy scripts), with the session email set to each of the 9 Bicep/ARM federation bundle deploy.sh embeds the user's email without shell escaping (command injection) #958 hostile emails:},${}, quotes, backslashes, a tab,$(...)and backticks. Each script must passbash -n, and its registration block, run with stubbedaws/azand no network, must leaveCONTACT_EMAILequal to the email, produce a payload that parses as JSON with the exact email, and create nopwnedfile. No download format shipsazure-wif-deploy.sh.tmpltoday; only the iacfiles tests render it. It goes through the sameshellEscapeData+renderTemplatethe handler uses.TestRegistrationScripts_EnvOverridesAndAccountNamechecks, for all 8 scripts, that unset or emptyCUDLY_CONTACT_EMAILfalls back to a pre-filled email containing}, that a set value wins, and that aCUDLY_ACCOUNT_NAMEofOps "prod" \ team<TAB>Breachesaccount_nameverbatim.TestRegistrationTemplates_NoDriftis the drift test. It scans everytemplates/*.sh.tmplthat POSTs to/api/registerand fails if one is missing from the tested list, puts{{.ContactEmail}}inside a${VAR:-...}, writes"contact_email"/"account_name"without the_JSONvariables, or carries ajson_escapethat differs from the Bicep script's.origin/main, 72 of the 80 subtests fail, and so does the drift test. The 8 passes are thea`id`b@example.comcase, which has no}or JSON metacharacter.TestGetFederationIaC_CLIMatrix, and the generator probe and hostile email noted above. The Bicep/ARM federation bundle deploy.sh embeds the user's email without shell escaping (command injection) #958 Bicep/ARM tests, the shell-escaping tests (nothing executes through$,`,"or\), the iacfiles template tests and the generator drift tests (scripts/) all still pass.go build ./...,go vet ./...,go vet -tags integration ./...,(cd tests/e2e && go vet -tags e2e ./...): clean.golangci-lintv2.10.1 on./internal/api/ ./internal/iacfiles/... ./scripts/, with and without--build-tags integration: 0 issues. No non-test Go files changed, so gocyclo had nothing to check.go test -race -short -count=1on those packages: ok.go test -race -tags integration -count=1on the same packages:internal/iacfilesandscriptspassed. In the fullinternal/apirun, 27 Postgres-backed tests (ladder, marketplace, planned purchases and others, none touching federation) failed after the shared testcontainer stalled for 364s on this busy machine. Rerun alone with-run '^(<those 27>)$', all 27 passed. None of them touch the changed files.secrets-scan.shon the changed files: "clean; planted key flagged".scripts/test-git-secrets-allowlist.sh: 183 PASS, 0 FAIL.Not verified locally: running the scripts end to end against real AWS, Azure or GCP accounts and a live
/api/register. Only the registration block runs, with the cloud CLIs stubbed. No Terraform files changed. Out of scope and unchanged: other${VAR:-{{.Field}}}defaults (ProjectID,ServiceAccountEmail,CUDlyAPIURL, ...). Those values are server-derived rather than user-supplied.🤖 Generated with Claude Code