azure-swa-exposes-deploy-token
A Static Web App exposes its deployment token as a credential for the CI/CD pipeline identity.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?swa) ==
ApplicationPlatform # Microsoft.Web/staticSites
?token is the SWA deployment token (APIKey) from listSecrets
?pipeline_identity is the CI/CD pipeline service identity (GitHub Actions OIDC subject, Azure Pipelines service connection MI, or federated identity)
emit
| source type | Compute |
|---|---|
| target type | Identity |
| source | ?swa |
| target | ?pipeline_identity |
| state logic | ACTIVE when the SWA exists and the deploy token is not reset/rotated. BLOCKED if token is rotated. |
Narrative
Static Web App {swa.name} exposes its build/deploy token as a long-lived CI/CD credential (accessible via listSecrets/action). Any principal holding this token can authenticate as the CI/CD pipeline identity {pipeline_identity.name}.
Raw rule rules/derived/azure/staticwebapps.yaml
id: azure-swa-exposes-deploy-token
emits: ExposesCredential
description: A Static Web App exposes its deployment token as a credential for the CI/CD pipeline identity.
applies_to:
- azure
match:
- - swa: null
- ContainsSecret
- token: null
where:
- 'node_type(?swa) == ApplicationPlatform # Microsoft.Web/staticSites'
- ?token is the SWA deployment token (APIKey) from listSecrets
- ?pipeline_identity is the CI/CD pipeline service identity (GitHub Actions OIDC subject, Azure Pipelines
service connection MI, or federated identity)
emit:
source_type: Compute
target_type: Identity
source: ?swa
target: ?pipeline_identity
permissions: []
state_logic: ACTIVE when the SWA exists and the deploy token is not reset/rotated. BLOCKED if token
is rotated.
confidence: 0.9
derived_from:
- ?swa ContainsSecret ?token (azure-swa-deploy-token-contains-secret)
false_positive_note: "The deploy token authorizes CDN content pushes as the CI/CD pipeline; it does\
\ not grant ARM RBAC roles or Entra app credentials. The token is a symmetric secret \u2014 rotation\
\ invalidates it (emit BLOCKED or remove). Do not derive CanExecuteAs from this edge alone; cicd-chains\
\ produces CanExecuteAs from the CanModifyCode edge combined with ExecutesAs on a runner, not from\
\ ExposesCredential directly. credential-chains may chain this to CredentialsFor(pipeline_identity)\
\ for identity-centric queries."
narrative: Static Web App {swa.name} exposes its build/deploy token as a long-lived CI/CD credential
(accessible via listSecrets/action). Any principal holding this token can authenticate as the CI/CD
pipeline identity {pipeline_identity.name}.