Reviewed commit: be11bdcb5. Note: origin/main moved to 3e9660d06 during the review; re-verify against current main before changing code.
The structural finding
Every serious IaC security defect found in the 2026-07-28 review is the same shape: for a given onboarding job, the Terraform path enforces a guard and the shell / CloudFormation / ARM path for the identical job does not.
This class cannot be caught by reviewing one cloud's template in isolation, which is exactly why it survived. Each individual instance looks like an isolated oversight; together they are a missing invariant.
The instances (each filed separately, listed here for the pattern)
-
AWS target, OIDC subject claim. iac/federation/aws-target/cloudformation/template.yaml:52-57,171-178 defaults OIDCSubjectClaim to "" and omits the :sub condition entirely. The Terraform sibling terraform/variables.tf:28-43 makes it mandatory with a validation reading "Leaving it empty would allow any principal in the OIDC provider tenant to assume this role."
-
GCP WIF, attribute condition. arm/CUDly-CrossSubscription/setup-gcp-wif.sh:99-103,133-139 creates the AWS-mode provider with no --attribute-condition and binds impersonation pool-wide. The Terraform sibling iac/federation/gcp-target/terraform/main.tf:137-147 has a hard precondition forbidding exactly that state and quoting the same attack.
-
Azure reservation role, assignment scope. arm/CUDly-CrossSubscription/template.json:86-100 assigns the purchase role at tenant /providers/Microsoft.Capacity scope as well as subscription scope. The Terraform sibling iac/federation/azure-target/terraform/main.tf:77-83 assigns subscription-only, and the shared module terraform/modules/iam/azure/cudly-reservation-role/main.tf:58-71 documents that the tenant scope was deliberately removed.
-
AWS target, OIDC thumbprint. iac/federation/aws-target/cloudformation/template.yaml:42-50 accepts the all-zeros placeholder thumbprint for arbitrary issuers. The Terraform sibling terraform/variables.tf:79-87 rejects it unless the issuer is one AWS natively validates, reasoning that "the all-zeros value bypasses the CA-chain check entirely."
A fifth, adjacent instance in our own CI IAM: terraform/environments/azure/ci-cd-permissions/sp.tf:40-49 trusts the bare pull_request subject while the AWS and GCP siblings pin to main and named environments.
Failure scenario
A customer picks whichever onboarding path their tooling supports. Choosing CloudFormation or the ARM/shell script instead of Terraform silently opts them out of guards that the Terraform path treats as mandatory, with no warning anywhere in the docs that the paths are not equivalent. In every case above the resulting exposure is spend authority on the customer's own cloud account.
The defect is not any single template. It is that the paths are maintained independently with no mechanism keeping them in parity.
Fix direction
Beyond fixing the four instances individually:
- Parity tests in CI that assert the guard set is equivalent across the paths for each onboarding job, so a future divergence fails CI rather than shipping. At minimum: every path that creates a trust relationship must require a subject/attribute restriction, and every role assignment must be scoped no wider than the Terraform sibling's.
- Treat the Terraform module as the normative definition and generate or lint the other paths against it.
- Document explicitly, in the onboarding docs, that the paths are intended to be equivalent, so a reviewer knows divergence is a bug.
Findings from the 2026-09-02 codebase audit
Added by an automated audit of 3c0f8ac94048a2c36fce5ccddee54e6c4849a5cd (tip of origin/main). Each item below was reported by one reviewer and independently confirmed by a second that did not write it. Full report: docs/audits/codebase-audit-2026-09-02.md.
A06-028 (medium)
A fifth instance of the same shape, this time shell-versus-shell rather than shell-versus-Terraform. internal/iacfiles/templates/azure-wif-deploy.sh.tmpl:77-81 ends the federated-credential create with || echo "(federated credential may already exist - continuing)", which swallows every non-zero exit and defeats the script's own set -euo pipefail at :14. The script then assigns the Reservation Purchaser role at subscription scope and prints '=== Done ===' (:83-97), so a Graph permission denial or a throttle produces a confident success with no credential in place at all. The same swallow is at azure-wif-cli.sh.tmpl:58-61. The GCP script does the compare-and-abort this needs: gcp-wif-cli.sh.tmpl:177-233 re-reads an existing provider and aborts unless issuer, attribute condition, mapping, state and audience all match. Audit finding A06-028.
A13b-012 (medium)
A further instance of this pattern, from finding A13b-012, and one that runs Terraform-to-Terraform rather than across formats. iac/federation/azure-target/terraform/variables.tf:19-33 declares cudly_issuer_url, cudly_federated_subject and cudly_federated_audience with no validation block on any of the three, and all three feed the federated identity credential unchecked at main.tf:56-58. The AWS sibling guards the equivalent inputs hard: the issuer at aws-target/terraform/variables.tf:11-15, the audience at :36-39, and the subject at :59-62 including the $/* rejection. Azure AD fetches JWKS from whatever host the issuer names and mints tokens for CUDly's app registration for any JWT that host signs with the default subject cudly-controller, one constant shared across every customer tenant, so a wrong or attacker-controlled issuer URL yields reservation-purchase authority in the customer's subscription. Worth adding to the parity-test set this issue proposes, since a cross-format-only test would not catch it.
A06-029 (low)
Another instance of this pattern, from finding A06-029, between sibling shell templates rather than across formats. CUDLY_FEDERATED_SUBJECT is guarded on two of the three onboarding scripts: aws-wif-cli.sh.tmpl:31-41 rejects an empty value and any $, * or whitespace because IAM expands policy variables inside Condition values, and gcp-wif-cli.sh.tmpl:50-61 pins a charset plus a 127-character cap because the value lands in a CEL string literal. Both Azure templates interpolate the override straight into the federated-credential JSON heredoc with no check at all (azure-wif-cli.sh.tmpl:26,47-56 and azure-wif-deploy.sh.tmpl:61,66-75), where a " closes the subject string and lets sibling keys such as audiences be injected into the request body. Operator-supplied rather than attacker-supplied, so this is defense in depth, but it is the same missing-invariant shape and belongs in the parity check.
Reviewed commit:
be11bdcb5. Note:origin/mainmoved to3e9660d06during the review; re-verify against currentmainbefore changing code.The structural finding
Every serious IaC security defect found in the 2026-07-28 review is the same shape: for a given onboarding job, the Terraform path enforces a guard and the shell / CloudFormation / ARM path for the identical job does not.
This class cannot be caught by reviewing one cloud's template in isolation, which is exactly why it survived. Each individual instance looks like an isolated oversight; together they are a missing invariant.
The instances (each filed separately, listed here for the pattern)
AWS target, OIDC subject claim.
iac/federation/aws-target/cloudformation/template.yaml:52-57,171-178defaultsOIDCSubjectClaimto""and omits the:subcondition entirely. The Terraform siblingterraform/variables.tf:28-43makes it mandatory with a validation reading "Leaving it empty would allow any principal in the OIDC provider tenant to assume this role."GCP WIF, attribute condition.
arm/CUDly-CrossSubscription/setup-gcp-wif.sh:99-103,133-139creates the AWS-mode provider with no--attribute-conditionand binds impersonation pool-wide. The Terraform siblingiac/federation/gcp-target/terraform/main.tf:137-147has a hardpreconditionforbidding exactly that state and quoting the same attack.Azure reservation role, assignment scope.
arm/CUDly-CrossSubscription/template.json:86-100assigns the purchase role at tenant/providers/Microsoft.Capacityscope as well as subscription scope. The Terraform siblingiac/federation/azure-target/terraform/main.tf:77-83assigns subscription-only, and the shared moduleterraform/modules/iam/azure/cudly-reservation-role/main.tf:58-71documents that the tenant scope was deliberately removed.AWS target, OIDC thumbprint.
iac/federation/aws-target/cloudformation/template.yaml:42-50accepts the all-zeros placeholder thumbprint for arbitrary issuers. The Terraform siblingterraform/variables.tf:79-87rejects it unless the issuer is one AWS natively validates, reasoning that "the all-zeros value bypasses the CA-chain check entirely."A fifth, adjacent instance in our own CI IAM:
terraform/environments/azure/ci-cd-permissions/sp.tf:40-49trusts the barepull_requestsubject while the AWS and GCP siblings pin tomainand named environments.Failure scenario
A customer picks whichever onboarding path their tooling supports. Choosing CloudFormation or the ARM/shell script instead of Terraform silently opts them out of guards that the Terraform path treats as mandatory, with no warning anywhere in the docs that the paths are not equivalent. In every case above the resulting exposure is spend authority on the customer's own cloud account.
The defect is not any single template. It is that the paths are maintained independently with no mechanism keeping them in parity.
Fix direction
Beyond fixing the four instances individually:
Findings from the 2026-09-02 codebase audit
Added by an automated audit of
3c0f8ac94048a2c36fce5ccddee54e6c4849a5cd(tip oforigin/main). Each item below was reported by one reviewer and independently confirmed by a second that did not write it. Full report:docs/audits/codebase-audit-2026-09-02.md.A06-028 (medium)
A fifth instance of the same shape, this time shell-versus-shell rather than shell-versus-Terraform. internal/iacfiles/templates/azure-wif-deploy.sh.tmpl:77-81 ends the federated-credential create with
|| echo "(federated credential may already exist - continuing)", which swallows every non-zero exit and defeats the script's ownset -euo pipefailat :14. The script then assigns the Reservation Purchaser role at subscription scope and prints '=== Done ===' (:83-97), so a Graph permission denial or a throttle produces a confident success with no credential in place at all. The same swallow is at azure-wif-cli.sh.tmpl:58-61. The GCP script does the compare-and-abort this needs: gcp-wif-cli.sh.tmpl:177-233 re-reads an existing provider and aborts unless issuer, attribute condition, mapping, state and audience all match. Audit finding A06-028.A13b-012 (medium)
A further instance of this pattern, from finding A13b-012, and one that runs Terraform-to-Terraform rather than across formats.
iac/federation/azure-target/terraform/variables.tf:19-33declarescudly_issuer_url,cudly_federated_subjectandcudly_federated_audiencewith novalidationblock on any of the three, and all three feed the federated identity credential unchecked atmain.tf:56-58. The AWS sibling guards the equivalent inputs hard: the issuer ataws-target/terraform/variables.tf:11-15, the audience at:36-39, and the subject at:59-62including the$/*rejection. Azure AD fetches JWKS from whatever host the issuer names and mints tokens for CUDly's app registration for any JWT that host signs with the default subjectcudly-controller, one constant shared across every customer tenant, so a wrong or attacker-controlled issuer URL yields reservation-purchase authority in the customer's subscription. Worth adding to the parity-test set this issue proposes, since a cross-format-only test would not catch it.A06-029 (low)
Another instance of this pattern, from finding A06-029, between sibling shell templates rather than across formats.
CUDLY_FEDERATED_SUBJECTis guarded on two of the three onboarding scripts:aws-wif-cli.sh.tmpl:31-41rejects an empty value and any$,*or whitespace because IAM expands policy variables inside Condition values, andgcp-wif-cli.sh.tmpl:50-61pins a charset plus a 127-character cap because the value lands in a CEL string literal. Both Azure templates interpolate the override straight into the federated-credential JSON heredoc with no check at all (azure-wif-cli.sh.tmpl:26,47-56andazure-wif-deploy.sh.tmpl:61,66-75), where a"closes thesubjectstring and lets sibling keys such asaudiencesbe injected into the request body. Operator-supplied rather than attacker-supplied, so this is defense in depth, but it is the same missing-invariant shape and belongs in the parity check.