Skip to content

Security: run-integration-tests exposes all secrets to PR-head code via pull_request_target #1128

Description

@njbrake

Note: this issue was drafted by Claude via back-and-forth with @njbrake. The reasoning and decisions are his; the prose is Claude's.

Summary

The run-integration-tests job in .github/workflows/tests-integration.yaml runs on pull_request_target (when a PR is labeled run-integration-tests), checks out the PR-head code (ref: ${{ github.event.pull_request.head.sha || github.sha }}), and then injects every provider secret into the test step (ANTHROPIC_API_KEY, OPENAI_API_KEY, ... and now OTARI_AI_TOKEN).

That combination is the classic "pwn request" pattern: once a maintainer applies the label, arbitrary code from the PR head runs with full access to all of these secrets, so a malicious PR could exfiltrate them. This predates any single provider; it is a property of the job. Raising it now because the otari platform token (OTARI_AI_TOKEN) carries billing.

Current mitigation

The only gate is the maintainer-applied run-integration-tests label, i.e. it relies on a human reviewing the PR before labeling.

Options to harden

  • Use a GitHub Environment with required reviewers for the secret-bearing job, so each run needs explicit approval.
  • Split the workflow so untrusted PR code never runs in the same job that holds secrets (e.g. build/checkout on pull_request, run the secret step only after maintainer approval on a trusted ref).
  • Or accept the label-gate as the control and document it explicitly, optionally scoping a spend cap on OTARI_AI_TOKEN.

Scope

Affects all secrets in the job, not just otari. Surfaced during the otari e2e work (#1127); CodeRabbit flagged the same on that PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    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