Claude Cursor GitHub Copilot Skill

backstage-scaffolder-template-review

Use this skill when reviewing Backstage Scaffolder software templates. Trigger when the user asks whether a template is safe for developer self-service, whether template RBAC gates are in place, whether input parameters are validated, whether a step action has excessive blast rad

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download vincentchuwaichow-vanguard-frontier-agentic-skills_backstage_backstage-scaffolder-template-review-febe32a.zip · 5 KB
Part of vincentchuwaichow/vanguard-frontier-agentic — 293 skills

Install

skills CLI npx skills add https://github.com/VincentChuWaiChow/vanguard-frontier-agentic/tree/master/skills/backstage/backstage-scaffolder-template-review
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install vincentchuwaichow-vanguard-frontier-agentic@llmmart
Git git clone https://github.com/VincentChuWaiChow/vanguard-frontier-agentic.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole vincentchuwaichow/vanguard-frontier-agentic collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Backstage Scaffolder Template Review

Purpose

Review Backstage Scaffolder Template kind resources for action blast-radius, input parameter injection risk, RBAC permission gate coverage, integration secret scope, catalog entity poisoning via catalog:register, and plaintext secret exposure in output: stanzas. Backstage Scaffolder gives developers a curated UI to trigger powerful backend actions — without RBAC gates and input validation, every authenticated developer effectively has write access to whatever the Scaffolder integration credentials can reach.

Lean operating rules

  • Prefer user-provided sanitized Template YAML as primary evidence; official Backstage docs are the authoritative fallback.
  • Treat any steps: action that provisions real cloud infrastructure (Terraform, Crossplane CRD apply, CloudFormation deploy, kubectl apply) with no RBAC permission gate as a CRITICAL finding.
  • Treat input parameters flowing unsanitized into publish:github.repoUrl, file-path actions, or shell-exec actions as a HIGH finding — path traversal and injection are realistic.
  • Treat publish:github with visibility: public as the default or without an allowedHosts constraint as a HIGH finding.
  • Treat output: stanzas exposing plaintext generated credentials, connection strings, or API keys in the Backstage UI as a HIGH finding.
  • Treat the absence of @backstage/plugin-permission-backend policies for infrastructure-provisioning templates as a HIGH finding — any authenticated Backstage user can trigger them.
  • Treat catalog:register accepting arbitrary user-supplied YAML without server-side entity schema validation as a MEDIUM finding — catalog poisoning overwrites ownership and lifecycle metadata.
  • Keep the answer scoped: report what was reviewed, the evidence level, and exactly which steps or fields triggered each finding.

References

Load these only when needed:

Response minimum

  • Scoped target (Template metadata.name) and evidence level
  • Each steps: action type and its provisioning blast radius
  • Input parameter validation gaps (missing maxLength, pattern, enum)
  • RBAC permission gate verdict (present / absent / partial)
  • Integration secret scope assessment
  • output: stanza exposure assessment
  • Safe next actions and open questions
