Repository navigation
Description
Summary
The Azure Bicep and ARM federation bundles (GET /api/federation/iac?format=bicep|arm) include a deploy.sh. It is rendered from internal/iacfiles/templates/azure-wif-bicep-deploy.sh.tmpl without shell escaping, and it embeds the requesting user's email inside a double-quoted string:
CONTACT_EMAIL="${CUDLY_CONTACT_EMAIL:-{{.ContactEmail}}}"The value is used as-is, so a command substitution inside that string, such as `...` or $(...), runs when someone executes deploy.sh.
The other shell outputs are escaped. The cli format and the CloudFormation deploy.sh both go through shellEscapeData (internal/api/handler_federation.go, around lines 274 and 640). The Bicep/ARM path renders the deploy script with the raw data (around line 532: renderTemplate("templates/azure-wif-bicep-deploy.sh.tmpl", data)).
Found by the agent working on #952 (PR #955) and confirmed on main at the time of filing.
Why the value can be hostile
ContactEmail is session.Email, the signed-in user's own address. Every email write path validates only with mail.ParseAddress: SetupAdmin, validateCreateUserRequest, and the profile update updateUserEmail in internal/auth/service_user.go. Go's net/mail accepts addresses that contain shell metacharacters:
a`id`b@example.com ACCEPT (Address = a`id`b@example.com)
"a$(id)b"@example.com ACCEPT (Address = a$(id)b@example.com)
Impact
A user who can change their own profile email can set it to an address like the ones above, download a Bicep or ARM bundle, and pass it to whoever deploys into the Azure tenant. That is a normal hand-off, since the bundle exists to be run by an Azure admin. When the admin runs deploy.sh, the embedded command runs on the admin's machine with their Azure CLI session.
This needs a signed-in user with view:accounts and a victim who runs the script, so it isn't remote or unauthenticated. But it is a cross-user code-execution path through a generated artifact.
Expected
The Bicep/ARM deploy.sh is rendered through the same shellEscapeData as the other shell outputs. A regression test renders the bundle with a hostile contact email and asserts the script contains no live command substitution.
Possibly also worth doing (judgment call for the fix PR): tighten email validation so stored addresses can't contain shell or HTML metacharacters. That would be defense in depth, not a substitute for escaping.
Suggested labels (I can't apply them): type/security, type/bug, priority/p2, severity/medium.
🤖 Generated with Claude Code
Activity
IAmJSD commentedon Oct 16, 2026
Claiming: working on this
fix(iac): keep "}" and JSON metacharacters in the Bicep/ARM contact e…
fix(iac): keep "}" and JSON metacharacters in 8 more deploy scripts' …