Give each CI agent only the tool access its job needs, and use workload identity to obtain short-lived credentials when the receiving service supports it. If you must use a persistent agent key, store it as a restricted CI secret and expose it only to the credential-bearing step; that limits distribution but does not make the key short-lived. Keep upstream database passwords and service tokens behind the tool endpoint, and verify that unauthorized and revoked calls fail.
Decide which runs may receive company access
Consider a failed-build investigator that reads a build report and retrieves the associated incident ticket. It needs those two records, not deployment permissions or a production database password. Before configuring the agent, decide whether it may run on merged code, manually approved jobs, or incoming pull requests.
GitHub's secrets documentation says ordinary fork-triggered workflows do not receive secrets other than GITHUB_TOKEN. Its secure-use reference warns that combining privileged pull_request_target or workflow_run execution with untrusted checkout can compromise the repository. Do not change triggers merely to make a missing credential available.
For this investigator, use a trusted workflow and a separate job for company access. Let untrusted tests produce evidence without that credential. Treat their logs and artifacts as input to inspect, and never execute scripts recovered from them in the privileged job.
A step-level environment variable limits accidental propagation. It does not isolate the secret from hostile code already running on the same runner. Review installation steps, local actions and agent startup configuration as part of the credential boundary.
Choose an actual credential lifetime
GitHub's OIDC documentation describes exchanging a workflow identity token for a short-lived access token at a supporting provider. This requires a trust relationship and validation by that provider. A GitHub identity token is not automatically a bearer token your MCP endpoint accepts.
Where supported, have the issuer validate the intended audience and the authorized repository, workflow and execution context before issuing narrowly scoped access. Use the documented claims for your repository rather than copying another repository's subject string. Grant id-token: write only to the job performing the exchange; GitHub's workflow reference identifies that permission as the ability to fetch an OIDC token.
Set the issued credential's lifetime to cover the expected investigation and bounded retries. Check its expiry at the receiving service. A ten-minute job timeout stops the job; it does not change the expiry of an independently issued key.
If the endpoint only accepts persistent keys, give this workflow a dedicated key and rotation owner. Store it in CI, document its remaining lifetime, and test revocation. See assigning separate scoped keys to agents before sharing one across repositories.
Scope the identity to the investigation
Write an access contract before choosing client flags: this job may retrieve build reports for this repository and read incident tickets from the relevant project. It may not edit tickets, trigger deployments or retrieve unrelated customer records. Enforce those restrictions at the tool service and upstream authorization layer.
For the example below, assume your MCP service exposes a read-only get_build_report tool. That name is an illustrative service contract, not a standard MCP tool. Substitute a verified tool from your server. Client permission rules control what the harness attempts; server authorization must still reject requests outside the identity's scope.
Keep the model-provider credential separate from the tool credential. A key that pays for inference should not authenticate to your build-report service. Similarly, reducing GITHUB_TOKEN permissions does not reduce the rights of an external MCP key. Inventory and scope each credential independently.
Load an explicit MCP configuration
Claude Code documents HTTP MCP configuration and environment expansion in authentication headers. Use a dedicated variable for the tool token. This template contains a placeholder endpoint and a variable reference, so it can be reviewed without distributing a live secret:
{
"mcpServers": {
"ci": {
"type": "http",
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer ${CI_MCP_TOKEN}"
}
}
}
}Generate this file from trusted workflow configuration, or keep a reviewed template on the protected branch. Do not accept the endpoint URL or configuration file from the pull request being investigated. Otherwise a substituted endpoint could receive the token.
Anthropic documents --bare for scripted execution: it skips automatic discovery of project instructions, hooks, plugins and MCP servers, while accepting servers supplied through --mcp-config. Use a tested Claude Code version with these documented options. An unattended run should not inherit a developer's login, shell tools or project hooks by accident.
Expose the key only when the agent runs
The following is a step fragment for an existing trusted job with Claude Code already installed. Configure that job with environment: ci-tools, timeout-minutes: 10 and permissions: {} if it needs no GitHub API access. Store both credentials as environment secrets and configure the available branch restrictions and approval rules. GitHub documents that environment secrets reach only referencing jobs, after any required approval.
- name: Investigate this build
shell: bash
env:
CI_MCP_TOKEN: ${{ secrets.CI_MCP_TOKEN }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
set -euo pipefail
: "${CI_MCP_TOKEN:?Missing tool credential}"
: "${ANTHROPIC_API_KEY:?Missing model credential}"
umask 077
config="$RUNNER_TEMP/.mcp.json"
trap 'rm -f "$config"' EXIT
cat > "$config" <<'JSON'
{
"mcpServers": {
"ci": {
"type": "http",
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer ${CI_MCP_TOKEN}"
}
}
}
}
JSON
claude --bare -p \
"Retrieve the build report for run $GITHUB_RUN_ID. Cite its identifier; report unavailable evidence explicitly." \
--mcp-config "$config" \
--strict-mcp-config \
--tools "" \
--allowedTools "mcp__ci__get_build_report" \
--permission-mode dontAsk \
--no-session-persistenceReplace the example URL and tool name, and ensure your report service understands GitHub run identifiers. The CLI reference distinguishes disabling built-in tools with --tools from approving MCP calls with --allowedTools. This example uses stored keys; an OIDC integration would obtain the tool token through its provider-specific exchange instead.
Using SPYN3 for the CI connection
SPYN3 provides one MCP endpoint per workspace at https://api.spyn3.com/agent/mcp. A CI agent holds a SPYN3 key while upstream credentials remain envelope-encrypted in the workspace. Limit its key to the required sources and call:tools; upstream tools count as writes unless marked read-only, and writes need call:write_tools. Proxied calls are audit-logged, and revoking a key takes effect on the next call. Create a dedicated CI key and test its permitted calls before adding it to CI secrets.
Test denial, expiry and missing evidence
Before scheduling the investigator, run acceptance checks against a test source:
- Retrieve a known report and confirm the audit record identifies the intended source and tool.
- Request a report outside the permitted repository and attempt a write. Both must fail at the service, independently of the prompt.
- Revoke the test credential and confirm the next call fails. For an expiring credential, repeat after expiry.
- Remove the CI secret and confirm the shell exits before starting the agent.
- Disconnect the report service and confirm the investigation reports missing evidence rather than presenting an unsupported diagnosis.
Check cancellation separately: stop a run, then verify whether its credential still works. Cleanup cannot be your only revocation mechanism. Set an issuer-enforced expiry where available, and retain an explicit revocation procedure for persistent keys.
Do not enable shell tracing around credentials or upload the runner's home directory as a diagnostic artifact. GitHub warns that automatic secret redaction is not guaranteed. Keep investigation output limited to information suitable for CI logs.
Use the leaked-key blast-radius guide to review what a stolen CI token could reach. Then document where to revoke agent access alongside the workflow, so the next operator can stop calls without reconstructing the pipeline.
Built for the next step
One key per sandbox
Point every VM or sandbox at one endpoint with its own scoped key; upstream secrets stay in the workspace.
Read the developer guideSPYN3 is a consolidated MCP layer: one hosted endpoint in front of every system you connect — MCP servers, Postgres, REST APIs, Google Drive — with tools foldered by source and read/write permissions per key. Switching agents means moving one URL. Free plan available; current capabilities are documented on the product facts page.
Sources
- GitHub Docs: Using secrets in GitHub Actions — Secret references in step environment variables and restrictions on secrets in fork-triggered workflows.. Verified 27 Oct 2026
- GitHub Docs: OpenID Connect — Workflow identity tokens, provider trust and claim validation, and exchange for short-lived provider credentials.. Verified 27 Oct 2026
- GitHub Docs: Workflow syntax for GitHub Actions — Job environments, timeouts, step environment variables, permissions: {}, and id-token: write.. Verified 27 Oct 2026
- GitHub Docs: Secure use reference — Risks of privileged workflows processing untrusted code, runner compromise, least privilege and limitations of log redaction.. Verified 27 Oct 2026
- GitHub Docs: Deployments and environments — Environment secret access, required approval, deployment branch restrictions and feature availability.. Verified 27 Oct 2026
- Anthropic docs: Claude Code MCP setup — Claude Code MCP commands, scopes, transports and JSON configuration. Verified 27 Oct 2026
- Anthropic: Run Claude Code programmatically — Print mode, bare mode configuration discovery boundaries, API-key authentication and noninteractive permission behavior.. Verified 27 Oct 2026
- Anthropic: Claude Code CLI reference — Explicit MCP configuration, strict MCP loading, built-in tool restriction, MCP permission rules and disabled session persistence.. Verified 27 Oct 2026