Files (vanguard-frontier-agentic)
  • references
    • workflow-and-output.md 6.6 KB
      # Workflow and output contract
      
      Use this reference only when performing a full Backstage Scaffolder template review, producing implementation guidance, triaging a scaffolder security incident, or completing a production-readiness pass.
      
      ## Review domains
      
      Check these areas before giving a verdict:
      
      - Template `metadata.name`, `spec.owner`, and namespace scoping
      - Each `steps:` entry: action type, input parameters, and provisioning blast radius
      - Input `parameters:` schema: type enforcement, `maxLength`, `pattern`, `enum`, and data-flow into step inputs
      - RBAC permission gate: presence and scope of `@backstage/plugin-permission-backend` policies for this template
      - Integration secret scope: GitHub PAT, Azure DevOps token, or other credential used by `publish:*` actions
      - `catalog:register` usage: whether registered YAML is user-supplied or template-controlled
      - `output:` stanza: whether plaintext secrets or credentials are surfaced in the Backstage UI
      
      ## Safe workflow
      
      1. **Frame scope**
         - Template name and `spec.owner`:
         - Target environment (dev / staging / production):
         - Backstage version and active plugins:
         - Whether `@backstage/plugin-permission-backend` is installed:
         - Required outcome of this review:
         - Explicit non-goals:
      
      2. **Collect evidence**
         - Prefer user-provided sanitized Template YAML as primary evidence.
         - Confirm Backstage version and installed plugins from `app-config.yaml` or Backstage `package.json`.
         - Label each finding as `user-provided evidence`, `documentation-based`, or `inference`.
      
      3. **Map action blast radius**
         For each `steps[].action`, ask:
         ```
         - What external system does this action write to?
         - What credential does it use and what is that credential's scope?
         - Is there an RBAC permission policy gating this template for that action?
         - Can a user-controlled input reach this action unsanitized?
         ```
         Example: `publish:github` with `repoUrl: ${{ parameters.repoName }}` where `repoName` has no `pattern`
         validation — a value like `../../../sensitive-repo` could traverse the expected org boundary.
      
      4. **Validate input parameter schema**
         Check each parameter field:
         ```yaml
         parameters:
           - title: Repository Name
             properties:
               repoName:
                 type: string
                 # REQUIRED: maxLength to prevent oversized inputs
                 maxLength: 63
                 # REQUIRED: pattern to block path traversal and injection
                 pattern: '^[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$'
         ```
         Missing `maxLength` or `pattern` on fields that flow into `publish:github.repoUrl`,
         `roadiehq:utils:fs:write`, or shell-exec actions is a HIGH finding.
      
      5. **Check RBAC permission gate**
         A permission policy protecting a Terraform-provisioning template looks like:
         ```typescript
         // packages/backend/src/plugins/permission.ts
         if (
           isPermission(request.permission, scaffolderTemplateRules.instantiateTemplate)
         ) {
           if (request.credentials.principal.type === 'user') {
             const groups = await catalogClient.getEntities({
               filter: { kind: 'Group', 'spec.members': request.credentials.principal.userEntityRef }
             });
             const isPlatformEngineer = groups.items.some(g => g.metadata.name === 'platform-engineers');
             return { result: isPlatformEngineer ? AuthorizeResult.ALLOW : AuthorizeResult.DENY };
           }
         }
         ```
         If no policy like this exists for infrastructure-provisioning templates, flag as CRITICAL.
      
      6. **Assess integration secret scope**
         Examine the Backstage `integrations:` config that the template's `publish:*` action uses:
         ```yaml
         # app-config.yaml
         integrations:
           github:
             - host: github.com
               token: ${GITHUB_TOKEN}  # scope: repo (read/write all repos in org)
         ```
         A token with `repo` scope on all org repos means any template using `publish:github`
         can write to any repo in the org. Prefer a scoped GitHub App with per-repo installation.
      
      7. **Review catalog:register usage**
         ```yaml
         steps:
           - id: register
             action: catalog:register
             input:
               repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
               catalogInfoPath: '/catalog-info.yaml'
         ```
         If `catalogInfoPath` or the registered YAML content is user-controlled (not template-generated),
         it can inject arbitrary `spec.owner`, `spec.lifecycle`, or `metadata.annotations` values
         into the catalog — overwriting existing entities' ownership metadata. Flag as MEDIUM.
      
      8. **Inspect output stanza**
         ```yaml
         output:
           links:
             - title: Repository
               url: ${{ steps['publish'].output.remoteUrl }}
           # HIGH: do not surface generated credentials here
           # - title: Database password
           #   url: ${{ steps['create-db'].output.password }}
         ```
         Any `output:` value that contains a generated password, API key, connection string,
         or bearer token is a HIGH finding — it persists in the Backstage task log in plaintext.
      
      9. **Recommend the smallest safe action**
         - Prefer narrowing input validation before adding RBAC, as validation is deploy-free.
         - For RBAC gaps, provide the minimum permission policy snippet.
         - If the safest action is to quarantine the template (mark it `spec.lifecycle: deprecated`
           and alert the platform team), say that plainly.
      
      ## Validation commands
      
      ```bash
      # List all templates in the catalog
      kubectl get templates -n backstage --all-namespaces
      
      # Inspect a specific template
      kubectl get template <name> -n backstage -o yaml
      
      # Check whether permission backend plugin is present
      grep -r 'plugin-permission-backend' packages/backend/package.json
      
      # List Backstage integrations config (sanitize before sharing)
      grep -A5 'integrations:' app-config.yaml
      
      # Enumerate templates with no permission policy annotation
      kubectl get templates -A -o json | jq '.items[] | select(.metadata.annotations["backstage.io/permission-policy"] == null) | .metadata.name'
      ```
      
      ## Output contract
      
      Return this structure:
      
      ```markdown
      # Backstage Scaffolder Template Review: <template-name>
      
      ## Executive verdict
      - Status: SAFE / SAFE WITH RISKS / NOT SAFE / NEEDS EVIDENCE
      - Biggest risk:
      - Evidence level:
      
      ## Scope and assumptions
      - Template name and owner:
      - Backstage version:
      - Permission backend installed:
      - Confirmed:
      - Unknown:
      - Out of scope:
      
      ## Findings
      
      | Severity | Field / Step | Finding | Evidence | Why it matters | Minimum safe action |
      |---|---|---|---|---|---|
      
      ## Action blast radius summary
      
      | Step ID | Action | Blast radius | RBAC gated? |
      |---|---|---|---|
      
      ## Recommended actions
      1. <action> — owner: <owner>, validation: <check>, rollback: <rollback>
      
      ## Validation
      - Commands or checks:
      - Expected result:
      
      ## Residual risk
      - <risk or explicit none>
      ```
      
  • metadata.json 1.2 KB
    {
      "id": "backstage-scaffolder-template-review",
      "name": "Backstage Scaffolder Template Review",
      "type": "skill",
      "provider": "backstage",
      "harnesses": ["codex", "claude-code", "cursor", "gemini", "kiro", "other"],
      "summary": "Review Backstage Scaffolder software templates for action blast-radius, input parameter injection, RBAC gate coverage, secret scope, catalog entity poisoning, and output exposure.",
      "source_type": "original",
      "official_docs": [
        "https://backstage.io/docs/features/software-templates/",
        "https://backstage.io/docs/features/software-templates/writing-templates",
        "https://backstage.io/docs/features/software-templates/builtin-actions",
        "https://backstage.io/docs/permissions/overview",
        "https://backstage.io/docs/integrations/github/github-apps"
      ],
      "security_notes": "Backstage Scaffolder templates without RBAC gate and without input validation allow any developer to trigger infrastructure provisioning actions. Templates that provision cloud resources via Terraform or Crossplane CRDs effectively grant cloud-write to all Backstage users.",
      "last_verified": "2026-05-02",
      "path": "skills/backstage/backstage-scaffolder-template-review",
      "author": "github: VincentChuWaiChow",
      "version": "0.1.0"
    }
    
  • SKILL.md 2.9 KB
    ---
    name: backstage-scaffolder-template-review
    description: Use this skill when reviewing Backstage Scaffolder software templates. Trigger when the user asks whether a template is safe for developer self-service, whether template RBAC gates are in place, whether input parameters are validated, whether a step action has excessive blast radius, or whether template outputs expose secrets.
    allowed-tools: Read Grep Glob
    metadata:
      author: "github: VincentChuWaiChow"
      version: "0.1.0"
      updated: "2026-05-05"
      category: delivery
    ---
    
    # Backstage Scaffolder Template Review
    
    ## Purpose
    
    Review Backstage Scaffolder `Template` kind resources for action blast-radius, input parameter injection risk, RBAC permission gate coverage, integration secret scope, catalog entity poisoning via `catalog:register`, and plaintext secret exposure in `output:` stanzas. Backstage Scaffolder gives developers a curated UI to trigger powerful backend actions — without RBAC gates and input validation, every authenticated developer effectively has write access to whatever the Scaffolder integration credentials can reach.
    
    ## Lean operating rules
    
    - Prefer user-provided sanitized Template YAML as primary evidence; official Backstage docs are the authoritative fallback.
    - Treat any `steps:` action that provisions real cloud infrastructure (Terraform, Crossplane CRD apply, CloudFormation deploy, `kubectl apply`) with no RBAC permission gate as a CRITICAL finding.
    - Treat input parameters flowing unsanitized into `publish:github.repoUrl`, file-path actions, or shell-exec actions as a HIGH finding — path traversal and injection are realistic.
    - Treat `publish:github` with `visibility: public` as the default or without an `allowedHosts` constraint as a HIGH finding.
    - Treat `output:` stanzas exposing plaintext generated credentials, connection strings, or API keys in the Backstage UI as a HIGH finding.
    - Treat the absence of `@backstage/plugin-permission-backend` policies for infrastructure-provisioning templates as a HIGH finding — any authenticated Backstage user can trigger them.
    - Treat `catalog:register` accepting arbitrary user-supplied YAML without server-side entity schema validation as a MEDIUM finding — catalog poisoning overwrites ownership and lifecycle metadata.
    - Keep the answer scoped: report what was reviewed, the evidence level, and exactly which steps or fields triggered each finding.
    
    ## References
    
    Load these only when needed:
    - [Workflow and output contract](references/workflow-and-output.md)
    
    ## Response minimum
    
    - Scoped target (Template `metadata.name`) and evidence level
    - Each `steps:` action type and its provisioning blast radius
    - Input parameter validation gaps (missing `maxLength`, `pattern`, `enum`)
    - RBAC permission gate verdict (present / absent / partial)
    - Integration secret scope assessment
    - `output:` stanza exposure assessment
    - Safe next actions and open questions
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related