T09 · Insecure Skill Coding Practices
- Location
references/github-action-template.yml:59- Finding
Unrelated Deployment Can Be Assigned to the Trusted Staging Alias
- Content
View full analysis
Vulnerability Details
File Location:
references/github-action-template.yml, lines 59–70
Vulnerability Type: Unsafe deployment fallback
Risk Level: HighVulnerable Code
yaml # Fallback to latest READY deployment if [ -z "$DEPLOYMENT_ID" ] || [ "$DEPLOYMENT_ID" = "null" ]; then echo "Falling back to latest READY deployment..." RESPONSE=$(curl -s \ -H "Authorization: Bearer $VERCEL_TOKEN" \ "https://api.vercel.com/v6/deployments?projectId=$VERCEL_PROJECT_ID&limit=5${TEAM_PARAM}") DEPLOYMENT_ID=$(echo "$RESPONSE" \ | jq -r '[(.deployments // [])[] | select(.state=="READY")] | first | .uid // ""') DEPLOYMENT_URL=$(echo "$RESPONSE" \ | jq -r '[(.deployments // [])[] | select(.state=="READY")] | first | .url // ""') fiTechnical Analysis
The workflow initially searches for a READY deployment associated with the triggering commit. If no matching deployment is found within the polling period, however, it falls back to the first READY deployment returned for the project.
The fallback does not verify the deployment's commit SHA, source branch, environment, creator, or relationship to the triggering GitHub Actions run. Consequently, it violates the documented guarantee that the stable staging alias points to the latest
maindeployment. The selected deployment could instead originate from another branch, an older commit, or a contributor-controlled preview deployment.Attack Path
- An attacker or contributor causes a preview deployment from an untrusted branch or commit to reach the READY state.
- A push to
maintriggers the staging-alias workflow. - The corresponding
maindeployment is delayed, fails, or is not returned among the ten deployments queried during polling. - After the polling period expires, the fallback requests recent project deployments.
...[truncated 916 chars]
- Remediation
View remediation
Remediation Suggestions
Remove the unverified fallback and fail closed when the expected deployment cannot be found. The workflow must not update the alias unless it verifies that the deployment belongs to the triggering event.
Recommended hardening measures:
- Require an exact match against the complete
${{ github.sha }}rather than accepting an arbitrary READY deployment. - Verify the source branch is
mainand, where available, validate the repository and deployment environment metadata. - If the expected deployment remains unavailable after the timeout, exit with a nonzero status and leave the existing alias unchanged.
- Increase the polling duration if normal deployments can exceed three minutes, rather than weakening deployment identity checks.
- Check HTTP status codes and Vercel API error responses by using options such as
curl --fail-with-body. - Use a repository-scoped, least-privilege Vercel credential capable only of managing the intended project and alias.
- Consider triggering alias assignment from a verified deployment-completion event instead of inferring completion by selecting from recent deployments.
- Require an exact match against the complete
