A GitHub codespace is a cloud machine that holds a live GitHub token, your development secrets as environment variables and whatever code the repository's dev container tells it to run, so a careless configuration turns a convenient editor into a credential store open to the wrong people. Codespaces are increasingly where AI coding agents and contractors work, which raises the stakes on what the environment can reach. This guide explains how identity, tokens, secrets, port forwarding and prebuilds work in GitHub Codespaces, which organisation settings and policies control them, what the audit log records and what a hardened baseline looks like. It is written for GitHub organisation owners, platform engineers and AppSec teams; workstation-wide controls are covered in the Developer Workstation and IDE Security Guide.
This is an independent guide from NHI Mgmt Group, based on GitHub's public documentation as of November 2026. It is not sponsored or reviewed by GitHub. Product features change, so confirm settings against GitHub's current documentation.
Key takeaways
- Every codespace carries a user token.
GITHUB_TOKENis a signed token representing the user, scoped to the source repository and any extra repositories the user authorises, and reissued on every create and restart. - Secrets become environment variables. Any process in the codespace, including a dependency's install script or an extension, can read them, so scope each secret to the fewest repositories.
- Public ports have no authentication. Ports are private by default, but a port set to Public is reachable by anyone on the internet; organisation policies can forbid it.
- The dev container is code you run.
devcontainer.jsoncan install extensions and executepostCreateCommand, and can request extra repository permissions, so review it like a workflow file. - Policies only bind organisation-billed codespaces. Codespaces users create at their own expense are not covered, so access settings and billing ownership are part of the security design.
How identity and access work in GitHub Codespaces
GitHub runs each codespace on its own newly created virtual machine, and states that two codespaces are never co-located on the same VM. Each has its own virtual network: firewalls block inbound internet connections and traffic between codespaces, while outbound connections are allowed. Only the creator can connect, through a TLS-encrypted tunnel authenticated with their GitHub identity. A restart moves the codespace to a new VM with current security updates.
The identity inside the codespace is the user's. GitHub issues a new token each time the codespace is created or restarted, exposes it as GITHUB_TOKEN and lets it expire automatically. Its reach depends on the user's access:
| User's access to source repository | Token scope | Notes |
|---|---|---|
| Write | Read and write to that repository | Can push directly |
| Read only | Clone only, then read and write on a fork | A commit or new branch triggers automatic forking or links an existing fork |
Additional repositories authorised from devcontainer.json | The permissions requested, up to what the user already holds | User sees a consent prompt; choice is remembered until the request changes |
| Publishing from a template | Read and write to the new repository | Applies to the repository created on publish |
Who may create codespaces at all is set under organisation Settings > Codespaces > General, "Codespaces access": all users, or selected members and collaborators. To create a codespace for an organisation repository a user needs write access, or read access with forking permitted. On the Free plan an organisation cannot disable Codespaces for private repositories, and codespaces are always available in public repositories. Removing a user's access immediately blocks them from opening existing codespaces from the organisation's private repositories; removed codespaces are kept for 7 days and then permanently deleted.
Admin roles and privileged access
Codespaces adds no separate admin role. Privilege comes from existing GitHub roles, and each one controls a different lever.
| Role | Codespaces levers | Why it is sensitive |
|---|---|---|
| Organisation owner | Codespaces access, billing ownership, policies (machine types, port visibility, idle timeout, retention, base image, maximum codespaces per user), organisation Codespaces secrets | Can widen who gets environments and which secrets they receive |
| Repository admin | Prebuild configurations, repository Codespaces secrets | Prebuild secrets are available to anyone who creates a codespace from the repository |
| Anyone with write access | Edit .devcontainer/devcontainer.json, Dockerfile, lifecycle scripts | Changes code that runs in every new codespace and the permissions it requests |
| Codespace user | Port visibility, personal secrets, Settings Sync, dotfiles | Can expose a port publicly or sync settings from untrusted sources |
- Protect the dev container path: add
.devcontainer/to CODEOWNERS and require review through branch protection or rulesets, so a change topostCreateCommandorcustomizations.codespaces.repositoriescannot land unreviewed. See the GitHub and GitHub Actions Security Guide. - Keep owner seats few: policies and organisation secrets are owner functions, so the owner count is a direct measure of who can weaken the Codespaces baseline. The GitHub Organisation Security Checklist covers owner hygiene.
Integrations, API tokens and service accounts
Codespaces secrets
Development environment secrets exist at user, repository and organisation level. When the same name exists at more than one level, the lowest level wins, so a repository secret overrides an organisation secret. A user can hold up to 100 secrets of up to 48 KB each, names cannot start with GITHUB_, and each secret has a "Repository access" list.
- Runtime exposure: secrets are exported as environment variables in the terminal, SSH sessions and dev container lifecycle scripts. They are not available at build time in a Dockerfile or custom entry point, or within a dev container feature. New values apply after a stop and restart.
- Write access gate: secrets are not copied if the user does not have write access to the codespace's repository, and are not injected into a codespace created from another person's fork pull request. This protects against a contributor's code reading maintainers' secrets.
- Prebuild secrets are shared: prebuilds can use repository or organisation Codespaces secrets, and anyone who creates a codespace from the repository can access those secrets. User secrets are not available during prebuild creation.
- Prefer federation over static keys: a cloud access key stored as a Codespaces secret is a long-lived non-human credential readable by any process in the environment. Use short-lived credentials where the target supports them and a dedicated, least-privileged identity per repository. See the Secrets Management Guide.
Cross-repository permissions
A dev container can request extra access under customizations.codespaces.repositories, per repository, with permissions such as contents, issues, pull_requests, packages (read only) and workflows (write only), or the shortcuts read-all and write-all. A wildcard such as my_org/* grants access to every repository in the organisation, though prebuilds must list repositories individually. Requests can only reference repositories under the same account or organisation, and users can only authorise permissions they already hold. Changes apply to codespaces created after the commit, not to existing ones. A write-all wildcard turns one token into organisation-wide write access, so treat it as a review blocker. When an incident involves a leaked token, the steps in How to revoke a leaked GitHub personal access token and check what it touched apply equally to tokens taken from a codespace.
Port forwarding and prebuilds
| Port visibility | Who can reach it | Authentication |
|---|---|---|
| Private (default) | The creator only | GitHub sign-in; access cookie expires after 3 hours |
| Public within organization | Members of the same organisation | GitHub sign-in |
| Public | Anyone on the internet | None |
Forwarded ports use the domain in GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN (for example app.github.dev). A public port reverts to private when it is removed and re-added or when the codespace restarts, but while public it exposes whatever is listening, often a development server with debug routes and seeded credentials. Organisation owners can restrict port visibility with a policy constraint.
Prebuilds run as GitHub Actions workflows and can only be configured by repository admins. Triggers are every push (default), on configuration change, or scheduled; scheduled and configuration-only triggers can leave codespaces on stale dependencies. Retention keeps 1 to 5 prebuild versions (default 2), regions can be limited, and "Disable prebuild optimization" stops codespaces being created from a prebuild while the latest workflow has failed or is still running.
Logging and detection
The organisation audit log has a codespaces category. Stream it to your SIEM alongside repository and secret events; the GitHub Audit Log Detection Guide covers streaming and query patterns.
| Event | Meaning | Detection use |
|---|---|---|
codespaces.allow_permissions | Codespace launched with custom permissions from devcontainer.json | Alert on new repositories requesting cross-repository write |
codespaces.create, codespaces.start_environment | Codespace created or started | Unusual volume, departed users, odd hours |
codespaces.connect | Credentials for a codespace refreshed | Correlate with token use from unexpected IPs |
codespaces.export_environment | Codespace exported to a branch | Unexpected code movement |
codespaces.policy_group_created, _updated, _deleted | Policy changes | Any change outside the change process, especially port visibility |
codespaces.trusted_repositories_access_update | A user changed Codespaces access and security settings | Review trust list widening |
codespaces.business_enablement_updated | Enterprise ownership setting changed | Billing ownership affects which policies apply |
Relevant ATT&CK techniques for detection mapping are T1528 Steal Application Access Token for theft of GITHUB_TOKEN, T1552.001 Credentials In Files for secrets written to disk or dotfiles, and T1195.002 Compromise Software Supply Chain for malicious dependencies and dev container changes.
Metrics:
- Number of public forwarded ports observed, target zero where policy allows none.
- Percentage of organisation Codespaces secrets scoped to selected repositories rather than all.
- Repositories whose dev container requests
write-allor wildcard permissions, target zero. - Share of active codespaces billed to the organisation and therefore bound by policy.
- Policy change events reviewed within one working day.
Hardening baseline
- Decide who and who pays: set Codespaces access to selected members and collaborators, and make the organisation the billing owner for private repositories so policies apply.
- Create a baseline policy for all repositories: restrict port visibility (private, or within organisation), set an idle timeout and retention period, cap maximum codespaces per user and limit machine types. Pilot on selected repositories first; roll back by editing or deleting the policy.
- Restrict base images to an approved, maintained image list where your teams can live with it.
- Review dev containers: CODEOWNERS on
.devcontainer/, no wildcard orwrite-allrequests, lifecycle commands pinned to known scripts, extensions limited to trusted publishers. - Scope secrets: move organisation secrets from all repositories to selected ones, keep prebuild secrets non-sensitive, and replace static cloud keys with short-lived credentials.
- Tune prebuilds: keep the every push trigger for actively developed repositories, limit regions and enable "Disable prebuild optimization" where stale environments are a risk.
- Educate users: keep Settings Sync off or limited to trusted repositories, open only trusted repositories, and never set a port to Public for anything holding data or credentials.
- Monitor: stream the audit log and alert on the events above.
When AI coding agents run inside codespaces they inherit the same token and secrets; scope them as you would a contractor. See the AI Coding Agents Security Guide.
Small teams and large enterprises
- Small organisations: on the Free plan Codespaces cannot be disabled for private repositories, so the practical controls are repository-scoped secrets, dev container review and user guidance on ports. Moving to a paid plan is what unlocks access settings and policies.
- Large organisations: use one baseline policy for all repositories plus stricter policies for selected repositories that handle regulated data, such as private-only ports and short retention. Note that a policy containing "Maximum codespaces per user" always applies to all repositories, so keep that constraint in the baseline policy rather than a targeted one.
- Contractors and agents: grant read access with forking where possible, so their codespaces get no repository secrets and push only to forks for review.
Common misconfigurations
- Organisation secrets shared with all repositories: any repository with a dev container, including a test project, receives production credentials as environment variables.
- Malicious dependencies reading the environment: install hooks run inside the codespace with full access to its variables. The Shai-Hulud npm worm used a
preinstallscript to harvest environment variables and credential files on developer machines and CI runners, exactly the material a codespace holds. - Public ports for demos: a development server shared publicly with no authentication, sometimes with admin routes enabled.
- Wildcard repository permissions:
my_org/*withwrite-allin a popular template, so every user who accepts the prompt hands the codespace token organisation-wide write. - User-billed codespaces outside policy: billing left with users means the organisation's port, timeout and image constraints never apply.
- Secrets in prebuilds: sensitive values given to prebuilds become available to everyone who can create a codespace from the repository.
Framework mapping
| Control area | NIST SP 800-53 Rev. 5 | NIST CSF 2.0 | Codespaces implementation |
|---|---|---|---|
| Least privilege | AC-6 | PR.AA-05 | Repository-scoped secrets, no wildcard permissions, selected users only |
| Boundary protection | SC-7 | PR.PS-01 | Port visibility policy |
| Authenticator management | IA-5 | PR.AA-05 | Short-lived credentials over static keys, secret rotation |
| Configuration and software control | CM-6, CM-11 | PR.PS-01 | Base image policy, reviewed dev containers, trusted extensions |
| Logging and review | AU-2, AU-6 | PR.PS-04 | Audit log streaming and alerts on codespaces.* events |
| Supply chain risk | SR-3 | GV.SC-07 | Dependency vetting and dev container review |
Practitioner checklist
- Limit Codespaces access to selected members and collaborators.
- Make the organisation the billing owner for private repositories so policies apply.
- Apply a policy restricting port visibility, idle timeout, retention, machine types and maximum codespaces per user.
- Scope every organisation and repository Codespaces secret to selected repositories.
- Keep sensitive values out of prebuild secrets.
- Protect
.devcontainer/with CODEOWNERS and block wildcard orwrite-allpermission requests. - Replace static cloud keys in secrets with short-lived credentials.
- Stream the audit log and alert on
codespaces.allow_permissionsand policy changes. - Tell users to decline extra permission prompts from repositories they do not trust.
Standards and references
- GitHub Docs: Security in GitHub Codespaces
- GitHub Docs: Managing repository access for your organization's codespaces
- GitHub Docs: Restricting access to machine types
- GitHub Docs: Managing your account-specific secrets for GitHub Codespaces
- GitHub Docs: Configuring prebuilds
- GitHub Docs: Default environment variables for your codespace
- GitHub Docs: Audit log events for your organization
- NIST: SP 800-53 Rev. 5
Related NHI Mgmt Group resources: Developer Workstation and IDE Security Guide · GitHub and GitHub Actions Security Guide · GitHub Audit Log Detection Guide · AI Coding Agents Security Guide