Skip to content

[uk-ai-resilience] [security] Fix GraphQL ID injection in project_command.go (Semgrep #627/#628, CWE-89) #43240

Description

@github-actions

Summary

Semgrep alerts #627 and #628 (both created 2026-06-16, open 17 days) flag unescaped GraphQL ID injection in two mutations in the project command.

File: pkg/cli/project_command.go lines 295 and 368
Rule: workflow-graphql-id-unescaped (CWE-89 — injection)
Severity: WARNING (defense-in-depth gap)

Tier & Risk Scoring

Dimension Score Notes
Exposure amplification 3 CLI command used for project management; affects any user invoking project commands
Patchability 2 Two call sites; wrap with existing helper or parameterise
Detectability 3 GitHub API node IDs are currently opaque; special chars unlikely but not impossible
Operational fragility 3 Malformed query could fail silently or be exploited if ID format changes
Ownership confidence 4 Active CLI team ownership
Aggregate 15 Tier B — Open With Conditions

SLA: High — fix within 7 days.

Root Cause

Alert #627createProject() (line 295)

ownerId is injected directly into the GraphQL mutation string via fmt.Sprintf without escapeGraphQLString(). The title argument on the same call (line 303) is already escaped — creating an inconsistency. If GitHub ever returns a node ID with special characters, this could trigger GraphQL injection.

Alert #628linkProjectToRepo() (line 368)

Both projectId and repositoryId are injected without escapeGraphQLString(). These values come from prior API calls, but are not escaped before interpolation into the mutation string.

Recommended Fix

Option A — wrap with existing helper:

// line 295 — createProject()
query := fmt.Sprintf(`mutation { createProject(input: {ownerId: "%s", title: "%s"}) { ... } }`,
    escapeGraphQLString(ownerId),  // add escape
    escapeGraphQLString(title))

// line 368 — linkProjectToRepo()
query := fmt.Sprintf(`mutation { linkProjectV2ToRepository(input: {projectId: "%s", repositoryId: "%s"}) { ... } }`,
    escapeGraphQLString(projectId),    // add escape
    escapeGraphQLString(repositoryId)) // add escape

Option B — parameterise via GraphQL variables (preferred):

gh api graphql -f query='mutation($ownerId:ID!,$title:String!){createProject(input:{ownerId:$ownerId,title:$title}){...}}' \
  -f ownerId="$ownerId" -f title="$title"

Governance Context

Identified by the UK AI Open Code Risk & Resilience Governance scan (2026-07-03). See discussion report for full tier classification and remediation queue.

References: Semgrep alert #627 · Semgrep alert #628 · run 28671336499

Generated by UK AI Operational Resilience · 91.2 AIC · ⌖ 8.39 AIC · ⊞ 5.2K ·

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions