Skip to content

GitHub App auth exempts public repos from automatic min-integrity: approved protection even though repo scoping does not address same-repo untrusted content #21955

@samuelkahessay

Description

@samuelkahessay

Context

As of v0.62.3, public repositories get automatic
min-integrity: approved protection unless the workflow sets an explicit guard
policy.

However, when GitHub App auth is configured, gh-aw intentionally skips that
automatic public-repo guard entirely.

That looks like a security-model gap rather than a docs issue or an accidental
regression.

The automatic public-repo guardrail exists to filter issues, pull requests,
comments, and similar content down to authors with push access.

That is a content trust problem inside a repository.

GitHub App auth solves a different problem:

  • which repositories the token can reach
  • how the token is minted and scoped

It does not decide which authors inside a public repository are trusted. A
repo-scoped App token can still read issues and comments from untrusted
contributors in that same repo unless a guard policy filters them.

Problem

For a public-repo workflow with no explicit repos / min-integrity settings:

  • PAT or custom-token flows receive automatic min-integrity: approved
  • GitHub App flows do not

That means the default trust boundary changes based on token type rather than
threat model.

Repo scoping is not a substitute for author-integrity filtering:

  • repo scope answers "which repositories can this token access?"
  • integrity filtering answers "which content inside this repository should the
    agent trust by default?"

Under the current design, public-repo workflows authenticated through a GitHub
App have a weaker default safety posture against same-repo untrusted content
than equivalent workflows using PAT/custom-token auth.

Evidence

Latest release context makes this more important, not less

v0.62.2/v0.62.3 replaced lockdown: true with min-integrity: approved as the
canonical mechanism in release notes and migration guidance.

That matters because the GitHub App exemption now applies to the mainline,
documented guard policy model rather than to a side path or transitional
feature.

Original design motivation was content trust in public repos, not repo scope

#19967 (March 7, 2026) --
@dsyme requested content-level filtering by contributor status for public
repos:

"As a part of defense in depth [...] we should have an option to 'box' or 'soft label' or 'spotlight' textual results returned from the GitHub MCP depending on contributor status"

"Obvs this should be default mode in public repos"

@lpcox responded with the repos/min-integrity guard policy design.

The original request was about which content inside a repository the agent
should trust, not about which repositories the token can reach. The App auth
exemption solves the latter problem but not the former.

v0.62.3 docs still explicitly exempt GitHub App auth from the automatic public-repo guard

From docs/src/content/docs/reference/lockdown-mode.md in v0.62.3:

  • lines 15-24 say public repos automatically get min-integrity: approved
  • those same lines explicitly say the automatic guard policy does not apply
    when a GitHub App token is configured

So the exemption is documented, not just implemented in code.

v0.62.3 compiler code still skips automatic guard-policy generation for GitHub App auth

From pkg/workflow/compiler_github_mcp_steps.go, lines 34-41:

// Skip automatic guard policy detection when a GitHub App is configured.
// GitHub App tokens are already scoped to specific repositories, so automatic
// guard policy detection is not needed -- the token's access is inherently bounded
// by the app installation and the listed repositories.
if hasGitHubApp(githubTool) {
    githubConfigLog.Print("GitHub App configured, skipping automatic guard policy determination (app tokens are already repo-scoped)")
    return
}

The code comment makes the assumption explicit: repo scope is being treated as
sufficient protection.

v0.62.3 environment wiring also suppresses guard-policy env vars under App auth

From pkg/workflow/mcp_environment.go, lines 82-89:

guardPoliciesExplicit := len(getGitHubGuardPolicies(githubTool)) > 0
if !guardPoliciesExplicit && !appConfigured {
    envVars["GITHUB_MCP_GUARD_MIN_INTEGRITY"] = "${{ steps.determine-automatic-lockdown.outputs.min_integrity }}"
    envVars["GITHUB_MCP_GUARD_REPOS"] = "${{ steps.determine-automatic-lockdown.outputs.repos }}"
}

So this is not merely a docs or step-name issue. The runtime configuration that
would enable automatic integrity filtering is intentionally not wired for
GitHub App auth.

The v0.62.3 test suite still encodes the exemption as correct behavior

pkg/workflow/github_mcp_app_token_test.go contains
TestGitHubMCPAppTokenNoLockdownDetectionStep, which asserts that the
determine-automatic-lockdown step must not be generated when a GitHub App
is configured.

That test still passes on v0.62.3:

go test ./pkg/workflow -run TestGitHubMCPAppTokenNoLockdownDetectionStep -count=1

This makes the current behavior an intentional, tested product decision rather
than an incidental side effect.

Current docs are also internally inconsistent

There is a secondary docs problem in v0.62.3:

  • lockdown-mode.md lines 22-24 explicitly exempt GitHub App auth from the
    automatic guard policy
  • but lockdown-mode.md line 41 and faq.md line 245 still say lockdown mode
    is automatically enabled for public repositories when "Additional
    Authentication" is configured
  • github-tools.md line 62 says public repos without explicit guard policy get
    automatic min-integrity: approved even without additional authentication

That inconsistency is not the core bug, but it does show the current design is
hard to reason about and easy for users to misunderstand.

Expected behavior

Public-repo workflows should not lose automatic min-integrity: approved
protection merely because authentication is provided by a GitHub App.

If the security goal is to protect public-repo workflows from untrusted
same-repo content, the default guardrail should depend on repository visibility
and explicit user configuration, not on whether the token is a PAT or a GitHub
App token.

Proposed fix

Apply the automatic public-repo guard policy based on repository visibility +
explicit configuration
, not on token type.

Minimum approach:

  1. Remove the GitHub App exemption from automatic guard-policy generation for
    public repos
  2. Wire GITHUB_MCP_GUARD_MIN_INTEGRITY / GITHUB_MCP_GUARD_REPOS the same
    way under GitHub App auth when no explicit guard policy is configured
  3. Update the GitHub App test coverage to expect automatic public-repo
    protection unless the workflow explicitly sets guard policy values
  4. Clean up the contradictory docs text so users are not told two different
    stories about when protection applies

If maintainers want GitHub App auth to remain exempt, then the docs should
state the tradeoff plainly:

  • GitHub App auth limits repo reach
  • but it removes the automatic public-repo integrity guardrail unless users
    configure min-integrity themselves

Environment

  • Repository observed on: github/gh-aw
  • Latest release verified: v0.62.3
  • Release commit: 458e90f2d0aa4842aa3fb4999d7663bce8b57dd4
  • Release published: 2026-03-20T06:28:51Z
  • Inspection date: 2026-03-20
  • Verification performed: code inspection, docs inspection, and targeted
    upstream test run on tag v0.62.3
  • Relevant docs:
    • docs/src/content/docs/reference/lockdown-mode.md
    • docs/src/content/docs/reference/faq.md
    • docs/src/content/docs/reference/github-tools.md
  • Related issues:
    • #19967 -- original design
      motivation for automatic public-repo content filtering
  • Relevant code:
    • pkg/workflow/compiler_github_mcp_steps.go (lines 34-41)
    • pkg/workflow/mcp_environment.go (lines 82-89)
    • pkg/workflow/github_mcp_app_token_test.go (lines 257-307)

Metadata

Metadata

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions